blob: 34f6fb72f2bc61c9617cb02f17d37477692d0ccc [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,
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200193 ALC662_AUTO,
194 ALC662_MODEL_LAST,
195};
196
Kailang Yangdf694da2005-12-05 19:42:22 +0100197/* ALC882 models */
198enum {
199 ALC882_3ST_DIG,
200 ALC882_6ST_DIG,
Takashi Iwai4b146cb2006-07-28 14:42:36 +0200201 ALC882_ARIMA,
Kailang Yangbdd148a2007-05-08 15:19:08 +0200202 ALC882_W2JC,
Kailang Yang272a5272007-05-14 11:00:38 +0200203 ALC882_TARGA,
204 ALC882_ASUS_A7J,
Takashi Iwai914759b2007-09-06 14:52:04 +0200205 ALC882_ASUS_A7M,
Tobin Davis9102cd12006-12-15 10:02:12 +0100206 ALC885_MACPRO,
Takashi Iwai87350ad2007-08-16 18:19:38 +0200207 ALC885_MBP3,
Kacper Szczesniak41d55452009-05-07 12:47:43 +0200208 ALC885_MB5,
Nicola Fagnanic54728d2007-07-19 23:28:52 +0200209 ALC885_IMAC24,
Kailang Yang272a5272007-05-14 11:00:38 +0200210 ALC882_AUTO,
Kailang Yangdf694da2005-12-05 19:42:22 +0100211 ALC882_MODEL_LAST,
212};
213
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200214/* ALC883 models */
215enum {
216 ALC883_3ST_2ch_DIG,
217 ALC883_3ST_6ch_DIG,
218 ALC883_3ST_6ch,
219 ALC883_6ST_DIG,
Kailang Yangccc656c2006-10-17 12:32:26 +0200220 ALC883_TARGA_DIG,
221 ALC883_TARGA_2ch_DIG,
Vladimir Avdoninbab282b92006-08-22 13:31:58 +0200222 ALC883_ACER,
Tobin Davis2880a862007-08-07 11:50:26 +0200223 ALC883_ACER_ASPIRE,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +0800224 ALC888_ACER_ASPIRE_4930G,
Tobin Davisc07584c2006-10-13 12:32:16 +0200225 ALC883_MEDION,
Kailang Yangea1fb292008-08-26 12:58:38 +0200226 ALC883_MEDION_MD2,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +0100227 ALC883_LAPTOP_EAPD,
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200228 ALC883_LENOVO_101E_2ch,
Kailang Yang272a5272007-05-14 11:00:38 +0200229 ALC883_LENOVO_NB0763,
Kailang Yang189609a2007-08-20 11:31:23 +0200230 ALC888_LENOVO_MS7195_DIG,
Kailang Yange2757d52008-08-26 13:17:46 +0200231 ALC888_LENOVO_SKY,
Kailang Yangea1fb292008-08-26 12:58:38 +0200232 ALC883_HAIER_W66,
Claudio Matsuoka4723c022007-07-13 14:36:19 +0200233 ALC888_3ST_HP,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +0100234 ALC888_6ST_DELL,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +0100235 ALC883_MITAC,
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +0100236 ALC883_CLEVO_M720,
Jiang zhefb97dc62008-03-06 11:07:11 +0100237 ALC883_FUJITSU_PI2515,
Vincent Petryef8ef5f2008-11-23 11:31:41 +0800238 ALC888_FUJITSU_XA3530,
Jiang zhe17bba1b2008-06-04 12:11:07 +0200239 ALC883_3ST_6ch_INTEL,
Kailang Yange2757d52008-08-26 13:17:46 +0200240 ALC888_ASUS_M90V,
241 ALC888_ASUS_EEE1601,
Wu Fengguang3ab90932008-11-17 09:51:09 +0100242 ALC1200_ASUS_P5Q,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200243 ALC883_AUTO,
244 ALC883_MODEL_LAST,
245};
246
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -0200247/* styles of capture selection */
248enum {
249 CAPT_MUX = 0, /* only mux based */
250 CAPT_MIX, /* only mixer based */
251 CAPT_1MUX_MIX, /* first mux and other mixers */
252};
253
Kailang Yangdf694da2005-12-05 19:42:22 +0100254/* for GPIO Poll */
255#define GPIO_MASK 0x03
256
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200257/* extra amp-initialization sequence types */
258enum {
259 ALC_INIT_NONE,
260 ALC_INIT_DEFAULT,
261 ALC_INIT_GPIO1,
262 ALC_INIT_GPIO2,
263 ALC_INIT_GPIO3,
264};
265
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266struct alc_spec {
267 /* codec parameterization */
Kailang Yangdf694da2005-12-05 19:42:22 +0100268 struct snd_kcontrol_new *mixers[5]; /* mixer arrays */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 unsigned int num_mixers;
Takashi Iwaif9e336f2008-10-31 16:37:07 +0100270 struct snd_kcontrol_new *cap_mixer; /* capture mixer */
Takashi Iwai45bdd1c2009-02-06 16:11:25 +0100271 unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272
Kailang Yangdf694da2005-12-05 19:42:22 +0100273 const struct hda_verb *init_verbs[5]; /* initialization verbs
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200274 * don't forget NULL
275 * termination!
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200276 */
277 unsigned int num_init_verbs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278
Takashi Iwai16ded522005-06-10 19:58:24 +0200279 char *stream_name_analog; /* analog PCM stream */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 struct hda_pcm_stream *stream_analog_playback;
281 struct hda_pcm_stream *stream_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +0100282 struct hda_pcm_stream *stream_analog_alt_playback;
283 struct hda_pcm_stream *stream_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200285 char *stream_name_digital; /* digital PCM stream */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286 struct hda_pcm_stream *stream_digital_playback;
287 struct hda_pcm_stream *stream_digital_capture;
288
289 /* playback */
Takashi Iwai16ded522005-06-10 19:58:24 +0200290 struct hda_multi_out multiout; /* playback set-up
291 * max_channels, dacs must be set
292 * dig_out_nid and hp_nid are optional
293 */
Takashi Iwai63300792008-01-24 15:31:36 +0100294 hda_nid_t alt_dac_nid;
Takashi Iwai6a05ac42009-02-13 11:19:09 +0100295 hda_nid_t slave_dig_outs[3]; /* optional - for auto-parsing */
Takashi Iwai8c441982009-01-20 18:30:20 +0100296 int dig_out_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297
298 /* capture */
299 unsigned int num_adc_nids;
300 hda_nid_t *adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100301 hda_nid_t *capsrc_nids;
Takashi Iwai16ded522005-06-10 19:58:24 +0200302 hda_nid_t dig_in_nid; /* digital-in NID; optional */
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -0200303 int capture_style; /* capture style (CAPT_*) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304
305 /* capture source */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200306 unsigned int num_mux_defs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 const struct hda_input_mux *input_mux;
308 unsigned int cur_mux[3];
309
310 /* channel model */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100311 const struct hda_channel_mode *channel_mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 int num_channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200313 int need_dac_fix;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314
315 /* PCM information */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100316 struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */
Takashi Iwai41e41f12005-06-08 14:48:49 +0200317
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200318 /* dynamic controls, init_verbs and input_mux */
319 struct auto_pin_cfg autocfg;
Takashi Iwai603c4012008-07-30 15:01:44 +0200320 struct snd_array kctls;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -0200321 struct hda_input_mux private_imux[3];
Takashi Iwai41923e42007-10-22 17:20:10 +0200322 hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
Takashi Iwai834be882006-03-01 14:16:17 +0100323
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100324 /* hooks */
325 void (*init_hook)(struct hda_codec *codec);
326 void (*unsol_event)(struct hda_codec *codec, unsigned int res);
327
Takashi Iwai834be882006-03-01 14:16:17 +0100328 /* for pin sensing */
329 unsigned int sense_updated: 1;
330 unsigned int jack_present: 1;
Takashi Iwaibec15c32008-01-28 18:16:30 +0100331 unsigned int master_sw: 1;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200332
Takashi Iwaie64f14f2009-01-20 18:32:55 +0100333 /* other flags */
334 unsigned int no_analog :1; /* digital I/O only */
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200335 int init_amp;
Takashi Iwaie64f14f2009-01-20 18:32:55 +0100336
Takashi Iwai2134ea42008-01-10 16:53:55 +0100337 /* for virtual master */
338 hda_nid_t vmaster_nid;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200339#ifdef CONFIG_SND_HDA_POWER_SAVE
340 struct hda_loopback_check loopback;
341#endif
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +0200342
343 /* for PLL fix */
344 hda_nid_t pll_nid;
345 unsigned int pll_coef_idx, pll_coef_bit;
Kailang Yangdf694da2005-12-05 19:42:22 +0100346};
347
348/*
349 * configuration template - to be copied to the spec instance
350 */
351struct alc_config_preset {
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200352 struct snd_kcontrol_new *mixers[5]; /* should be identical size
353 * with spec
354 */
Takashi Iwaif9e336f2008-10-31 16:37:07 +0100355 struct snd_kcontrol_new *cap_mixer; /* capture mixer */
Kailang Yangdf694da2005-12-05 19:42:22 +0100356 const struct hda_verb *init_verbs[5];
357 unsigned int num_dacs;
358 hda_nid_t *dac_nids;
359 hda_nid_t dig_out_nid; /* optional */
360 hda_nid_t hp_nid; /* optional */
Wu Fengguangb25c9da2009-02-06 15:02:27 +0800361 hda_nid_t *slave_dig_outs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100362 unsigned int num_adc_nids;
363 hda_nid_t *adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100364 hda_nid_t *capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +0100365 hda_nid_t dig_in_nid;
366 unsigned int num_channel_mode;
367 const struct hda_channel_mode *channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200368 int need_dac_fix;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200369 unsigned int num_mux_defs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100370 const struct hda_input_mux *input_mux;
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100371 void (*unsol_event)(struct hda_codec *, unsigned int);
372 void (*init_hook)(struct hda_codec *);
Takashi Iwaicb53c622007-08-10 17:21:45 +0200373#ifdef CONFIG_SND_HDA_POWER_SAVE
374 struct hda_amp_list *loopbacks;
375#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376};
377
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378
379/*
380 * input MUX handling
381 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200382static int alc_mux_enum_info(struct snd_kcontrol *kcontrol,
383 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384{
385 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
386 struct alc_spec *spec = codec->spec;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200387 unsigned int mux_idx = snd_ctl_get_ioffidx(kcontrol, &uinfo->id);
388 if (mux_idx >= spec->num_mux_defs)
389 mux_idx = 0;
390 return snd_hda_input_mux_info(&spec->input_mux[mux_idx], uinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391}
392
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200393static int alc_mux_enum_get(struct snd_kcontrol *kcontrol,
394 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395{
396 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
397 struct alc_spec *spec = codec->spec;
398 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
399
400 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
401 return 0;
402}
403
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200404static int alc_mux_enum_put(struct snd_kcontrol *kcontrol,
405 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406{
407 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
408 struct alc_spec *spec = codec->spec;
Takashi Iwaicd896c32008-11-18 12:36:33 +0100409 const struct hda_input_mux *imux;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Takashi Iwaicd896c32008-11-18 12:36:33 +0100411 unsigned int mux_idx;
Takashi Iwaie1406342008-02-11 18:32:32 +0100412 hda_nid_t nid = spec->capsrc_nids ?
413 spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414
Takashi Iwaicd896c32008-11-18 12:36:33 +0100415 mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx;
416 imux = &spec->input_mux[mux_idx];
417
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -0200418 if (spec->capture_style &&
419 !(spec->capture_style == CAPT_1MUX_MIX && !adc_idx)) {
Takashi Iwai54cbc9a2008-10-31 15:24:04 +0100420 /* Matrix-mixer style (e.g. ALC882) */
421 unsigned int *cur_val = &spec->cur_mux[adc_idx];
422 unsigned int i, idx;
423
424 idx = ucontrol->value.enumerated.item[0];
425 if (idx >= imux->num_items)
426 idx = imux->num_items - 1;
427 if (*cur_val == idx)
428 return 0;
429 for (i = 0; i < imux->num_items; i++) {
430 unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE;
431 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT,
432 imux->items[i].index,
433 HDA_AMP_MUTE, v);
434 }
435 *cur_val = idx;
436 return 1;
437 } else {
438 /* MUX style (e.g. ALC880) */
Takashi Iwaicd896c32008-11-18 12:36:33 +0100439 return snd_hda_input_mux_put(codec, imux, ucontrol, nid,
Takashi Iwai54cbc9a2008-10-31 15:24:04 +0100440 &spec->cur_mux[adc_idx]);
441 }
442}
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200443
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444/*
445 * channel mode setting
446 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200447static int alc_ch_mode_info(struct snd_kcontrol *kcontrol,
448 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449{
450 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
451 struct alc_spec *spec = codec->spec;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100452 return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode,
453 spec->num_channel_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454}
455
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200456static int alc_ch_mode_get(struct snd_kcontrol *kcontrol,
457 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458{
459 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
460 struct alc_spec *spec = codec->spec;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100461 return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200462 spec->num_channel_mode,
463 spec->multiout.max_channels);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464}
465
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200466static int alc_ch_mode_put(struct snd_kcontrol *kcontrol,
467 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468{
469 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
470 struct alc_spec *spec = codec->spec;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200471 int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
472 spec->num_channel_mode,
473 &spec->multiout.max_channels);
Takashi Iwaibd2033f2006-10-10 19:49:31 +0200474 if (err >= 0 && spec->need_dac_fix)
Takashi Iwai4e195a72006-07-28 14:47:34 +0200475 spec->multiout.num_dacs = spec->multiout.max_channels / 2;
476 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477}
478
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479/*
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100480 * Control the mode of pin widget settings via the mixer. "pc" is used
Kailang Yangea1fb292008-08-26 12:58:38 +0200481 * instead of "%" to avoid consequences of accidently treating the % as
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100482 * being part of a format specifier. Maximum allowed length of a value is
483 * 63 characters plus NULL terminator.
Jonathan Woithe7cf51e482006-02-09 12:01:26 +0100484 *
485 * Note: some retasking pin complexes seem to ignore requests for input
486 * states other than HiZ (eg: PIN_VREFxx) and revert to HiZ if any of these
487 * are requested. Therefore order this list so that this behaviour will not
488 * cause problems when mixer clients move through the enum sequentially.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200489 * NIDs 0x0f and 0x10 have been observed to have this behaviour as of
490 * March 2006.
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200491 */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100492static char *alc_pin_mode_names[] = {
Jonathan Woithe7cf51e482006-02-09 12:01:26 +0100493 "Mic 50pc bias", "Mic 80pc bias",
494 "Line in", "Line out", "Headphone out",
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100495};
496static unsigned char alc_pin_mode_values[] = {
Jonathan Woithe7cf51e482006-02-09 12:01:26 +0100497 PIN_VREF50, PIN_VREF80, PIN_IN, PIN_OUT, PIN_HP,
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100498};
499/* The control can present all 5 options, or it can limit the options based
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200500 * in the pin being assumed to be exclusively an input or an output pin. In
501 * addition, "input" pins may or may not process the mic bias option
502 * depending on actual widget capability (NIDs 0x0f and 0x10 don't seem to
503 * accept requests for bias as of chip versions up to March 2006) and/or
504 * wiring in the computer.
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100505 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200506#define ALC_PIN_DIR_IN 0x00
507#define ALC_PIN_DIR_OUT 0x01
508#define ALC_PIN_DIR_INOUT 0x02
509#define ALC_PIN_DIR_IN_NOMICBIAS 0x03
510#define ALC_PIN_DIR_INOUT_NOMICBIAS 0x04
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100511
Kailang Yangea1fb292008-08-26 12:58:38 +0200512/* Info about the pin modes supported by the different pin direction modes.
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100513 * For each direction the minimum and maximum values are given.
514 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200515static signed char alc_pin_mode_dir_info[5][2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100516 { 0, 2 }, /* ALC_PIN_DIR_IN */
517 { 3, 4 }, /* ALC_PIN_DIR_OUT */
518 { 0, 4 }, /* ALC_PIN_DIR_INOUT */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200519 { 2, 2 }, /* ALC_PIN_DIR_IN_NOMICBIAS */
520 { 2, 4 }, /* ALC_PIN_DIR_INOUT_NOMICBIAS */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100521};
522#define alc_pin_mode_min(_dir) (alc_pin_mode_dir_info[_dir][0])
523#define alc_pin_mode_max(_dir) (alc_pin_mode_dir_info[_dir][1])
524#define alc_pin_mode_n_items(_dir) \
525 (alc_pin_mode_max(_dir)-alc_pin_mode_min(_dir)+1)
526
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200527static int alc_pin_mode_info(struct snd_kcontrol *kcontrol,
528 struct snd_ctl_elem_info *uinfo)
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200529{
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100530 unsigned int item_num = uinfo->value.enumerated.item;
531 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
532
533 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200534 uinfo->count = 1;
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100535 uinfo->value.enumerated.items = alc_pin_mode_n_items(dir);
536
537 if (item_num<alc_pin_mode_min(dir) || item_num>alc_pin_mode_max(dir))
538 item_num = alc_pin_mode_min(dir);
539 strcpy(uinfo->value.enumerated.name, alc_pin_mode_names[item_num]);
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200540 return 0;
541}
542
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200543static int alc_pin_mode_get(struct snd_kcontrol *kcontrol,
544 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200545{
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100546 unsigned int i;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200547 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
548 hda_nid_t nid = kcontrol->private_value & 0xffff;
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100549 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200550 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200551 unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
552 AC_VERB_GET_PIN_WIDGET_CONTROL,
553 0x00);
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200554
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100555 /* Find enumerated value for current pinctl setting */
556 i = alc_pin_mode_min(dir);
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200557 while (alc_pin_mode_values[i] != pinctl && i <= alc_pin_mode_max(dir))
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100558 i++;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200559 *valp = i <= alc_pin_mode_max(dir) ? i: alc_pin_mode_min(dir);
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100560 return 0;
561}
562
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200563static int alc_pin_mode_put(struct snd_kcontrol *kcontrol,
564 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100565{
566 signed int change;
567 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
568 hda_nid_t nid = kcontrol->private_value & 0xffff;
569 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
570 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200571 unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
572 AC_VERB_GET_PIN_WIDGET_CONTROL,
573 0x00);
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100574
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200575 if (val < alc_pin_mode_min(dir) || val > alc_pin_mode_max(dir))
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100576 val = alc_pin_mode_min(dir);
577
578 change = pinctl != alc_pin_mode_values[val];
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100579 if (change) {
580 /* Set pin mode to that requested */
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200581 snd_hda_codec_write_cache(codec, nid, 0,
582 AC_VERB_SET_PIN_WIDGET_CONTROL,
583 alc_pin_mode_values[val]);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100584
Kailang Yangea1fb292008-08-26 12:58:38 +0200585 /* Also enable the retasking pin's input/output as required
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100586 * for the requested pin mode. Enum values of 2 or less are
587 * input modes.
588 *
589 * Dynamically switching the input/output buffers probably
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200590 * reduces noise slightly (particularly on input) so we'll
591 * do it. However, having both input and output buffers
592 * enabled simultaneously doesn't seem to be problematic if
593 * this turns out to be necessary in the future.
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100594 */
595 if (val <= 2) {
Takashi Iwai47fd8302007-08-10 17:11:07 +0200596 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
597 HDA_AMP_MUTE, HDA_AMP_MUTE);
598 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
599 HDA_AMP_MUTE, 0);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100600 } else {
Takashi Iwai47fd8302007-08-10 17:11:07 +0200601 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
602 HDA_AMP_MUTE, HDA_AMP_MUTE);
603 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
604 HDA_AMP_MUTE, 0);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100605 }
606 }
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200607 return change;
608}
609
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100610#define ALC_PIN_MODE(xname, nid, dir) \
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200611 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100612 .info = alc_pin_mode_info, \
613 .get = alc_pin_mode_get, \
614 .put = alc_pin_mode_put, \
615 .private_value = nid | (dir<<16) }
Kailang Yangdf694da2005-12-05 19:42:22 +0100616
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100617/* A switch control for ALC260 GPIO pins. Multiple GPIOs can be ganged
618 * together using a mask with more than one bit set. This control is
619 * currently used only by the ALC260 test model. At this stage they are not
620 * needed for any "production" models.
621 */
622#ifdef CONFIG_SND_DEBUG
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200623#define alc_gpio_data_info snd_ctl_boolean_mono_info
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200624
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200625static int alc_gpio_data_get(struct snd_kcontrol *kcontrol,
626 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100627{
628 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
629 hda_nid_t nid = kcontrol->private_value & 0xffff;
630 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
631 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200632 unsigned int val = snd_hda_codec_read(codec, nid, 0,
633 AC_VERB_GET_GPIO_DATA, 0x00);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100634
635 *valp = (val & mask) != 0;
636 return 0;
637}
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200638static int alc_gpio_data_put(struct snd_kcontrol *kcontrol,
639 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100640{
641 signed int change;
642 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
643 hda_nid_t nid = kcontrol->private_value & 0xffff;
644 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
645 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200646 unsigned int gpio_data = snd_hda_codec_read(codec, nid, 0,
647 AC_VERB_GET_GPIO_DATA,
648 0x00);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100649
650 /* Set/unset the masked GPIO bit(s) as needed */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200651 change = (val == 0 ? 0 : mask) != (gpio_data & mask);
652 if (val == 0)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100653 gpio_data &= ~mask;
654 else
655 gpio_data |= mask;
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200656 snd_hda_codec_write_cache(codec, nid, 0,
657 AC_VERB_SET_GPIO_DATA, gpio_data);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100658
659 return change;
660}
661#define ALC_GPIO_DATA_SWITCH(xname, nid, mask) \
662 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
663 .info = alc_gpio_data_info, \
664 .get = alc_gpio_data_get, \
665 .put = alc_gpio_data_put, \
666 .private_value = nid | (mask<<16) }
667#endif /* CONFIG_SND_DEBUG */
668
Jonathan Woithe92621f12006-02-28 11:47:47 +0100669/* A switch control to allow the enabling of the digital IO pins on the
670 * ALC260. This is incredibly simplistic; the intention of this control is
671 * to provide something in the test model allowing digital outputs to be
672 * identified if present. If models are found which can utilise these
673 * outputs a more complete mixer control can be devised for those models if
674 * necessary.
675 */
676#ifdef CONFIG_SND_DEBUG
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200677#define alc_spdif_ctrl_info snd_ctl_boolean_mono_info
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200678
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200679static int alc_spdif_ctrl_get(struct snd_kcontrol *kcontrol,
680 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe92621f12006-02-28 11:47:47 +0100681{
682 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
683 hda_nid_t nid = kcontrol->private_value & 0xffff;
684 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
685 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200686 unsigned int val = snd_hda_codec_read(codec, nid, 0,
Andrew Paprocki3982d172007-12-19 12:13:44 +0100687 AC_VERB_GET_DIGI_CONVERT_1, 0x00);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100688
689 *valp = (val & mask) != 0;
690 return 0;
691}
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200692static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol,
693 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe92621f12006-02-28 11:47:47 +0100694{
695 signed int change;
696 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
697 hda_nid_t nid = kcontrol->private_value & 0xffff;
698 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
699 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200700 unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
Andrew Paprocki3982d172007-12-19 12:13:44 +0100701 AC_VERB_GET_DIGI_CONVERT_1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200702 0x00);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100703
704 /* Set/unset the masked control bit(s) as needed */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200705 change = (val == 0 ? 0 : mask) != (ctrl_data & mask);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100706 if (val==0)
707 ctrl_data &= ~mask;
708 else
709 ctrl_data |= mask;
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200710 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
711 ctrl_data);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100712
713 return change;
714}
715#define ALC_SPDIF_CTRL_SWITCH(xname, nid, mask) \
716 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
717 .info = alc_spdif_ctrl_info, \
718 .get = alc_spdif_ctrl_get, \
719 .put = alc_spdif_ctrl_put, \
720 .private_value = nid | (mask<<16) }
721#endif /* CONFIG_SND_DEBUG */
722
Jonathan Woithef8225f62008-01-08 12:16:54 +0100723/* A switch control to allow the enabling EAPD digital outputs on the ALC26x.
724 * Again, this is only used in the ALC26x test models to help identify when
725 * the EAPD line must be asserted for features to work.
726 */
727#ifdef CONFIG_SND_DEBUG
728#define alc_eapd_ctrl_info snd_ctl_boolean_mono_info
729
730static int alc_eapd_ctrl_get(struct snd_kcontrol *kcontrol,
731 struct snd_ctl_elem_value *ucontrol)
732{
733 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
734 hda_nid_t nid = kcontrol->private_value & 0xffff;
735 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
736 long *valp = ucontrol->value.integer.value;
737 unsigned int val = snd_hda_codec_read(codec, nid, 0,
738 AC_VERB_GET_EAPD_BTLENABLE, 0x00);
739
740 *valp = (val & mask) != 0;
741 return 0;
742}
743
744static int alc_eapd_ctrl_put(struct snd_kcontrol *kcontrol,
745 struct snd_ctl_elem_value *ucontrol)
746{
747 int change;
748 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
749 hda_nid_t nid = kcontrol->private_value & 0xffff;
750 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
751 long val = *ucontrol->value.integer.value;
752 unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
753 AC_VERB_GET_EAPD_BTLENABLE,
754 0x00);
755
756 /* Set/unset the masked control bit(s) as needed */
757 change = (!val ? 0 : mask) != (ctrl_data & mask);
758 if (!val)
759 ctrl_data &= ~mask;
760 else
761 ctrl_data |= mask;
762 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
763 ctrl_data);
764
765 return change;
766}
767
768#define ALC_EAPD_CTRL_SWITCH(xname, nid, mask) \
769 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
770 .info = alc_eapd_ctrl_info, \
771 .get = alc_eapd_ctrl_get, \
772 .put = alc_eapd_ctrl_put, \
773 .private_value = nid | (mask<<16) }
774#endif /* CONFIG_SND_DEBUG */
775
Kailang Yangdf694da2005-12-05 19:42:22 +0100776/*
Takashi Iwai23f0c042009-02-26 13:03:58 +0100777 * set up the input pin config (depending on the given auto-pin type)
778 */
779static void alc_set_input_pin(struct hda_codec *codec, hda_nid_t nid,
780 int auto_pin_type)
781{
782 unsigned int val = PIN_IN;
783
784 if (auto_pin_type <= AUTO_PIN_FRONT_MIC) {
785 unsigned int pincap;
Takashi Iwai1327a322009-03-23 13:07:47 +0100786 pincap = snd_hda_query_pin_caps(codec, nid);
Takashi Iwai23f0c042009-02-26 13:03:58 +0100787 pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
788 if (pincap & AC_PINCAP_VREF_80)
789 val = PIN_VREF80;
790 }
791 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, val);
792}
793
794/*
Takashi Iwaid88897e2008-10-31 15:01:37 +0100795 */
796static void add_mixer(struct alc_spec *spec, struct snd_kcontrol_new *mix)
797{
798 if (snd_BUG_ON(spec->num_mixers >= ARRAY_SIZE(spec->mixers)))
799 return;
800 spec->mixers[spec->num_mixers++] = mix;
801}
802
803static void add_verb(struct alc_spec *spec, const struct hda_verb *verb)
804{
805 if (snd_BUG_ON(spec->num_init_verbs >= ARRAY_SIZE(spec->init_verbs)))
806 return;
807 spec->init_verbs[spec->num_init_verbs++] = verb;
808}
809
Takashi Iwaidaead532008-11-28 12:55:36 +0100810#ifdef CONFIG_PROC_FS
811/*
812 * hook for proc
813 */
814static void print_realtek_coef(struct snd_info_buffer *buffer,
815 struct hda_codec *codec, hda_nid_t nid)
816{
817 int coeff;
818
819 if (nid != 0x20)
820 return;
821 coeff = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PROC_COEF, 0);
822 snd_iprintf(buffer, " Processing Coefficient: 0x%02x\n", coeff);
823 coeff = snd_hda_codec_read(codec, nid, 0,
824 AC_VERB_GET_COEF_INDEX, 0);
825 snd_iprintf(buffer, " Coefficient Index: 0x%02x\n", coeff);
826}
827#else
828#define print_realtek_coef NULL
829#endif
830
Takashi Iwaid88897e2008-10-31 15:01:37 +0100831/*
Kailang Yangdf694da2005-12-05 19:42:22 +0100832 * set up from the preset table
833 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200834static void setup_preset(struct alc_spec *spec,
835 const struct alc_config_preset *preset)
Kailang Yangdf694da2005-12-05 19:42:22 +0100836{
837 int i;
838
839 for (i = 0; i < ARRAY_SIZE(preset->mixers) && preset->mixers[i]; i++)
Takashi Iwaid88897e2008-10-31 15:01:37 +0100840 add_mixer(spec, preset->mixers[i]);
Takashi Iwaif9e336f2008-10-31 16:37:07 +0100841 spec->cap_mixer = preset->cap_mixer;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200842 for (i = 0; i < ARRAY_SIZE(preset->init_verbs) && preset->init_verbs[i];
843 i++)
Takashi Iwaid88897e2008-10-31 15:01:37 +0100844 add_verb(spec, preset->init_verbs[i]);
Kailang Yangea1fb292008-08-26 12:58:38 +0200845
Kailang Yangdf694da2005-12-05 19:42:22 +0100846 spec->channel_mode = preset->channel_mode;
847 spec->num_channel_mode = preset->num_channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200848 spec->need_dac_fix = preset->need_dac_fix;
Kailang Yangdf694da2005-12-05 19:42:22 +0100849
850 spec->multiout.max_channels = spec->channel_mode[0].channels;
851
852 spec->multiout.num_dacs = preset->num_dacs;
853 spec->multiout.dac_nids = preset->dac_nids;
854 spec->multiout.dig_out_nid = preset->dig_out_nid;
Wu Fengguangb25c9da2009-02-06 15:02:27 +0800855 spec->multiout.slave_dig_outs = preset->slave_dig_outs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100856 spec->multiout.hp_nid = preset->hp_nid;
Kailang Yangea1fb292008-08-26 12:58:38 +0200857
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200858 spec->num_mux_defs = preset->num_mux_defs;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200859 if (!spec->num_mux_defs)
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200860 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +0100861 spec->input_mux = preset->input_mux;
862
863 spec->num_adc_nids = preset->num_adc_nids;
864 spec->adc_nids = preset->adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100865 spec->capsrc_nids = preset->capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +0100866 spec->dig_in_nid = preset->dig_in_nid;
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100867
868 spec->unsol_event = preset->unsol_event;
869 spec->init_hook = preset->init_hook;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200870#ifdef CONFIG_SND_HDA_POWER_SAVE
871 spec->loopback.amplist = preset->loopbacks;
872#endif
Kailang Yangdf694da2005-12-05 19:42:22 +0100873}
874
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200875/* Enable GPIO mask and set output */
876static struct hda_verb alc_gpio1_init_verbs[] = {
877 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
878 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
879 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
880 { }
881};
882
883static struct hda_verb alc_gpio2_init_verbs[] = {
884 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
885 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
886 {0x01, AC_VERB_SET_GPIO_DATA, 0x02},
887 { }
888};
889
Kailang Yangbdd148a2007-05-08 15:19:08 +0200890static struct hda_verb alc_gpio3_init_verbs[] = {
891 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
892 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
893 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
894 { }
895};
896
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +0200897/*
898 * Fix hardware PLL issue
899 * On some codecs, the analog PLL gating control must be off while
900 * the default value is 1.
901 */
902static void alc_fix_pll(struct hda_codec *codec)
903{
904 struct alc_spec *spec = codec->spec;
905 unsigned int val;
906
907 if (!spec->pll_nid)
908 return;
909 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
910 spec->pll_coef_idx);
911 val = snd_hda_codec_read(codec, spec->pll_nid, 0,
912 AC_VERB_GET_PROC_COEF, 0);
913 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
914 spec->pll_coef_idx);
915 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_PROC_COEF,
916 val & ~(1 << spec->pll_coef_bit));
917}
918
919static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
920 unsigned int coef_idx, unsigned int coef_bit)
921{
922 struct alc_spec *spec = codec->spec;
923 spec->pll_nid = nid;
924 spec->pll_coef_idx = coef_idx;
925 spec->pll_coef_bit = coef_bit;
926 alc_fix_pll(codec);
927}
928
Takashi Iwaia9fd4f32009-05-08 15:57:59 +0200929static void alc_automute_pin(struct hda_codec *codec)
Kailang Yangc9b58002007-10-16 14:30:01 +0200930{
931 struct alc_spec *spec = codec->spec;
Kailang Yangc9b58002007-10-16 14:30:01 +0200932 unsigned int present;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +0200933 unsigned int nid = spec->autocfg.hp_pins[0];
934 int i;
Kailang Yangc9b58002007-10-16 14:30:01 +0200935
936 /* need to execute and sync at first */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +0200937 snd_hda_codec_read(codec, nid, 0, AC_VERB_SET_PIN_SENSE, 0);
938 present = snd_hda_codec_read(codec, nid, 0,
Kailang Yangc9b58002007-10-16 14:30:01 +0200939 AC_VERB_GET_PIN_SENSE, 0);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +0200940 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
941 for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) {
942 nid = spec->autocfg.speaker_pins[i];
943 if (!nid)
944 break;
945 snd_hda_codec_write(codec, nid, 0,
946 AC_VERB_SET_PIN_WIDGET_CONTROL,
947 spec->jack_present ? 0 : PIN_OUT);
948 }
Kailang Yangc9b58002007-10-16 14:30:01 +0200949}
950
Takashi Iwai4605b712008-10-31 14:18:24 +0100951#if 0 /* it's broken in some acses -- temporarily disabled */
Kailang Yang7fb0d782008-10-15 11:12:35 +0200952static void alc_mic_automute(struct hda_codec *codec)
953{
954 struct alc_spec *spec = codec->spec;
955 unsigned int present;
956 unsigned int mic_nid = spec->autocfg.input_pins[AUTO_PIN_MIC];
957 unsigned int fmic_nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC];
958 unsigned int mix_nid = spec->capsrc_nids[0];
959 unsigned int capsrc_idx_mic, capsrc_idx_fmic;
960
961 capsrc_idx_mic = mic_nid - 0x18;
962 capsrc_idx_fmic = fmic_nid - 0x18;
963 present = snd_hda_codec_read(codec, mic_nid, 0,
964 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
965 snd_hda_codec_write(codec, mix_nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
966 0x7000 | (capsrc_idx_mic << 8) | (present ? 0 : 0x80));
967 snd_hda_codec_write(codec, mix_nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
968 0x7000 | (capsrc_idx_fmic << 8) | (present ? 0x80 : 0));
969 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, capsrc_idx_fmic,
970 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
971}
Takashi Iwai4605b712008-10-31 14:18:24 +0100972#else
Takashi Iwai45bdd1c2009-02-06 16:11:25 +0100973#define alc_mic_automute(codec) do {} while(0) /* NOP */
Takashi Iwai4605b712008-10-31 14:18:24 +0100974#endif /* disabled */
Kailang Yang7fb0d782008-10-15 11:12:35 +0200975
Kailang Yangc9b58002007-10-16 14:30:01 +0200976/* unsolicited event for HP jack sensing */
977static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res)
978{
979 if (codec->vendor_id == 0x10ec0880)
980 res >>= 28;
981 else
982 res >>= 26;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +0200983 switch (res) {
984 case ALC880_HP_EVENT:
985 alc_automute_pin(codec);
986 break;
987 case ALC880_MIC_EVENT:
Kailang Yang7fb0d782008-10-15 11:12:35 +0200988 alc_mic_automute(codec);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +0200989 break;
990 }
Kailang Yang7fb0d782008-10-15 11:12:35 +0200991}
992
993static void alc_inithook(struct hda_codec *codec)
994{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +0200995 alc_automute_pin(codec);
Kailang Yang7fb0d782008-10-15 11:12:35 +0200996 alc_mic_automute(codec);
Kailang Yangc9b58002007-10-16 14:30:01 +0200997}
998
Kailang Yangf9423e72008-05-27 12:32:25 +0200999/* additional initialization for ALC888 variants */
1000static void alc888_coef_init(struct hda_codec *codec)
1001{
1002 unsigned int tmp;
1003
1004 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0);
1005 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
1006 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
Takashi Iwai37db6232009-03-05 09:40:16 +01001007 if ((tmp & 0xf0) == 0x20)
Kailang Yangf9423e72008-05-27 12:32:25 +02001008 /* alc888S-VC */
1009 snd_hda_codec_read(codec, 0x20, 0,
1010 AC_VERB_SET_PROC_COEF, 0x830);
1011 else
1012 /* alc888-VB */
1013 snd_hda_codec_read(codec, 0x20, 0,
1014 AC_VERB_SET_PROC_COEF, 0x3030);
1015}
1016
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001017static void alc_auto_init_amp(struct hda_codec *codec, int type)
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001018{
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001019 unsigned int tmp;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001020
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001021 switch (type) {
1022 case ALC_INIT_GPIO1:
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001023 snd_hda_sequence_write(codec, alc_gpio1_init_verbs);
1024 break;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001025 case ALC_INIT_GPIO2:
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001026 snd_hda_sequence_write(codec, alc_gpio2_init_verbs);
1027 break;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001028 case ALC_INIT_GPIO3:
Kailang Yangbdd148a2007-05-08 15:19:08 +02001029 snd_hda_sequence_write(codec, alc_gpio3_init_verbs);
1030 break;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001031 case ALC_INIT_DEFAULT:
Kailang Yangbdd148a2007-05-08 15:19:08 +02001032 switch (codec->vendor_id) {
Kailang Yangc9b58002007-10-16 14:30:01 +02001033 case 0x10ec0260:
1034 snd_hda_codec_write(codec, 0x0f, 0,
1035 AC_VERB_SET_EAPD_BTLENABLE, 2);
1036 snd_hda_codec_write(codec, 0x10, 0,
1037 AC_VERB_SET_EAPD_BTLENABLE, 2);
1038 break;
1039 case 0x10ec0262:
Kailang Yangbdd148a2007-05-08 15:19:08 +02001040 case 0x10ec0267:
1041 case 0x10ec0268:
Kailang Yangc9b58002007-10-16 14:30:01 +02001042 case 0x10ec0269:
Takashi Iwaic6e8f2d2009-02-06 12:45:52 +01001043 case 0x10ec0272:
Kailang Yangf9423e72008-05-27 12:32:25 +02001044 case 0x10ec0660:
1045 case 0x10ec0662:
1046 case 0x10ec0663:
Kailang Yangc9b58002007-10-16 14:30:01 +02001047 case 0x10ec0862:
Takashi Iwai20a3a052008-05-23 17:52:53 +02001048 case 0x10ec0889:
Kailang Yangbdd148a2007-05-08 15:19:08 +02001049 snd_hda_codec_write(codec, 0x14, 0,
1050 AC_VERB_SET_EAPD_BTLENABLE, 2);
1051 snd_hda_codec_write(codec, 0x15, 0,
1052 AC_VERB_SET_EAPD_BTLENABLE, 2);
Kailang Yangc9b58002007-10-16 14:30:01 +02001053 break;
Kailang Yangbdd148a2007-05-08 15:19:08 +02001054 }
Kailang Yangc9b58002007-10-16 14:30:01 +02001055 switch (codec->vendor_id) {
1056 case 0x10ec0260:
1057 snd_hda_codec_write(codec, 0x1a, 0,
1058 AC_VERB_SET_COEF_INDEX, 7);
1059 tmp = snd_hda_codec_read(codec, 0x1a, 0,
1060 AC_VERB_GET_PROC_COEF, 0);
1061 snd_hda_codec_write(codec, 0x1a, 0,
1062 AC_VERB_SET_COEF_INDEX, 7);
1063 snd_hda_codec_write(codec, 0x1a, 0,
1064 AC_VERB_SET_PROC_COEF,
1065 tmp | 0x2010);
1066 break;
1067 case 0x10ec0262:
1068 case 0x10ec0880:
1069 case 0x10ec0882:
1070 case 0x10ec0883:
1071 case 0x10ec0885:
Takashi Iwai4a5a4c52009-02-06 12:46:59 +01001072 case 0x10ec0887:
Takashi Iwai20a3a052008-05-23 17:52:53 +02001073 case 0x10ec0889:
Kailang Yangc9b58002007-10-16 14:30:01 +02001074 snd_hda_codec_write(codec, 0x20, 0,
1075 AC_VERB_SET_COEF_INDEX, 7);
1076 tmp = snd_hda_codec_read(codec, 0x20, 0,
1077 AC_VERB_GET_PROC_COEF, 0);
1078 snd_hda_codec_write(codec, 0x20, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +02001079 AC_VERB_SET_COEF_INDEX, 7);
Kailang Yangc9b58002007-10-16 14:30:01 +02001080 snd_hda_codec_write(codec, 0x20, 0,
1081 AC_VERB_SET_PROC_COEF,
1082 tmp | 0x2010);
1083 break;
Kailang Yangf9423e72008-05-27 12:32:25 +02001084 case 0x10ec0888:
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001085 alc888_coef_init(codec);
Kailang Yangf9423e72008-05-27 12:32:25 +02001086 break;
Kailang Yangc9b58002007-10-16 14:30:01 +02001087 case 0x10ec0267:
1088 case 0x10ec0268:
1089 snd_hda_codec_write(codec, 0x20, 0,
1090 AC_VERB_SET_COEF_INDEX, 7);
1091 tmp = snd_hda_codec_read(codec, 0x20, 0,
1092 AC_VERB_GET_PROC_COEF, 0);
1093 snd_hda_codec_write(codec, 0x20, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +02001094 AC_VERB_SET_COEF_INDEX, 7);
Kailang Yangc9b58002007-10-16 14:30:01 +02001095 snd_hda_codec_write(codec, 0x20, 0,
1096 AC_VERB_SET_PROC_COEF,
1097 tmp | 0x3000);
1098 break;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001099 }
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001100 break;
1101 }
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001102}
Kailang Yangea1fb292008-08-26 12:58:38 +02001103
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001104static void alc_init_auto_hp(struct hda_codec *codec)
1105{
1106 struct alc_spec *spec = codec->spec;
1107
1108 if (!spec->autocfg.hp_pins[0])
Kailang Yangc9b58002007-10-16 14:30:01 +02001109 return;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001110
Kailang Yangc9b58002007-10-16 14:30:01 +02001111 if (!spec->autocfg.speaker_pins[0]) {
Takashi Iwai2a2ed0d2009-04-28 13:01:26 +02001112 if (spec->autocfg.line_out_pins[0] &&
1113 spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT)
Kailang Yangc9b58002007-10-16 14:30:01 +02001114 spec->autocfg.speaker_pins[0] =
Kailang Yang8c427222008-01-10 13:03:59 +01001115 spec->autocfg.line_out_pins[0];
Kailang Yangc9b58002007-10-16 14:30:01 +02001116 else
1117 return;
1118 }
1119
Takashi Iwai2a2ed0d2009-04-28 13:01:26 +02001120 snd_printdd("realtek: Enable HP auto-muting on NID 0x%x\n",
1121 spec->autocfg.hp_pins[0]);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001122 snd_hda_codec_write_cache(codec, spec->autocfg.hp_pins[0], 0,
1123 AC_VERB_SET_UNSOLICITED_ENABLE,
1124 AC_USRSP_EN | ALC880_HP_EVENT);
1125 spec->unsol_event = alc_sku_unsol_event;
1126}
1127
1128/* check subsystem ID and set up device-specific initialization;
1129 * return 1 if initialized, 0 if invalid SSID
1130 */
1131/* 32-bit subsystem ID for BIOS loading in HD Audio codec.
1132 * 31 ~ 16 : Manufacture ID
1133 * 15 ~ 8 : SKU ID
1134 * 7 ~ 0 : Assembly ID
1135 * port-A --> pin 39/41, port-E --> pin 14/15, port-D --> pin 35/36
1136 */
1137static int alc_subsystem_id(struct hda_codec *codec,
1138 hda_nid_t porta, hda_nid_t porte,
1139 hda_nid_t portd)
1140{
1141 unsigned int ass, tmp, i;
1142 unsigned nid;
1143 struct alc_spec *spec = codec->spec;
1144
1145 ass = codec->subsystem_id & 0xffff;
1146 if ((ass != codec->bus->pci->subsystem_device) && (ass & 1))
1147 goto do_sku;
1148
1149 /* invalid SSID, check the special NID pin defcfg instead */
1150 /*
1151 * 31~30 : port conetcivity
1152 * 29~21 : reserve
1153 * 20 : PCBEEP input
1154 * 19~16 : Check sum (15:1)
1155 * 15~1 : Custom
1156 * 0 : override
1157 */
1158 nid = 0x1d;
1159 if (codec->vendor_id == 0x10ec0260)
1160 nid = 0x17;
1161 ass = snd_hda_codec_get_pincfg(codec, nid);
1162 snd_printd("realtek: No valid SSID, "
1163 "checking pincfg 0x%08x for NID 0x%x\n",
Takashi Iwaicb6605c2009-04-28 13:03:19 +02001164 ass, nid);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001165 if (!(ass & 1) && !(ass & 0x100000))
1166 return 0;
1167 if ((ass >> 30) != 1) /* no physical connection */
1168 return 0;
1169
1170 /* check sum */
1171 tmp = 0;
1172 for (i = 1; i < 16; i++) {
1173 if ((ass >> i) & 1)
1174 tmp++;
1175 }
1176 if (((ass >> 16) & 0xf) != tmp)
1177 return 0;
1178do_sku:
1179 snd_printd("realtek: Enabling init ASM_ID=0x%04x CODEC_ID=%08x\n",
1180 ass & 0xffff, codec->vendor_id);
1181 /*
1182 * 0 : override
1183 * 1 : Swap Jack
1184 * 2 : 0 --> Desktop, 1 --> Laptop
1185 * 3~5 : External Amplifier control
1186 * 7~6 : Reserved
1187 */
1188 tmp = (ass & 0x38) >> 3; /* external Amp control */
1189 switch (tmp) {
1190 case 1:
1191 spec->init_amp = ALC_INIT_GPIO1;
1192 break;
1193 case 3:
1194 spec->init_amp = ALC_INIT_GPIO2;
1195 break;
1196 case 7:
1197 spec->init_amp = ALC_INIT_GPIO3;
1198 break;
1199 case 5:
1200 spec->init_amp = ALC_INIT_DEFAULT;
1201 break;
1202 }
1203
1204 /* is laptop or Desktop and enable the function "Mute internal speaker
1205 * when the external headphone out jack is plugged"
1206 */
1207 if (!(ass & 0x8000))
1208 return 1;
1209 /*
1210 * 10~8 : Jack location
1211 * 12~11: Headphone out -> 00: PortA, 01: PortE, 02: PortD, 03: Resvered
1212 * 14~13: Resvered
1213 * 15 : 1 --> enable the function "Mute internal speaker
1214 * when the external headphone out jack is plugged"
1215 */
Kailang Yangc9b58002007-10-16 14:30:01 +02001216 if (!spec->autocfg.hp_pins[0]) {
1217 tmp = (ass >> 11) & 0x3; /* HP to chassis */
1218 if (tmp == 0)
1219 spec->autocfg.hp_pins[0] = porta;
1220 else if (tmp == 1)
1221 spec->autocfg.hp_pins[0] = porte;
1222 else if (tmp == 2)
1223 spec->autocfg.hp_pins[0] = portd;
1224 else
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001225 return 1;
Kailang Yangc9b58002007-10-16 14:30:01 +02001226 }
1227
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001228 alc_init_auto_hp(codec);
1229 return 1;
1230}
Kailang Yangea1fb292008-08-26 12:58:38 +02001231
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001232static void alc_ssid_check(struct hda_codec *codec,
1233 hda_nid_t porta, hda_nid_t porte, hda_nid_t portd)
1234{
1235 if (!alc_subsystem_id(codec, porta, porte, portd)) {
1236 struct alc_spec *spec = codec->spec;
1237 snd_printd("realtek: "
1238 "Enable default setup for auto mode as fallback\n");
1239 spec->init_amp = ALC_INIT_DEFAULT;
1240 alc_init_auto_hp(codec);
1241 }
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001242}
1243
Takashi Iwai41e41f12005-06-08 14:48:49 +02001244/*
Takashi Iwaif95474e2007-07-10 00:47:43 +02001245 * Fix-up pin default configurations
1246 */
1247
1248struct alc_pincfg {
1249 hda_nid_t nid;
1250 u32 val;
1251};
1252
1253static void alc_fix_pincfg(struct hda_codec *codec,
1254 const struct snd_pci_quirk *quirk,
1255 const struct alc_pincfg **pinfix)
1256{
1257 const struct alc_pincfg *cfg;
1258
1259 quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk);
1260 if (!quirk)
1261 return;
1262
1263 cfg = pinfix[quirk->value];
Takashi Iwai0e8a21b2009-02-20 14:13:06 +01001264 for (; cfg->nid; cfg++)
1265 snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val);
Takashi Iwaif95474e2007-07-10 00:47:43 +02001266}
1267
1268/*
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001269 * ALC888
1270 */
1271
1272/*
1273 * 2ch mode
1274 */
1275static struct hda_verb alc888_4ST_ch2_intel_init[] = {
1276/* Mic-in jack as mic in */
1277 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1278 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1279/* Line-in jack as Line in */
1280 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
1281 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1282/* Line-Out as Front */
1283 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00},
1284 { } /* end */
1285};
1286
1287/*
1288 * 4ch mode
1289 */
1290static struct hda_verb alc888_4ST_ch4_intel_init[] = {
1291/* Mic-in jack as mic in */
1292 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1293 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1294/* Line-in jack as Surround */
1295 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1296 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1297/* Line-Out as Front */
1298 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00},
1299 { } /* end */
1300};
1301
1302/*
1303 * 6ch mode
1304 */
1305static struct hda_verb alc888_4ST_ch6_intel_init[] = {
1306/* Mic-in jack as CLFE */
1307 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1308 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1309/* Line-in jack as Surround */
1310 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1311 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1312/* Line-Out as CLFE (workaround because Mic-in is not loud enough) */
1313 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
1314 { } /* end */
1315};
1316
1317/*
1318 * 8ch mode
1319 */
1320static struct hda_verb alc888_4ST_ch8_intel_init[] = {
1321/* Mic-in jack as CLFE */
1322 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1323 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1324/* Line-in jack as Surround */
1325 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1326 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1327/* Line-Out as Side */
1328 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
1329 { } /* end */
1330};
1331
1332static struct hda_channel_mode alc888_4ST_8ch_intel_modes[4] = {
1333 { 2, alc888_4ST_ch2_intel_init },
1334 { 4, alc888_4ST_ch4_intel_init },
1335 { 6, alc888_4ST_ch6_intel_init },
1336 { 8, alc888_4ST_ch8_intel_init },
1337};
1338
1339/*
1340 * ALC888 Fujitsu Siemens Amillo xa3530
1341 */
1342
1343static struct hda_verb alc888_fujitsu_xa3530_verbs[] = {
1344/* Front Mic: set to PIN_IN (empty by default) */
1345 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1346/* Connect Internal HP to Front */
1347 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1348 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1349 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
1350/* Connect Bass HP to Front */
1351 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1352 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1353 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
1354/* Connect Line-Out side jack (SPDIF) to Side */
1355 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1356 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1357 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
1358/* Connect Mic jack to CLFE */
1359 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1360 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1361 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02},
1362/* Connect Line-in jack to Surround */
1363 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1364 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1365 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
1366/* Connect HP out jack to Front */
1367 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1368 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1369 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
1370/* Enable unsolicited event for HP jack and Line-out jack */
1371 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
1372 {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
1373 {}
1374};
1375
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001376static void alc_automute_amp(struct hda_codec *codec)
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001377{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001378 struct alc_spec *spec = codec->spec;
1379 unsigned int val, mute;
1380 hda_nid_t nid;
1381 int i;
1382
1383 spec->jack_present = 0;
1384 for (i = 0; i < ARRAY_SIZE(spec->autocfg.hp_pins); i++) {
1385 nid = spec->autocfg.hp_pins[i];
1386 if (!nid)
1387 break;
1388 val = snd_hda_codec_read(codec, nid, 0,
1389 AC_VERB_GET_PIN_SENSE, 0);
1390 if (val & AC_PINSENSE_PRESENCE) {
1391 spec->jack_present = 1;
1392 break;
1393 }
1394 }
1395
1396 mute = spec->jack_present ? HDA_AMP_MUTE : 0;
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001397 /* Toggle internal speakers muting */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001398 for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) {
1399 nid = spec->autocfg.speaker_pins[i];
1400 if (!nid)
1401 break;
1402 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
1403 HDA_AMP_MUTE, mute);
1404 }
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001405}
1406
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001407static void alc_automute_amp_unsol_event(struct hda_codec *codec,
1408 unsigned int res)
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001409{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001410 if (codec->vendor_id == 0x10ec0880)
1411 res >>= 28;
1412 else
1413 res >>= 26;
1414 if (res == ALC880_HP_EVENT)
1415 alc_automute_amp(codec);
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001416}
1417
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001418static void alc888_fujitsu_xa3530_init_hook(struct hda_codec *codec)
1419{
1420 struct alc_spec *spec = codec->spec;
1421
1422 spec->autocfg.hp_pins[0] = 0x17; /* line-out */
1423 spec->autocfg.hp_pins[1] = 0x1b; /* hp */
1424 spec->autocfg.speaker_pins[0] = 0x14; /* speaker */
1425 spec->autocfg.speaker_pins[1] = 0x15; /* bass */
1426 alc_automute_amp(codec);
1427}
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001428
1429/*
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001430 * ALC888 Acer Aspire 4930G model
1431 */
1432
1433static struct hda_verb alc888_acer_aspire_4930g_verbs[] = {
1434/* Front Mic: set to PIN_IN (empty by default) */
1435 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1436/* Unselect Front Mic by default in input mixer 3 */
1437 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001438/* Enable unsolicited event for HP jack */
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001439 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
1440/* Connect Internal HP to front */
1441 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1442 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1443 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
1444/* Connect HP out to front */
1445 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1446 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1447 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
1448 { }
1449};
1450
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001451static struct hda_input_mux alc888_2_capture_sources[2] = {
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001452 /* Front mic only available on one ADC */
1453 {
1454 .num_items = 4,
1455 .items = {
1456 { "Mic", 0x0 },
1457 { "Line", 0x2 },
1458 { "CD", 0x4 },
1459 { "Front Mic", 0xb },
1460 },
1461 },
1462 {
1463 .num_items = 3,
1464 .items = {
1465 { "Mic", 0x0 },
1466 { "Line", 0x2 },
1467 { "CD", 0x4 },
1468 },
1469 }
1470};
1471
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001472static struct snd_kcontrol_new alc888_base_mixer[] = {
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001473 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1474 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
1475 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1476 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
1477 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
1478 HDA_OUTPUT),
1479 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
1480 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1481 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
1482 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
1483 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
1484 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1485 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1486 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1487 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1488 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1489 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
1490 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001491 { } /* end */
1492};
1493
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001494static void alc888_acer_aspire_4930g_init_hook(struct hda_codec *codec)
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001495{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001496 struct alc_spec *spec = codec->spec;
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001497
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001498 spec->autocfg.hp_pins[0] = 0x15;
1499 spec->autocfg.speaker_pins[0] = 0x14;
1500 alc_automute_amp(codec);
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001501}
1502
1503/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001504 * ALC880 3-stack model
1505 *
1506 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0e)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001507 * Pin assignment: Front = 0x14, Line-In/Surr = 0x1a, Mic/CLFE = 0x18,
1508 * F-Mic = 0x1b, HP = 0x19
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509 */
1510
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001511static hda_nid_t alc880_dac_nids[4] = {
1512 /* front, rear, clfe, rear_surr */
1513 0x02, 0x05, 0x04, 0x03
1514};
1515
1516static hda_nid_t alc880_adc_nids[3] = {
1517 /* ADC0-2 */
1518 0x07, 0x08, 0x09,
1519};
1520
1521/* The datasheet says the node 0x07 is connected from inputs,
1522 * but it shows zero connection in the real implementation on some devices.
Kailang Yangdf694da2005-12-05 19:42:22 +01001523 * Note: this is a 915GAV bug, fixed on 915GLV
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001525static hda_nid_t alc880_adc_nids_alt[2] = {
1526 /* ADC1-2 */
1527 0x08, 0x09,
1528};
1529
1530#define ALC880_DIGOUT_NID 0x06
1531#define ALC880_DIGIN_NID 0x0a
1532
1533static struct hda_input_mux alc880_capture_source = {
1534 .num_items = 4,
1535 .items = {
1536 { "Mic", 0x0 },
1537 { "Front Mic", 0x3 },
1538 { "Line", 0x2 },
1539 { "CD", 0x4 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001541};
1542
1543/* channel source setting (2/6 channel selection for 3-stack) */
1544/* 2ch mode */
1545static struct hda_verb alc880_threestack_ch2_init[] = {
1546 /* set line-in to input, mute it */
1547 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
1548 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1549 /* set mic-in to input vref 80%, mute it */
1550 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1551 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552 { } /* end */
1553};
1554
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001555/* 6ch mode */
1556static struct hda_verb alc880_threestack_ch6_init[] = {
1557 /* set line-in to output, unmute it */
1558 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1559 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1560 /* set mic-in to output, unmute it */
1561 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1562 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1563 { } /* end */
1564};
1565
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001566static struct hda_channel_mode alc880_threestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001567 { 2, alc880_threestack_ch2_init },
1568 { 6, alc880_threestack_ch6_init },
1569};
1570
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001571static struct snd_kcontrol_new alc880_three_stack_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02001572 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001573 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02001574 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001575 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02001576 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1577 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001578 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1579 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1581 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1582 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1583 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1584 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1585 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1586 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
1587 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588 HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001589 {
1590 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1591 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01001592 .info = alc_ch_mode_info,
1593 .get = alc_ch_mode_get,
1594 .put = alc_ch_mode_put,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001595 },
1596 { } /* end */
1597};
1598
1599/* capture mixer elements */
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001600static int alc_cap_vol_info(struct snd_kcontrol *kcontrol,
1601 struct snd_ctl_elem_info *uinfo)
1602{
1603 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1604 struct alc_spec *spec = codec->spec;
1605 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001606
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001607 mutex_lock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001608 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0,
1609 HDA_INPUT);
1610 err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001611 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001612 return err;
1613}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001615static int alc_cap_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
1616 unsigned int size, unsigned int __user *tlv)
1617{
1618 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1619 struct alc_spec *spec = codec->spec;
1620 int err;
1621
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001622 mutex_lock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001623 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0,
1624 HDA_INPUT);
1625 err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001626 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001627 return err;
1628}
1629
1630typedef int (*getput_call_t)(struct snd_kcontrol *kcontrol,
1631 struct snd_ctl_elem_value *ucontrol);
1632
1633static int alc_cap_getput_caller(struct snd_kcontrol *kcontrol,
1634 struct snd_ctl_elem_value *ucontrol,
1635 getput_call_t func)
1636{
1637 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1638 struct alc_spec *spec = codec->spec;
1639 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1640 int err;
1641
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001642 mutex_lock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001643 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[adc_idx],
1644 3, 0, HDA_INPUT);
1645 err = func(kcontrol, ucontrol);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001646 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001647 return err;
1648}
1649
1650static int alc_cap_vol_get(struct snd_kcontrol *kcontrol,
1651 struct snd_ctl_elem_value *ucontrol)
1652{
1653 return alc_cap_getput_caller(kcontrol, ucontrol,
1654 snd_hda_mixer_amp_volume_get);
1655}
1656
1657static int alc_cap_vol_put(struct snd_kcontrol *kcontrol,
1658 struct snd_ctl_elem_value *ucontrol)
1659{
1660 return alc_cap_getput_caller(kcontrol, ucontrol,
1661 snd_hda_mixer_amp_volume_put);
1662}
1663
1664/* capture mixer elements */
1665#define alc_cap_sw_info snd_ctl_boolean_stereo_info
1666
1667static int alc_cap_sw_get(struct snd_kcontrol *kcontrol,
1668 struct snd_ctl_elem_value *ucontrol)
1669{
1670 return alc_cap_getput_caller(kcontrol, ucontrol,
1671 snd_hda_mixer_amp_switch_get);
1672}
1673
1674static int alc_cap_sw_put(struct snd_kcontrol *kcontrol,
1675 struct snd_ctl_elem_value *ucontrol)
1676{
1677 return alc_cap_getput_caller(kcontrol, ucontrol,
1678 snd_hda_mixer_amp_switch_put);
1679}
1680
Takashi Iwaia23b6882009-03-23 15:21:36 +01001681#define _DEFINE_CAPMIX(num) \
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001682 { \
1683 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
1684 .name = "Capture Switch", \
1685 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
1686 .count = num, \
1687 .info = alc_cap_sw_info, \
1688 .get = alc_cap_sw_get, \
1689 .put = alc_cap_sw_put, \
1690 }, \
1691 { \
1692 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
1693 .name = "Capture Volume", \
1694 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | \
1695 SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
1696 SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK), \
1697 .count = num, \
1698 .info = alc_cap_vol_info, \
1699 .get = alc_cap_vol_get, \
1700 .put = alc_cap_vol_put, \
1701 .tlv = { .c = alc_cap_vol_tlv }, \
Takashi Iwaia23b6882009-03-23 15:21:36 +01001702 }
1703
1704#define _DEFINE_CAPSRC(num) \
Takashi Iwai3c3e9892008-10-31 17:48:56 +01001705 { \
1706 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
1707 /* .name = "Capture Source", */ \
1708 .name = "Input Source", \
1709 .count = num, \
1710 .info = alc_mux_enum_info, \
1711 .get = alc_mux_enum_get, \
1712 .put = alc_mux_enum_put, \
Takashi Iwaia23b6882009-03-23 15:21:36 +01001713 }
1714
1715#define DEFINE_CAPMIX(num) \
1716static struct snd_kcontrol_new alc_capture_mixer ## num[] = { \
1717 _DEFINE_CAPMIX(num), \
1718 _DEFINE_CAPSRC(num), \
1719 { } /* end */ \
1720}
1721
1722#define DEFINE_CAPMIX_NOSRC(num) \
1723static struct snd_kcontrol_new alc_capture_mixer_nosrc ## num[] = { \
1724 _DEFINE_CAPMIX(num), \
1725 { } /* end */ \
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001726}
1727
1728/* up to three ADCs */
1729DEFINE_CAPMIX(1);
1730DEFINE_CAPMIX(2);
1731DEFINE_CAPMIX(3);
Takashi Iwaia23b6882009-03-23 15:21:36 +01001732DEFINE_CAPMIX_NOSRC(1);
1733DEFINE_CAPMIX_NOSRC(2);
1734DEFINE_CAPMIX_NOSRC(3);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001735
1736/*
1737 * ALC880 5-stack model
1738 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001739 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0d),
1740 * Side = 0x02 (0xd)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001741 * Pin assignment: Front = 0x14, Surr = 0x17, CLFE = 0x16
1742 * Line-In/Side = 0x1a, Mic = 0x18, F-Mic = 0x1b, HP = 0x19
1743 */
1744
1745/* additional mixers to alc880_three_stack_mixer */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001746static struct snd_kcontrol_new alc880_five_stack_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001747 HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001748 HDA_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749 { } /* end */
1750};
1751
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001752/* channel source setting (6/8 channel selection for 5-stack) */
1753/* 6ch mode */
1754static struct hda_verb alc880_fivestack_ch6_init[] = {
1755 /* set line-in to input, mute it */
1756 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
1757 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02001758 { } /* end */
1759};
1760
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001761/* 8ch mode */
1762static struct hda_verb alc880_fivestack_ch8_init[] = {
1763 /* set line-in to output, unmute it */
1764 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1765 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1766 { } /* end */
1767};
1768
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001769static struct hda_channel_mode alc880_fivestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001770 { 6, alc880_fivestack_ch6_init },
1771 { 8, alc880_fivestack_ch8_init },
1772};
1773
1774
1775/*
1776 * ALC880 6-stack model
1777 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001778 * DAC: Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e),
1779 * Side = 0x05 (0x0f)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001780 * Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, Side = 0x17,
1781 * Mic = 0x18, F-Mic = 0x19, Line = 0x1a, HP = 0x1b
1782 */
1783
1784static hda_nid_t alc880_6st_dac_nids[4] = {
1785 /* front, rear, clfe, rear_surr */
1786 0x02, 0x03, 0x04, 0x05
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02001787};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001788
1789static struct hda_input_mux alc880_6stack_capture_source = {
1790 .num_items = 4,
1791 .items = {
1792 { "Mic", 0x0 },
1793 { "Front Mic", 0x1 },
1794 { "Line", 0x2 },
1795 { "CD", 0x4 },
1796 },
1797};
1798
1799/* fixed 8-channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001800static struct hda_channel_mode alc880_sixstack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001801 { 8, NULL },
1802};
1803
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001804static struct snd_kcontrol_new alc880_six_stack_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001805 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001806 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001807 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001808 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001809 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1810 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001811 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1812 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001813 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001814 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001815 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1816 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1817 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1818 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1819 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1820 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1821 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1822 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001823 {
1824 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1825 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01001826 .info = alc_ch_mode_info,
1827 .get = alc_ch_mode_get,
1828 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02001829 },
1830 { } /* end */
1831};
1832
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001833
1834/*
1835 * ALC880 W810 model
1836 *
1837 * W810 has rear IO for:
1838 * Front (DAC 02)
1839 * Surround (DAC 03)
1840 * Center/LFE (DAC 04)
1841 * Digital out (06)
1842 *
1843 * The system also has a pair of internal speakers, and a headphone jack.
1844 * These are both connected to Line2 on the codec, hence to DAC 02.
Kailang Yangea1fb292008-08-26 12:58:38 +02001845 *
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001846 * There is a variable resistor to control the speaker or headphone
1847 * volume. This is a hardware-only device without a software API.
1848 *
1849 * Plugging headphones in will disable the internal speakers. This is
1850 * implemented in hardware, not via the driver using jack sense. In
1851 * a similar fashion, plugging into the rear socket marked "front" will
1852 * disable both the speakers and headphones.
1853 *
1854 * For input, there's a microphone jack, and an "audio in" jack.
1855 * These may not do anything useful with this driver yet, because I
1856 * haven't setup any initialization verbs for these yet...
1857 */
1858
1859static hda_nid_t alc880_w810_dac_nids[3] = {
1860 /* front, rear/surround, clfe */
1861 0x02, 0x03, 0x04
1862};
1863
1864/* fixed 6 channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001865static struct hda_channel_mode alc880_w810_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001866 { 6, NULL }
1867};
1868
1869/* Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, HP = 0x1b */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001870static struct snd_kcontrol_new alc880_w810_base_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001871 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001872 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001873 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001874 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001875 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1876 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001877 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1878 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001879 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
1880 { } /* end */
1881};
1882
1883
1884/*
1885 * Z710V model
1886 *
1887 * DAC: Front = 0x02 (0x0c), HP = 0x03 (0x0d)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001888 * Pin assignment: Front = 0x14, HP = 0x15, Mic = 0x18, Mic2 = 0x19(?),
1889 * Line = 0x1a
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001890 */
1891
1892static hda_nid_t alc880_z71v_dac_nids[1] = {
1893 0x02
1894};
1895#define ALC880_Z71V_HP_DAC 0x03
1896
1897/* fixed 2 channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001898static struct hda_channel_mode alc880_2_jack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001899 { 2, NULL }
1900};
1901
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001902static struct snd_kcontrol_new alc880_z71v_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001903 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001904 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001905 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001906 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001907 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1908 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1909 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1910 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1911 { } /* end */
1912};
1913
1914
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001915/*
1916 * ALC880 F1734 model
1917 *
1918 * DAC: HP = 0x02 (0x0c), Front = 0x03 (0x0d)
1919 * Pin assignment: HP = 0x14, Front = 0x15, Mic = 0x18
1920 */
1921
1922static hda_nid_t alc880_f1734_dac_nids[1] = {
1923 0x03
1924};
1925#define ALC880_F1734_HP_DAC 0x02
1926
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001927static struct snd_kcontrol_new alc880_f1734_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001928 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001929 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01001930 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1931 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001932 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1933 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Takashi Iwai937b4162008-02-11 14:52:36 +01001934 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1935 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001936 { } /* end */
1937};
1938
Takashi Iwai937b4162008-02-11 14:52:36 +01001939static struct hda_input_mux alc880_f1734_capture_source = {
1940 .num_items = 2,
1941 .items = {
1942 { "Mic", 0x1 },
1943 { "CD", 0x4 },
1944 },
1945};
1946
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001947
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001948/*
1949 * ALC880 ASUS model
1950 *
1951 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
1952 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
1953 * Mic = 0x18, Line = 0x1a
1954 */
1955
1956#define alc880_asus_dac_nids alc880_w810_dac_nids /* identical with w810 */
1957#define alc880_asus_modes alc880_threestack_modes /* 2/6 channel mode */
1958
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001959static struct snd_kcontrol_new alc880_asus_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001960 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001961 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001962 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001963 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001964 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1965 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001966 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1967 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001968 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1969 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1970 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1971 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1972 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1973 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001974 {
1975 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1976 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01001977 .info = alc_ch_mode_info,
1978 .get = alc_ch_mode_get,
1979 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02001980 },
1981 { } /* end */
1982};
1983
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001984/*
1985 * ALC880 ASUS W1V model
1986 *
1987 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
1988 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
1989 * Mic = 0x18, Line = 0x1a, Line2 = 0x1b
1990 */
1991
1992/* additional mixers to alc880_asus_mixer */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001993static struct snd_kcontrol_new alc880_asus_w1v_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001994 HDA_CODEC_VOLUME("Line2 Playback Volume", 0x0b, 0x03, HDA_INPUT),
1995 HDA_CODEC_MUTE("Line2 Playback Switch", 0x0b, 0x03, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001996 { } /* end */
1997};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001998
Kailang Yangdf694da2005-12-05 19:42:22 +01001999/* TCL S700 */
2000static struct snd_kcontrol_new alc880_tcl_s700_mixer[] = {
2001 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2002 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
2003 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
2004 HDA_CODEC_VOLUME("CD Playback Volume", 0x0B, 0x04, HDA_INPUT),
2005 HDA_CODEC_MUTE("CD Playback Switch", 0x0B, 0x04, HDA_INPUT),
2006 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0B, 0x0, HDA_INPUT),
2007 HDA_CODEC_MUTE("Mic Playback Switch", 0x0B, 0x0, HDA_INPUT),
2008 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
2009 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01002010 { } /* end */
2011};
2012
Kailang Yangccc656c2006-10-17 12:32:26 +02002013/* Uniwill */
2014static struct snd_kcontrol_new alc880_uniwill_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01002015 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2016 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
2017 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2018 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02002019 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2020 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
2021 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2022 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
2023 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("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2026 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2027 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2028 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2029 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2030 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02002031 {
2032 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2033 .name = "Channel Mode",
2034 .info = alc_ch_mode_info,
2035 .get = alc_ch_mode_get,
2036 .put = alc_ch_mode_put,
2037 },
2038 { } /* end */
2039};
2040
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01002041static struct snd_kcontrol_new alc880_fujitsu_mixer[] = {
2042 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2043 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
2044 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2045 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
2046 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2047 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2048 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2049 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2050 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2051 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
2052 { } /* end */
2053};
2054
Kailang Yangccc656c2006-10-17 12:32:26 +02002055static struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01002056 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2057 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
2058 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2059 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02002060 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2061 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2062 { } /* end */
2063};
2064
Linus Torvalds1da177e2005-04-16 15:20:36 -07002065/*
Takashi Iwai2134ea42008-01-10 16:53:55 +01002066 * virtual master controls
2067 */
2068
2069/*
2070 * slave controls for virtual master
2071 */
2072static const char *alc_slave_vols[] = {
2073 "Front Playback Volume",
2074 "Surround Playback Volume",
2075 "Center Playback Volume",
2076 "LFE Playback Volume",
2077 "Side Playback Volume",
2078 "Headphone Playback Volume",
2079 "Speaker Playback Volume",
2080 "Mono Playback Volume",
Takashi Iwai2134ea42008-01-10 16:53:55 +01002081 "Line-Out Playback Volume",
Takashi Iwai26f5df22008-11-03 17:39:46 +01002082 "PCM Playback Volume",
Takashi Iwai2134ea42008-01-10 16:53:55 +01002083 NULL,
2084};
2085
2086static const char *alc_slave_sws[] = {
2087 "Front Playback Switch",
2088 "Surround Playback Switch",
2089 "Center Playback Switch",
2090 "LFE Playback Switch",
2091 "Side Playback Switch",
2092 "Headphone Playback Switch",
2093 "Speaker Playback Switch",
2094 "Mono Playback Switch",
Takashi Iwaiedb54a52008-01-29 12:47:02 +01002095 "IEC958 Playback Switch",
Takashi Iwai2134ea42008-01-10 16:53:55 +01002096 NULL,
2097};
2098
2099/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002100 * build control elements
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101 */
Takashi Iwai603c4012008-07-30 15:01:44 +02002102
2103static void alc_free_kctls(struct hda_codec *codec);
2104
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002105/* additional beep mixers; the actual parameters are overwritten at build */
2106static struct snd_kcontrol_new alc_beep_mixer[] = {
2107 HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_INPUT),
2108 HDA_CODEC_MUTE("Beep Playback Switch", 0, 0, HDA_INPUT),
2109 { } /* end */
2110};
2111
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112static int alc_build_controls(struct hda_codec *codec)
2113{
2114 struct alc_spec *spec = codec->spec;
2115 int err;
2116 int i;
2117
2118 for (i = 0; i < spec->num_mixers; i++) {
2119 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
2120 if (err < 0)
2121 return err;
2122 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002123 if (spec->cap_mixer) {
2124 err = snd_hda_add_new_ctls(codec, spec->cap_mixer);
2125 if (err < 0)
2126 return err;
2127 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002128 if (spec->multiout.dig_out_nid) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002129 err = snd_hda_create_spdif_out_ctls(codec,
2130 spec->multiout.dig_out_nid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002131 if (err < 0)
2132 return err;
Takashi Iwaie64f14f2009-01-20 18:32:55 +01002133 if (!spec->no_analog) {
2134 err = snd_hda_create_spdif_share_sw(codec,
2135 &spec->multiout);
2136 if (err < 0)
2137 return err;
2138 spec->multiout.share_spdif = 1;
2139 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002140 }
2141 if (spec->dig_in_nid) {
2142 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
2143 if (err < 0)
2144 return err;
2145 }
Takashi Iwai2134ea42008-01-10 16:53:55 +01002146
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002147 /* create beep controls if needed */
2148 if (spec->beep_amp) {
2149 struct snd_kcontrol_new *knew;
2150 for (knew = alc_beep_mixer; knew->name; knew++) {
2151 struct snd_kcontrol *kctl;
2152 kctl = snd_ctl_new1(knew, codec);
2153 if (!kctl)
2154 return -ENOMEM;
2155 kctl->private_value = spec->beep_amp;
2156 err = snd_hda_ctl_add(codec, kctl);
2157 if (err < 0)
2158 return err;
2159 }
2160 }
2161
Takashi Iwai2134ea42008-01-10 16:53:55 +01002162 /* if we have no master control, let's create it */
Takashi Iwaie64f14f2009-01-20 18:32:55 +01002163 if (!spec->no_analog &&
2164 !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
Takashi Iwai1c82ed12008-02-18 13:05:50 +01002165 unsigned int vmaster_tlv[4];
Takashi Iwai2134ea42008-01-10 16:53:55 +01002166 snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
Takashi Iwai1c82ed12008-02-18 13:05:50 +01002167 HDA_OUTPUT, vmaster_tlv);
Takashi Iwai2134ea42008-01-10 16:53:55 +01002168 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
Takashi Iwai1c82ed12008-02-18 13:05:50 +01002169 vmaster_tlv, alc_slave_vols);
Takashi Iwai2134ea42008-01-10 16:53:55 +01002170 if (err < 0)
2171 return err;
2172 }
Takashi Iwaie64f14f2009-01-20 18:32:55 +01002173 if (!spec->no_analog &&
2174 !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
Takashi Iwai2134ea42008-01-10 16:53:55 +01002175 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
2176 NULL, alc_slave_sws);
2177 if (err < 0)
2178 return err;
2179 }
2180
Takashi Iwai603c4012008-07-30 15:01:44 +02002181 alc_free_kctls(codec); /* no longer needed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182 return 0;
2183}
2184
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002185
Linus Torvalds1da177e2005-04-16 15:20:36 -07002186/*
2187 * initialize the codec volumes, etc
2188 */
2189
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002190/*
2191 * generic initialization of ADC, input mixers and output mixers
2192 */
2193static struct hda_verb alc880_volume_init_verbs[] = {
2194 /*
2195 * Unmute ADC0-2 and set the default input to mic-in
2196 */
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002197 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002198 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002199 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002200 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002201 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002202 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002203
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002204 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
2205 * mixer widget
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002206 * Note: PASD motherboards uses the Line In 2 as the input for front
2207 * panel mic (mic 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002208 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002209 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02002210 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2211 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2212 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
2213 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2214 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
2215 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
2216 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002217
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002218 /*
2219 * Set up output mixers (0x0c - 0x0f)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002220 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002221 /* set vol=0 to output mixers */
2222 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2223 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2224 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2225 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2226 /* set up input amps for analog loopback */
2227 /* Amp Indices: DAC = 0, mixer = 1 */
Takashi Iwai05acb862005-06-10 19:50:25 +02002228 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2229 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02002230 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2231 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02002232 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2233 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02002234 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2235 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236
2237 { }
2238};
2239
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002240/*
2241 * 3-stack pin configuration:
2242 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
2243 */
2244static struct hda_verb alc880_pin_3stack_init_verbs[] = {
2245 /*
2246 * preset connection lists of input pins
2247 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
2248 */
2249 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
2250 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2251 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
2252
2253 /*
2254 * Set pin mode and muting
2255 */
2256 /* set front pin widgets 0x14 for output */
2257 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2258 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2259 /* Mic1 (rear panel) pin widget for input and vref at 80% */
2260 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2261 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2262 /* Mic2 (as headphone out) for HP output */
2263 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2264 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2265 /* Line In pin widget for input */
2266 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2267 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2268 /* Line2 (as front mic) pin widget for input and vref at 80% */
2269 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2270 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2271 /* CD pin widget for input */
2272 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2273
2274 { }
2275};
2276
2277/*
2278 * 5-stack pin configuration:
2279 * front = 0x14, surround = 0x17, clfe = 0x16, mic = 0x18, HP = 0x19,
2280 * line-in/side = 0x1a, f-mic = 0x1b
2281 */
2282static struct hda_verb alc880_pin_5stack_init_verbs[] = {
2283 /*
2284 * preset connection lists of input pins
2285 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
2286 */
2287 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2288 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/side */
2289
2290 /*
2291 * Set pin mode and muting
2292 */
2293 /* set pin widgets 0x14-0x17 for output */
Takashi Iwai05acb862005-06-10 19:50:25 +02002294 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2295 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2296 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2297 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002298 /* unmute pins for output (no gain on this amp) */
2299 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2300 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2301 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2302 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2303
Linus Torvalds1da177e2005-04-16 15:20:36 -07002304 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02002305 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002306 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2307 /* Mic2 (as headphone out) for HP output */
2308 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02002309 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002310 /* Line In pin widget for input */
2311 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2312 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2313 /* Line2 (as front mic) pin widget for input and vref at 80% */
2314 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2315 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2316 /* CD pin widget for input */
2317 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002318
2319 { }
2320};
2321
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002322/*
2323 * W810 pin configuration:
2324 * front = 0x14, surround = 0x15, clfe = 0x16, HP = 0x1b
2325 */
2326static struct hda_verb alc880_pin_w810_init_verbs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002327 /* hphone/speaker input selector: front DAC */
2328 {0x13, AC_VERB_SET_CONNECT_SEL, 0x0},
2329
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002330 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2331 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2332 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2333 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2334 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2335 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2336
2337 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02002338 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002339
Linus Torvalds1da177e2005-04-16 15:20:36 -07002340 { }
2341};
2342
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002343/*
2344 * Z71V pin configuration:
2345 * Speaker-out = 0x14, HP = 0x15, Mic = 0x18, Line-in = 0x1a, Mic2 = 0x1b (?)
2346 */
2347static struct hda_verb alc880_pin_z71v_init_verbs[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02002348 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002349 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai05acb862005-06-10 19:50:25 +02002350 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002351 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02002352
Takashi Iwai16ded522005-06-10 19:58:24 +02002353 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002354 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02002355 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002356 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02002357
2358 { }
2359};
2360
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002361/*
2362 * 6-stack pin configuration:
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002363 * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18,
2364 * f-mic = 0x19, line = 0x1a, HP = 0x1b
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002365 */
2366static struct hda_verb alc880_pin_6stack_init_verbs[] = {
2367 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2368
Takashi Iwai16ded522005-06-10 19:58:24 +02002369 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002370 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002371 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002372 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002373 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002374 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002375 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002376 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2377
Takashi Iwai16ded522005-06-10 19:58:24 +02002378 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002379 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002380 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002381 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002382 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002383 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002384 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai16ded522005-06-10 19:58:24 +02002385 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002386 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangea1fb292008-08-26 12:58:38 +02002387
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002388 { }
2389};
Takashi Iwai16ded522005-06-10 19:58:24 +02002390
Kailang Yangccc656c2006-10-17 12:32:26 +02002391/*
2392 * Uniwill pin configuration:
2393 * HP = 0x14, InternalSpeaker = 0x15, mic = 0x18, internal mic = 0x19,
2394 * line = 0x1a
2395 */
2396static struct hda_verb alc880_uniwill_init_verbs[] = {
2397 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2398
2399 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2400 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2401 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2402 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2403 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2404 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2405 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2406 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2407 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2408 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2409 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2410 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2411 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2412 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2413
2414 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2415 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2416 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2417 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2418 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2419 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2420 /* {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, */
2421 /* {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
2422 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2423
2424 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
2425 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
2426
2427 { }
2428};
2429
2430/*
2431* Uniwill P53
Kailang Yangea1fb292008-08-26 12:58:38 +02002432* HP = 0x14, InternalSpeaker = 0x15, mic = 0x19,
Kailang Yangccc656c2006-10-17 12:32:26 +02002433 */
2434static struct hda_verb alc880_uniwill_p53_init_verbs[] = {
2435 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2436
2437 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2438 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2439 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2440 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2441 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2442 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2443 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2444 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2445 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2446 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2447 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2448 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2449
2450 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2451 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2452 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2453 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2454 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2455 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2456
2457 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
2458 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_DCVOL_EVENT},
2459
2460 { }
2461};
2462
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01002463static struct hda_verb alc880_beep_init_verbs[] = {
2464 { 0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) },
2465 { }
2466};
2467
Takashi Iwai458a4fa2007-05-05 12:18:40 +02002468/* auto-toggle front mic */
2469static void alc880_uniwill_mic_automute(struct hda_codec *codec)
2470{
2471 unsigned int present;
2472 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02002473
2474 present = snd_hda_codec_read(codec, 0x18, 0,
2475 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02002476 bits = present ? HDA_AMP_MUTE : 0;
2477 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02002478}
2479
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002480static void alc880_uniwill_init_hook(struct hda_codec *codec)
Takashi Iwai458a4fa2007-05-05 12:18:40 +02002481{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002482 struct alc_spec *spec = codec->spec;
2483
2484 spec->autocfg.hp_pins[0] = 0x14;
2485 spec->autocfg.speaker_pins[0] = 0x15;
2486 spec->autocfg.speaker_pins[0] = 0x16;
2487 alc_automute_amp(codec);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02002488 alc880_uniwill_mic_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02002489}
2490
2491static void alc880_uniwill_unsol_event(struct hda_codec *codec,
2492 unsigned int res)
2493{
2494 /* Looks like the unsol event is incompatible with the standard
2495 * definition. 4bit tag is placed at 28 bit!
2496 */
Takashi Iwai458a4fa2007-05-05 12:18:40 +02002497 switch (res >> 28) {
Takashi Iwai458a4fa2007-05-05 12:18:40 +02002498 case ALC880_MIC_EVENT:
2499 alc880_uniwill_mic_automute(codec);
2500 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002501 default:
2502 alc_automute_amp_unsol_event(codec, res);
2503 break;
Takashi Iwai458a4fa2007-05-05 12:18:40 +02002504 }
Kailang Yangccc656c2006-10-17 12:32:26 +02002505}
2506
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002507static void alc880_uniwill_p53_init_hook(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02002508{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002509 struct alc_spec *spec = codec->spec;
Kailang Yangccc656c2006-10-17 12:32:26 +02002510
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002511 spec->autocfg.hp_pins[0] = 0x14;
2512 spec->autocfg.speaker_pins[0] = 0x15;
2513 alc_automute_amp(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02002514}
2515
2516static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec)
2517{
2518 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02002519
Kailang Yangccc656c2006-10-17 12:32:26 +02002520 present = snd_hda_codec_read(codec, 0x21, 0,
Takashi Iwai47fd8302007-08-10 17:11:07 +02002521 AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
2522 present &= HDA_AMP_VOLMASK;
2523 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0,
2524 HDA_AMP_VOLMASK, present);
2525 snd_hda_codec_amp_stereo(codec, 0x0d, HDA_OUTPUT, 0,
2526 HDA_AMP_VOLMASK, present);
Kailang Yangccc656c2006-10-17 12:32:26 +02002527}
Takashi Iwai47fd8302007-08-10 17:11:07 +02002528
Kailang Yangccc656c2006-10-17 12:32:26 +02002529static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec,
2530 unsigned int res)
2531{
2532 /* Looks like the unsol event is incompatible with the standard
2533 * definition. 4bit tag is placed at 28 bit!
2534 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002535 if ((res >> 28) == ALC880_DCVOL_EVENT)
Kailang Yangccc656c2006-10-17 12:32:26 +02002536 alc880_uniwill_p53_dcvol_automute(codec);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002537 else
2538 alc_automute_amp_unsol_event(codec, res);
Kailang Yangccc656c2006-10-17 12:32:26 +02002539}
2540
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002541/*
2542 * F1734 pin configuration:
2543 * HP = 0x14, speaker-out = 0x15, mic = 0x18
2544 */
2545static struct hda_verb alc880_pin_f1734_init_verbs[] = {
Michael Gruberee7a9c72008-03-10 11:30:59 +01002546 {0x07, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002547 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
2548 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
2549 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
2550 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
2551
2552 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2553 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2554 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2555 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2556
2557 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2558 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Michael Gruberee7a9c72008-03-10 11:30:59 +01002559 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002560 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2561 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2562 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2563 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2564 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2565 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02002566
Takashi Iwai937b4162008-02-11 14:52:36 +01002567 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
2568 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_DCVOL_EVENT},
2569
Takashi Iwai16ded522005-06-10 19:58:24 +02002570 { }
2571};
2572
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002573/*
2574 * ASUS pin configuration:
2575 * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a
2576 */
2577static struct hda_verb alc880_pin_asus_init_verbs[] = {
2578 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
2579 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
2580 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
2581 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
2582
2583 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2584 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2585 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2586 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2587 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2588 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2589 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2590 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2591
2592 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2593 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2594 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2595 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2596 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2597 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2598 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2599 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2600 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangea1fb292008-08-26 12:58:38 +02002601
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002602 { }
2603};
2604
2605/* Enable GPIO mask and set output */
Kailang Yangbc9f98a2007-04-12 13:06:07 +02002606#define alc880_gpio1_init_verbs alc_gpio1_init_verbs
2607#define alc880_gpio2_init_verbs alc_gpio2_init_verbs
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002608
Kailang Yangdf694da2005-12-05 19:42:22 +01002609/* Clevo m520g init */
2610static struct hda_verb alc880_pin_clevo_init_verbs[] = {
2611 /* headphone output */
2612 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
2613 /* line-out */
2614 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2615 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2616 /* Line-in */
2617 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2618 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2619 /* CD */
2620 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2621 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2622 /* Mic1 (rear panel) */
2623 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2624 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2625 /* Mic2 (front panel) */
2626 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2627 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2628 /* headphone */
2629 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2630 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2631 /* change to EAPD mode */
2632 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
2633 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
2634
2635 { }
2636};
2637
2638static struct hda_verb alc880_pin_tcl_S700_init_verbs[] = {
Takashi Iwai4b146cb2006-07-28 14:42:36 +02002639 /* change to EAPD mode */
2640 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
2641 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
2642
Kailang Yangdf694da2005-12-05 19:42:22 +01002643 /* Headphone output */
2644 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2645 /* Front output*/
2646 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2647 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
2648
2649 /* Line In pin widget for input */
2650 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2651 /* CD pin widget for input */
2652 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2653 /* Mic1 (rear panel) pin widget for input and vref at 80% */
2654 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2655
2656 /* change to EAPD mode */
2657 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
2658 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
2659
2660 { }
2661};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002662
2663/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002664 * LG m1 express dual
2665 *
2666 * Pin assignment:
2667 * Rear Line-In/Out (blue): 0x14
2668 * Build-in Mic-In: 0x15
2669 * Speaker-out: 0x17
2670 * HP-Out (green): 0x1b
2671 * Mic-In/Out (red): 0x19
2672 * SPDIF-Out: 0x1e
2673 */
2674
2675/* To make 5.1 output working (green=Front, blue=Surr, red=CLFE) */
2676static hda_nid_t alc880_lg_dac_nids[3] = {
2677 0x05, 0x02, 0x03
2678};
2679
2680/* seems analog CD is not working */
2681static struct hda_input_mux alc880_lg_capture_source = {
2682 .num_items = 3,
2683 .items = {
2684 { "Mic", 0x1 },
2685 { "Line", 0x5 },
2686 { "Internal Mic", 0x6 },
2687 },
2688};
2689
2690/* 2,4,6 channel modes */
2691static struct hda_verb alc880_lg_ch2_init[] = {
2692 /* set line-in and mic-in to input */
2693 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2694 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2695 { }
2696};
2697
2698static struct hda_verb alc880_lg_ch4_init[] = {
2699 /* set line-in to out and mic-in to input */
2700 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
2701 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2702 { }
2703};
2704
2705static struct hda_verb alc880_lg_ch6_init[] = {
2706 /* set line-in and mic-in to output */
2707 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
2708 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
2709 { }
2710};
2711
2712static struct hda_channel_mode alc880_lg_ch_modes[3] = {
2713 { 2, alc880_lg_ch2_init },
2714 { 4, alc880_lg_ch4_init },
2715 { 6, alc880_lg_ch6_init },
2716};
2717
2718static struct snd_kcontrol_new alc880_lg_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01002719 HDA_CODEC_VOLUME("Front Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
2720 HDA_BIND_MUTE("Front Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002721 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2722 HDA_BIND_MUTE("Surround Playback Switch", 0x0c, 2, HDA_INPUT),
2723 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
2724 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
2725 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
2726 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
2727 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2728 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
2729 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x06, HDA_INPUT),
2730 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x06, HDA_INPUT),
2731 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x07, HDA_INPUT),
2732 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x07, HDA_INPUT),
2733 {
2734 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2735 .name = "Channel Mode",
2736 .info = alc_ch_mode_info,
2737 .get = alc_ch_mode_get,
2738 .put = alc_ch_mode_put,
2739 },
2740 { } /* end */
2741};
2742
2743static struct hda_verb alc880_lg_init_verbs[] = {
2744 /* set capture source to mic-in */
2745 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2746 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2747 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2748 /* mute all amp mixer inputs */
2749 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02002750 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
2751 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002752 /* line-in to input */
2753 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2754 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2755 /* built-in mic */
2756 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2757 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2758 /* speaker-out */
2759 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2760 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2761 /* mic-in to input */
2762 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
2763 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2764 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2765 /* HP-out */
2766 {0x13, AC_VERB_SET_CONNECT_SEL, 0x03},
2767 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2768 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2769 /* jack sense */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002770 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002771 { }
2772};
2773
2774/* toggle speaker-output according to the hp-jack state */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002775static void alc880_lg_init_hook(struct hda_codec *codec)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002776{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002777 struct alc_spec *spec = codec->spec;
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002778
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002779 spec->autocfg.hp_pins[0] = 0x1b;
2780 spec->autocfg.speaker_pins[0] = 0x17;
2781 alc_automute_amp(codec);
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002782}
2783
2784/*
Takashi Iwaid6815182006-03-23 16:06:23 +01002785 * LG LW20
2786 *
2787 * Pin assignment:
2788 * Speaker-out: 0x14
2789 * Mic-In: 0x18
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02002790 * Built-in Mic-In: 0x19
2791 * Line-In: 0x1b
2792 * HP-Out: 0x1a
Takashi Iwaid6815182006-03-23 16:06:23 +01002793 * SPDIF-Out: 0x1e
2794 */
2795
Takashi Iwaid6815182006-03-23 16:06:23 +01002796static struct hda_input_mux alc880_lg_lw_capture_source = {
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02002797 .num_items = 3,
Takashi Iwaid6815182006-03-23 16:06:23 +01002798 .items = {
2799 { "Mic", 0x0 },
2800 { "Internal Mic", 0x1 },
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02002801 { "Line In", 0x2 },
Takashi Iwaid6815182006-03-23 16:06:23 +01002802 },
2803};
2804
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002805#define alc880_lg_lw_modes alc880_threestack_modes
2806
Takashi Iwaid6815182006-03-23 16:06:23 +01002807static struct snd_kcontrol_new alc880_lg_lw_mixer[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002808 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2809 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
2810 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
2811 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
2812 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2813 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
2814 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2815 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
2816 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2817 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaid6815182006-03-23 16:06:23 +01002818 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2819 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2820 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
2821 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002822 {
2823 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2824 .name = "Channel Mode",
2825 .info = alc_ch_mode_info,
2826 .get = alc_ch_mode_get,
2827 .put = alc_ch_mode_put,
2828 },
Takashi Iwaid6815182006-03-23 16:06:23 +01002829 { } /* end */
2830};
2831
2832static struct hda_verb alc880_lg_lw_init_verbs[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002833 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2834 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
2835 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
2836
Takashi Iwaid6815182006-03-23 16:06:23 +01002837 /* set capture source to mic-in */
2838 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2839 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2840 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02002841 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaid6815182006-03-23 16:06:23 +01002842 /* speaker-out */
2843 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2844 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2845 /* HP-out */
Takashi Iwaid6815182006-03-23 16:06:23 +01002846 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2847 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2848 /* mic-in to input */
2849 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2850 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2851 /* built-in mic */
2852 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2853 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2854 /* jack sense */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002855 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaid6815182006-03-23 16:06:23 +01002856 { }
2857};
2858
2859/* toggle speaker-output according to the hp-jack state */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002860static void alc880_lg_lw_init_hook(struct hda_codec *codec)
Takashi Iwaid6815182006-03-23 16:06:23 +01002861{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002862 struct alc_spec *spec = codec->spec;
Takashi Iwaid6815182006-03-23 16:06:23 +01002863
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002864 spec->autocfg.hp_pins[0] = 0x1b;
2865 spec->autocfg.speaker_pins[0] = 0x14;
2866 alc_automute_amp(codec);
Takashi Iwaid6815182006-03-23 16:06:23 +01002867}
2868
Takashi Iwaidf99cd32008-04-25 15:25:04 +02002869static struct snd_kcontrol_new alc880_medion_rim_mixer[] = {
2870 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2871 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
2872 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2873 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2874 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2875 HDA_CODEC_MUTE("Internal Playback Switch", 0x0b, 0x1, HDA_INPUT),
2876 { } /* end */
2877};
2878
2879static struct hda_input_mux alc880_medion_rim_capture_source = {
2880 .num_items = 2,
2881 .items = {
2882 { "Mic", 0x0 },
2883 { "Internal Mic", 0x1 },
2884 },
2885};
2886
2887static struct hda_verb alc880_medion_rim_init_verbs[] = {
2888 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2889
2890 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2891 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2892
2893 /* Mic1 (rear panel) pin widget for input and vref at 80% */
2894 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2895 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2896 /* Mic2 (as headphone out) for HP output */
2897 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2898 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2899 /* Internal Speaker */
2900 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2901 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2902
2903 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
2904 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
2905
2906 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
2907 { }
2908};
2909
2910/* toggle speaker-output according to the hp-jack state */
2911static void alc880_medion_rim_automute(struct hda_codec *codec)
2912{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002913 struct alc_spec *spec = codec->spec;
2914 alc_automute_amp(codec);
2915 /* toggle EAPD */
2916 if (spec->jack_present)
Takashi Iwaidf99cd32008-04-25 15:25:04 +02002917 snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0);
2918 else
2919 snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 2);
2920}
2921
2922static void alc880_medion_rim_unsol_event(struct hda_codec *codec,
2923 unsigned int res)
2924{
2925 /* Looks like the unsol event is incompatible with the standard
2926 * definition. 4bit tag is placed at 28 bit!
2927 */
2928 if ((res >> 28) == ALC880_HP_EVENT)
2929 alc880_medion_rim_automute(codec);
2930}
2931
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002932static void alc880_medion_rim_init_hook(struct hda_codec *codec)
2933{
2934 struct alc_spec *spec = codec->spec;
2935
2936 spec->autocfg.hp_pins[0] = 0x14;
2937 spec->autocfg.speaker_pins[0] = 0x1b;
2938 alc880_medion_rim_automute(codec);
2939}
2940
Takashi Iwaicb53c622007-08-10 17:21:45 +02002941#ifdef CONFIG_SND_HDA_POWER_SAVE
2942static struct hda_amp_list alc880_loopbacks[] = {
2943 { 0x0b, HDA_INPUT, 0 },
2944 { 0x0b, HDA_INPUT, 1 },
2945 { 0x0b, HDA_INPUT, 2 },
2946 { 0x0b, HDA_INPUT, 3 },
2947 { 0x0b, HDA_INPUT, 4 },
2948 { } /* end */
2949};
2950
2951static struct hda_amp_list alc880_lg_loopbacks[] = {
2952 { 0x0b, HDA_INPUT, 1 },
2953 { 0x0b, HDA_INPUT, 6 },
2954 { 0x0b, HDA_INPUT, 7 },
2955 { } /* end */
2956};
2957#endif
2958
Takashi Iwaid6815182006-03-23 16:06:23 +01002959/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002960 * Common callbacks
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002961 */
Takashi Iwai16ded522005-06-10 19:58:24 +02002962
Linus Torvalds1da177e2005-04-16 15:20:36 -07002963static int alc_init(struct hda_codec *codec)
2964{
2965 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002966 unsigned int i;
2967
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02002968 alc_fix_pll(codec);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02002969 alc_auto_init_amp(codec, spec->init_amp);
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02002970
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002971 for (i = 0; i < spec->num_init_verbs; i++)
2972 snd_hda_sequence_write(codec, spec->init_verbs[i]);
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002973
2974 if (spec->init_hook)
2975 spec->init_hook(codec);
2976
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977 return 0;
2978}
2979
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002980static void alc_unsol_event(struct hda_codec *codec, unsigned int res)
2981{
2982 struct alc_spec *spec = codec->spec;
2983
2984 if (spec->unsol_event)
2985 spec->unsol_event(codec, res);
2986}
2987
Takashi Iwaicb53c622007-08-10 17:21:45 +02002988#ifdef CONFIG_SND_HDA_POWER_SAVE
2989static int alc_check_power_status(struct hda_codec *codec, hda_nid_t nid)
2990{
2991 struct alc_spec *spec = codec->spec;
2992 return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
2993}
2994#endif
2995
Linus Torvalds1da177e2005-04-16 15:20:36 -07002996/*
2997 * Analog playback callbacks
2998 */
2999static int alc880_playback_pcm_open(struct hda_pcm_stream *hinfo,
3000 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003001 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003002{
3003 struct alc_spec *spec = codec->spec;
Takashi Iwai9a081602008-02-12 18:37:26 +01003004 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
3005 hinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003006}
3007
3008static int alc880_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
3009 struct hda_codec *codec,
3010 unsigned int stream_tag,
3011 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003012 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003013{
3014 struct alc_spec *spec = codec->spec;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003015 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
3016 stream_tag, format, substream);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003017}
3018
3019static int alc880_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
3020 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003021 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003022{
3023 struct alc_spec *spec = codec->spec;
3024 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
3025}
3026
3027/*
3028 * Digital out
3029 */
3030static int alc880_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
3031 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003032 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003033{
3034 struct alc_spec *spec = codec->spec;
3035 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
3036}
3037
Takashi Iwai6b97eb42007-04-05 14:51:48 +02003038static int alc880_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
3039 struct hda_codec *codec,
3040 unsigned int stream_tag,
3041 unsigned int format,
3042 struct snd_pcm_substream *substream)
3043{
3044 struct alc_spec *spec = codec->spec;
3045 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
3046 stream_tag, format, substream);
3047}
3048
Takashi Iwai9b5f12e2009-02-13 11:47:37 +01003049static int alc880_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
3050 struct hda_codec *codec,
3051 struct snd_pcm_substream *substream)
3052{
3053 struct alc_spec *spec = codec->spec;
3054 return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
3055}
3056
Linus Torvalds1da177e2005-04-16 15:20:36 -07003057static int alc880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
3058 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003059 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003060{
3061 struct alc_spec *spec = codec->spec;
3062 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
3063}
3064
3065/*
3066 * Analog capture
3067 */
Takashi Iwai63300792008-01-24 15:31:36 +01003068static int alc880_alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003069 struct hda_codec *codec,
3070 unsigned int stream_tag,
3071 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003072 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003073{
3074 struct alc_spec *spec = codec->spec;
3075
Takashi Iwai63300792008-01-24 15:31:36 +01003076 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1],
Linus Torvalds1da177e2005-04-16 15:20:36 -07003077 stream_tag, 0, format);
3078 return 0;
3079}
3080
Takashi Iwai63300792008-01-24 15:31:36 +01003081static int alc880_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003082 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003083 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003084{
3085 struct alc_spec *spec = codec->spec;
3086
Takashi Iwai888afa12008-03-18 09:57:50 +01003087 snd_hda_codec_cleanup_stream(codec,
3088 spec->adc_nids[substream->number + 1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003089 return 0;
3090}
3091
3092
3093/*
3094 */
3095static struct hda_pcm_stream alc880_pcm_analog_playback = {
3096 .substreams = 1,
3097 .channels_min = 2,
3098 .channels_max = 8,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003099 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003100 .ops = {
3101 .open = alc880_playback_pcm_open,
3102 .prepare = alc880_playback_pcm_prepare,
3103 .cleanup = alc880_playback_pcm_cleanup
3104 },
3105};
3106
3107static struct hda_pcm_stream alc880_pcm_analog_capture = {
Takashi Iwai63300792008-01-24 15:31:36 +01003108 .substreams = 1,
3109 .channels_min = 2,
3110 .channels_max = 2,
3111 /* NID is set in alc_build_pcms */
3112};
3113
3114static struct hda_pcm_stream alc880_pcm_analog_alt_playback = {
3115 .substreams = 1,
3116 .channels_min = 2,
3117 .channels_max = 2,
3118 /* NID is set in alc_build_pcms */
3119};
3120
3121static struct hda_pcm_stream alc880_pcm_analog_alt_capture = {
3122 .substreams = 2, /* can be overridden */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003123 .channels_min = 2,
3124 .channels_max = 2,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003125 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003126 .ops = {
Takashi Iwai63300792008-01-24 15:31:36 +01003127 .prepare = alc880_alt_capture_pcm_prepare,
3128 .cleanup = alc880_alt_capture_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07003129 },
3130};
3131
3132static struct hda_pcm_stream alc880_pcm_digital_playback = {
3133 .substreams = 1,
3134 .channels_min = 2,
3135 .channels_max = 2,
3136 /* NID is set in alc_build_pcms */
3137 .ops = {
3138 .open = alc880_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02003139 .close = alc880_dig_playback_pcm_close,
Takashi Iwai9b5f12e2009-02-13 11:47:37 +01003140 .prepare = alc880_dig_playback_pcm_prepare,
3141 .cleanup = alc880_dig_playback_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07003142 },
3143};
3144
3145static struct hda_pcm_stream alc880_pcm_digital_capture = {
3146 .substreams = 1,
3147 .channels_min = 2,
3148 .channels_max = 2,
3149 /* NID is set in alc_build_pcms */
3150};
3151
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01003152/* Used by alc_build_pcms to flag that a PCM has no playback stream */
Takashi Iwai63300792008-01-24 15:31:36 +01003153static struct hda_pcm_stream alc_pcm_null_stream = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01003154 .substreams = 0,
3155 .channels_min = 0,
3156 .channels_max = 0,
3157};
3158
Linus Torvalds1da177e2005-04-16 15:20:36 -07003159static int alc_build_pcms(struct hda_codec *codec)
3160{
3161 struct alc_spec *spec = codec->spec;
3162 struct hda_pcm *info = spec->pcm_rec;
3163 int i;
3164
3165 codec->num_pcms = 1;
3166 codec->pcm_info = info;
3167
Takashi Iwaie64f14f2009-01-20 18:32:55 +01003168 if (spec->no_analog)
3169 goto skip_analog;
3170
Linus Torvalds1da177e2005-04-16 15:20:36 -07003171 info->name = spec->stream_name_analog;
Takashi Iwai4a471b72005-12-07 13:56:29 +01003172 if (spec->stream_analog_playback) {
Takashi Iwaida3cec32008-08-08 17:12:14 +02003173 if (snd_BUG_ON(!spec->multiout.dac_nids))
3174 return -EINVAL;
Takashi Iwai4a471b72005-12-07 13:56:29 +01003175 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
3176 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
3177 }
3178 if (spec->stream_analog_capture) {
Takashi Iwaida3cec32008-08-08 17:12:14 +02003179 if (snd_BUG_ON(!spec->adc_nids))
3180 return -EINVAL;
Takashi Iwai4a471b72005-12-07 13:56:29 +01003181 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
3182 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
3183 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003184
Takashi Iwai4a471b72005-12-07 13:56:29 +01003185 if (spec->channel_mode) {
3186 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0;
3187 for (i = 0; i < spec->num_channel_mode; i++) {
3188 if (spec->channel_mode[i].channels > info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max) {
3189 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->channel_mode[i].channels;
3190 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003191 }
3192 }
3193
Takashi Iwaie64f14f2009-01-20 18:32:55 +01003194 skip_analog:
Takashi Iwaie08a0072006-09-07 17:52:14 +02003195 /* SPDIF for stream index #1 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003196 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
Takashi Iwaie08a0072006-09-07 17:52:14 +02003197 codec->num_pcms = 2;
Wu Fengguangb25c9da2009-02-06 15:02:27 +08003198 codec->slave_dig_outs = spec->multiout.slave_dig_outs;
Takashi Iwaic06134d2006-10-11 18:49:13 +02003199 info = spec->pcm_rec + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003200 info->name = spec->stream_name_digital;
Takashi Iwai8c441982009-01-20 18:30:20 +01003201 if (spec->dig_out_type)
3202 info->pcm_type = spec->dig_out_type;
3203 else
3204 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Takashi Iwai4a471b72005-12-07 13:56:29 +01003205 if (spec->multiout.dig_out_nid &&
3206 spec->stream_digital_playback) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003207 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_digital_playback);
3208 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
3209 }
Takashi Iwai4a471b72005-12-07 13:56:29 +01003210 if (spec->dig_in_nid &&
3211 spec->stream_digital_capture) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003212 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_digital_capture);
3213 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
3214 }
Takashi Iwai963f8032008-08-11 10:04:40 +02003215 /* FIXME: do we need this for all Realtek codec models? */
3216 codec->spdif_status_reset = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003217 }
3218
Takashi Iwaie64f14f2009-01-20 18:32:55 +01003219 if (spec->no_analog)
3220 return 0;
3221
Takashi Iwaie08a0072006-09-07 17:52:14 +02003222 /* If the use of more than one ADC is requested for the current
3223 * model, configure a second analog capture-only PCM.
3224 */
3225 /* Additional Analaog capture for index #2 */
Takashi Iwai63300792008-01-24 15:31:36 +01003226 if ((spec->alt_dac_nid && spec->stream_analog_alt_playback) ||
3227 (spec->num_adc_nids > 1 && spec->stream_analog_alt_capture)) {
Takashi Iwaie08a0072006-09-07 17:52:14 +02003228 codec->num_pcms = 3;
Takashi Iwaic06134d2006-10-11 18:49:13 +02003229 info = spec->pcm_rec + 2;
Takashi Iwaie08a0072006-09-07 17:52:14 +02003230 info->name = spec->stream_name_analog;
Takashi Iwai63300792008-01-24 15:31:36 +01003231 if (spec->alt_dac_nid) {
3232 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
3233 *spec->stream_analog_alt_playback;
3234 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
3235 spec->alt_dac_nid;
3236 } else {
3237 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
3238 alc_pcm_null_stream;
3239 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
3240 }
3241 if (spec->num_adc_nids > 1) {
3242 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
3243 *spec->stream_analog_alt_capture;
3244 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
3245 spec->adc_nids[1];
3246 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams =
3247 spec->num_adc_nids - 1;
3248 } else {
3249 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
3250 alc_pcm_null_stream;
3251 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0;
Takashi Iwaie08a0072006-09-07 17:52:14 +02003252 }
3253 }
3254
Linus Torvalds1da177e2005-04-16 15:20:36 -07003255 return 0;
3256}
3257
Takashi Iwai603c4012008-07-30 15:01:44 +02003258static void alc_free_kctls(struct hda_codec *codec)
3259{
3260 struct alc_spec *spec = codec->spec;
3261
3262 if (spec->kctls.list) {
3263 struct snd_kcontrol_new *kctl = spec->kctls.list;
3264 int i;
3265 for (i = 0; i < spec->kctls.used; i++)
3266 kfree(kctl[i].name);
3267 }
3268 snd_array_free(&spec->kctls);
3269}
3270
Linus Torvalds1da177e2005-04-16 15:20:36 -07003271static void alc_free(struct hda_codec *codec)
3272{
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003273 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003274
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003275 if (!spec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003276 return;
3277
Takashi Iwai603c4012008-07-30 15:01:44 +02003278 alc_free_kctls(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003279 kfree(spec);
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09003280 snd_hda_detach_beep_device(codec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003281}
3282
Takashi Iwaie044c392008-10-27 16:56:24 +01003283#ifdef SND_HDA_NEEDS_RESUME
Takashi Iwaie044c392008-10-27 16:56:24 +01003284static int alc_resume(struct hda_codec *codec)
3285{
Takashi Iwaie044c392008-10-27 16:56:24 +01003286 codec->patch_ops.init(codec);
3287 snd_hda_codec_resume_amp(codec);
3288 snd_hda_codec_resume_cache(codec);
3289 return 0;
3290}
Takashi Iwaie044c392008-10-27 16:56:24 +01003291#endif
3292
Linus Torvalds1da177e2005-04-16 15:20:36 -07003293/*
3294 */
3295static struct hda_codec_ops alc_patch_ops = {
3296 .build_controls = alc_build_controls,
3297 .build_pcms = alc_build_pcms,
3298 .init = alc_init,
3299 .free = alc_free,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003300 .unsol_event = alc_unsol_event,
Takashi Iwaie044c392008-10-27 16:56:24 +01003301#ifdef SND_HDA_NEEDS_RESUME
3302 .resume = alc_resume,
3303#endif
Takashi Iwaicb53c622007-08-10 17:21:45 +02003304#ifdef CONFIG_SND_HDA_POWER_SAVE
3305 .check_power_status = alc_check_power_status,
3306#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07003307};
3308
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003309
3310/*
3311 * Test configuration for debugging
3312 *
3313 * Almost all inputs/outputs are enabled. I/O pins can be configured via
3314 * enum controls.
3315 */
3316#ifdef CONFIG_SND_DEBUG
3317static hda_nid_t alc880_test_dac_nids[4] = {
3318 0x02, 0x03, 0x04, 0x05
3319};
3320
3321static struct hda_input_mux alc880_test_capture_source = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003322 .num_items = 7,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003323 .items = {
3324 { "In-1", 0x0 },
3325 { "In-2", 0x1 },
3326 { "In-3", 0x2 },
3327 { "In-4", 0x3 },
3328 { "CD", 0x4 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003329 { "Front", 0x5 },
3330 { "Surround", 0x6 },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003331 },
3332};
3333
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01003334static struct hda_channel_mode alc880_test_modes[4] = {
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003335 { 2, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02003336 { 4, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003337 { 6, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02003338 { 8, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003339};
3340
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003341static int alc_test_pin_ctl_info(struct snd_kcontrol *kcontrol,
3342 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003343{
3344 static char *texts[] = {
3345 "N/A", "Line Out", "HP Out",
3346 "In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%"
3347 };
3348 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
3349 uinfo->count = 1;
3350 uinfo->value.enumerated.items = 8;
3351 if (uinfo->value.enumerated.item >= 8)
3352 uinfo->value.enumerated.item = 7;
3353 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
3354 return 0;
3355}
3356
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003357static int alc_test_pin_ctl_get(struct snd_kcontrol *kcontrol,
3358 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003359{
3360 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3361 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
3362 unsigned int pin_ctl, item = 0;
3363
3364 pin_ctl = snd_hda_codec_read(codec, nid, 0,
3365 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
3366 if (pin_ctl & AC_PINCTL_OUT_EN) {
3367 if (pin_ctl & AC_PINCTL_HP_EN)
3368 item = 2;
3369 else
3370 item = 1;
3371 } else if (pin_ctl & AC_PINCTL_IN_EN) {
3372 switch (pin_ctl & AC_PINCTL_VREFEN) {
3373 case AC_PINCTL_VREF_HIZ: item = 3; break;
3374 case AC_PINCTL_VREF_50: item = 4; break;
3375 case AC_PINCTL_VREF_GRD: item = 5; break;
3376 case AC_PINCTL_VREF_80: item = 6; break;
3377 case AC_PINCTL_VREF_100: item = 7; break;
3378 }
3379 }
3380 ucontrol->value.enumerated.item[0] = item;
3381 return 0;
3382}
3383
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003384static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol,
3385 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003386{
3387 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3388 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
3389 static unsigned int ctls[] = {
3390 0, AC_PINCTL_OUT_EN, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN,
3391 AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ,
3392 AC_PINCTL_IN_EN | AC_PINCTL_VREF_50,
3393 AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD,
3394 AC_PINCTL_IN_EN | AC_PINCTL_VREF_80,
3395 AC_PINCTL_IN_EN | AC_PINCTL_VREF_100,
3396 };
3397 unsigned int old_ctl, new_ctl;
3398
3399 old_ctl = snd_hda_codec_read(codec, nid, 0,
3400 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
3401 new_ctl = ctls[ucontrol->value.enumerated.item[0]];
3402 if (old_ctl != new_ctl) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003403 int val;
3404 snd_hda_codec_write_cache(codec, nid, 0,
3405 AC_VERB_SET_PIN_WIDGET_CONTROL,
3406 new_ctl);
Takashi Iwai47fd8302007-08-10 17:11:07 +02003407 val = ucontrol->value.enumerated.item[0] >= 3 ?
3408 HDA_AMP_MUTE : 0;
3409 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
3410 HDA_AMP_MUTE, val);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003411 return 1;
3412 }
3413 return 0;
3414}
3415
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003416static int alc_test_pin_src_info(struct snd_kcontrol *kcontrol,
3417 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003418{
3419 static char *texts[] = {
3420 "Front", "Surround", "CLFE", "Side"
3421 };
3422 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
3423 uinfo->count = 1;
3424 uinfo->value.enumerated.items = 4;
3425 if (uinfo->value.enumerated.item >= 4)
3426 uinfo->value.enumerated.item = 3;
3427 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
3428 return 0;
3429}
3430
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003431static int alc_test_pin_src_get(struct snd_kcontrol *kcontrol,
3432 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003433{
3434 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3435 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
3436 unsigned int sel;
3437
3438 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0);
3439 ucontrol->value.enumerated.item[0] = sel & 3;
3440 return 0;
3441}
3442
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003443static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol,
3444 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003445{
3446 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3447 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
3448 unsigned int sel;
3449
3450 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3;
3451 if (ucontrol->value.enumerated.item[0] != sel) {
3452 sel = ucontrol->value.enumerated.item[0] & 3;
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003453 snd_hda_codec_write_cache(codec, nid, 0,
3454 AC_VERB_SET_CONNECT_SEL, sel);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003455 return 1;
3456 }
3457 return 0;
3458}
3459
3460#define PIN_CTL_TEST(xname,nid) { \
3461 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
3462 .name = xname, \
3463 .info = alc_test_pin_ctl_info, \
3464 .get = alc_test_pin_ctl_get, \
3465 .put = alc_test_pin_ctl_put, \
3466 .private_value = nid \
3467 }
3468
3469#define PIN_SRC_TEST(xname,nid) { \
3470 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
3471 .name = xname, \
3472 .info = alc_test_pin_src_info, \
3473 .get = alc_test_pin_src_get, \
3474 .put = alc_test_pin_src_put, \
3475 .private_value = nid \
3476 }
3477
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003478static struct snd_kcontrol_new alc880_test_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02003479 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3480 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
3481 HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
3482 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003483 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
3484 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
3485 HDA_BIND_MUTE("CLFE Playback Switch", 0x0e, 2, HDA_INPUT),
3486 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003487 PIN_CTL_TEST("Front Pin Mode", 0x14),
3488 PIN_CTL_TEST("Surround Pin Mode", 0x15),
3489 PIN_CTL_TEST("CLFE Pin Mode", 0x16),
3490 PIN_CTL_TEST("Side Pin Mode", 0x17),
3491 PIN_CTL_TEST("In-1 Pin Mode", 0x18),
3492 PIN_CTL_TEST("In-2 Pin Mode", 0x19),
3493 PIN_CTL_TEST("In-3 Pin Mode", 0x1a),
3494 PIN_CTL_TEST("In-4 Pin Mode", 0x1b),
3495 PIN_SRC_TEST("In-1 Pin Source", 0x18),
3496 PIN_SRC_TEST("In-2 Pin Source", 0x19),
3497 PIN_SRC_TEST("In-3 Pin Source", 0x1a),
3498 PIN_SRC_TEST("In-4 Pin Source", 0x1b),
3499 HDA_CODEC_VOLUME("In-1 Playback Volume", 0x0b, 0x0, HDA_INPUT),
3500 HDA_CODEC_MUTE("In-1 Playback Switch", 0x0b, 0x0, HDA_INPUT),
3501 HDA_CODEC_VOLUME("In-2 Playback Volume", 0x0b, 0x1, HDA_INPUT),
3502 HDA_CODEC_MUTE("In-2 Playback Switch", 0x0b, 0x1, HDA_INPUT),
3503 HDA_CODEC_VOLUME("In-3 Playback Volume", 0x0b, 0x2, HDA_INPUT),
3504 HDA_CODEC_MUTE("In-3 Playback Switch", 0x0b, 0x2, HDA_INPUT),
3505 HDA_CODEC_VOLUME("In-4 Playback Volume", 0x0b, 0x3, HDA_INPUT),
3506 HDA_CODEC_MUTE("In-4 Playback Switch", 0x0b, 0x3, HDA_INPUT),
3507 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x4, HDA_INPUT),
3508 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x4, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003509 {
3510 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3511 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01003512 .info = alc_ch_mode_info,
3513 .get = alc_ch_mode_get,
3514 .put = alc_ch_mode_put,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003515 },
3516 { } /* end */
3517};
3518
3519static struct hda_verb alc880_test_init_verbs[] = {
3520 /* Unmute inputs of 0x0c - 0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02003521 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3522 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3523 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3524 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3525 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3526 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3527 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3528 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003529 /* Vol output for 0x0c-0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02003530 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3531 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3532 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3533 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003534 /* Set output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02003535 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3536 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3537 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3538 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003539 /* Unmute output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02003540 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3541 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3542 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3543 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003544 /* Set input pins 0x18-0x1c */
Takashi Iwai16ded522005-06-10 19:58:24 +02003545 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3546 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwai05acb862005-06-10 19:50:25 +02003547 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3548 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3549 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003550 /* Mute input pins 0x18-0x1b */
Takashi Iwai05acb862005-06-10 19:50:25 +02003551 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3552 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3553 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3554 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003555 /* ADC set up */
Takashi Iwai05acb862005-06-10 19:50:25 +02003556 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003557 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02003558 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003559 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02003560 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003561 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02003562 /* Analog input/passthru */
3563 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3564 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
3565 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
3566 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
3567 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003568 { }
3569};
3570#endif
3571
Linus Torvalds1da177e2005-04-16 15:20:36 -07003572/*
3573 */
3574
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003575static const char *alc880_models[ALC880_MODEL_LAST] = {
3576 [ALC880_3ST] = "3stack",
3577 [ALC880_TCL_S700] = "tcl",
3578 [ALC880_3ST_DIG] = "3stack-digout",
3579 [ALC880_CLEVO] = "clevo",
3580 [ALC880_5ST] = "5stack",
3581 [ALC880_5ST_DIG] = "5stack-digout",
3582 [ALC880_W810] = "w810",
3583 [ALC880_Z71V] = "z71v",
3584 [ALC880_6ST] = "6stack",
3585 [ALC880_6ST_DIG] = "6stack-digout",
3586 [ALC880_ASUS] = "asus",
3587 [ALC880_ASUS_W1V] = "asus-w1v",
3588 [ALC880_ASUS_DIG] = "asus-dig",
3589 [ALC880_ASUS_DIG2] = "asus-dig2",
3590 [ALC880_UNIWILL_DIG] = "uniwill",
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003591 [ALC880_UNIWILL_P53] = "uniwill-p53",
3592 [ALC880_FUJITSU] = "fujitsu",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003593 [ALC880_F1734] = "F1734",
3594 [ALC880_LG] = "lg",
3595 [ALC880_LG_LW] = "lg-lw",
Takashi Iwaidf99cd32008-04-25 15:25:04 +02003596 [ALC880_MEDION_RIM] = "medion",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003597#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003598 [ALC880_TEST] = "test",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003599#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003600 [ALC880_AUTO] = "auto",
3601};
3602
3603static struct snd_pci_quirk alc880_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003604 SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003605 SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG),
3606 SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST),
3607 SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_3ST_DIG),
3608 SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_6ST_DIG),
3609 SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_6ST_DIG),
3610 SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_6ST_DIG),
3611 SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_3ST_DIG),
3612 SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003613 SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_6ST_DIG),
3614 SND_PCI_QUIRK(0x103c, 0x2a09, "HP", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003615 SND_PCI_QUIRK(0x1043, 0x10b3, "ASUS W1V", ALC880_ASUS_W1V),
3616 SND_PCI_QUIRK(0x1043, 0x10c2, "ASUS W6A", ALC880_ASUS_DIG),
3617 SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS Wxx", ALC880_ASUS_DIG),
3618 SND_PCI_QUIRK(0x1043, 0x1113, "ASUS", ALC880_ASUS_DIG),
3619 SND_PCI_QUIRK(0x1043, 0x1123, "ASUS", ALC880_ASUS_DIG),
3620 SND_PCI_QUIRK(0x1043, 0x1173, "ASUS", ALC880_ASUS_DIG),
3621 SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_Z71V),
3622 /* SND_PCI_QUIRK(0x1043, 0x1964, "ASUS", ALC880_ASUS_DIG), */
3623 SND_PCI_QUIRK(0x1043, 0x1973, "ASUS", ALC880_ASUS_DIG),
3624 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS", ALC880_ASUS_DIG),
Travis Place186c3112008-05-20 11:54:41 +02003625 SND_PCI_QUIRK(0x1043, 0x814e, "ASUS P5GD1 w/SPDIF", ALC880_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003626 SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG),
3627 SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST),
3628 SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST),
Takashi Iwaidea0a502009-02-09 17:14:52 +01003629 SND_PCI_QUIRK_VENDOR(0x1043, "ASUS", ALC880_ASUS), /* default ASUS */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003630 SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003631 SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST),
3632 SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003633 SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_5ST),
3634 SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003635 SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_6ST_DIG),
3636 SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_6ST_DIG),
3637 SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_6ST_DIG),
3638 SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003639 SND_PCI_QUIRK(0x1558, 0x0520, "Clevo m520G", ALC880_CLEVO),
3640 SND_PCI_QUIRK(0x1558, 0x0660, "Clevo m655n", ALC880_CLEVO),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003641 SND_PCI_QUIRK(0x1558, 0x5401, "ASUS", ALC880_ASUS_DIG2),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003642 SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003643 SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_UNIWILL_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003644 SND_PCI_QUIRK(0x1584, 0x9054, "Uniwlll", ALC880_F1734),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003645 SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL),
3646 SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003647 SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810),
Takashi Iwaidf99cd32008-04-25 15:25:04 +02003648 SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_MEDION_RIM),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003649 SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003650 SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003651 SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734),
Travis Place1d116042008-06-23 11:42:30 +02003652 SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FUJITSU),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003653 SND_PCI_QUIRK(0x1734, 0x10ac, "FSC", ALC880_UNIWILL),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003654 SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003655 SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003656 SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG),
3657 SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003658 SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003659 SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700),
3660 SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG), /* broken BIOS */
3661 SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG),
3662 SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003663 SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_5ST_DIG),
3664 SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003665 SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003666 SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003667 SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_3ST_DIG),
3668 SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003669 SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_5ST_DIG),
3670 SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_5ST_DIG),
3671 SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +01003672 /* default Intel */
3673 SND_PCI_QUIRK_VENDOR(0x8086, "Intel mobo", ALC880_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003674 SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG),
3675 SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003676 {}
3677};
3678
Takashi Iwai16ded522005-06-10 19:58:24 +02003679/*
Kailang Yangdf694da2005-12-05 19:42:22 +01003680 * ALC880 codec presets
Takashi Iwai16ded522005-06-10 19:58:24 +02003681 */
Takashi Iwai16ded522005-06-10 19:58:24 +02003682static struct alc_config_preset alc880_presets[] = {
3683 [ALC880_3ST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003684 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003685 .init_verbs = { alc880_volume_init_verbs,
3686 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003687 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02003688 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003689 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
3690 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003691 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003692 .input_mux = &alc880_capture_source,
3693 },
3694 [ALC880_3ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003695 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003696 .init_verbs = { alc880_volume_init_verbs,
3697 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003698 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02003699 .dac_nids = alc880_dac_nids,
3700 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003701 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
3702 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003703 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003704 .input_mux = &alc880_capture_source,
3705 },
Kailang Yangdf694da2005-12-05 19:42:22 +01003706 [ALC880_TCL_S700] = {
3707 .mixers = { alc880_tcl_s700_mixer },
3708 .init_verbs = { alc880_volume_init_verbs,
3709 alc880_pin_tcl_S700_init_verbs,
3710 alc880_gpio2_init_verbs },
3711 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3712 .dac_nids = alc880_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01003713 .adc_nids = alc880_adc_nids_alt, /* FIXME: correct? */
3714 .num_adc_nids = 1, /* single ADC */
Kailang Yangdf694da2005-12-05 19:42:22 +01003715 .hp_nid = 0x03,
3716 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3717 .channel_mode = alc880_2_jack_modes,
3718 .input_mux = &alc880_capture_source,
3719 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003720 [ALC880_5ST] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003721 .mixers = { alc880_three_stack_mixer,
3722 alc880_five_stack_mixer},
3723 .init_verbs = { alc880_volume_init_verbs,
3724 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003725 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3726 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003727 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
3728 .channel_mode = alc880_fivestack_modes,
3729 .input_mux = &alc880_capture_source,
3730 },
3731 [ALC880_5ST_DIG] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003732 .mixers = { alc880_three_stack_mixer,
3733 alc880_five_stack_mixer },
3734 .init_verbs = { alc880_volume_init_verbs,
3735 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003736 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3737 .dac_nids = alc880_dac_nids,
3738 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003739 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
3740 .channel_mode = alc880_fivestack_modes,
3741 .input_mux = &alc880_capture_source,
3742 },
Takashi Iwaib6482d42005-06-27 15:32:43 +02003743 [ALC880_6ST] = {
3744 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003745 .init_verbs = { alc880_volume_init_verbs,
3746 alc880_pin_6stack_init_verbs },
Takashi Iwaib6482d42005-06-27 15:32:43 +02003747 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
3748 .dac_nids = alc880_6st_dac_nids,
3749 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
3750 .channel_mode = alc880_sixstack_modes,
3751 .input_mux = &alc880_6stack_capture_source,
3752 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003753 [ALC880_6ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003754 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003755 .init_verbs = { alc880_volume_init_verbs,
3756 alc880_pin_6stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003757 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
3758 .dac_nids = alc880_6st_dac_nids,
3759 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003760 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
3761 .channel_mode = alc880_sixstack_modes,
3762 .input_mux = &alc880_6stack_capture_source,
3763 },
3764 [ALC880_W810] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003765 .mixers = { alc880_w810_base_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003766 .init_verbs = { alc880_volume_init_verbs,
3767 alc880_pin_w810_init_verbs,
Takashi Iwaib0af0de2005-06-21 14:49:19 +02003768 alc880_gpio2_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003769 .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids),
3770 .dac_nids = alc880_w810_dac_nids,
3771 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003772 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
3773 .channel_mode = alc880_w810_modes,
3774 .input_mux = &alc880_capture_source,
3775 },
3776 [ALC880_Z71V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003777 .mixers = { alc880_z71v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003778 .init_verbs = { alc880_volume_init_verbs,
3779 alc880_pin_z71v_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003780 .num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids),
3781 .dac_nids = alc880_z71v_dac_nids,
3782 .dig_out_nid = ALC880_DIGOUT_NID,
3783 .hp_nid = 0x03,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003784 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3785 .channel_mode = alc880_2_jack_modes,
Takashi Iwai16ded522005-06-10 19:58:24 +02003786 .input_mux = &alc880_capture_source,
3787 },
3788 [ALC880_F1734] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003789 .mixers = { alc880_f1734_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003790 .init_verbs = { alc880_volume_init_verbs,
3791 alc880_pin_f1734_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003792 .num_dacs = ARRAY_SIZE(alc880_f1734_dac_nids),
3793 .dac_nids = alc880_f1734_dac_nids,
3794 .hp_nid = 0x02,
3795 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3796 .channel_mode = alc880_2_jack_modes,
Takashi Iwai937b4162008-02-11 14:52:36 +01003797 .input_mux = &alc880_f1734_capture_source,
3798 .unsol_event = alc880_uniwill_p53_unsol_event,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003799 .init_hook = alc880_uniwill_p53_init_hook,
Takashi Iwai16ded522005-06-10 19:58:24 +02003800 },
3801 [ALC880_ASUS] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003802 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003803 .init_verbs = { alc880_volume_init_verbs,
3804 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003805 alc880_gpio1_init_verbs },
3806 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3807 .dac_nids = alc880_asus_dac_nids,
3808 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3809 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003810 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003811 .input_mux = &alc880_capture_source,
3812 },
3813 [ALC880_ASUS_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003814 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003815 .init_verbs = { alc880_volume_init_verbs,
3816 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003817 alc880_gpio1_init_verbs },
3818 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3819 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003820 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003821 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3822 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003823 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003824 .input_mux = &alc880_capture_source,
3825 },
Kailang Yangdf694da2005-12-05 19:42:22 +01003826 [ALC880_ASUS_DIG2] = {
3827 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003828 .init_verbs = { alc880_volume_init_verbs,
3829 alc880_pin_asus_init_verbs,
Kailang Yangdf694da2005-12-05 19:42:22 +01003830 alc880_gpio2_init_verbs }, /* use GPIO2 */
3831 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3832 .dac_nids = alc880_asus_dac_nids,
3833 .dig_out_nid = ALC880_DIGOUT_NID,
3834 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3835 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003836 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01003837 .input_mux = &alc880_capture_source,
3838 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003839 [ALC880_ASUS_W1V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003840 .mixers = { alc880_asus_mixer, alc880_asus_w1v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003841 .init_verbs = { alc880_volume_init_verbs,
3842 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003843 alc880_gpio1_init_verbs },
3844 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3845 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003846 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003847 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3848 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003849 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003850 .input_mux = &alc880_capture_source,
3851 },
3852 [ALC880_UNIWILL_DIG] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01003853 .mixers = { alc880_asus_mixer },
Kailang Yangccc656c2006-10-17 12:32:26 +02003854 .init_verbs = { alc880_volume_init_verbs,
3855 alc880_pin_asus_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003856 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3857 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003858 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003859 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3860 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003861 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003862 .input_mux = &alc880_capture_source,
3863 },
Kailang Yangccc656c2006-10-17 12:32:26 +02003864 [ALC880_UNIWILL] = {
3865 .mixers = { alc880_uniwill_mixer },
3866 .init_verbs = { alc880_volume_init_verbs,
3867 alc880_uniwill_init_verbs },
3868 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3869 .dac_nids = alc880_asus_dac_nids,
3870 .dig_out_nid = ALC880_DIGOUT_NID,
3871 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
3872 .channel_mode = alc880_threestack_modes,
3873 .need_dac_fix = 1,
3874 .input_mux = &alc880_capture_source,
3875 .unsol_event = alc880_uniwill_unsol_event,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003876 .init_hook = alc880_uniwill_init_hook,
Kailang Yangccc656c2006-10-17 12:32:26 +02003877 },
3878 [ALC880_UNIWILL_P53] = {
3879 .mixers = { alc880_uniwill_p53_mixer },
3880 .init_verbs = { alc880_volume_init_verbs,
3881 alc880_uniwill_p53_init_verbs },
3882 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3883 .dac_nids = alc880_asus_dac_nids,
3884 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003885 .channel_mode = alc880_threestack_modes,
3886 .input_mux = &alc880_capture_source,
3887 .unsol_event = alc880_uniwill_p53_unsol_event,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003888 .init_hook = alc880_uniwill_p53_init_hook,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003889 },
3890 [ALC880_FUJITSU] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01003891 .mixers = { alc880_fujitsu_mixer },
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003892 .init_verbs = { alc880_volume_init_verbs,
3893 alc880_uniwill_p53_init_verbs,
3894 alc880_beep_init_verbs },
3895 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3896 .dac_nids = alc880_dac_nids,
Takashi Iwaid53d7d92007-08-20 15:20:02 +02003897 .dig_out_nid = ALC880_DIGOUT_NID,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003898 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3899 .channel_mode = alc880_2_jack_modes,
Kailang Yangccc656c2006-10-17 12:32:26 +02003900 .input_mux = &alc880_capture_source,
3901 .unsol_event = alc880_uniwill_p53_unsol_event,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003902 .init_hook = alc880_uniwill_p53_init_hook,
Kailang Yangccc656c2006-10-17 12:32:26 +02003903 },
Kailang Yangdf694da2005-12-05 19:42:22 +01003904 [ALC880_CLEVO] = {
3905 .mixers = { alc880_three_stack_mixer },
3906 .init_verbs = { alc880_volume_init_verbs,
3907 alc880_pin_clevo_init_verbs },
3908 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3909 .dac_nids = alc880_dac_nids,
3910 .hp_nid = 0x03,
3911 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
3912 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003913 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01003914 .input_mux = &alc880_capture_source,
3915 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003916 [ALC880_LG] = {
3917 .mixers = { alc880_lg_mixer },
3918 .init_verbs = { alc880_volume_init_verbs,
3919 alc880_lg_init_verbs },
3920 .num_dacs = ARRAY_SIZE(alc880_lg_dac_nids),
3921 .dac_nids = alc880_lg_dac_nids,
3922 .dig_out_nid = ALC880_DIGOUT_NID,
3923 .num_channel_mode = ARRAY_SIZE(alc880_lg_ch_modes),
3924 .channel_mode = alc880_lg_ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003925 .need_dac_fix = 1,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003926 .input_mux = &alc880_lg_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003927 .unsol_event = alc_automute_amp_unsol_event,
3928 .init_hook = alc880_lg_init_hook,
Takashi Iwaicb53c622007-08-10 17:21:45 +02003929#ifdef CONFIG_SND_HDA_POWER_SAVE
3930 .loopbacks = alc880_lg_loopbacks,
3931#endif
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003932 },
Takashi Iwaid6815182006-03-23 16:06:23 +01003933 [ALC880_LG_LW] = {
3934 .mixers = { alc880_lg_lw_mixer },
3935 .init_verbs = { alc880_volume_init_verbs,
3936 alc880_lg_lw_init_verbs },
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003937 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwaid6815182006-03-23 16:06:23 +01003938 .dac_nids = alc880_dac_nids,
3939 .dig_out_nid = ALC880_DIGOUT_NID,
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003940 .num_channel_mode = ARRAY_SIZE(alc880_lg_lw_modes),
3941 .channel_mode = alc880_lg_lw_modes,
Takashi Iwaid6815182006-03-23 16:06:23 +01003942 .input_mux = &alc880_lg_lw_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003943 .unsol_event = alc_automute_amp_unsol_event,
3944 .init_hook = alc880_lg_lw_init_hook,
Takashi Iwaid6815182006-03-23 16:06:23 +01003945 },
Takashi Iwaidf99cd32008-04-25 15:25:04 +02003946 [ALC880_MEDION_RIM] = {
3947 .mixers = { alc880_medion_rim_mixer },
3948 .init_verbs = { alc880_volume_init_verbs,
3949 alc880_medion_rim_init_verbs,
3950 alc_gpio2_init_verbs },
3951 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3952 .dac_nids = alc880_dac_nids,
3953 .dig_out_nid = ALC880_DIGOUT_NID,
3954 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3955 .channel_mode = alc880_2_jack_modes,
3956 .input_mux = &alc880_medion_rim_capture_source,
3957 .unsol_event = alc880_medion_rim_unsol_event,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003958 .init_hook = alc880_medion_rim_init_hook,
Takashi Iwaidf99cd32008-04-25 15:25:04 +02003959 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003960#ifdef CONFIG_SND_DEBUG
3961 [ALC880_TEST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003962 .mixers = { alc880_test_mixer },
3963 .init_verbs = { alc880_test_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003964 .num_dacs = ARRAY_SIZE(alc880_test_dac_nids),
3965 .dac_nids = alc880_test_dac_nids,
3966 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003967 .num_channel_mode = ARRAY_SIZE(alc880_test_modes),
3968 .channel_mode = alc880_test_modes,
3969 .input_mux = &alc880_test_capture_source,
3970 },
3971#endif
3972};
3973
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003974/*
3975 * Automatic parse of I/O pins from the BIOS configuration
3976 */
3977
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003978enum {
3979 ALC_CTL_WIDGET_VOL,
3980 ALC_CTL_WIDGET_MUTE,
3981 ALC_CTL_BIND_MUTE,
3982};
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003983static struct snd_kcontrol_new alc880_control_templates[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003984 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
3985 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Takashi Iwai985be542005-11-02 18:26:49 +01003986 HDA_BIND_MUTE(NULL, 0, 0, 0),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003987};
3988
3989/* add dynamic controls */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003990static int add_control(struct alc_spec *spec, int type, const char *name,
3991 unsigned long val)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003992{
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003993 struct snd_kcontrol_new *knew;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003994
Takashi Iwai603c4012008-07-30 15:01:44 +02003995 snd_array_init(&spec->kctls, sizeof(*knew), 32);
3996 knew = snd_array_new(&spec->kctls);
3997 if (!knew)
3998 return -ENOMEM;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003999 *knew = alc880_control_templates[type];
Paulo Marques543537b2005-06-23 00:09:02 -07004000 knew->name = kstrdup(name, GFP_KERNEL);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004001 if (!knew->name)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004002 return -ENOMEM;
4003 knew->private_value = val;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004004 return 0;
4005}
4006
4007#define alc880_is_fixed_pin(nid) ((nid) >= 0x14 && (nid) <= 0x17)
4008#define alc880_fixed_pin_idx(nid) ((nid) - 0x14)
4009#define alc880_is_multi_pin(nid) ((nid) >= 0x18)
4010#define alc880_multi_pin_idx(nid) ((nid) - 0x18)
4011#define alc880_is_input_pin(nid) ((nid) >= 0x18)
4012#define alc880_input_pin_idx(nid) ((nid) - 0x18)
4013#define alc880_idx_to_dac(nid) ((nid) + 0x02)
4014#define alc880_dac_to_idx(nid) ((nid) - 0x02)
4015#define alc880_idx_to_mixer(nid) ((nid) + 0x0c)
4016#define alc880_idx_to_selector(nid) ((nid) + 0x10)
4017#define ALC880_PIN_CD_NID 0x1c
4018
4019/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004020static int alc880_auto_fill_dac_nids(struct alc_spec *spec,
4021 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004022{
4023 hda_nid_t nid;
4024 int assigned[4];
4025 int i, j;
4026
4027 memset(assigned, 0, sizeof(assigned));
Takashi Iwaib0af0de2005-06-21 14:49:19 +02004028 spec->multiout.dac_nids = spec->private_dac_nids;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004029
4030 /* check the pins hardwired to audio widget */
4031 for (i = 0; i < cfg->line_outs; i++) {
4032 nid = cfg->line_out_pins[i];
4033 if (alc880_is_fixed_pin(nid)) {
4034 int idx = alc880_fixed_pin_idx(nid);
Libin Yang5014f192005-11-23 15:48:36 +01004035 spec->multiout.dac_nids[i] = alc880_idx_to_dac(idx);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004036 assigned[idx] = 1;
4037 }
4038 }
4039 /* left pins can be connect to any audio widget */
4040 for (i = 0; i < cfg->line_outs; i++) {
4041 nid = cfg->line_out_pins[i];
4042 if (alc880_is_fixed_pin(nid))
4043 continue;
4044 /* search for an empty channel */
4045 for (j = 0; j < cfg->line_outs; j++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004046 if (!assigned[j]) {
4047 spec->multiout.dac_nids[i] =
4048 alc880_idx_to_dac(j);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004049 assigned[j] = 1;
4050 break;
4051 }
4052 }
4053 }
4054 spec->multiout.num_dacs = cfg->line_outs;
4055 return 0;
4056}
4057
4058/* add playback controls from the parsed DAC table */
Kailang Yangdf694da2005-12-05 19:42:22 +01004059static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
4060 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004061{
4062 char name[32];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004063 static const char *chname[4] = {
4064 "Front", "Surround", NULL /*CLFE*/, "Side"
4065 };
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004066 hda_nid_t nid;
4067 int i, err;
4068
4069 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004070 if (!spec->multiout.dac_nids[i])
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004071 continue;
4072 nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i]));
4073 if (i == 2) {
4074 /* Center/LFE */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004075 err = add_control(spec, ALC_CTL_WIDGET_VOL,
4076 "Center Playback Volume",
4077 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
4078 HDA_OUTPUT));
4079 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004080 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004081 err = add_control(spec, ALC_CTL_WIDGET_VOL,
4082 "LFE Playback Volume",
4083 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
4084 HDA_OUTPUT));
4085 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004086 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004087 err = add_control(spec, ALC_CTL_BIND_MUTE,
4088 "Center Playback Switch",
4089 HDA_COMPOSE_AMP_VAL(nid, 1, 2,
4090 HDA_INPUT));
4091 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004092 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004093 err = add_control(spec, ALC_CTL_BIND_MUTE,
4094 "LFE Playback Switch",
4095 HDA_COMPOSE_AMP_VAL(nid, 2, 2,
4096 HDA_INPUT));
4097 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004098 return err;
4099 } else {
4100 sprintf(name, "%s Playback Volume", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004101 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
4102 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
4103 HDA_OUTPUT));
4104 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004105 return err;
4106 sprintf(name, "%s Playback Switch", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004107 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
4108 HDA_COMPOSE_AMP_VAL(nid, 3, 2,
4109 HDA_INPUT));
4110 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004111 return err;
4112 }
4113 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004114 return 0;
4115}
4116
Takashi Iwai8d88bc32005-11-17 11:09:23 +01004117/* add playback controls for speaker and HP outputs */
4118static int alc880_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
4119 const char *pfx)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004120{
4121 hda_nid_t nid;
4122 int err;
Takashi Iwai8d88bc32005-11-17 11:09:23 +01004123 char name[32];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004124
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004125 if (!pin)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004126 return 0;
4127
4128 if (alc880_is_fixed_pin(pin)) {
4129 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
Takashi Iwai82bc9552006-03-21 11:24:42 +01004130 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004131 if (!spec->multiout.hp_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004132 spec->multiout.hp_nid = nid;
Takashi Iwai82bc9552006-03-21 11:24:42 +01004133 else
4134 spec->multiout.extra_out_nid[0] = nid;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004135 /* control HP volume/switch on the output mixer amp */
4136 nid = alc880_idx_to_mixer(alc880_fixed_pin_idx(pin));
Takashi Iwai8d88bc32005-11-17 11:09:23 +01004137 sprintf(name, "%s Playback Volume", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004138 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
4139 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
4140 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004141 return err;
Takashi Iwai8d88bc32005-11-17 11:09:23 +01004142 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004143 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
4144 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
4145 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004146 return err;
4147 } else if (alc880_is_multi_pin(pin)) {
4148 /* set manual connection */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004149 /* we have only a switch on HP-out PIN */
Takashi Iwai8d88bc32005-11-17 11:09:23 +01004150 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004151 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
4152 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
4153 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004154 return err;
4155 }
4156 return 0;
4157}
4158
4159/* create input playback/capture controls for the given pin */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004160static int new_analog_input(struct alc_spec *spec, hda_nid_t pin,
4161 const char *ctlname,
Kailang Yangdf694da2005-12-05 19:42:22 +01004162 int idx, hda_nid_t mix_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004163{
4164 char name[32];
Kailang Yangdf694da2005-12-05 19:42:22 +01004165 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004166
4167 sprintf(name, "%s Playback Volume", ctlname);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004168 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
4169 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
4170 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004171 return err;
4172 sprintf(name, "%s Playback Switch", ctlname);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004173 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
4174 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
4175 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004176 return err;
4177 return 0;
4178}
4179
4180/* create playback/capture controls for input pins */
Kailang Yangdf694da2005-12-05 19:42:22 +01004181static int alc880_auto_create_analog_input_ctls(struct alc_spec *spec,
4182 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004183{
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02004184 struct hda_input_mux *imux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01004185 int i, err, idx;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004186
4187 for (i = 0; i < AUTO_PIN_LAST; i++) {
4188 if (alc880_is_input_pin(cfg->input_pins[i])) {
Kailang Yangdf694da2005-12-05 19:42:22 +01004189 idx = alc880_input_pin_idx(cfg->input_pins[i]);
Takashi Iwai4a471b72005-12-07 13:56:29 +01004190 err = new_analog_input(spec, cfg->input_pins[i],
4191 auto_pin_cfg_labels[i],
Kailang Yangdf694da2005-12-05 19:42:22 +01004192 idx, 0x0b);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004193 if (err < 0)
4194 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004195 imux->items[imux->num_items].label =
4196 auto_pin_cfg_labels[i];
4197 imux->items[imux->num_items].index =
4198 alc880_input_pin_idx(cfg->input_pins[i]);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004199 imux->num_items++;
4200 }
4201 }
4202 return 0;
4203}
4204
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004205static void alc_set_pin_output(struct hda_codec *codec, hda_nid_t nid,
4206 unsigned int pin_type)
4207{
4208 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
4209 pin_type);
4210 /* unmute pin */
Takashi Iwaid260cdf2008-02-13 17:19:35 +01004211 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
4212 AMP_OUT_UNMUTE);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004213}
4214
Kailang Yangdf694da2005-12-05 19:42:22 +01004215static void alc880_auto_set_output_and_unmute(struct hda_codec *codec,
4216 hda_nid_t nid, int pin_type,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004217 int dac_idx)
4218{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004219 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004220 /* need the manual connection? */
4221 if (alc880_is_multi_pin(nid)) {
4222 struct alc_spec *spec = codec->spec;
4223 int idx = alc880_multi_pin_idx(nid);
4224 snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
4225 AC_VERB_SET_CONNECT_SEL,
4226 alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
4227 }
4228}
4229
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02004230static int get_pin_type(int line_out_type)
4231{
4232 if (line_out_type == AUTO_PIN_HP_OUT)
4233 return PIN_HP;
4234 else
4235 return PIN_OUT;
4236}
4237
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004238static void alc880_auto_init_multi_out(struct hda_codec *codec)
4239{
4240 struct alc_spec *spec = codec->spec;
4241 int i;
Kailang Yangea1fb292008-08-26 12:58:38 +02004242
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004243 for (i = 0; i < spec->autocfg.line_outs; i++) {
4244 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02004245 int pin_type = get_pin_type(spec->autocfg.line_out_type);
4246 alc880_auto_set_output_and_unmute(codec, nid, pin_type, i);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004247 }
4248}
4249
Takashi Iwai8d88bc32005-11-17 11:09:23 +01004250static void alc880_auto_init_extra_out(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004251{
4252 struct alc_spec *spec = codec->spec;
4253 hda_nid_t pin;
4254
Takashi Iwai82bc9552006-03-21 11:24:42 +01004255 pin = spec->autocfg.speaker_pins[0];
Takashi Iwai8d88bc32005-11-17 11:09:23 +01004256 if (pin) /* connect to front */
4257 alc880_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02004258 pin = spec->autocfg.hp_pins[0];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004259 if (pin) /* connect to front */
4260 alc880_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
4261}
4262
4263static void alc880_auto_init_analog_input(struct hda_codec *codec)
4264{
4265 struct alc_spec *spec = codec->spec;
4266 int i;
4267
4268 for (i = 0; i < AUTO_PIN_LAST; i++) {
4269 hda_nid_t nid = spec->autocfg.input_pins[i];
4270 if (alc880_is_input_pin(nid)) {
Takashi Iwai23f0c042009-02-26 13:03:58 +01004271 alc_set_input_pin(codec, nid, i);
Takashi Iwaie82c0252009-03-23 15:17:38 +01004272 if (nid != ALC880_PIN_CD_NID &&
4273 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004274 snd_hda_codec_write(codec, nid, 0,
4275 AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004276 AMP_OUT_MUTE);
4277 }
4278 }
4279}
4280
4281/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004282/* return 1 if successful, 0 if the proper config is not found,
4283 * or a negative error code
4284 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004285static int alc880_parse_auto_config(struct hda_codec *codec)
4286{
4287 struct alc_spec *spec = codec->spec;
Takashi Iwai6a05ac42009-02-13 11:19:09 +01004288 int i, err;
Kailang Yangdf694da2005-12-05 19:42:22 +01004289 static hda_nid_t alc880_ignore[] = { 0x1d, 0 };
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004290
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004291 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
4292 alc880_ignore);
4293 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004294 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004295 if (!spec->autocfg.line_outs)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004296 return 0; /* can't find valid BIOS pin config */
Kailang Yangdf694da2005-12-05 19:42:22 +01004297
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004298 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
4299 if (err < 0)
4300 return err;
4301 err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
4302 if (err < 0)
4303 return err;
4304 err = alc880_auto_create_extra_out(spec,
4305 spec->autocfg.speaker_pins[0],
4306 "Speaker");
4307 if (err < 0)
4308 return err;
4309 err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
4310 "Headphone");
4311 if (err < 0)
4312 return err;
4313 err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg);
4314 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004315 return err;
4316
4317 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
4318
Takashi Iwai6a05ac42009-02-13 11:19:09 +01004319 /* check multiple SPDIF-out (for recent codecs) */
4320 for (i = 0; i < spec->autocfg.dig_outs; i++) {
4321 hda_nid_t dig_nid;
4322 err = snd_hda_get_connections(codec,
4323 spec->autocfg.dig_out_pins[i],
4324 &dig_nid, 1);
4325 if (err < 0)
4326 continue;
4327 if (!i)
4328 spec->multiout.dig_out_nid = dig_nid;
4329 else {
4330 spec->multiout.slave_dig_outs = spec->slave_dig_outs;
4331 spec->slave_dig_outs[i - 1] = dig_nid;
4332 if (i == ARRAY_SIZE(spec->slave_dig_outs) - 1)
4333 break;
4334 }
4335 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004336 if (spec->autocfg.dig_in_pin)
4337 spec->dig_in_nid = ALC880_DIGIN_NID;
4338
Takashi Iwai603c4012008-07-30 15:01:44 +02004339 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +01004340 add_mixer(spec, spec->kctls.list);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004341
Takashi Iwaid88897e2008-10-31 15:01:37 +01004342 add_verb(spec, alc880_volume_init_verbs);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004343
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004344 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02004345 spec->input_mux = &spec->private_imux[0];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004346
Takashi Iwai4a79ba32009-04-22 16:31:35 +02004347 alc_ssid_check(codec, 0x15, 0x1b, 0x14);
4348
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004349 return 1;
4350}
4351
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004352/* additional initialization for auto-configuration model */
4353static void alc880_auto_init(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004354{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004355 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004356 alc880_auto_init_multi_out(codec);
Takashi Iwai8d88bc32005-11-17 11:09:23 +01004357 alc880_auto_init_extra_out(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004358 alc880_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004359 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02004360 alc_inithook(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004361}
4362
Takashi Iwaif9e336f2008-10-31 16:37:07 +01004363static void set_capture_mixer(struct alc_spec *spec)
4364{
Takashi Iwaia23b6882009-03-23 15:21:36 +01004365 static struct snd_kcontrol_new *caps[2][3] = {
4366 { alc_capture_mixer_nosrc1,
4367 alc_capture_mixer_nosrc2,
4368 alc_capture_mixer_nosrc3 },
4369 { alc_capture_mixer1,
4370 alc_capture_mixer2,
4371 alc_capture_mixer3 },
Takashi Iwaif9e336f2008-10-31 16:37:07 +01004372 };
Takashi Iwaia23b6882009-03-23 15:21:36 +01004373 if (spec->num_adc_nids > 0 && spec->num_adc_nids <= 3) {
4374 int mux;
4375 if (spec->input_mux && spec->input_mux->num_items > 1)
4376 mux = 1;
4377 else
4378 mux = 0;
4379 spec->cap_mixer = caps[mux][spec->num_adc_nids - 1];
4380 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01004381}
4382
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01004383#define set_beep_amp(spec, nid, idx, dir) \
4384 ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir))
4385
4386/*
4387 * OK, here we have finally the patch for ALC880
4388 */
4389
Linus Torvalds1da177e2005-04-16 15:20:36 -07004390static int patch_alc880(struct hda_codec *codec)
4391{
4392 struct alc_spec *spec;
4393 int board_config;
Kailang Yangdf694da2005-12-05 19:42:22 +01004394 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004395
Takashi Iwaie560d8d2005-09-09 14:21:46 +02004396 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004397 if (spec == NULL)
4398 return -ENOMEM;
4399
4400 codec->spec = spec;
4401
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004402 board_config = snd_hda_check_board_config(codec, ALC880_MODEL_LAST,
4403 alc880_models,
4404 alc880_cfg_tbl);
4405 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004406 printk(KERN_INFO "hda_codec: Unknown model for ALC880, "
4407 "trying auto-probe from BIOS...\n");
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004408 board_config = ALC880_AUTO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004409 }
4410
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004411 if (board_config == ALC880_AUTO) {
4412 /* automatic parse from the BIOS config */
4413 err = alc880_parse_auto_config(codec);
4414 if (err < 0) {
4415 alc_free(codec);
4416 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004417 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004418 printk(KERN_INFO
4419 "hda_codec: Cannot set up configuration "
4420 "from BIOS. Using 3-stack mode...\n");
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004421 board_config = ALC880_3ST;
4422 }
4423 }
4424
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09004425 err = snd_hda_attach_beep_device(codec, 0x1);
4426 if (err < 0) {
4427 alc_free(codec);
4428 return err;
4429 }
4430
Kailang Yangdf694da2005-12-05 19:42:22 +01004431 if (board_config != ALC880_AUTO)
4432 setup_preset(spec, &alc880_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004433
4434 spec->stream_name_analog = "ALC880 Analog";
4435 spec->stream_analog_playback = &alc880_pcm_analog_playback;
4436 spec->stream_analog_capture = &alc880_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01004437 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004438
4439 spec->stream_name_digital = "ALC880 Digital";
4440 spec->stream_digital_playback = &alc880_pcm_digital_playback;
4441 spec->stream_digital_capture = &alc880_pcm_digital_capture;
4442
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004443 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004444 /* check whether NID 0x07 is valid */
Takashi Iwai54d17402005-11-21 16:33:22 +01004445 unsigned int wcap = get_wcaps(codec, alc880_adc_nids[0]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004446 /* get type */
4447 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004448 if (wcap != AC_WID_AUD_IN) {
4449 spec->adc_nids = alc880_adc_nids_alt;
4450 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids_alt);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004451 } else {
4452 spec->adc_nids = alc880_adc_nids;
4453 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004454 }
4455 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01004456 set_capture_mixer(spec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01004457 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004458
Takashi Iwai2134ea42008-01-10 16:53:55 +01004459 spec->vmaster_nid = 0x0c;
4460
Linus Torvalds1da177e2005-04-16 15:20:36 -07004461 codec->patch_ops = alc_patch_ops;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004462 if (board_config == ALC880_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004463 spec->init_hook = alc880_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02004464#ifdef CONFIG_SND_HDA_POWER_SAVE
4465 if (!spec->loopback.amplist)
4466 spec->loopback.amplist = alc880_loopbacks;
4467#endif
Takashi Iwaidaead532008-11-28 12:55:36 +01004468 codec->proc_widget_hook = print_realtek_coef;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004469
4470 return 0;
4471}
4472
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004473
Linus Torvalds1da177e2005-04-16 15:20:36 -07004474/*
4475 * ALC260 support
4476 */
4477
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004478static hda_nid_t alc260_dac_nids[1] = {
4479 /* front */
4480 0x02,
4481};
4482
4483static hda_nid_t alc260_adc_nids[1] = {
4484 /* ADC0 */
4485 0x04,
4486};
4487
Kailang Yangdf694da2005-12-05 19:42:22 +01004488static hda_nid_t alc260_adc_nids_alt[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004489 /* ADC1 */
4490 0x05,
4491};
4492
Jonathan Woithed57fdac2006-02-28 11:38:35 +01004493/* NIDs used when simultaneous access to both ADCs makes sense. Note that
4494 * alc260_capture_mixer assumes ADC0 (nid 0x04) is the first ADC.
4495 */
4496static hda_nid_t alc260_dual_adc_nids[2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004497 /* ADC0, ADC1 */
4498 0x04, 0x05
4499};
4500
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004501#define ALC260_DIGOUT_NID 0x03
4502#define ALC260_DIGIN_NID 0x06
4503
4504static struct hda_input_mux alc260_capture_source = {
4505 .num_items = 4,
4506 .items = {
4507 { "Mic", 0x0 },
4508 { "Front Mic", 0x1 },
4509 { "Line", 0x2 },
4510 { "CD", 0x4 },
4511 },
4512};
4513
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01004514/* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004515 * headphone jack and the internal CD lines since these are the only pins at
4516 * which audio can appear. For flexibility, also allow the option of
4517 * recording the mixer output on the second ADC (ADC0 doesn't have a
4518 * connection to the mixer output).
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004519 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004520static struct hda_input_mux alc260_fujitsu_capture_sources[2] = {
4521 {
4522 .num_items = 3,
4523 .items = {
4524 { "Mic/Line", 0x0 },
4525 { "CD", 0x4 },
4526 { "Headphone", 0x2 },
4527 },
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004528 },
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004529 {
4530 .num_items = 4,
4531 .items = {
4532 { "Mic/Line", 0x0 },
4533 { "CD", 0x4 },
4534 { "Headphone", 0x2 },
4535 { "Mixer", 0x5 },
4536 },
4537 },
4538
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004539};
4540
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004541/* Acer TravelMate(/Extensa/Aspire) notebooks have similar configuration to
4542 * the Fujitsu S702x, but jacks are marked differently.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004543 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004544static struct hda_input_mux alc260_acer_capture_sources[2] = {
4545 {
4546 .num_items = 4,
4547 .items = {
4548 { "Mic", 0x0 },
4549 { "Line", 0x2 },
4550 { "CD", 0x4 },
4551 { "Headphone", 0x5 },
4552 },
4553 },
4554 {
4555 .num_items = 5,
4556 .items = {
4557 { "Mic", 0x0 },
4558 { "Line", 0x2 },
4559 { "CD", 0x4 },
4560 { "Headphone", 0x6 },
4561 { "Mixer", 0x5 },
4562 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004563 },
4564};
Michael Schwingencc959482009-02-22 18:58:45 +01004565
4566/* Maxdata Favorit 100XS */
4567static struct hda_input_mux alc260_favorit100_capture_sources[2] = {
4568 {
4569 .num_items = 2,
4570 .items = {
4571 { "Line/Mic", 0x0 },
4572 { "CD", 0x4 },
4573 },
4574 },
4575 {
4576 .num_items = 3,
4577 .items = {
4578 { "Line/Mic", 0x0 },
4579 { "CD", 0x4 },
4580 { "Mixer", 0x5 },
4581 },
4582 },
4583};
4584
Linus Torvalds1da177e2005-04-16 15:20:36 -07004585/*
4586 * This is just place-holder, so there's something for alc_build_pcms to look
4587 * at when it calculates the maximum number of channels. ALC260 has no mixer
4588 * element which allows changing the channel mode, so the verb list is
4589 * never used.
4590 */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01004591static struct hda_channel_mode alc260_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004592 { 2, NULL },
4593};
4594
Kailang Yangdf694da2005-12-05 19:42:22 +01004595
4596/* Mixer combinations
4597 *
4598 * basic: base_output + input + pc_beep + capture
4599 * HP: base_output + input + capture_alt
4600 * HP_3013: hp_3013 + input + capture
4601 * fujitsu: fujitsu + capture
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004602 * acer: acer + capture
Kailang Yangdf694da2005-12-05 19:42:22 +01004603 */
4604
4605static struct snd_kcontrol_new alc260_base_output_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02004606 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01004607 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01004608 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
4609 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
4610 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
4611 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
4612 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004613};
Kailang Yangdf694da2005-12-05 19:42:22 +01004614
4615static struct snd_kcontrol_new alc260_input_mixer[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004616 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4617 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
4618 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
4619 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
4620 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
4621 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
4622 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT),
4623 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004624 { } /* end */
4625};
4626
Takashi Iwaibec15c32008-01-28 18:16:30 +01004627/* update HP, line and mono out pins according to the master switch */
4628static void alc260_hp_master_update(struct hda_codec *codec,
4629 hda_nid_t hp, hda_nid_t line,
4630 hda_nid_t mono)
4631{
4632 struct alc_spec *spec = codec->spec;
4633 unsigned int val = spec->master_sw ? PIN_HP : 0;
4634 /* change HP and line-out pins */
Takashi Iwai30cde0a2008-11-07 14:49:28 +01004635 snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwaibec15c32008-01-28 18:16:30 +01004636 val);
Takashi Iwai30cde0a2008-11-07 14:49:28 +01004637 snd_hda_codec_write(codec, line, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwaibec15c32008-01-28 18:16:30 +01004638 val);
4639 /* mono (speaker) depending on the HP jack sense */
4640 val = (val && !spec->jack_present) ? PIN_OUT : 0;
Takashi Iwai30cde0a2008-11-07 14:49:28 +01004641 snd_hda_codec_write(codec, mono, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwaibec15c32008-01-28 18:16:30 +01004642 val);
4643}
4644
4645static int alc260_hp_master_sw_get(struct snd_kcontrol *kcontrol,
4646 struct snd_ctl_elem_value *ucontrol)
4647{
4648 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4649 struct alc_spec *spec = codec->spec;
4650 *ucontrol->value.integer.value = spec->master_sw;
4651 return 0;
4652}
4653
4654static int alc260_hp_master_sw_put(struct snd_kcontrol *kcontrol,
4655 struct snd_ctl_elem_value *ucontrol)
4656{
4657 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4658 struct alc_spec *spec = codec->spec;
4659 int val = !!*ucontrol->value.integer.value;
4660 hda_nid_t hp, line, mono;
4661
4662 if (val == spec->master_sw)
4663 return 0;
4664 spec->master_sw = val;
4665 hp = (kcontrol->private_value >> 16) & 0xff;
4666 line = (kcontrol->private_value >> 8) & 0xff;
4667 mono = kcontrol->private_value & 0xff;
4668 alc260_hp_master_update(codec, hp, line, mono);
4669 return 1;
4670}
4671
4672static struct snd_kcontrol_new alc260_hp_output_mixer[] = {
4673 {
4674 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4675 .name = "Master Playback Switch",
4676 .info = snd_ctl_boolean_mono_info,
4677 .get = alc260_hp_master_sw_get,
4678 .put = alc260_hp_master_sw_put,
4679 .private_value = (0x0f << 16) | (0x10 << 8) | 0x11
4680 },
4681 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4682 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
4683 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
4684 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
4685 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
4686 HDA_OUTPUT),
4687 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2, HDA_INPUT),
4688 { } /* end */
4689};
4690
4691static struct hda_verb alc260_hp_unsol_verbs[] = {
4692 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
4693 {},
4694};
4695
4696static void alc260_hp_automute(struct hda_codec *codec)
4697{
4698 struct alc_spec *spec = codec->spec;
4699 unsigned int present;
4700
4701 present = snd_hda_codec_read(codec, 0x10, 0,
4702 AC_VERB_GET_PIN_SENSE, 0);
4703 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
4704 alc260_hp_master_update(codec, 0x0f, 0x10, 0x11);
4705}
4706
4707static void alc260_hp_unsol_event(struct hda_codec *codec, unsigned int res)
4708{
4709 if ((res >> 26) == ALC880_HP_EVENT)
4710 alc260_hp_automute(codec);
4711}
4712
Kailang Yangdf694da2005-12-05 19:42:22 +01004713static struct snd_kcontrol_new alc260_hp_3013_mixer[] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01004714 {
4715 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4716 .name = "Master Playback Switch",
4717 .info = snd_ctl_boolean_mono_info,
4718 .get = alc260_hp_master_sw_get,
4719 .put = alc260_hp_master_sw_put,
Takashi Iwai30cde0a2008-11-07 14:49:28 +01004720 .private_value = (0x15 << 16) | (0x10 << 8) | 0x11
Takashi Iwaibec15c32008-01-28 18:16:30 +01004721 },
Kailang Yangdf694da2005-12-05 19:42:22 +01004722 HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT),
4723 HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT),
4724 HDA_CODEC_VOLUME("Aux-In Playback Volume", 0x07, 0x06, HDA_INPUT),
4725 HDA_CODEC_MUTE("Aux-In Playback Switch", 0x07, 0x06, HDA_INPUT),
4726 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4727 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01004728 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
4729 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02004730 { } /* end */
4731};
4732
Kailang Yang3f878302008-08-26 13:02:23 +02004733static struct hda_bind_ctls alc260_dc7600_bind_master_vol = {
4734 .ops = &snd_hda_bind_vol,
4735 .values = {
4736 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_OUTPUT),
4737 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_OUTPUT),
4738 HDA_COMPOSE_AMP_VAL(0x0a, 3, 0, HDA_OUTPUT),
4739 0
4740 },
4741};
4742
4743static struct hda_bind_ctls alc260_dc7600_bind_switch = {
4744 .ops = &snd_hda_bind_sw,
4745 .values = {
4746 HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT),
4747 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
4748 0
4749 },
4750};
4751
4752static struct snd_kcontrol_new alc260_hp_dc7600_mixer[] = {
4753 HDA_BIND_VOL("Master Playback Volume", &alc260_dc7600_bind_master_vol),
4754 HDA_BIND_SW("LineOut Playback Switch", &alc260_dc7600_bind_switch),
4755 HDA_CODEC_MUTE("Speaker Playback Switch", 0x0f, 0x0, HDA_OUTPUT),
4756 HDA_CODEC_MUTE("Headphone Playback Switch", 0x10, 0x0, HDA_OUTPUT),
4757 { } /* end */
4758};
4759
Takashi Iwaibec15c32008-01-28 18:16:30 +01004760static struct hda_verb alc260_hp_3013_unsol_verbs[] = {
4761 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
4762 {},
4763};
4764
4765static void alc260_hp_3013_automute(struct hda_codec *codec)
4766{
4767 struct alc_spec *spec = codec->spec;
4768 unsigned int present;
4769
4770 present = snd_hda_codec_read(codec, 0x15, 0,
4771 AC_VERB_GET_PIN_SENSE, 0);
4772 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
Takashi Iwai30cde0a2008-11-07 14:49:28 +01004773 alc260_hp_master_update(codec, 0x15, 0x10, 0x11);
Takashi Iwaibec15c32008-01-28 18:16:30 +01004774}
4775
4776static void alc260_hp_3013_unsol_event(struct hda_codec *codec,
4777 unsigned int res)
4778{
4779 if ((res >> 26) == ALC880_HP_EVENT)
4780 alc260_hp_3013_automute(codec);
4781}
4782
Kailang Yang3f878302008-08-26 13:02:23 +02004783static void alc260_hp_3012_automute(struct hda_codec *codec)
4784{
4785 unsigned int present, bits;
4786
4787 present = snd_hda_codec_read(codec, 0x10, 0,
4788 AC_VERB_GET_PIN_SENSE, 0) & AC_PINSENSE_PRESENCE;
4789
4790 bits = present ? 0 : PIN_OUT;
4791 snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
4792 bits);
4793 snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
4794 bits);
4795 snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
4796 bits);
4797}
4798
4799static void alc260_hp_3012_unsol_event(struct hda_codec *codec,
4800 unsigned int res)
4801{
4802 if ((res >> 26) == ALC880_HP_EVENT)
4803 alc260_hp_3012_automute(codec);
4804}
4805
4806/* Fujitsu S702x series laptops. ALC260 pin usage: Mic/Line jack = 0x12,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004807 * HP jack = 0x14, CD audio = 0x16, internal speaker = 0x10.
4808 */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01004809static struct snd_kcontrol_new alc260_fujitsu_mixer[] = {
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004810 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01004811 HDA_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004812 ALC_PIN_MODE("Headphone Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004813 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4814 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
4815 HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT),
4816 HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004817 ALC_PIN_MODE("Mic/Line Jack Mode", 0x12, ALC_PIN_DIR_IN),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01004818 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT),
4819 HDA_BIND_MUTE("Speaker Playback Switch", 0x09, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01004820 { } /* end */
4821};
4822
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004823/* Mixer for Acer TravelMate(/Extensa/Aspire) notebooks. Note that current
4824 * versions of the ALC260 don't act on requests to enable mic bias from NID
4825 * 0x0f (used to drive the headphone jack in these laptops). The ALC260
4826 * datasheet doesn't mention this restriction. At this stage it's not clear
4827 * whether this behaviour is intentional or is a hardware bug in chip
4828 * revisions available in early 2006. Therefore for now allow the
4829 * "Headphone Jack Mode" control to span all choices, but if it turns out
4830 * that the lack of mic bias for this NID is intentional we could change the
4831 * mode from ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
4832 *
4833 * In addition, Acer TravelMate(/Extensa/Aspire) notebooks in early 2006
4834 * don't appear to make the mic bias available from the "line" jack, even
4835 * though the NID used for this jack (0x14) can supply it. The theory is
4836 * that perhaps Acer have included blocking capacitors between the ALC260
4837 * and the output jack. If this turns out to be the case for all such
4838 * models the "Line Jack Mode" mode could be changed from ALC_PIN_DIR_INOUT
4839 * to ALC_PIN_DIR_INOUT_NOMICBIAS.
Jonathan Woithebd869482006-11-28 11:35:52 +01004840 *
4841 * The C20x Tablet series have a mono internal speaker which is controlled
4842 * via the chip's Mono sum widget and pin complex, so include the necessary
4843 * controls for such models. On models without a "mono speaker" the control
4844 * won't do anything.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004845 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004846static struct snd_kcontrol_new alc260_acer_mixer[] = {
4847 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4848 HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004849 ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01004850 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
Jonathan Woithebd869482006-11-28 11:35:52 +01004851 HDA_OUTPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01004852 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2,
Jonathan Woithebd869482006-11-28 11:35:52 +01004853 HDA_INPUT),
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004854 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4855 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
4856 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
4857 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
4858 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
4859 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
4860 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
4861 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004862 { } /* end */
4863};
4864
Michael Schwingencc959482009-02-22 18:58:45 +01004865/* Maxdata Favorit 100XS: one output and one input (0x12) jack
4866 */
4867static struct snd_kcontrol_new alc260_favorit100_mixer[] = {
4868 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4869 HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
4870 ALC_PIN_MODE("Output Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
4871 HDA_CODEC_VOLUME("Line/Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
4872 HDA_CODEC_MUTE("Line/Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
4873 ALC_PIN_MODE("Line/Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
4874 { } /* end */
4875};
4876
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004877/* Packard bell V7900 ALC260 pin usage: HP = 0x0f, Mic jack = 0x12,
4878 * Line In jack = 0x14, CD audio = 0x16, pc beep = 0x17.
4879 */
4880static struct snd_kcontrol_new alc260_will_mixer[] = {
4881 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4882 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
4883 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
4884 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
4885 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
4886 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
4887 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
4888 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
4889 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4890 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004891 { } /* end */
4892};
4893
4894/* Replacer 672V ALC260 pin usage: Mic jack = 0x12,
4895 * Line In jack = 0x14, ATAPI Mic = 0x13, speaker = 0x0f.
4896 */
4897static struct snd_kcontrol_new alc260_replacer_672v_mixer[] = {
4898 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4899 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
4900 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
4901 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
4902 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
4903 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x07, 0x1, HDA_INPUT),
4904 HDA_CODEC_MUTE("ATATI Mic Playback Switch", 0x07, 0x1, HDA_INPUT),
4905 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
4906 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
4907 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
4908 { } /* end */
4909};
4910
Kailang Yangdf694da2005-12-05 19:42:22 +01004911/*
4912 * initialization verbs
4913 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004914static struct hda_verb alc260_init_verbs[] = {
4915 /* Line In pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02004916 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004917 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02004918 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004919 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02004920 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004921 /* Mic2 (front panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02004922 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004923 /* LINE-2 is used for line-out in rear */
Takashi Iwai05acb862005-06-10 19:50:25 +02004924 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004925 /* select line-out */
Jonathan Woithefd56f2d2006-01-24 10:35:46 +01004926 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004927 /* LINE-OUT pin */
Takashi Iwai05acb862005-06-10 19:50:25 +02004928 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004929 /* enable HP */
Takashi Iwai05acb862005-06-10 19:50:25 +02004930 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004931 /* enable Mono */
Takashi Iwai05acb862005-06-10 19:50:25 +02004932 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4933 /* mute capture amp left and right */
Takashi Iwai16ded522005-06-10 19:58:24 +02004934 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004935 /* set connection select to line in (default select for this ADC) */
4936 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai16ded522005-06-10 19:58:24 +02004937 /* mute capture amp left and right */
4938 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4939 /* set connection select to line in (default select for this ADC) */
4940 {0x05, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai05acb862005-06-10 19:50:25 +02004941 /* set vol=0 Line-Out mixer amp left and right */
4942 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4943 /* unmute pin widget amp left and right (no gain on this amp) */
4944 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4945 /* set vol=0 HP mixer amp left and right */
4946 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4947 /* unmute pin widget amp left and right (no gain on this amp) */
4948 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4949 /* set vol=0 Mono mixer amp left and right */
4950 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4951 /* unmute pin widget amp left and right (no gain on this amp) */
4952 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4953 /* unmute LINE-2 out pin */
4954 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004955 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
4956 * Line In 2 = 0x03
4957 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02004958 /* mute analog inputs */
4959 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4960 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4961 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4962 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4963 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004964 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
Takashi Iwai05acb862005-06-10 19:50:25 +02004965 /* mute Front out path */
4966 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4967 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4968 /* mute Headphone out path */
4969 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4970 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4971 /* mute Mono out path */
4972 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4973 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004974 { }
4975};
4976
Takashi Iwai474167d2006-05-17 17:17:43 +02004977#if 0 /* should be identical with alc260_init_verbs? */
Kailang Yangdf694da2005-12-05 19:42:22 +01004978static struct hda_verb alc260_hp_init_verbs[] = {
4979 /* Headphone and output */
4980 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
4981 /* mono output */
4982 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4983 /* Mic1 (rear panel) pin widget for input and vref at 80% */
4984 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4985 /* Mic2 (front panel) pin widget for input and vref at 80% */
4986 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4987 /* Line In pin widget for input */
4988 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4989 /* Line-2 pin widget for output */
4990 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4991 /* CD pin widget for input */
4992 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4993 /* unmute amp left and right */
4994 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
4995 /* set connection select to line in (default select for this ADC) */
4996 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
4997 /* unmute Line-Out mixer amp left and right (volume = 0) */
4998 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
4999 /* mute pin widget amp left and right (no gain on this amp) */
5000 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
5001 /* unmute HP mixer amp left and right (volume = 0) */
5002 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
5003 /* mute pin widget amp left and right (no gain on this amp) */
5004 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005005 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
5006 * Line In 2 = 0x03
5007 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02005008 /* mute analog inputs */
5009 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5010 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5011 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5012 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5013 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01005014 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
5015 /* Unmute Front out path */
5016 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5017 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
5018 /* Unmute Headphone out path */
5019 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5020 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
5021 /* Unmute Mono out path */
5022 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5023 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
5024 { }
5025};
Takashi Iwai474167d2006-05-17 17:17:43 +02005026#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01005027
5028static struct hda_verb alc260_hp_3013_init_verbs[] = {
5029 /* Line out and output */
5030 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
5031 /* mono output */
5032 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
5033 /* Mic1 (rear panel) pin widget for input and vref at 80% */
5034 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
5035 /* Mic2 (front panel) pin widget for input and vref at 80% */
5036 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
5037 /* Line In pin widget for input */
5038 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
5039 /* Headphone pin widget for output */
5040 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
5041 /* CD pin widget for input */
5042 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
5043 /* unmute amp left and right */
5044 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
5045 /* set connection select to line in (default select for this ADC) */
5046 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
5047 /* unmute Line-Out mixer amp left and right (volume = 0) */
5048 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
5049 /* mute pin widget amp left and right (no gain on this amp) */
5050 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
5051 /* unmute HP mixer amp left and right (volume = 0) */
5052 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
5053 /* mute pin widget amp left and right (no gain on this amp) */
5054 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005055 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
5056 * Line In 2 = 0x03
5057 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02005058 /* mute analog inputs */
5059 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5060 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5061 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5062 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5063 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01005064 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
5065 /* Unmute Front out path */
5066 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5067 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
5068 /* Unmute Headphone out path */
5069 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5070 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
5071 /* Unmute Mono out path */
5072 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5073 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
5074 { }
5075};
5076
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005077/* Initialisation sequence for ALC260 as configured in Fujitsu S702x
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005078 * laptops. ALC260 pin usage: Mic/Line jack = 0x12, HP jack = 0x14, CD
5079 * audio = 0x16, internal speaker = 0x10.
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005080 */
5081static struct hda_verb alc260_fujitsu_init_verbs[] = {
5082 /* Disable all GPIOs */
5083 {0x01, AC_VERB_SET_GPIO_MASK, 0},
5084 /* Internal speaker is connected to headphone pin */
5085 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5086 /* Headphone/Line-out jack connects to Line1 pin; make it an output */
5087 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Jonathan Woithef7ace402006-02-28 11:46:14 +01005088 /* Mic/Line-in jack is connected to mic1 pin, so make it an input */
5089 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
5090 /* Ensure all other unused pins are disabled and muted. */
5091 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5092 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005093 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01005094 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005095 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01005096 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5097 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5098 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005099
Jonathan Woithef7ace402006-02-28 11:46:14 +01005100 /* Disable digital (SPDIF) pins */
5101 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
5102 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01005103
Kailang Yangea1fb292008-08-26 12:58:38 +02005104 /* Ensure Line1 pin widget takes its input from the OUT1 sum bus
Jonathan Woithef7ace402006-02-28 11:46:14 +01005105 * when acting as an output.
5106 */
5107 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
5108
5109 /* Start with output sum widgets muted and their output gains at min */
Takashi Iwai8b33a5a2006-02-09 11:57:01 +01005110 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5111 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5112 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5113 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5114 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5115 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5116 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5117 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5118 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005119
Jonathan Woithef7ace402006-02-28 11:46:14 +01005120 /* Unmute HP pin widget amp left and right (no equiv mixer ctrl) */
5121 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5122 /* Unmute Line1 pin widget output buffer since it starts as an output.
5123 * If the pin mode is changed by the user the pin mode control will
5124 * take care of enabling the pin's input/output buffers as needed.
5125 * Therefore there's no need to enable the input buffer at this
5126 * stage.
Jonathan Woithecdcd9262006-02-28 11:36:42 +01005127 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01005128 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +02005129 /* Unmute input buffer of pin widget used for Line-in (no equiv
Jonathan Woithecdcd9262006-02-28 11:36:42 +01005130 * mixer ctrl)
5131 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01005132 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005133
Jonathan Woithef7ace402006-02-28 11:46:14 +01005134 /* Mute capture amp left and right */
5135 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +02005136 /* Set ADC connection select to match default mixer setting - line
Jonathan Woithef7ace402006-02-28 11:46:14 +01005137 * in (on mic1 pin)
5138 */
5139 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005140
Jonathan Woithef7ace402006-02-28 11:46:14 +01005141 /* Do the same for the second ADC: mute capture input amp and
5142 * set ADC connection to line in (on mic1 pin)
5143 */
5144 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5145 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01005146
Jonathan Woithef7ace402006-02-28 11:46:14 +01005147 /* Mute all inputs to mixer widget (even unconnected ones) */
5148 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
5149 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
5150 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
5151 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
5152 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
5153 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
5154 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
5155 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
Takashi Iwai4a471b72005-12-07 13:56:29 +01005156
5157 { }
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005158};
5159
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005160/* Initialisation sequence for ALC260 as configured in Acer TravelMate and
5161 * similar laptops (adapted from Fujitsu init verbs).
5162 */
5163static struct hda_verb alc260_acer_init_verbs[] = {
5164 /* On TravelMate laptops, GPIO 0 enables the internal speaker and
5165 * the headphone jack. Turn this on and rely on the standard mute
5166 * methods whenever the user wants to turn these outputs off.
5167 */
5168 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
5169 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
5170 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
5171 /* Internal speaker/Headphone jack is connected to Line-out pin */
5172 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5173 /* Internal microphone/Mic jack is connected to Mic1 pin */
5174 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
5175 /* Line In jack is connected to Line1 pin */
5176 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Jonathan Woithebd869482006-11-28 11:35:52 +01005177 /* Some Acers (eg: C20x Tablets) use Mono pin for internal speaker */
5178 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005179 /* Ensure all other unused pins are disabled and muted. */
5180 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5181 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005182 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5183 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5184 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5185 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5186 /* Disable digital (SPDIF) pins */
5187 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
5188 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
5189
Kailang Yangea1fb292008-08-26 12:58:38 +02005190 /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005191 * bus when acting as outputs.
5192 */
5193 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
5194 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
5195
5196 /* Start with output sum widgets muted and their output gains at min */
5197 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5198 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5199 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5200 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5201 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5202 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5203 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5204 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5205 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5206
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005207 /* Unmute Line-out pin widget amp left and right
5208 * (no equiv mixer ctrl)
5209 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005210 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithebd869482006-11-28 11:35:52 +01005211 /* Unmute mono pin widget amp output (no equiv mixer ctrl) */
5212 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005213 /* Unmute Mic1 and Line1 pin widget input buffers since they start as
5214 * inputs. If the pin mode is changed by the user the pin mode control
5215 * will take care of enabling the pin's input/output buffers as needed.
5216 * Therefore there's no need to enable the input buffer at this
5217 * stage.
5218 */
5219 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5220 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5221
5222 /* Mute capture amp left and right */
5223 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5224 /* Set ADC connection select to match default mixer setting - mic
5225 * (on mic1 pin)
5226 */
5227 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
5228
5229 /* Do similar with the second ADC: mute capture input amp and
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005230 * set ADC connection to mic to match ALSA's default state.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005231 */
5232 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005233 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005234
5235 /* Mute all inputs to mixer widget (even unconnected ones) */
5236 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
5237 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
5238 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
5239 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
5240 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
5241 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
5242 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
5243 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
5244
5245 { }
5246};
5247
Michael Schwingencc959482009-02-22 18:58:45 +01005248/* Initialisation sequence for Maxdata Favorit 100XS
5249 * (adapted from Acer init verbs).
5250 */
5251static struct hda_verb alc260_favorit100_init_verbs[] = {
5252 /* GPIO 0 enables the output jack.
5253 * Turn this on and rely on the standard mute
5254 * methods whenever the user wants to turn these outputs off.
5255 */
5256 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
5257 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
5258 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
5259 /* Line/Mic input jack is connected to Mic1 pin */
5260 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
5261 /* Ensure all other unused pins are disabled and muted. */
5262 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5263 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5264 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5265 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5266 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5267 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5268 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5269 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5270 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5271 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5272 /* Disable digital (SPDIF) pins */
5273 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
5274 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
5275
5276 /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
5277 * bus when acting as outputs.
5278 */
5279 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
5280 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
5281
5282 /* Start with output sum widgets muted and their output gains at min */
5283 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5284 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5285 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5286 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5287 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5288 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5289 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5290 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5291 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5292
5293 /* Unmute Line-out pin widget amp left and right
5294 * (no equiv mixer ctrl)
5295 */
5296 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5297 /* Unmute Mic1 and Line1 pin widget input buffers since they start as
5298 * inputs. If the pin mode is changed by the user the pin mode control
5299 * will take care of enabling the pin's input/output buffers as needed.
5300 * Therefore there's no need to enable the input buffer at this
5301 * stage.
5302 */
5303 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5304
5305 /* Mute capture amp left and right */
5306 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5307 /* Set ADC connection select to match default mixer setting - mic
5308 * (on mic1 pin)
5309 */
5310 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
5311
5312 /* Do similar with the second ADC: mute capture input amp and
5313 * set ADC connection to mic to match ALSA's default state.
5314 */
5315 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5316 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
5317
5318 /* Mute all inputs to mixer widget (even unconnected ones) */
5319 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
5320 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
5321 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
5322 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
5323 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
5324 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
5325 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
5326 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
5327
5328 { }
5329};
5330
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005331static struct hda_verb alc260_will_verbs[] = {
5332 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5333 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x00},
5334 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
5335 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
5336 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
5337 {0x1a, AC_VERB_SET_PROC_COEF, 0x3040},
5338 {}
5339};
5340
5341static struct hda_verb alc260_replacer_672v_verbs[] = {
5342 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
5343 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
5344 {0x1a, AC_VERB_SET_PROC_COEF, 0x3050},
5345
5346 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
5347 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
5348 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
5349
5350 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
5351 {}
5352};
5353
5354/* toggle speaker-output according to the hp-jack state */
5355static void alc260_replacer_672v_automute(struct hda_codec *codec)
5356{
5357 unsigned int present;
5358
5359 /* speaker --> GPIO Data 0, hp or spdif --> GPIO data 1 */
5360 present = snd_hda_codec_read(codec, 0x0f, 0,
5361 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
5362 if (present) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02005363 snd_hda_codec_write_cache(codec, 0x01, 0,
5364 AC_VERB_SET_GPIO_DATA, 1);
5365 snd_hda_codec_write_cache(codec, 0x0f, 0,
5366 AC_VERB_SET_PIN_WIDGET_CONTROL,
5367 PIN_HP);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005368 } else {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02005369 snd_hda_codec_write_cache(codec, 0x01, 0,
5370 AC_VERB_SET_GPIO_DATA, 0);
5371 snd_hda_codec_write_cache(codec, 0x0f, 0,
5372 AC_VERB_SET_PIN_WIDGET_CONTROL,
5373 PIN_OUT);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005374 }
5375}
5376
5377static void alc260_replacer_672v_unsol_event(struct hda_codec *codec,
5378 unsigned int res)
5379{
5380 if ((res >> 26) == ALC880_HP_EVENT)
5381 alc260_replacer_672v_automute(codec);
5382}
5383
Kailang Yang3f878302008-08-26 13:02:23 +02005384static struct hda_verb alc260_hp_dc7600_verbs[] = {
5385 {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
5386 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
5387 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5388 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5389 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5390 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5391 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
5392 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
5393 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
5394 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
5395 {}
5396};
5397
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005398/* Test configuration for debugging, modelled after the ALC880 test
5399 * configuration.
5400 */
5401#ifdef CONFIG_SND_DEBUG
5402static hda_nid_t alc260_test_dac_nids[1] = {
5403 0x02,
5404};
5405static hda_nid_t alc260_test_adc_nids[2] = {
5406 0x04, 0x05,
5407};
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005408/* For testing the ALC260, each input MUX needs its own definition since
Kailang Yangea1fb292008-08-26 12:58:38 +02005409 * the signal assignments are different. This assumes that the first ADC
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005410 * is NID 0x04.
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01005411 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005412static struct hda_input_mux alc260_test_capture_sources[2] = {
5413 {
5414 .num_items = 7,
5415 .items = {
5416 { "MIC1 pin", 0x0 },
5417 { "MIC2 pin", 0x1 },
5418 { "LINE1 pin", 0x2 },
5419 { "LINE2 pin", 0x3 },
5420 { "CD pin", 0x4 },
5421 { "LINE-OUT pin", 0x5 },
5422 { "HP-OUT pin", 0x6 },
5423 },
5424 },
5425 {
5426 .num_items = 8,
5427 .items = {
5428 { "MIC1 pin", 0x0 },
5429 { "MIC2 pin", 0x1 },
5430 { "LINE1 pin", 0x2 },
5431 { "LINE2 pin", 0x3 },
5432 { "CD pin", 0x4 },
5433 { "Mixer", 0x5 },
5434 { "LINE-OUT pin", 0x6 },
5435 { "HP-OUT pin", 0x7 },
5436 },
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005437 },
5438};
5439static struct snd_kcontrol_new alc260_test_mixer[] = {
5440 /* Output driver widgets */
5441 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
5442 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
5443 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x09, 0x0, HDA_OUTPUT),
5444 HDA_BIND_MUTE("LOUT2 Playback Switch", 0x09, 2, HDA_INPUT),
5445 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5446 HDA_BIND_MUTE("LOUT1 Playback Switch", 0x08, 2, HDA_INPUT),
5447
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005448 /* Modes for retasking pin widgets
5449 * Note: the ALC260 doesn't seem to act on requests to enable mic
5450 * bias from NIDs 0x0f and 0x10. The ALC260 datasheet doesn't
5451 * mention this restriction. At this stage it's not clear whether
5452 * this behaviour is intentional or is a hardware bug in chip
5453 * revisions available at least up until early 2006. Therefore for
5454 * now allow the "HP-OUT" and "LINE-OUT" Mode controls to span all
5455 * choices, but if it turns out that the lack of mic bias for these
5456 * NIDs is intentional we could change their modes from
5457 * ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
5458 */
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005459 ALC_PIN_MODE("HP-OUT pin mode", 0x10, ALC_PIN_DIR_INOUT),
5460 ALC_PIN_MODE("LINE-OUT pin mode", 0x0f, ALC_PIN_DIR_INOUT),
5461 ALC_PIN_MODE("LINE2 pin mode", 0x15, ALC_PIN_DIR_INOUT),
5462 ALC_PIN_MODE("LINE1 pin mode", 0x14, ALC_PIN_DIR_INOUT),
5463 ALC_PIN_MODE("MIC2 pin mode", 0x13, ALC_PIN_DIR_INOUT),
5464 ALC_PIN_MODE("MIC1 pin mode", 0x12, ALC_PIN_DIR_INOUT),
5465
5466 /* Loopback mixer controls */
5467 HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x07, 0x00, HDA_INPUT),
5468 HDA_CODEC_MUTE("MIC1 Playback Switch", 0x07, 0x00, HDA_INPUT),
5469 HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x07, 0x01, HDA_INPUT),
5470 HDA_CODEC_MUTE("MIC2 Playback Switch", 0x07, 0x01, HDA_INPUT),
5471 HDA_CODEC_VOLUME("LINE1 Playback Volume", 0x07, 0x02, HDA_INPUT),
5472 HDA_CODEC_MUTE("LINE1 Playback Switch", 0x07, 0x02, HDA_INPUT),
5473 HDA_CODEC_VOLUME("LINE2 Playback Volume", 0x07, 0x03, HDA_INPUT),
5474 HDA_CODEC_MUTE("LINE2 Playback Switch", 0x07, 0x03, HDA_INPUT),
5475 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
5476 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005477 HDA_CODEC_VOLUME("LINE-OUT loopback Playback Volume", 0x07, 0x06, HDA_INPUT),
5478 HDA_CODEC_MUTE("LINE-OUT loopback Playback Switch", 0x07, 0x06, HDA_INPUT),
5479 HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x07, 0x7, HDA_INPUT),
5480 HDA_CODEC_MUTE("HP-OUT loopback Playback Switch", 0x07, 0x7, HDA_INPUT),
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01005481
5482 /* Controls for GPIO pins, assuming they are configured as outputs */
5483 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
5484 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
5485 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
5486 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
5487
Jonathan Woithe92621f12006-02-28 11:47:47 +01005488 /* Switches to allow the digital IO pins to be enabled. The datasheet
5489 * is ambigious as to which NID is which; testing on laptops which
Kailang Yangea1fb292008-08-26 12:58:38 +02005490 * make this output available should provide clarification.
Jonathan Woithe92621f12006-02-28 11:47:47 +01005491 */
5492 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x03, 0x01),
5493 ALC_SPDIF_CTRL_SWITCH("SPDIF Capture Switch", 0x06, 0x01),
5494
Jonathan Woithef8225f62008-01-08 12:16:54 +01005495 /* A switch allowing EAPD to be enabled. Some laptops seem to use
5496 * this output to turn on an external amplifier.
5497 */
5498 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
5499 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
5500
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005501 { } /* end */
5502};
5503static struct hda_verb alc260_test_init_verbs[] = {
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01005504 /* Enable all GPIOs as outputs with an initial value of 0 */
5505 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f},
5506 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
5507 {0x01, AC_VERB_SET_GPIO_MASK, 0x0f},
5508
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005509 /* Enable retasking pins as output, initially without power amp */
5510 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5511 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5512 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5513 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5514 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5515 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5516
Jonathan Woithe92621f12006-02-28 11:47:47 +01005517 /* Disable digital (SPDIF) pins initially, but users can enable
5518 * them via a mixer switch. In the case of SPDIF-out, this initverb
5519 * payload also sets the generation to 0, output to be in "consumer"
5520 * PCM format, copyright asserted, no pre-emphasis and no validity
5521 * control.
5522 */
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005523 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
5524 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
5525
Kailang Yangea1fb292008-08-26 12:58:38 +02005526 /* Ensure mic1, mic2, line1 and line2 pin widgets take input from the
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005527 * OUT1 sum bus when acting as an output.
5528 */
5529 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
5530 {0x0c, AC_VERB_SET_CONNECT_SEL, 0},
5531 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
5532 {0x0e, AC_VERB_SET_CONNECT_SEL, 0},
5533
5534 /* Start with output sum widgets muted and their output gains at min */
5535 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5536 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5537 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5538 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5539 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5540 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5541 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5542 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5543 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5544
Jonathan Woithecdcd9262006-02-28 11:36:42 +01005545 /* Unmute retasking pin widget output buffers since the default
5546 * state appears to be output. As the pin mode is changed by the
5547 * user the pin mode control will take care of enabling the pin's
5548 * input/output buffers as needed.
5549 */
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005550 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5551 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5552 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5553 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5554 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5555 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5556 /* Also unmute the mono-out pin widget */
5557 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5558
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005559 /* Mute capture amp left and right */
5560 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithef7ace402006-02-28 11:46:14 +01005561 /* Set ADC connection select to match default mixer setting (mic1
5562 * pin)
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005563 */
5564 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
5565
5566 /* Do the same for the second ADC: mute capture input amp and
Jonathan Woithef7ace402006-02-28 11:46:14 +01005567 * set ADC connection to mic1 pin
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005568 */
5569 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5570 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
5571
5572 /* Mute all inputs to mixer widget (even unconnected ones) */
5573 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
5574 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
5575 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
5576 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
5577 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
5578 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
5579 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
5580 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
5581
5582 { }
5583};
5584#endif
5585
Takashi Iwai63300792008-01-24 15:31:36 +01005586#define alc260_pcm_analog_playback alc880_pcm_analog_alt_playback
5587#define alc260_pcm_analog_capture alc880_pcm_analog_capture
Linus Torvalds1da177e2005-04-16 15:20:36 -07005588
Takashi Iwaia3bcba32005-12-06 19:05:29 +01005589#define alc260_pcm_digital_playback alc880_pcm_digital_playback
5590#define alc260_pcm_digital_capture alc880_pcm_digital_capture
5591
Kailang Yangdf694da2005-12-05 19:42:22 +01005592/*
5593 * for BIOS auto-configuration
5594 */
5595
5596static int alc260_add_playback_controls(struct alc_spec *spec, hda_nid_t nid,
Takashi Iwai863b4512008-10-21 17:01:47 +02005597 const char *pfx, int *vol_bits)
Kailang Yangdf694da2005-12-05 19:42:22 +01005598{
5599 hda_nid_t nid_vol;
5600 unsigned long vol_val, sw_val;
5601 char name[32];
5602 int err;
5603
5604 if (nid >= 0x0f && nid < 0x11) {
5605 nid_vol = nid - 0x7;
5606 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
5607 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
5608 } else if (nid == 0x11) {
5609 nid_vol = nid - 0x7;
5610 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT);
5611 sw_val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
5612 } else if (nid >= 0x12 && nid <= 0x15) {
5613 nid_vol = 0x08;
5614 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
5615 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
5616 } else
5617 return 0; /* N/A */
Kailang Yangea1fb292008-08-26 12:58:38 +02005618
Takashi Iwai863b4512008-10-21 17:01:47 +02005619 if (!(*vol_bits & (1 << nid_vol))) {
5620 /* first control for the volume widget */
5621 snprintf(name, sizeof(name), "%s Playback Volume", pfx);
5622 err = add_control(spec, ALC_CTL_WIDGET_VOL, name, vol_val);
5623 if (err < 0)
5624 return err;
5625 *vol_bits |= (1 << nid_vol);
5626 }
Kailang Yangdf694da2005-12-05 19:42:22 +01005627 snprintf(name, sizeof(name), "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005628 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, sw_val);
5629 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01005630 return err;
5631 return 1;
5632}
5633
5634/* add playback controls from the parsed DAC table */
5635static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec,
5636 const struct auto_pin_cfg *cfg)
5637{
5638 hda_nid_t nid;
5639 int err;
Takashi Iwai863b4512008-10-21 17:01:47 +02005640 int vols = 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01005641
5642 spec->multiout.num_dacs = 1;
5643 spec->multiout.dac_nids = spec->private_dac_nids;
5644 spec->multiout.dac_nids[0] = 0x02;
5645
5646 nid = cfg->line_out_pins[0];
5647 if (nid) {
Takashi Iwai863b4512008-10-21 17:01:47 +02005648 err = alc260_add_playback_controls(spec, nid, "Front", &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01005649 if (err < 0)
5650 return err;
5651 }
5652
Takashi Iwai82bc9552006-03-21 11:24:42 +01005653 nid = cfg->speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01005654 if (nid) {
Takashi Iwai863b4512008-10-21 17:01:47 +02005655 err = alc260_add_playback_controls(spec, nid, "Speaker", &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01005656 if (err < 0)
5657 return err;
5658 }
5659
Takashi Iwaieb06ed82006-09-20 17:10:27 +02005660 nid = cfg->hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01005661 if (nid) {
Takashi Iwai863b4512008-10-21 17:01:47 +02005662 err = alc260_add_playback_controls(spec, nid, "Headphone",
5663 &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01005664 if (err < 0)
5665 return err;
5666 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005667 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01005668}
5669
5670/* create playback/capture controls for input pins */
5671static int alc260_auto_create_analog_input_ctls(struct alc_spec *spec,
5672 const struct auto_pin_cfg *cfg)
5673{
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02005674 struct hda_input_mux *imux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01005675 int i, err, idx;
5676
5677 for (i = 0; i < AUTO_PIN_LAST; i++) {
5678 if (cfg->input_pins[i] >= 0x12) {
5679 idx = cfg->input_pins[i] - 0x12;
Takashi Iwai4a471b72005-12-07 13:56:29 +01005680 err = new_analog_input(spec, cfg->input_pins[i],
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005681 auto_pin_cfg_labels[i], idx,
5682 0x07);
Kailang Yangdf694da2005-12-05 19:42:22 +01005683 if (err < 0)
5684 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005685 imux->items[imux->num_items].label =
5686 auto_pin_cfg_labels[i];
Kailang Yangdf694da2005-12-05 19:42:22 +01005687 imux->items[imux->num_items].index = idx;
5688 imux->num_items++;
5689 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005690 if (cfg->input_pins[i] >= 0x0f && cfg->input_pins[i] <= 0x10){
Kailang Yangdf694da2005-12-05 19:42:22 +01005691 idx = cfg->input_pins[i] - 0x09;
Takashi Iwai4a471b72005-12-07 13:56:29 +01005692 err = new_analog_input(spec, cfg->input_pins[i],
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005693 auto_pin_cfg_labels[i], idx,
5694 0x07);
Kailang Yangdf694da2005-12-05 19:42:22 +01005695 if (err < 0)
5696 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005697 imux->items[imux->num_items].label =
5698 auto_pin_cfg_labels[i];
Kailang Yangdf694da2005-12-05 19:42:22 +01005699 imux->items[imux->num_items].index = idx;
5700 imux->num_items++;
5701 }
5702 }
5703 return 0;
5704}
5705
5706static void alc260_auto_set_output_and_unmute(struct hda_codec *codec,
5707 hda_nid_t nid, int pin_type,
5708 int sel_idx)
5709{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005710 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01005711 /* need the manual connection? */
5712 if (nid >= 0x12) {
5713 int idx = nid - 0x12;
5714 snd_hda_codec_write(codec, idx + 0x0b, 0,
5715 AC_VERB_SET_CONNECT_SEL, sel_idx);
Kailang Yangdf694da2005-12-05 19:42:22 +01005716 }
5717}
5718
5719static void alc260_auto_init_multi_out(struct hda_codec *codec)
5720{
5721 struct alc_spec *spec = codec->spec;
5722 hda_nid_t nid;
5723
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005724 nid = spec->autocfg.line_out_pins[0];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02005725 if (nid) {
5726 int pin_type = get_pin_type(spec->autocfg.line_out_type);
5727 alc260_auto_set_output_and_unmute(codec, nid, pin_type, 0);
5728 }
Kailang Yangea1fb292008-08-26 12:58:38 +02005729
Takashi Iwai82bc9552006-03-21 11:24:42 +01005730 nid = spec->autocfg.speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01005731 if (nid)
5732 alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
5733
Takashi Iwaieb06ed82006-09-20 17:10:27 +02005734 nid = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01005735 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02005736 alc260_auto_set_output_and_unmute(codec, nid, PIN_HP, 0);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005737}
Kailang Yangdf694da2005-12-05 19:42:22 +01005738
5739#define ALC260_PIN_CD_NID 0x16
5740static void alc260_auto_init_analog_input(struct hda_codec *codec)
5741{
5742 struct alc_spec *spec = codec->spec;
5743 int i;
5744
5745 for (i = 0; i < AUTO_PIN_LAST; i++) {
5746 hda_nid_t nid = spec->autocfg.input_pins[i];
5747 if (nid >= 0x12) {
Takashi Iwai23f0c042009-02-26 13:03:58 +01005748 alc_set_input_pin(codec, nid, i);
Takashi Iwaie82c0252009-03-23 15:17:38 +01005749 if (nid != ALC260_PIN_CD_NID &&
5750 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005751 snd_hda_codec_write(codec, nid, 0,
5752 AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangdf694da2005-12-05 19:42:22 +01005753 AMP_OUT_MUTE);
5754 }
5755 }
5756}
5757
5758/*
5759 * generic initialization of ADC, input mixers and output mixers
5760 */
5761static struct hda_verb alc260_volume_init_verbs[] = {
5762 /*
5763 * Unmute ADC0-1 and set the default input to mic-in
5764 */
5765 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
5766 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5767 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
5768 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +02005769
Kailang Yangdf694da2005-12-05 19:42:22 +01005770 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
5771 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005772 * Note: PASD motherboards uses the Line In 2 as the input for
5773 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01005774 */
5775 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02005776 /* mute analog inputs */
5777 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5778 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5779 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5780 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5781 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01005782
5783 /*
5784 * Set up output mixers (0x08 - 0x0a)
5785 */
5786 /* set vol=0 to output mixers */
5787 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5788 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5789 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5790 /* set up input amps for analog loopback */
5791 /* Amp Indices: DAC = 0, mixer = 1 */
5792 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5793 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5794 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5795 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5796 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5797 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +02005798
Kailang Yangdf694da2005-12-05 19:42:22 +01005799 { }
5800};
5801
5802static int alc260_parse_auto_config(struct hda_codec *codec)
5803{
5804 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01005805 int err;
5806 static hda_nid_t alc260_ignore[] = { 0x17, 0 };
5807
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005808 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
5809 alc260_ignore);
5810 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01005811 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005812 err = alc260_auto_create_multi_out_ctls(spec, &spec->autocfg);
5813 if (err < 0)
Takashi Iwai4a471b72005-12-07 13:56:29 +01005814 return err;
Takashi Iwai603c4012008-07-30 15:01:44 +02005815 if (!spec->kctls.list)
Kailang Yangdf694da2005-12-05 19:42:22 +01005816 return 0; /* can't find valid BIOS pin config */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005817 err = alc260_auto_create_analog_input_ctls(spec, &spec->autocfg);
5818 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01005819 return err;
5820
5821 spec->multiout.max_channels = 2;
5822
Takashi Iwai0852d7a2009-02-11 11:35:15 +01005823 if (spec->autocfg.dig_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +01005824 spec->multiout.dig_out_nid = ALC260_DIGOUT_NID;
Takashi Iwai603c4012008-07-30 15:01:44 +02005825 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +01005826 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +01005827
Takashi Iwaid88897e2008-10-31 15:01:37 +01005828 add_verb(spec, alc260_volume_init_verbs);
Kailang Yangdf694da2005-12-05 19:42:22 +01005829
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005830 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02005831 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01005832
Takashi Iwai4a79ba32009-04-22 16:31:35 +02005833 alc_ssid_check(codec, 0x10, 0x15, 0x0f);
5834
Kailang Yangdf694da2005-12-05 19:42:22 +01005835 return 1;
5836}
5837
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005838/* additional initialization for auto-configuration model */
5839static void alc260_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01005840{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005841 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01005842 alc260_auto_init_multi_out(codec);
5843 alc260_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005844 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02005845 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01005846}
5847
Takashi Iwaicb53c622007-08-10 17:21:45 +02005848#ifdef CONFIG_SND_HDA_POWER_SAVE
5849static struct hda_amp_list alc260_loopbacks[] = {
5850 { 0x07, HDA_INPUT, 0 },
5851 { 0x07, HDA_INPUT, 1 },
5852 { 0x07, HDA_INPUT, 2 },
5853 { 0x07, HDA_INPUT, 3 },
5854 { 0x07, HDA_INPUT, 4 },
5855 { } /* end */
5856};
5857#endif
5858
Kailang Yangdf694da2005-12-05 19:42:22 +01005859/*
5860 * ALC260 configurations
5861 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005862static const char *alc260_models[ALC260_MODEL_LAST] = {
5863 [ALC260_BASIC] = "basic",
5864 [ALC260_HP] = "hp",
5865 [ALC260_HP_3013] = "hp-3013",
Takashi Iwai2922c9a2008-08-27 18:12:42 +02005866 [ALC260_HP_DC7600] = "hp-dc7600",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005867 [ALC260_FUJITSU_S702X] = "fujitsu",
5868 [ALC260_ACER] = "acer",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005869 [ALC260_WILL] = "will",
5870 [ALC260_REPLACER_672V] = "replacer",
Michael Schwingencc959482009-02-22 18:58:45 +01005871 [ALC260_FAVORIT100] = "favorit100",
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005872#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005873 [ALC260_TEST] = "test",
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005874#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005875 [ALC260_AUTO] = "auto",
5876};
5877
5878static struct snd_pci_quirk alc260_cfg_tbl[] = {
Jonathan Woithebd869482006-11-28 11:35:52 +01005879 SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005880 SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER),
Michael Schwingencc959482009-02-22 18:58:45 +01005881 SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FAVORIT100),
Takashi Iwai9720b712007-03-13 21:46:23 +01005882 SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013),
Takashi Iwaia8a5d062007-03-15 15:10:28 +01005883 SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_HP_3013),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005884 SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013),
Jaroslav Kysela34ec8a02008-07-10 14:49:19 +02005885 SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP_3013),
Kailang Yang3f878302008-08-26 13:02:23 +02005886 SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_DC7600),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005887 SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013),
5888 SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP),
5889 SND_PCI_QUIRK(0x103c, 0x3015, "HP", ALC260_HP),
5890 SND_PCI_QUIRK(0x103c, 0x3016, "HP", ALC260_HP),
5891 SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_BASIC),
5892 SND_PCI_QUIRK(0x104d, 0x81cc, "Sony VAIO", ALC260_BASIC),
5893 SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC),
5894 SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X),
5895 SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005896 SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_REPLACER_672V),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01005897 SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_WILL),
Takashi Iwai16ded522005-06-10 19:58:24 +02005898 {}
5899};
5900
Kailang Yangdf694da2005-12-05 19:42:22 +01005901static struct alc_config_preset alc260_presets[] = {
5902 [ALC260_BASIC] = {
5903 .mixers = { alc260_base_output_mixer,
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01005904 alc260_input_mixer },
Kailang Yangdf694da2005-12-05 19:42:22 +01005905 .init_verbs = { alc260_init_verbs },
5906 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5907 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005908 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
Kailang Yangdf694da2005-12-05 19:42:22 +01005909 .adc_nids = alc260_adc_nids,
5910 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5911 .channel_mode = alc260_modes,
5912 .input_mux = &alc260_capture_source,
5913 },
5914 [ALC260_HP] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01005915 .mixers = { alc260_hp_output_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005916 alc260_input_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01005917 .init_verbs = { alc260_init_verbs,
5918 alc260_hp_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01005919 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5920 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005921 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
5922 .adc_nids = alc260_adc_nids_alt,
Kailang Yangdf694da2005-12-05 19:42:22 +01005923 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5924 .channel_mode = alc260_modes,
5925 .input_mux = &alc260_capture_source,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005926 .unsol_event = alc260_hp_unsol_event,
5927 .init_hook = alc260_hp_automute,
Kailang Yangdf694da2005-12-05 19:42:22 +01005928 },
Kailang Yang3f878302008-08-26 13:02:23 +02005929 [ALC260_HP_DC7600] = {
5930 .mixers = { alc260_hp_dc7600_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005931 alc260_input_mixer },
Kailang Yang3f878302008-08-26 13:02:23 +02005932 .init_verbs = { alc260_init_verbs,
5933 alc260_hp_dc7600_verbs },
5934 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5935 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005936 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
5937 .adc_nids = alc260_adc_nids_alt,
Kailang Yang3f878302008-08-26 13:02:23 +02005938 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5939 .channel_mode = alc260_modes,
5940 .input_mux = &alc260_capture_source,
5941 .unsol_event = alc260_hp_3012_unsol_event,
5942 .init_hook = alc260_hp_3012_automute,
5943 },
Kailang Yangdf694da2005-12-05 19:42:22 +01005944 [ALC260_HP_3013] = {
5945 .mixers = { alc260_hp_3013_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005946 alc260_input_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01005947 .init_verbs = { alc260_hp_3013_init_verbs,
5948 alc260_hp_3013_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01005949 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5950 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005951 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
5952 .adc_nids = alc260_adc_nids_alt,
Kailang Yangdf694da2005-12-05 19:42:22 +01005953 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5954 .channel_mode = alc260_modes,
5955 .input_mux = &alc260_capture_source,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005956 .unsol_event = alc260_hp_3013_unsol_event,
5957 .init_hook = alc260_hp_3013_automute,
Kailang Yangdf694da2005-12-05 19:42:22 +01005958 },
5959 [ALC260_FUJITSU_S702X] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005960 .mixers = { alc260_fujitsu_mixer },
Kailang Yangdf694da2005-12-05 19:42:22 +01005961 .init_verbs = { alc260_fujitsu_init_verbs },
5962 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5963 .dac_nids = alc260_dac_nids,
Jonathan Woithed57fdac2006-02-28 11:38:35 +01005964 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
5965 .adc_nids = alc260_dual_adc_nids,
Kailang Yangdf694da2005-12-05 19:42:22 +01005966 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5967 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005968 .num_mux_defs = ARRAY_SIZE(alc260_fujitsu_capture_sources),
5969 .input_mux = alc260_fujitsu_capture_sources,
Kailang Yangdf694da2005-12-05 19:42:22 +01005970 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005971 [ALC260_ACER] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005972 .mixers = { alc260_acer_mixer },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005973 .init_verbs = { alc260_acer_init_verbs },
5974 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5975 .dac_nids = alc260_dac_nids,
5976 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
5977 .adc_nids = alc260_dual_adc_nids,
5978 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5979 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005980 .num_mux_defs = ARRAY_SIZE(alc260_acer_capture_sources),
5981 .input_mux = alc260_acer_capture_sources,
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005982 },
Michael Schwingencc959482009-02-22 18:58:45 +01005983 [ALC260_FAVORIT100] = {
5984 .mixers = { alc260_favorit100_mixer },
5985 .init_verbs = { alc260_favorit100_init_verbs },
5986 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5987 .dac_nids = alc260_dac_nids,
5988 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
5989 .adc_nids = alc260_dual_adc_nids,
5990 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5991 .channel_mode = alc260_modes,
5992 .num_mux_defs = ARRAY_SIZE(alc260_favorit100_capture_sources),
5993 .input_mux = alc260_favorit100_capture_sources,
5994 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005995 [ALC260_WILL] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005996 .mixers = { alc260_will_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005997 .init_verbs = { alc260_init_verbs, alc260_will_verbs },
5998 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5999 .dac_nids = alc260_dac_nids,
6000 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
6001 .adc_nids = alc260_adc_nids,
6002 .dig_out_nid = ALC260_DIGOUT_NID,
6003 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6004 .channel_mode = alc260_modes,
6005 .input_mux = &alc260_capture_source,
6006 },
6007 [ALC260_REPLACER_672V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006008 .mixers = { alc260_replacer_672v_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006009 .init_verbs = { alc260_init_verbs, alc260_replacer_672v_verbs },
6010 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6011 .dac_nids = alc260_dac_nids,
6012 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
6013 .adc_nids = alc260_adc_nids,
6014 .dig_out_nid = ALC260_DIGOUT_NID,
6015 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6016 .channel_mode = alc260_modes,
6017 .input_mux = &alc260_capture_source,
6018 .unsol_event = alc260_replacer_672v_unsol_event,
6019 .init_hook = alc260_replacer_672v_automute,
6020 },
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006021#ifdef CONFIG_SND_DEBUG
6022 [ALC260_TEST] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006023 .mixers = { alc260_test_mixer },
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006024 .init_verbs = { alc260_test_init_verbs },
6025 .num_dacs = ARRAY_SIZE(alc260_test_dac_nids),
6026 .dac_nids = alc260_test_dac_nids,
6027 .num_adc_nids = ARRAY_SIZE(alc260_test_adc_nids),
6028 .adc_nids = alc260_test_adc_nids,
6029 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6030 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006031 .num_mux_defs = ARRAY_SIZE(alc260_test_capture_sources),
6032 .input_mux = alc260_test_capture_sources,
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006033 },
6034#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01006035};
6036
Linus Torvalds1da177e2005-04-16 15:20:36 -07006037static int patch_alc260(struct hda_codec *codec)
6038{
6039 struct alc_spec *spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01006040 int err, board_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006041
Takashi Iwaie560d8d2005-09-09 14:21:46 +02006042 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006043 if (spec == NULL)
6044 return -ENOMEM;
6045
6046 codec->spec = spec;
6047
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006048 board_config = snd_hda_check_board_config(codec, ALC260_MODEL_LAST,
6049 alc260_models,
6050 alc260_cfg_tbl);
6051 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006052 snd_printd(KERN_INFO "hda_codec: Unknown model for ALC260, "
6053 "trying auto-probe from BIOS...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01006054 board_config = ALC260_AUTO;
Takashi Iwai16ded522005-06-10 19:58:24 +02006055 }
6056
Kailang Yangdf694da2005-12-05 19:42:22 +01006057 if (board_config == ALC260_AUTO) {
6058 /* automatic parse from the BIOS config */
6059 err = alc260_parse_auto_config(codec);
6060 if (err < 0) {
6061 alc_free(codec);
6062 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006063 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006064 printk(KERN_INFO
6065 "hda_codec: Cannot set up configuration "
6066 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01006067 board_config = ALC260_BASIC;
6068 }
Takashi Iwai16ded522005-06-10 19:58:24 +02006069 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006070
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09006071 err = snd_hda_attach_beep_device(codec, 0x1);
6072 if (err < 0) {
6073 alc_free(codec);
6074 return err;
6075 }
6076
Kailang Yangdf694da2005-12-05 19:42:22 +01006077 if (board_config != ALC260_AUTO)
6078 setup_preset(spec, &alc260_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006079
6080 spec->stream_name_analog = "ALC260 Analog";
6081 spec->stream_analog_playback = &alc260_pcm_analog_playback;
6082 spec->stream_analog_capture = &alc260_pcm_analog_capture;
6083
Takashi Iwaia3bcba32005-12-06 19:05:29 +01006084 spec->stream_name_digital = "ALC260 Digital";
6085 spec->stream_digital_playback = &alc260_pcm_digital_playback;
6086 spec->stream_digital_capture = &alc260_pcm_digital_capture;
6087
Takashi Iwai4ef0ef12008-11-03 17:47:49 +01006088 if (!spec->adc_nids && spec->input_mux) {
6089 /* check whether NID 0x04 is valid */
6090 unsigned int wcap = get_wcaps(codec, 0x04);
6091 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
6092 /* get type */
6093 if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
6094 spec->adc_nids = alc260_adc_nids_alt;
6095 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt);
6096 } else {
6097 spec->adc_nids = alc260_adc_nids;
6098 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids);
6099 }
6100 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006101 set_capture_mixer(spec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01006102 set_beep_amp(spec, 0x07, 0x05, HDA_INPUT);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006103
Takashi Iwai2134ea42008-01-10 16:53:55 +01006104 spec->vmaster_nid = 0x08;
6105
Linus Torvalds1da177e2005-04-16 15:20:36 -07006106 codec->patch_ops = alc_patch_ops;
Kailang Yangdf694da2005-12-05 19:42:22 +01006107 if (board_config == ALC260_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01006108 spec->init_hook = alc260_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02006109#ifdef CONFIG_SND_HDA_POWER_SAVE
6110 if (!spec->loopback.amplist)
6111 spec->loopback.amplist = alc260_loopbacks;
6112#endif
Takashi Iwaidaead532008-11-28 12:55:36 +01006113 codec->proc_widget_hook = print_realtek_coef;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006114
6115 return 0;
6116}
6117
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006118
Linus Torvalds1da177e2005-04-16 15:20:36 -07006119/*
6120 * ALC882 support
6121 *
6122 * ALC882 is almost identical with ALC880 but has cleaner and more flexible
6123 * configuration. Each pin widget can choose any input DACs and a mixer.
6124 * Each ADC is connected from a mixer of all inputs. This makes possible
6125 * 6-channel independent captures.
6126 *
6127 * In addition, an independent DAC for the multi-playback (not used in this
6128 * driver yet).
6129 */
Kailang Yangdf694da2005-12-05 19:42:22 +01006130#define ALC882_DIGOUT_NID 0x06
6131#define ALC882_DIGIN_NID 0x0a
Linus Torvalds1da177e2005-04-16 15:20:36 -07006132
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01006133static struct hda_channel_mode alc882_ch_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006134 { 8, NULL }
6135};
6136
6137static hda_nid_t alc882_dac_nids[4] = {
6138 /* front, rear, clfe, rear_surr */
6139 0x02, 0x03, 0x04, 0x05
6140};
6141
Kailang Yangdf694da2005-12-05 19:42:22 +01006142/* identical with ALC880 */
6143#define alc882_adc_nids alc880_adc_nids
6144#define alc882_adc_nids_alt alc880_adc_nids_alt
Linus Torvalds1da177e2005-04-16 15:20:36 -07006145
Takashi Iwaie1406342008-02-11 18:32:32 +01006146static hda_nid_t alc882_capsrc_nids[3] = { 0x24, 0x23, 0x22 };
6147static hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 };
6148
Linus Torvalds1da177e2005-04-16 15:20:36 -07006149/* input MUX */
6150/* FIXME: should be a matrix-type input source selection */
6151
6152static struct hda_input_mux alc882_capture_source = {
6153 .num_items = 4,
6154 .items = {
6155 { "Mic", 0x0 },
6156 { "Front Mic", 0x1 },
6157 { "Line", 0x2 },
6158 { "CD", 0x4 },
6159 },
6160};
Kacper Szczesniak41d55452009-05-07 12:47:43 +02006161
6162static struct hda_input_mux mb5_capture_source = {
6163 .num_items = 3,
6164 .items = {
6165 { "Mic", 0x1 },
6166 { "Line", 0x2 },
6167 { "CD", 0x4 },
6168 },
6169};
6170
Kailang Yangdf694da2005-12-05 19:42:22 +01006171/*
Kailang Yang272a5272007-05-14 11:00:38 +02006172 * 2ch mode
6173 */
6174static struct hda_verb alc882_3ST_ch2_init[] = {
6175 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
6176 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6177 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
6178 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6179 { } /* end */
6180};
6181
6182/*
6183 * 6ch mode
6184 */
6185static struct hda_verb alc882_3ST_ch6_init[] = {
6186 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6187 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6188 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
6189 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6190 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6191 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6192 { } /* end */
6193};
6194
6195static struct hda_channel_mode alc882_3ST_6ch_modes[2] = {
6196 { 2, alc882_3ST_ch2_init },
6197 { 6, alc882_3ST_ch6_init },
6198};
6199
6200/*
Kailang Yangdf694da2005-12-05 19:42:22 +01006201 * 6ch mode
6202 */
6203static struct hda_verb alc882_sixstack_ch6_init[] = {
6204 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
6205 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6206 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6207 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6208 { } /* end */
6209};
6210
6211/*
6212 * 8ch mode
6213 */
6214static struct hda_verb alc882_sixstack_ch8_init[] = {
6215 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6216 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6217 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6218 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6219 { } /* end */
6220};
6221
6222static struct hda_channel_mode alc882_sixstack_modes[2] = {
6223 { 6, alc882_sixstack_ch6_init },
6224 { 8, alc882_sixstack_ch8_init },
6225};
6226
Takashi Iwai87350ad2007-08-16 18:19:38 +02006227/*
6228 * macbook pro ALC885 can switch LineIn to LineOut without loosing Mic
6229 */
6230
6231/*
6232 * 2ch mode
6233 */
6234static struct hda_verb alc885_mbp_ch2_init[] = {
6235 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
6236 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6237 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6238 { } /* end */
6239};
6240
6241/*
6242 * 6ch mode
6243 */
6244static struct hda_verb alc885_mbp_ch6_init[] = {
6245 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6246 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6247 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6248 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6249 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6250 { } /* end */
6251};
6252
6253static struct hda_channel_mode alc885_mbp_6ch_modes[2] = {
6254 { 2, alc885_mbp_ch2_init },
6255 { 6, alc885_mbp_ch6_init },
6256};
6257
6258
Linus Torvalds1da177e2005-04-16 15:20:36 -07006259/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
6260 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
6261 */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01006262static struct snd_kcontrol_new alc882_base_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02006263 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01006264 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02006265 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01006266 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02006267 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
6268 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01006269 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
6270 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02006271 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01006272 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07006273 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6274 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6275 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6276 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6277 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6278 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006279 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07006280 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6281 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006282 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07006283 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07006284 { } /* end */
6285};
6286
Takashi Iwai87350ad2007-08-16 18:19:38 +02006287static struct snd_kcontrol_new alc885_mbp3_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01006288 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
6289 HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
6290 HDA_CODEC_MUTE ("Speaker Playback Switch", 0x14, 0x00, HDA_OUTPUT),
6291 HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
6292 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6293 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02006294 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
6295 HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01006296 HDA_CODEC_VOLUME("Line Boost", 0x1a, 0x00, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02006297 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT),
6298 { } /* end */
6299};
Kacper Szczesniak41d55452009-05-07 12:47:43 +02006300
6301static struct snd_kcontrol_new alc885_mb5_mixer[] = {
6302 HDA_CODEC_VOLUME("Front Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
6303 HDA_BIND_MUTE ("Front Playback Switch", 0x0d, 0x02, HDA_INPUT),
6304 HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
6305 HDA_BIND_MUTE ("Line-Out Playback Switch", 0x0c, 0x02, HDA_INPUT),
6306 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6307 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6308 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
6309 HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
6310 HDA_CODEC_VOLUME("Line Boost", 0x15, 0x00, HDA_INPUT),
6311 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0x00, HDA_INPUT),
6312 { } /* end */
6313};
Kailang Yangbdd148a2007-05-08 15:19:08 +02006314static struct snd_kcontrol_new alc882_w2jc_mixer[] = {
6315 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6316 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6317 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6318 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6319 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6320 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6321 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6322 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
6323 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangbdd148a2007-05-08 15:19:08 +02006324 { } /* end */
6325};
6326
Kailang Yang272a5272007-05-14 11:00:38 +02006327static struct snd_kcontrol_new alc882_targa_mixer[] = {
6328 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6329 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6330 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6331 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6332 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6333 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6334 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6335 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6336 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai96fe7cc82007-09-07 10:57:44 +02006337 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02006338 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
6339 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai96fe7cc82007-09-07 10:57:44 +02006340 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02006341 { } /* end */
6342};
6343
6344/* Pin assignment: Front=0x14, HP = 0x15, Front = 0x16, ???
6345 * Front Mic=0x18, Line In = 0x1a, Line In = 0x1b, CD = 0x1c
6346 */
6347static struct snd_kcontrol_new alc882_asus_a7j_mixer[] = {
6348 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6349 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
6350 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
6351 HDA_CODEC_MUTE("Mobile Front Playback Switch", 0x16, 0x0, HDA_OUTPUT),
6352 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6353 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6354 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6355 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6356 HDA_CODEC_VOLUME("Mobile Line Playback Volume", 0x0b, 0x03, HDA_INPUT),
6357 HDA_CODEC_MUTE("Mobile Line Playback Switch", 0x0b, 0x03, HDA_INPUT),
6358 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6359 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai96fe7cc82007-09-07 10:57:44 +02006360 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02006361 { } /* end */
6362};
6363
Takashi Iwai914759b2007-09-06 14:52:04 +02006364static struct snd_kcontrol_new alc882_asus_a7m_mixer[] = {
6365 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6366 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6367 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
6368 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6369 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6370 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6371 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6372 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6373 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
6374 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai914759b2007-09-06 14:52:04 +02006375 { } /* end */
6376};
6377
Kailang Yangdf694da2005-12-05 19:42:22 +01006378static struct snd_kcontrol_new alc882_chmode_mixer[] = {
6379 {
6380 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6381 .name = "Channel Mode",
6382 .info = alc_ch_mode_info,
6383 .get = alc_ch_mode_get,
6384 .put = alc_ch_mode_put,
6385 },
6386 { } /* end */
6387};
6388
Linus Torvalds1da177e2005-04-16 15:20:36 -07006389static struct hda_verb alc882_init_verbs[] = {
6390 /* Front mixer: unmute input/output amp left and right (volume = 0) */
Takashi Iwai05acb862005-06-10 19:50:25 +02006391 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6392 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6393 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006394 /* Rear mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02006395 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6396 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6397 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006398 /* CLFE mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02006399 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6400 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6401 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006402 /* Side mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02006403 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6404 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6405 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006406
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006407 /* Front Pin: output 0 (0x0c) */
Takashi Iwai05acb862005-06-10 19:50:25 +02006408 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02006409 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006410 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006411 /* Rear Pin: output 1 (0x0d) */
Takashi Iwai05acb862005-06-10 19:50:25 +02006412 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02006413 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006414 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006415 /* CLFE Pin: output 2 (0x0e) */
Takashi Iwai05acb862005-06-10 19:50:25 +02006416 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02006417 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006418 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006419 /* Side Pin: output 3 (0x0f) */
Takashi Iwai05acb862005-06-10 19:50:25 +02006420 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02006421 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006422 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006423 /* Mic (rear) pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02006424 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006425 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6426 /* Front Mic pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02006427 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006428 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6429 /* Line In pin: input */
Takashi Iwai05acb862005-06-10 19:50:25 +02006430 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006431 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6432 /* Line-2 In: Headphone output (output 0 - 0x0c) */
6433 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6434 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6435 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006436 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02006437 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006438
6439 /* FIXME: use matrix-type input source selection */
6440 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
6441 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
Takashi Iwai05acb862005-06-10 19:50:25 +02006442 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6443 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6444 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6445 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006446 /* Input mixer2 */
Takashi Iwai05acb862005-06-10 19:50:25 +02006447 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6448 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6449 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6450 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006451 /* Input mixer3 */
Takashi Iwai05acb862005-06-10 19:50:25 +02006452 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6453 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6454 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6455 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6456 /* ADC1: mute amp left and right */
6457 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02006458 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02006459 /* ADC2: mute amp left and right */
6460 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02006461 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02006462 /* ADC3: mute amp left and right */
6463 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02006464 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006465
6466 { }
6467};
6468
Takashi Iwai4b146cb2006-07-28 14:42:36 +02006469static struct hda_verb alc882_eapd_verbs[] = {
6470 /* change to EAPD mode */
6471 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01006472 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006473 { }
Takashi Iwai4b146cb2006-07-28 14:42:36 +02006474};
6475
Tobin Davis9102cd12006-12-15 10:02:12 +01006476/* Mac Pro test */
6477static struct snd_kcontrol_new alc882_macpro_mixer[] = {
6478 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6479 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6480 HDA_CODEC_MUTE("Headphone Playback Switch", 0x18, 0x0, HDA_OUTPUT),
6481 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
6482 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01006483 /* FIXME: this looks suspicious...
Tobin Davis9102cd12006-12-15 10:02:12 +01006484 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x02, HDA_INPUT),
6485 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01006486 */
Tobin Davis9102cd12006-12-15 10:02:12 +01006487 { } /* end */
6488};
6489
6490static struct hda_verb alc882_macpro_init_verbs[] = {
6491 /* Front mixer: unmute input/output amp left and right (volume = 0) */
6492 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6493 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6494 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6495 /* Front Pin: output 0 (0x0c) */
6496 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6497 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6498 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
6499 /* Front Mic pin: input vref at 80% */
6500 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
6501 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6502 /* Speaker: output */
6503 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6504 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6505 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x04},
6506 /* Headphone output (output 0 - 0x0c) */
6507 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6508 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6509 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
6510
6511 /* FIXME: use matrix-type input source selection */
6512 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
6513 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
6514 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6515 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6516 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6517 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6518 /* Input mixer2 */
6519 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6520 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6521 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6522 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6523 /* Input mixer3 */
6524 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6525 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6526 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6527 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6528 /* ADC1: mute amp left and right */
6529 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6530 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
6531 /* ADC2: mute amp left and right */
6532 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6533 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
6534 /* ADC3: mute amp left and right */
6535 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6536 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
6537
6538 { }
6539};
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006540
Kacper Szczesniak41d55452009-05-07 12:47:43 +02006541/* Macbook 5,1 */
6542static struct hda_verb alc885_mb5_init_verbs[] = {
6543 /* Front mixer */
6544 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6545 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6546 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6547 /* LineOut mixer */
6548 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6549 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6550 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6551 /* Front Pin: output 0 (0x0d) */
6552 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
6553 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6554 {0x18, AC_VERB_SET_CONNECT_SEL, 0x01},
6555 /* HP Pin: output 0 (0x0c) */
6556 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6557 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6558 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
6559 /* Front Mic pin: input vref at 80% */
6560 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
6561 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6562 /* Line In pin */
6563 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
6564 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6565
6566 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6567 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6568 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6569 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6570 { }
6571};
6572
Takashi Iwai87350ad2007-08-16 18:19:38 +02006573/* Macbook Pro rev3 */
6574static struct hda_verb alc885_mbp3_init_verbs[] = {
6575 /* Front mixer: unmute input/output amp left and right (volume = 0) */
6576 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6577 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6578 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6579 /* Rear mixer */
6580 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6581 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6582 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6583 /* Front Pin: output 0 (0x0c) */
6584 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6585 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6586 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
6587 /* HP Pin: output 0 (0x0d) */
6588 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
6589 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6590 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
6591 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
6592 /* Mic (rear) pin: input vref at 80% */
6593 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
6594 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6595 /* Front Mic pin: input vref at 80% */
6596 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
6597 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6598 /* Line In pin: use output 1 when in LineOut mode */
6599 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
6600 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6601 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
6602
6603 /* FIXME: use matrix-type input source selection */
6604 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
6605 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
6606 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6607 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6608 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6609 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6610 /* Input mixer2 */
6611 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6612 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6613 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6614 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6615 /* Input mixer3 */
6616 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6617 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6618 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6619 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6620 /* ADC1: mute amp left and right */
6621 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6622 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
6623 /* ADC2: mute amp left and right */
6624 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6625 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
6626 /* ADC3: mute amp left and right */
6627 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6628 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
6629
6630 { }
6631};
6632
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006633/* iMac 24 mixer. */
6634static struct snd_kcontrol_new alc885_imac24_mixer[] = {
6635 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
6636 HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x00, HDA_INPUT),
6637 { } /* end */
6638};
6639
6640/* iMac 24 init verbs. */
6641static struct hda_verb alc885_imac24_init_verbs[] = {
6642 /* Internal speakers: output 0 (0x0c) */
6643 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6644 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6645 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
6646 /* Internal speakers: output 0 (0x0c) */
6647 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6648 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6649 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
6650 /* Headphone: output 0 (0x0c) */
6651 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6652 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6653 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
6654 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
6655 /* Front Mic: input vref at 80% */
6656 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
6657 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6658 { }
6659};
6660
6661/* Toggle speaker-output according to the hp-jack state */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02006662static void alc885_imac24_automute_init_hook(struct hda_codec *codec)
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006663{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02006664 struct alc_spec *spec = codec->spec;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006665
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02006666 spec->autocfg.hp_pins[0] = 0x14;
6667 spec->autocfg.speaker_pins[0] = 0x18;
6668 spec->autocfg.speaker_pins[1] = 0x1a;
6669 alc_automute_amp(codec);
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006670}
6671
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02006672static void alc885_mbp3_init_hook(struct hda_codec *codec)
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006673{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02006674 struct alc_spec *spec = codec->spec;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006675
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02006676 spec->autocfg.hp_pins[0] = 0x15;
6677 spec->autocfg.speaker_pins[0] = 0x14;
6678 alc_automute_amp(codec);
Takashi Iwai87350ad2007-08-16 18:19:38 +02006679}
6680
6681
Kailang Yang272a5272007-05-14 11:00:38 +02006682static struct hda_verb alc882_targa_verbs[] = {
6683 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6684 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6685
6686 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6687 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02006688
Kailang Yang272a5272007-05-14 11:00:38 +02006689 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
6690 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
6691 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
6692
6693 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
6694 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
6695 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
6696 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
6697 { } /* end */
6698};
6699
6700/* toggle speaker-output according to the hp-jack state */
6701static void alc882_targa_automute(struct hda_codec *codec)
6702{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02006703 struct alc_spec *spec = codec->spec;
6704 alc_automute_amp(codec);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02006705 snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02006706 spec->jack_present ? 1 : 3);
6707}
6708
6709static void alc882_targa_init_hook(struct hda_codec *codec)
6710{
6711 struct alc_spec *spec = codec->spec;
6712
6713 spec->autocfg.hp_pins[0] = 0x14;
6714 spec->autocfg.speaker_pins[0] = 0x1b;
6715 alc882_targa_automute(codec);
Kailang Yang272a5272007-05-14 11:00:38 +02006716}
6717
6718static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res)
6719{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02006720 if ((res >> 26) == ALC880_HP_EVENT)
Kailang Yang272a5272007-05-14 11:00:38 +02006721 alc882_targa_automute(codec);
Kailang Yang272a5272007-05-14 11:00:38 +02006722}
6723
6724static struct hda_verb alc882_asus_a7j_verbs[] = {
6725 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6726 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6727
6728 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6729 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6730 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02006731
Kailang Yang272a5272007-05-14 11:00:38 +02006732 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
6733 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
6734 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
6735
6736 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
6737 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
6738 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
6739 { } /* end */
6740};
6741
Takashi Iwai914759b2007-09-06 14:52:04 +02006742static struct hda_verb alc882_asus_a7m_verbs[] = {
6743 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6744 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6745
6746 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6747 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6748 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02006749
Takashi Iwai914759b2007-09-06 14:52:04 +02006750 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
6751 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
6752 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
6753
6754 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
6755 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
6756 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
6757 { } /* end */
6758};
6759
Tobin Davis9102cd12006-12-15 10:02:12 +01006760static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted)
6761{
6762 unsigned int gpiostate, gpiomask, gpiodir;
6763
6764 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
6765 AC_VERB_GET_GPIO_DATA, 0);
6766
6767 if (!muted)
6768 gpiostate |= (1 << pin);
6769 else
6770 gpiostate &= ~(1 << pin);
6771
6772 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
6773 AC_VERB_GET_GPIO_MASK, 0);
6774 gpiomask |= (1 << pin);
6775
6776 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
6777 AC_VERB_GET_GPIO_DIRECTION, 0);
6778 gpiodir |= (1 << pin);
6779
6780
6781 snd_hda_codec_write(codec, codec->afg, 0,
6782 AC_VERB_SET_GPIO_MASK, gpiomask);
6783 snd_hda_codec_write(codec, codec->afg, 0,
6784 AC_VERB_SET_GPIO_DIRECTION, gpiodir);
6785
6786 msleep(1);
6787
6788 snd_hda_codec_write(codec, codec->afg, 0,
6789 AC_VERB_SET_GPIO_DATA, gpiostate);
6790}
6791
Takashi Iwai7debbe52007-08-16 15:01:03 +02006792/* set up GPIO at initialization */
6793static void alc885_macpro_init_hook(struct hda_codec *codec)
6794{
6795 alc882_gpio_mute(codec, 0, 0);
6796 alc882_gpio_mute(codec, 1, 0);
6797}
6798
6799/* set up GPIO and update auto-muting at initialization */
6800static void alc885_imac24_init_hook(struct hda_codec *codec)
6801{
6802 alc885_macpro_init_hook(codec);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02006803 alc885_imac24_automute_init_hook(codec);
Takashi Iwai7debbe52007-08-16 15:01:03 +02006804}
6805
Kailang Yangdf694da2005-12-05 19:42:22 +01006806/*
6807 * generic initialization of ADC, input mixers and output mixers
6808 */
6809static struct hda_verb alc882_auto_init_verbs[] = {
6810 /*
6811 * Unmute ADC0-2 and set the default input to mic-in
6812 */
6813 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
6814 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6815 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
6816 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6817 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
6818 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6819
Takashi Iwaicb53c622007-08-10 17:21:45 +02006820 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +01006821 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006822 * Note: PASD motherboards uses the Line In 2 as the input for
6823 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01006824 */
6825 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02006826 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6827 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6828 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6829 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6830 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01006831
6832 /*
6833 * Set up output mixers (0x0c - 0x0f)
6834 */
6835 /* set vol=0 to output mixers */
6836 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6837 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6838 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6839 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6840 /* set up input amps for analog loopback */
6841 /* Amp Indices: DAC = 0, mixer = 1 */
6842 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6843 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6844 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6845 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6846 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6847 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6848 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6849 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6850 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6851 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6852
6853 /* FIXME: use matrix-type input source selection */
6854 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
6855 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
6856 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6857 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
6858 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
6859 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
6860 /* Input mixer2 */
6861 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6862 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
6863 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
6864 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
6865 /* Input mixer3 */
6866 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6867 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
6868 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
6869 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
6870
6871 { }
6872};
6873
Takashi Iwaicb53c622007-08-10 17:21:45 +02006874#ifdef CONFIG_SND_HDA_POWER_SAVE
6875#define alc882_loopbacks alc880_loopbacks
6876#endif
6877
Kailang Yangdf694da2005-12-05 19:42:22 +01006878/* pcm configuration: identiacal with ALC880 */
6879#define alc882_pcm_analog_playback alc880_pcm_analog_playback
6880#define alc882_pcm_analog_capture alc880_pcm_analog_capture
6881#define alc882_pcm_digital_playback alc880_pcm_digital_playback
6882#define alc882_pcm_digital_capture alc880_pcm_digital_capture
6883
6884/*
6885 * configuration and preset
6886 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006887static const char *alc882_models[ALC882_MODEL_LAST] = {
6888 [ALC882_3ST_DIG] = "3stack-dig",
6889 [ALC882_6ST_DIG] = "6stack-dig",
6890 [ALC882_ARIMA] = "arima",
Kailang Yangbdd148a2007-05-08 15:19:08 +02006891 [ALC882_W2JC] = "w2jc",
Takashi Iwai0438a002007-09-06 14:54:11 +02006892 [ALC882_TARGA] = "targa",
6893 [ALC882_ASUS_A7J] = "asus-a7j",
6894 [ALC882_ASUS_A7M] = "asus-a7m",
Tobin Davis9102cd12006-12-15 10:02:12 +01006895 [ALC885_MACPRO] = "macpro",
Kacper Szczesniak41d55452009-05-07 12:47:43 +02006896 [ALC885_MB5] = "mb5",
Takashi Iwai87350ad2007-08-16 18:19:38 +02006897 [ALC885_MBP3] = "mbp3",
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006898 [ALC885_IMAC24] = "imac24",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006899 [ALC882_AUTO] = "auto",
6900};
6901
6902static struct snd_pci_quirk alc882_cfg_tbl[] = {
6903 SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG),
Kailang Yang272a5272007-05-14 11:00:38 +02006904 SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J),
Kailang Yangac8842a2007-09-20 12:51:39 +02006905 SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J),
Takashi Iwai914759b2007-09-06 14:52:04 +02006906 SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01006907 SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC),
Claudio Matsuokac5d9f1c2007-07-19 23:18:32 +02006908 SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG),
Tobin Davis7b9470d2006-12-28 13:56:48 +01006909 SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01006910 SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG),
Jiang zhe44447042008-01-28 12:28:24 +01006911 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01006912 SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */
6913 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG),
6914 SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA),
Kailang Yangdf694da2005-12-05 19:42:22 +01006915 {}
6916};
6917
6918static struct alc_config_preset alc882_presets[] = {
6919 [ALC882_3ST_DIG] = {
6920 .mixers = { alc882_base_mixer },
6921 .init_verbs = { alc882_init_verbs },
6922 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6923 .dac_nids = alc882_dac_nids,
6924 .dig_out_nid = ALC882_DIGOUT_NID,
Kailang Yangdf694da2005-12-05 19:42:22 +01006925 .dig_in_nid = ALC882_DIGIN_NID,
6926 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
6927 .channel_mode = alc882_ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02006928 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01006929 .input_mux = &alc882_capture_source,
6930 },
6931 [ALC882_6ST_DIG] = {
6932 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
6933 .init_verbs = { alc882_init_verbs },
6934 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6935 .dac_nids = alc882_dac_nids,
6936 .dig_out_nid = ALC882_DIGOUT_NID,
Kailang Yangdf694da2005-12-05 19:42:22 +01006937 .dig_in_nid = ALC882_DIGIN_NID,
6938 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
6939 .channel_mode = alc882_sixstack_modes,
6940 .input_mux = &alc882_capture_source,
6941 },
Takashi Iwai4b146cb2006-07-28 14:42:36 +02006942 [ALC882_ARIMA] = {
6943 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
6944 .init_verbs = { alc882_init_verbs, alc882_eapd_verbs },
6945 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6946 .dac_nids = alc882_dac_nids,
6947 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
6948 .channel_mode = alc882_sixstack_modes,
6949 .input_mux = &alc882_capture_source,
6950 },
Kailang Yangbdd148a2007-05-08 15:19:08 +02006951 [ALC882_W2JC] = {
6952 .mixers = { alc882_w2jc_mixer, alc882_chmode_mixer },
6953 .init_verbs = { alc882_init_verbs, alc882_eapd_verbs,
6954 alc880_gpio1_init_verbs },
6955 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6956 .dac_nids = alc882_dac_nids,
6957 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
6958 .channel_mode = alc880_threestack_modes,
6959 .need_dac_fix = 1,
6960 .input_mux = &alc882_capture_source,
6961 .dig_out_nid = ALC882_DIGOUT_NID,
6962 },
Takashi Iwai87350ad2007-08-16 18:19:38 +02006963 [ALC885_MBP3] = {
6964 .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer },
6965 .init_verbs = { alc885_mbp3_init_verbs,
6966 alc880_gpio1_init_verbs },
6967 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6968 .dac_nids = alc882_dac_nids,
6969 .channel_mode = alc885_mbp_6ch_modes,
6970 .num_channel_mode = ARRAY_SIZE(alc885_mbp_6ch_modes),
6971 .input_mux = &alc882_capture_source,
6972 .dig_out_nid = ALC882_DIGOUT_NID,
6973 .dig_in_nid = ALC882_DIGIN_NID,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02006974 .unsol_event = alc_automute_amp_unsol_event,
6975 .init_hook = alc885_mbp3_init_hook,
Takashi Iwai87350ad2007-08-16 18:19:38 +02006976 },
Kacper Szczesniak41d55452009-05-07 12:47:43 +02006977 [ALC885_MB5] = {
6978 .mixers = { alc885_mb5_mixer },
6979 .init_verbs = { alc885_mb5_init_verbs,
6980 alc880_gpio1_init_verbs },
6981 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6982 .dac_nids = alc882_dac_nids,
6983 .channel_mode = alc885_mbp_6ch_modes,
6984 .num_channel_mode = ARRAY_SIZE(alc885_mbp_6ch_modes),
6985 .input_mux = &mb5_capture_source,
6986 .dig_out_nid = ALC882_DIGOUT_NID,
6987 .dig_in_nid = ALC882_DIGIN_NID,
6988 },
Tobin Davis9102cd12006-12-15 10:02:12 +01006989 [ALC885_MACPRO] = {
6990 .mixers = { alc882_macpro_mixer },
6991 .init_verbs = { alc882_macpro_init_verbs },
6992 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6993 .dac_nids = alc882_dac_nids,
6994 .dig_out_nid = ALC882_DIGOUT_NID,
6995 .dig_in_nid = ALC882_DIGIN_NID,
6996 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
6997 .channel_mode = alc882_ch_modes,
6998 .input_mux = &alc882_capture_source,
Takashi Iwai7debbe52007-08-16 15:01:03 +02006999 .init_hook = alc885_macpro_init_hook,
Tobin Davis9102cd12006-12-15 10:02:12 +01007000 },
Nicola Fagnanic54728d2007-07-19 23:28:52 +02007001 [ALC885_IMAC24] = {
7002 .mixers = { alc885_imac24_mixer },
7003 .init_verbs = { alc885_imac24_init_verbs },
7004 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
7005 .dac_nids = alc882_dac_nids,
7006 .dig_out_nid = ALC882_DIGOUT_NID,
7007 .dig_in_nid = ALC882_DIGIN_NID,
7008 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
7009 .channel_mode = alc882_ch_modes,
7010 .input_mux = &alc882_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02007011 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai7debbe52007-08-16 15:01:03 +02007012 .init_hook = alc885_imac24_init_hook,
Nicola Fagnanic54728d2007-07-19 23:28:52 +02007013 },
Kailang Yang272a5272007-05-14 11:00:38 +02007014 [ALC882_TARGA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007015 .mixers = { alc882_targa_mixer, alc882_chmode_mixer },
Kailang Yang272a5272007-05-14 11:00:38 +02007016 .init_verbs = { alc882_init_verbs, alc882_targa_verbs},
7017 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
7018 .dac_nids = alc882_dac_nids,
7019 .dig_out_nid = ALC882_DIGOUT_NID,
7020 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
7021 .adc_nids = alc882_adc_nids,
Takashi Iwaie1406342008-02-11 18:32:32 +01007022 .capsrc_nids = alc882_capsrc_nids,
Kailang Yang272a5272007-05-14 11:00:38 +02007023 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
7024 .channel_mode = alc882_3ST_6ch_modes,
7025 .need_dac_fix = 1,
7026 .input_mux = &alc882_capture_source,
7027 .unsol_event = alc882_targa_unsol_event,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02007028 .init_hook = alc882_targa_init_hook,
Kailang Yang272a5272007-05-14 11:00:38 +02007029 },
7030 [ALC882_ASUS_A7J] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007031 .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer },
Kailang Yang272a5272007-05-14 11:00:38 +02007032 .init_verbs = { alc882_init_verbs, alc882_asus_a7j_verbs},
7033 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
7034 .dac_nids = alc882_dac_nids,
7035 .dig_out_nid = ALC882_DIGOUT_NID,
7036 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
7037 .adc_nids = alc882_adc_nids,
Takashi Iwaie1406342008-02-11 18:32:32 +01007038 .capsrc_nids = alc882_capsrc_nids,
Kailang Yang272a5272007-05-14 11:00:38 +02007039 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
7040 .channel_mode = alc882_3ST_6ch_modes,
7041 .need_dac_fix = 1,
7042 .input_mux = &alc882_capture_source,
Kailang Yangea1fb292008-08-26 12:58:38 +02007043 },
Takashi Iwai914759b2007-09-06 14:52:04 +02007044 [ALC882_ASUS_A7M] = {
7045 .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer },
7046 .init_verbs = { alc882_init_verbs, alc882_eapd_verbs,
7047 alc880_gpio1_init_verbs,
7048 alc882_asus_a7m_verbs },
7049 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
7050 .dac_nids = alc882_dac_nids,
7051 .dig_out_nid = ALC882_DIGOUT_NID,
7052 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
7053 .channel_mode = alc880_threestack_modes,
7054 .need_dac_fix = 1,
7055 .input_mux = &alc882_capture_source,
Kailang Yangea1fb292008-08-26 12:58:38 +02007056 },
Kailang Yangdf694da2005-12-05 19:42:22 +01007057};
7058
7059
7060/*
Takashi Iwaif95474e2007-07-10 00:47:43 +02007061 * Pin config fixes
7062 */
Kailang Yangea1fb292008-08-26 12:58:38 +02007063enum {
Takashi Iwaif95474e2007-07-10 00:47:43 +02007064 PINFIX_ABIT_AW9D_MAX
7065};
7066
7067static struct alc_pincfg alc882_abit_aw9d_pinfix[] = {
7068 { 0x15, 0x01080104 }, /* side */
7069 { 0x16, 0x01011012 }, /* rear */
7070 { 0x17, 0x01016011 }, /* clfe */
7071 { }
7072};
7073
7074static const struct alc_pincfg *alc882_pin_fixes[] = {
7075 [PINFIX_ABIT_AW9D_MAX] = alc882_abit_aw9d_pinfix,
7076};
7077
7078static struct snd_pci_quirk alc882_pinfix_tbl[] = {
7079 SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
7080 {}
7081};
7082
7083/*
Kailang Yangdf694da2005-12-05 19:42:22 +01007084 * BIOS auto configuration
7085 */
7086static void alc882_auto_set_output_and_unmute(struct hda_codec *codec,
7087 hda_nid_t nid, int pin_type,
7088 int dac_idx)
7089{
7090 /* set as output */
7091 struct alc_spec *spec = codec->spec;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007092 int idx;
7093
Takashi Iwaif6c7e542008-02-12 18:32:23 +01007094 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01007095 if (spec->multiout.dac_nids[dac_idx] == 0x25)
7096 idx = 4;
7097 else
7098 idx = spec->multiout.dac_nids[dac_idx] - 2;
Kailang Yangdf694da2005-12-05 19:42:22 +01007099 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
7100
7101}
7102
7103static void alc882_auto_init_multi_out(struct hda_codec *codec)
7104{
7105 struct alc_spec *spec = codec->spec;
7106 int i;
7107
7108 for (i = 0; i <= HDA_SIDE; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007109 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02007110 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01007111 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02007112 alc882_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007113 i);
Kailang Yangdf694da2005-12-05 19:42:22 +01007114 }
7115}
7116
7117static void alc882_auto_init_hp_out(struct hda_codec *codec)
7118{
7119 struct alc_spec *spec = codec->spec;
7120 hda_nid_t pin;
7121
Takashi Iwaieb06ed82006-09-20 17:10:27 +02007122 pin = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01007123 if (pin) /* connect to front */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007124 /* use dac 0 */
7125 alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01007126 pin = spec->autocfg.speaker_pins[0];
7127 if (pin)
7128 alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Kailang Yangdf694da2005-12-05 19:42:22 +01007129}
7130
7131#define alc882_is_input_pin(nid) alc880_is_input_pin(nid)
7132#define ALC882_PIN_CD_NID ALC880_PIN_CD_NID
7133
7134static void alc882_auto_init_analog_input(struct hda_codec *codec)
7135{
7136 struct alc_spec *spec = codec->spec;
7137 int i;
7138
7139 for (i = 0; i < AUTO_PIN_LAST; i++) {
7140 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwai7194cae2008-03-06 16:58:17 +01007141 if (!nid)
7142 continue;
Takashi Iwai23f0c042009-02-26 13:03:58 +01007143 alc_set_input_pin(codec, nid, AUTO_PIN_FRONT_MIC /*i*/);
Takashi Iwai7194cae2008-03-06 16:58:17 +01007144 if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
7145 snd_hda_codec_write(codec, nid, 0,
7146 AC_VERB_SET_AMP_GAIN_MUTE,
7147 AMP_OUT_MUTE);
Kailang Yangdf694da2005-12-05 19:42:22 +01007148 }
7149}
7150
Takashi Iwaif511b012008-08-15 16:46:42 +02007151static void alc882_auto_init_input_src(struct hda_codec *codec)
7152{
7153 struct alc_spec *spec = codec->spec;
Takashi Iwaif511b012008-08-15 16:46:42 +02007154 int c;
7155
7156 for (c = 0; c < spec->num_adc_nids; c++) {
7157 hda_nid_t conn_list[HDA_MAX_NUM_INPUTS];
7158 hda_nid_t nid = spec->capsrc_nids[c];
Herton Ronaldo Krzesinskib98b7b32009-01-29 13:18:31 -02007159 unsigned int mux_idx;
7160 const struct hda_input_mux *imux;
Takashi Iwaif511b012008-08-15 16:46:42 +02007161 int conns, mute, idx, item;
7162
7163 conns = snd_hda_get_connections(codec, nid, conn_list,
7164 ARRAY_SIZE(conn_list));
7165 if (conns < 0)
7166 continue;
Herton Ronaldo Krzesinskib98b7b32009-01-29 13:18:31 -02007167 mux_idx = c >= spec->num_mux_defs ? 0 : c;
7168 imux = &spec->input_mux[mux_idx];
Takashi Iwaif511b012008-08-15 16:46:42 +02007169 for (idx = 0; idx < conns; idx++) {
7170 /* if the current connection is the selected one,
7171 * unmute it as default - otherwise mute it
7172 */
7173 mute = AMP_IN_MUTE(idx);
7174 for (item = 0; item < imux->num_items; item++) {
7175 if (imux->items[item].index == idx) {
7176 if (spec->cur_mux[c] == item)
7177 mute = AMP_IN_UNMUTE(idx);
7178 break;
7179 }
7180 }
Herton Ronaldo Krzesinskib98b7b32009-01-29 13:18:31 -02007181 /* check if we have a selector or mixer
7182 * we could check for the widget type instead, but
7183 * just check for Amp-In presence (in case of mixer
7184 * without amp-in there is something wrong, this
7185 * function shouldn't be used or capsrc nid is wrong)
7186 */
7187 if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)
7188 snd_hda_codec_write(codec, nid, 0,
7189 AC_VERB_SET_AMP_GAIN_MUTE,
7190 mute);
7191 else if (mute != AMP_IN_MUTE(idx))
7192 snd_hda_codec_write(codec, nid, 0,
7193 AC_VERB_SET_CONNECT_SEL,
7194 idx);
Takashi Iwaif511b012008-08-15 16:46:42 +02007195 }
7196 }
7197}
7198
Takashi Iwai776e1842007-08-29 15:07:11 +02007199/* add mic boosts if needed */
7200static int alc_auto_add_mic_boost(struct hda_codec *codec)
7201{
7202 struct alc_spec *spec = codec->spec;
7203 int err;
7204 hda_nid_t nid;
7205
7206 nid = spec->autocfg.input_pins[AUTO_PIN_MIC];
Takashi Iwaice22e032008-01-11 17:38:35 +01007207 if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
Takashi Iwai776e1842007-08-29 15:07:11 +02007208 err = add_control(spec, ALC_CTL_WIDGET_VOL,
7209 "Mic Boost",
7210 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
7211 if (err < 0)
7212 return err;
7213 }
7214 nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC];
Takashi Iwaice22e032008-01-11 17:38:35 +01007215 if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
Takashi Iwai776e1842007-08-29 15:07:11 +02007216 err = add_control(spec, ALC_CTL_WIDGET_VOL,
7217 "Front Mic Boost",
7218 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
7219 if (err < 0)
7220 return err;
7221 }
7222 return 0;
7223}
7224
Kailang Yangdf694da2005-12-05 19:42:22 +01007225/* almost identical with ALC880 parser... */
7226static int alc882_parse_auto_config(struct hda_codec *codec)
7227{
7228 struct alc_spec *spec = codec->spec;
7229 int err = alc880_parse_auto_config(codec);
7230
7231 if (err < 0)
7232 return err;
Takashi Iwai776e1842007-08-29 15:07:11 +02007233 else if (!err)
7234 return 0; /* no config found */
7235
7236 err = alc_auto_add_mic_boost(codec);
7237 if (err < 0)
7238 return err;
7239
7240 /* hack - override the init verbs */
7241 spec->init_verbs[0] = alc882_auto_init_verbs;
7242
7243 return 1; /* config found */
Kailang Yangdf694da2005-12-05 19:42:22 +01007244}
7245
Takashi Iwaiae6b8132006-03-03 16:47:17 +01007246/* additional initialization for auto-configuration model */
7247static void alc882_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01007248{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01007249 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01007250 alc882_auto_init_multi_out(codec);
7251 alc882_auto_init_hp_out(codec);
7252 alc882_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +02007253 alc882_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01007254 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02007255 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01007256}
7257
Takashi Iwai7943a8a2008-04-16 17:29:09 +02007258static int patch_alc883(struct hda_codec *codec); /* called in patch_alc882() */
7259
Linus Torvalds1da177e2005-04-16 15:20:36 -07007260static int patch_alc882(struct hda_codec *codec)
7261{
7262 struct alc_spec *spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01007263 int err, board_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007264
Takashi Iwaie560d8d2005-09-09 14:21:46 +02007265 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007266 if (spec == NULL)
7267 return -ENOMEM;
7268
Linus Torvalds1da177e2005-04-16 15:20:36 -07007269 codec->spec = spec;
7270
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007271 board_config = snd_hda_check_board_config(codec, ALC882_MODEL_LAST,
7272 alc882_models,
7273 alc882_cfg_tbl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007274
Kailang Yangdf694da2005-12-05 19:42:22 +01007275 if (board_config < 0 || board_config >= ALC882_MODEL_LAST) {
Tobin Davis081d17c2007-02-15 17:46:18 +01007276 /* Pick up systems that don't supply PCI SSID */
7277 switch (codec->subsystem_id) {
7278 case 0x106b0c00: /* Mac Pro */
7279 board_config = ALC885_MACPRO;
7280 break;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02007281 case 0x106b1000: /* iMac 24 */
Peter Korsgaardf3911c52008-09-27 09:13:45 +02007282 case 0x106b2800: /* AppleTV */
Mark Eggleston3077e442009-01-31 17:57:54 +01007283 case 0x106b3e00: /* iMac 24 Aluminium */
Nicola Fagnanic54728d2007-07-19 23:28:52 +02007284 board_config = ALC885_IMAC24;
7285 break;
Luke Yelavich2d466382009-02-23 13:00:33 +11007286 case 0x106b00a0: /* MacBookPro3,1 - Another revision */
Takashi Iwaic7e07572008-06-26 14:42:51 +02007287 case 0x106b00a1: /* Macbook (might be wrong - PCI SSID?) */
David Woodhouse9c95c432008-09-18 13:37:13 -07007288 case 0x106b00a4: /* MacbookPro4,1 */
Takashi Iwai87350ad2007-08-16 18:19:38 +02007289 case 0x106b2c00: /* Macbook Pro rev3 */
Takashi Iwaic7e07572008-06-26 14:42:51 +02007290 case 0x106b3600: /* Macbook 3.1 */
Luke Yelavich2a884642009-01-28 15:58:38 +11007291 case 0x106b3800: /* MacbookPro4,1 - latter revision */
Takashi Iwai87350ad2007-08-16 18:19:38 +02007292 board_config = ALC885_MBP3;
7293 break;
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007294 case 0x106b3f00: /* Macbook 5,1 */
7295 board_config = ALC885_MB5;
7296 break;
Tobin Davis081d17c2007-02-15 17:46:18 +01007297 default:
Takashi Iwai7943a8a2008-04-16 17:29:09 +02007298 /* ALC889A is handled better as ALC888-compatible */
Clive Messer669faba2008-09-30 15:49:13 +02007299 if (codec->revision_id == 0x100101 ||
7300 codec->revision_id == 0x100103) {
Takashi Iwai7943a8a2008-04-16 17:29:09 +02007301 alc_free(codec);
7302 return patch_alc883(codec);
7303 }
Tobin Davis081d17c2007-02-15 17:46:18 +01007304 printk(KERN_INFO "hda_codec: Unknown model for ALC882, "
7305 "trying auto-probe from BIOS...\n");
7306 board_config = ALC882_AUTO;
7307 }
Kailang Yangdf694da2005-12-05 19:42:22 +01007308 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007309
Takashi Iwaif95474e2007-07-10 00:47:43 +02007310 alc_fix_pincfg(codec, alc882_pinfix_tbl, alc882_pin_fixes);
7311
Kailang Yangdf694da2005-12-05 19:42:22 +01007312 if (board_config == ALC882_AUTO) {
7313 /* automatic parse from the BIOS config */
7314 err = alc882_parse_auto_config(codec);
7315 if (err < 0) {
7316 alc_free(codec);
7317 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007318 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007319 printk(KERN_INFO
7320 "hda_codec: Cannot set up configuration "
7321 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01007322 board_config = ALC882_3ST_DIG;
7323 }
7324 }
7325
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09007326 err = snd_hda_attach_beep_device(codec, 0x1);
7327 if (err < 0) {
7328 alc_free(codec);
7329 return err;
7330 }
7331
Kailang Yangdf694da2005-12-05 19:42:22 +01007332 if (board_config != ALC882_AUTO)
7333 setup_preset(spec, &alc882_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007334
Kailang Yang2f893282008-05-27 12:14:47 +02007335 if (codec->vendor_id == 0x10ec0885) {
7336 spec->stream_name_analog = "ALC885 Analog";
7337 spec->stream_name_digital = "ALC885 Digital";
7338 } else {
7339 spec->stream_name_analog = "ALC882 Analog";
7340 spec->stream_name_digital = "ALC882 Digital";
7341 }
7342
Kailang Yangdf694da2005-12-05 19:42:22 +01007343 spec->stream_analog_playback = &alc882_pcm_analog_playback;
7344 spec->stream_analog_capture = &alc882_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01007345 /* FIXME: setup DAC5 */
7346 /*spec->stream_analog_alt_playback = &alc880_pcm_analog_alt_playback;*/
7347 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007348
Kailang Yangdf694da2005-12-05 19:42:22 +01007349 spec->stream_digital_playback = &alc882_pcm_digital_playback;
7350 spec->stream_digital_capture = &alc882_pcm_digital_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007351
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02007352 spec->capture_style = CAPT_MIX; /* matrix-style capture */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007353 if (!spec->adc_nids && spec->input_mux) {
Kailang Yangdf694da2005-12-05 19:42:22 +01007354 /* check whether NID 0x07 is valid */
Takashi Iwai4a471b72005-12-07 13:56:29 +01007355 unsigned int wcap = get_wcaps(codec, 0x07);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007356 /* get type */
7357 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Kailang Yangdf694da2005-12-05 19:42:22 +01007358 if (wcap != AC_WID_AUD_IN) {
7359 spec->adc_nids = alc882_adc_nids_alt;
7360 spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids_alt);
Takashi Iwaie1406342008-02-11 18:32:32 +01007361 spec->capsrc_nids = alc882_capsrc_nids_alt;
Kailang Yangdf694da2005-12-05 19:42:22 +01007362 } else {
7363 spec->adc_nids = alc882_adc_nids;
7364 spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids);
Takashi Iwaie1406342008-02-11 18:32:32 +01007365 spec->capsrc_nids = alc882_capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +01007366 }
7367 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007368 set_capture_mixer(spec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01007369 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007370
Takashi Iwai2134ea42008-01-10 16:53:55 +01007371 spec->vmaster_nid = 0x0c;
7372
Linus Torvalds1da177e2005-04-16 15:20:36 -07007373 codec->patch_ops = alc_patch_ops;
Kailang Yangdf694da2005-12-05 19:42:22 +01007374 if (board_config == ALC882_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01007375 spec->init_hook = alc882_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02007376#ifdef CONFIG_SND_HDA_POWER_SAVE
7377 if (!spec->loopback.amplist)
7378 spec->loopback.amplist = alc882_loopbacks;
7379#endif
Takashi Iwaidaead532008-11-28 12:55:36 +01007380 codec->proc_widget_hook = print_realtek_coef;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007381
7382 return 0;
7383}
7384
7385/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007386 * ALC883 support
7387 *
7388 * ALC883 is almost identical with ALC880 but has cleaner and more flexible
7389 * configuration. Each pin widget can choose any input DACs and a mixer.
7390 * Each ADC is connected from a mixer of all inputs. This makes possible
7391 * 6-channel independent captures.
7392 *
7393 * In addition, an independent DAC for the multi-playback (not used in this
7394 * driver yet).
7395 */
7396#define ALC883_DIGOUT_NID 0x06
7397#define ALC883_DIGIN_NID 0x0a
7398
Wu Fengguang3ab90932008-11-17 09:51:09 +01007399#define ALC1200_DIGOUT_NID 0x10
7400
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007401static hda_nid_t alc883_dac_nids[4] = {
7402 /* front, rear, clfe, rear_surr */
Herton Ronaldo Krzesinskif32a19e2008-03-18 09:27:08 +01007403 0x02, 0x03, 0x04, 0x05
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007404};
7405
7406static hda_nid_t alc883_adc_nids[2] = {
7407 /* ADC1-2 */
7408 0x08, 0x09,
7409};
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007410
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007411static hda_nid_t alc883_adc_nids_alt[1] = {
7412 /* ADC1 */
7413 0x08,
7414};
7415
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08007416static hda_nid_t alc883_adc_nids_rev[2] = {
7417 /* ADC2-1 */
7418 0x09, 0x08
7419};
7420
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02007421#define alc889_adc_nids alc880_adc_nids
7422
Takashi Iwaie1406342008-02-11 18:32:32 +01007423static hda_nid_t alc883_capsrc_nids[2] = { 0x23, 0x22 };
7424
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08007425static hda_nid_t alc883_capsrc_nids_rev[2] = { 0x22, 0x23 };
7426
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02007427#define alc889_capsrc_nids alc882_capsrc_nids
7428
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007429/* input MUX */
7430/* FIXME: should be a matrix-type input source selection */
7431
7432static struct hda_input_mux alc883_capture_source = {
7433 .num_items = 4,
7434 .items = {
7435 { "Mic", 0x0 },
7436 { "Front Mic", 0x1 },
7437 { "Line", 0x2 },
7438 { "CD", 0x4 },
7439 },
7440};
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007441
Jiang zhe17bba1b2008-06-04 12:11:07 +02007442static struct hda_input_mux alc883_3stack_6ch_intel = {
7443 .num_items = 4,
7444 .items = {
7445 { "Mic", 0x1 },
7446 { "Front Mic", 0x0 },
7447 { "Line", 0x2 },
7448 { "CD", 0x4 },
7449 },
7450};
7451
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007452static struct hda_input_mux alc883_lenovo_101e_capture_source = {
7453 .num_items = 2,
7454 .items = {
7455 { "Mic", 0x1 },
7456 { "Line", 0x2 },
7457 },
7458};
7459
Kailang Yang272a5272007-05-14 11:00:38 +02007460static struct hda_input_mux alc883_lenovo_nb0763_capture_source = {
7461 .num_items = 4,
7462 .items = {
7463 { "Mic", 0x0 },
7464 { "iMic", 0x1 },
7465 { "Line", 0x2 },
7466 { "CD", 0x4 },
7467 },
7468};
7469
Jiang zhefb97dc62008-03-06 11:07:11 +01007470static struct hda_input_mux alc883_fujitsu_pi2515_capture_source = {
7471 .num_items = 2,
7472 .items = {
7473 { "Mic", 0x0 },
7474 { "Int Mic", 0x1 },
7475 },
7476};
7477
Kailang Yange2757d52008-08-26 13:17:46 +02007478static struct hda_input_mux alc883_lenovo_sky_capture_source = {
7479 .num_items = 3,
7480 .items = {
7481 { "Mic", 0x0 },
7482 { "Front Mic", 0x1 },
7483 { "Line", 0x4 },
7484 },
7485};
7486
7487static struct hda_input_mux alc883_asus_eee1601_capture_source = {
7488 .num_items = 2,
7489 .items = {
7490 { "Mic", 0x0 },
7491 { "Line", 0x2 },
7492 },
7493};
7494
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007495/*
7496 * 2ch mode
7497 */
7498static struct hda_channel_mode alc883_3ST_2ch_modes[1] = {
7499 { 2, NULL }
7500};
7501
7502/*
7503 * 2ch mode
7504 */
7505static struct hda_verb alc883_3ST_ch2_init[] = {
7506 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7507 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7508 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7509 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7510 { } /* end */
7511};
7512
7513/*
Tobin Davisb2011312007-09-17 12:45:11 +02007514 * 4ch mode
7515 */
7516static struct hda_verb alc883_3ST_ch4_init[] = {
7517 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7518 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7519 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7520 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7521 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7522 { } /* end */
7523};
7524
7525/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007526 * 6ch mode
7527 */
7528static struct hda_verb alc883_3ST_ch6_init[] = {
7529 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7530 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7531 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7532 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7533 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7534 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7535 { } /* end */
7536};
7537
Tobin Davisb2011312007-09-17 12:45:11 +02007538static struct hda_channel_mode alc883_3ST_6ch_modes[3] = {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007539 { 2, alc883_3ST_ch2_init },
Tobin Davisb2011312007-09-17 12:45:11 +02007540 { 4, alc883_3ST_ch4_init },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007541 { 6, alc883_3ST_ch6_init },
7542};
7543
7544/*
Jiang zhe17bba1b2008-06-04 12:11:07 +02007545 * 2ch mode
7546 */
7547static struct hda_verb alc883_3ST_ch2_intel_init[] = {
7548 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7549 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7550 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7551 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7552 { } /* end */
7553};
7554
7555/*
7556 * 4ch mode
7557 */
7558static struct hda_verb alc883_3ST_ch4_intel_init[] = {
7559 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7560 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7561 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7562 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7563 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7564 { } /* end */
7565};
7566
7567/*
7568 * 6ch mode
7569 */
7570static struct hda_verb alc883_3ST_ch6_intel_init[] = {
7571 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7572 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7573 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x02 },
7574 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7575 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7576 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7577 { } /* end */
7578};
7579
7580static struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = {
7581 { 2, alc883_3ST_ch2_intel_init },
7582 { 4, alc883_3ST_ch4_intel_init },
7583 { 6, alc883_3ST_ch6_intel_init },
7584};
7585
7586/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007587 * 6ch mode
7588 */
7589static struct hda_verb alc883_sixstack_ch6_init[] = {
7590 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
7591 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7592 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7593 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7594 { } /* end */
7595};
7596
7597/*
7598 * 8ch mode
7599 */
7600static struct hda_verb alc883_sixstack_ch8_init[] = {
7601 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7602 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7603 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7604 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7605 { } /* end */
7606};
7607
7608static struct hda_channel_mode alc883_sixstack_modes[2] = {
7609 { 6, alc883_sixstack_ch6_init },
7610 { 8, alc883_sixstack_ch8_init },
7611};
7612
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01007613static struct hda_verb alc883_medion_eapd_verbs[] = {
7614 /* eanable EAPD on medion laptop */
7615 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
7616 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
7617 { }
7618};
7619
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007620/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
7621 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
7622 */
7623
7624static struct snd_kcontrol_new alc883_base_mixer[] = {
7625 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7626 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7627 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7628 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
7629 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7630 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
7631 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7632 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
7633 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
7634 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
7635 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7636 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7637 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7638 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7639 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7640 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007641 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007642 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7643 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007644 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007645 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007646 { } /* end */
7647};
7648
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01007649static struct snd_kcontrol_new alc883_mitac_mixer[] = {
7650 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7651 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7652 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7653 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
7654 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7655 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
7656 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
7657 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7658 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7659 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7660 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7661 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
7662 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01007663 { } /* end */
7664};
7665
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007666static struct snd_kcontrol_new alc883_clevo_m720_mixer[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01007667 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7668 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
7669 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7670 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
7671 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7672 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7673 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7674 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7675 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
7676 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Jiang zhe368c7a92008-03-04 11:20:33 +01007677 { } /* end */
7678};
7679
Jiang zhefb97dc62008-03-06 11:07:11 +01007680static struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = {
7681 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7682 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
7683 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7684 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
7685 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7686 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7687 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7688 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7689 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
7690 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Jiang zhefb97dc62008-03-06 11:07:11 +01007691 { } /* end */
7692};
7693
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007694static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = {
7695 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7696 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7697 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7698 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7699 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7700 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7701 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7702 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007703 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007704 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7705 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007706 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007707 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007708 { } /* end */
7709};
7710
7711static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
7712 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7713 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7714 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7715 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
7716 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7717 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
7718 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7719 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
7720 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7721 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7722 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7723 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7724 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7725 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007726 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007727 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7728 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007729 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007730 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007731 { } /* end */
7732};
7733
Jiang zhe17bba1b2008-06-04 12:11:07 +02007734static struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = {
7735 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7736 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7737 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7738 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
7739 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
7740 HDA_OUTPUT),
7741 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
7742 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7743 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
7744 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
7745 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7746 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7747 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7748 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7749 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7750 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
7751 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
7752 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7753 HDA_CODEC_VOLUME("Front Mic Boost", 0x18, 0, HDA_INPUT),
7754 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Jiang zhe17bba1b2008-06-04 12:11:07 +02007755 { } /* end */
7756};
7757
Takashi Iwaid1d985f2006-11-23 19:27:12 +01007758static struct snd_kcontrol_new alc883_fivestack_mixer[] = {
Tobin Davisc07584c2006-10-13 12:32:16 +02007759 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02007760 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007761 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02007762 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007763 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7764 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02007765 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7766 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007767 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7768 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7769 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7770 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7771 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7772 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007773 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007774 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7775 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007776 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007777 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007778 { } /* end */
7779};
7780
Kailang Yangccc656c2006-10-17 12:32:26 +02007781static struct snd_kcontrol_new alc883_tagra_mixer[] = {
7782 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7783 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7784 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7785 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7786 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
7787 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7788 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
7789 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7790 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
7791 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7792 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7793 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7794 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7795 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007796 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02007797 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02007798 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007799};
Kailang Yangccc656c2006-10-17 12:32:26 +02007800
7801static struct snd_kcontrol_new alc883_tagra_2ch_mixer[] = {
7802 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7803 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7804 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7805 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7806 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7807 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007808 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02007809 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Jiang zhe4383fae2008-04-14 12:58:57 +02007810 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7811 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
7812 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02007813 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007814};
Kailang Yangccc656c2006-10-17 12:32:26 +02007815
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007816static struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = {
7817 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7818 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01007819 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7820 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007821 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7822 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7823 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7824 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007825 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007826};
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007827
Kailang Yang272a5272007-05-14 11:00:38 +02007828static struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = {
7829 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7830 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
7831 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7832 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7833 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7834 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7835 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7836 HDA_CODEC_VOLUME("iMic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7837 HDA_CODEC_MUTE("iMic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02007838 { } /* end */
7839};
7840
7841static struct snd_kcontrol_new alc883_medion_md2_mixer[] = {
7842 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7843 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7844 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
7845 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7846 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7847 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7848 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7849 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7850 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02007851 { } /* end */
Kailang Yangea1fb292008-08-26 12:58:38 +02007852};
Kailang Yang272a5272007-05-14 11:00:38 +02007853
Tobin Davis2880a862007-08-07 11:50:26 +02007854static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = {
Kailang Yangd1a991a2007-08-15 16:21:59 +02007855 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7856 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02007857 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02007858 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7859 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Kailang Yangd1a991a2007-08-15 16:21:59 +02007860 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7861 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7862 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02007863 { } /* end */
Kailang Yangd1a991a2007-08-15 16:21:59 +02007864};
Tobin Davis2880a862007-08-07 11:50:26 +02007865
Kailang Yange2757d52008-08-26 13:17:46 +02007866static struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = {
7867 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7868 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7869 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
7870 HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
7871 HDA_CODEC_VOLUME_MONO("Center Playback Volume",
7872 0x0d, 1, 0x0, HDA_OUTPUT),
7873 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
7874 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
7875 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
7876 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
7877 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02007878 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7879 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7880 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7881 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7882 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7883 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7884 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7885 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7886 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
7887 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02007888 { } /* end */
7889};
7890
7891static struct hda_bind_ctls alc883_bind_cap_vol = {
7892 .ops = &snd_hda_bind_vol,
7893 .values = {
7894 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
7895 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
7896 0
7897 },
7898};
7899
7900static struct hda_bind_ctls alc883_bind_cap_switch = {
7901 .ops = &snd_hda_bind_sw,
7902 .values = {
7903 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
7904 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
7905 0
7906 },
7907};
7908
7909static struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = {
7910 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7911 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7912 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7913 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7914 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7915 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7916 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7917 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007918 { } /* end */
7919};
7920
7921static struct snd_kcontrol_new alc883_asus_eee1601_cap_mixer[] = {
Kailang Yange2757d52008-08-26 13:17:46 +02007922 HDA_BIND_VOL("Capture Volume", &alc883_bind_cap_vol),
7923 HDA_BIND_SW("Capture Switch", &alc883_bind_cap_switch),
7924 {
7925 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7926 /* .name = "Capture Source", */
7927 .name = "Input Source",
7928 .count = 1,
Takashi Iwai54cbc9a2008-10-31 15:24:04 +01007929 .info = alc_mux_enum_info,
7930 .get = alc_mux_enum_get,
7931 .put = alc_mux_enum_put,
Kailang Yange2757d52008-08-26 13:17:46 +02007932 },
7933 { } /* end */
7934};
7935
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007936static struct snd_kcontrol_new alc883_chmode_mixer[] = {
7937 {
7938 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7939 .name = "Channel Mode",
7940 .info = alc_ch_mode_info,
7941 .get = alc_ch_mode_get,
7942 .put = alc_ch_mode_put,
7943 },
7944 { } /* end */
7945};
7946
7947static struct hda_verb alc883_init_verbs[] = {
7948 /* ADC1: mute amp left and right */
Kailang Yange2757d52008-08-26 13:17:46 +02007949 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007950 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
7951 /* ADC2: mute amp left and right */
7952 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7953 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
7954 /* Front mixer: unmute input/output amp left and right (volume = 0) */
7955 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7956 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7957 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7958 /* Rear mixer */
7959 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7960 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7961 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7962 /* CLFE mixer */
7963 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7964 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7965 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7966 /* Side mixer */
7967 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7968 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7969 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7970
Takashi Iwaicb53c622007-08-10 17:21:45 +02007971 /* mute analog input loopbacks */
7972 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7973 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7974 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7975 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7976 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007977
7978 /* Front Pin: output 0 (0x0c) */
7979 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7980 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7981 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
7982 /* Rear Pin: output 1 (0x0d) */
7983 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7984 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7985 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
7986 /* CLFE Pin: output 2 (0x0e) */
7987 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7988 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7989 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
7990 /* Side Pin: output 3 (0x0f) */
7991 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7992 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7993 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
7994 /* Mic (rear) pin: input vref at 80% */
7995 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7996 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7997 /* Front Mic pin: input vref at 80% */
7998 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7999 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8000 /* Line In pin: input */
8001 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8002 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8003 /* Line-2 In: Headphone output (output 0 - 0x0c) */
8004 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8005 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8006 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
8007 /* CD pin widget for input */
8008 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8009
8010 /* FIXME: use matrix-type input source selection */
8011 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
8012 /* Input mixer2 */
8013 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yange2757d52008-08-26 13:17:46 +02008014 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8015 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8016 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008017 /* Input mixer3 */
8018 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yange2757d52008-08-26 13:17:46 +02008019 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8020 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8021 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008022 { }
8023};
8024
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008025/* toggle speaker-output according to the hp-jack state */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008026static void alc883_mitac_init_hook(struct hda_codec *codec)
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008027{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008028 struct alc_spec *spec = codec->spec;
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008029
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008030 spec->autocfg.hp_pins[0] = 0x15;
8031 spec->autocfg.speaker_pins[0] = 0x14;
8032 spec->autocfg.speaker_pins[1] = 0x17;
8033 alc_automute_amp(codec);
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008034}
8035
8036/* auto-toggle front mic */
8037/*
8038static void alc883_mitac_mic_automute(struct hda_codec *codec)
8039{
8040 unsigned int present;
8041 unsigned char bits;
8042
8043 present = snd_hda_codec_read(codec, 0x18, 0,
8044 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
8045 bits = present ? HDA_AMP_MUTE : 0;
8046 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
8047}
8048*/
8049
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008050static struct hda_verb alc883_mitac_verbs[] = {
8051 /* HP */
8052 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8053 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8054 /* Subwoofer */
8055 {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
8056 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8057
8058 /* enable unsolicited event */
8059 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8060 /* {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, */
8061
8062 { } /* end */
8063};
8064
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008065static struct hda_verb alc883_clevo_m720_verbs[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01008066 /* HP */
8067 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8068 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8069 /* Int speaker */
8070 {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
8071 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8072
8073 /* enable unsolicited event */
8074 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008075 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Jiang zhe368c7a92008-03-04 11:20:33 +01008076
8077 { } /* end */
8078};
8079
Jiang zhefb97dc62008-03-06 11:07:11 +01008080static struct hda_verb alc883_2ch_fujitsu_pi2515_verbs[] = {
8081 /* HP */
8082 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8083 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8084 /* Subwoofer */
8085 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
8086 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8087
8088 /* enable unsolicited event */
8089 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8090
8091 { } /* end */
8092};
8093
Kailang Yangccc656c2006-10-17 12:32:26 +02008094static struct hda_verb alc883_tagra_verbs[] = {
8095 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8096 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8097
8098 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8099 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02008100
Kailang Yangccc656c2006-10-17 12:32:26 +02008101 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
8102 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
8103 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8104
8105 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008106 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
8107 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
8108 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
Kailang Yangccc656c2006-10-17 12:32:26 +02008109
8110 { } /* end */
8111};
8112
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008113static struct hda_verb alc883_lenovo_101e_verbs[] = {
8114 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8115 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT|AC_USRSP_EN},
8116 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT|AC_USRSP_EN},
8117 { } /* end */
8118};
8119
Kailang Yang272a5272007-05-14 11:00:38 +02008120static struct hda_verb alc883_lenovo_nb0763_verbs[] = {
8121 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8122 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8123 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8124 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8125 { } /* end */
8126};
8127
8128static struct hda_verb alc888_lenovo_ms7195_verbs[] = {
8129 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8130 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8131 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8132 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT | AC_USRSP_EN},
8133 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8134 { } /* end */
8135};
8136
Kailang Yang189609a2007-08-20 11:31:23 +02008137static struct hda_verb alc883_haier_w66_verbs[] = {
8138 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8139 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8140
8141 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8142
8143 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
8144 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8145 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8146 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8147 { } /* end */
8148};
8149
Kailang Yange2757d52008-08-26 13:17:46 +02008150static struct hda_verb alc888_lenovo_sky_verbs[] = {
8151 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8152 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8153 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8154 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8155 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8156 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8157 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
8158 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8159 { } /* end */
8160};
8161
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03008162static struct hda_verb alc888_6st_dell_verbs[] = {
8163 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8164 { }
8165};
8166
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008167static void alc888_3st_hp_init_hook(struct hda_codec *codec)
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03008168{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008169 struct alc_spec *spec = codec->spec;
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03008170
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008171 spec->autocfg.hp_pins[0] = 0x1b;
8172 spec->autocfg.speaker_pins[0] = 0x14;
8173 spec->autocfg.speaker_pins[1] = 0x16;
8174 spec->autocfg.speaker_pins[2] = 0x18;
8175 alc_automute_amp(codec);
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03008176}
8177
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008178static struct hda_verb alc888_3st_hp_verbs[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008179 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */
Herton Ronaldo Krzesinskif32a19e2008-03-18 09:27:08 +01008180 {0x16, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Rear : output 1 (0x0d) */
8181 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* CLFE : output 2 (0x0e) */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008182 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03008183 { } /* end */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008184};
8185
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03008186/*
8187 * 2ch mode
8188 */
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008189static struct hda_verb alc888_3st_hp_2ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008190 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
8191 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
8192 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
8193 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03008194 { } /* end */
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008195};
8196
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03008197/*
8198 * 4ch mode
8199 */
8200static struct hda_verb alc888_3st_hp_4ch_init[] = {
8201 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
8202 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
8203 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8204 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
8205 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 },
8206 { } /* end */
8207};
8208
8209/*
8210 * 6ch mode
8211 */
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008212static struct hda_verb alc888_3st_hp_6ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008213 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8214 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03008215 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008216 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8217 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03008218 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 },
8219 { } /* end */
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008220};
8221
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03008222static struct hda_channel_mode alc888_3st_hp_modes[3] = {
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008223 { 2, alc888_3st_hp_2ch_init },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03008224 { 4, alc888_3st_hp_4ch_init },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008225 { 6, alc888_3st_hp_6ch_init },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008226};
8227
Kailang Yang272a5272007-05-14 11:00:38 +02008228/* toggle front-jack and RCA according to the hp-jack state */
8229static void alc888_lenovo_ms7195_front_automute(struct hda_codec *codec)
8230{
8231 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02008232
Kailang Yang272a5272007-05-14 11:00:38 +02008233 present = snd_hda_codec_read(codec, 0x1b, 0,
8234 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02008235 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8236 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
8237 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8238 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02008239}
8240
8241/* toggle RCA according to the front-jack state */
8242static void alc888_lenovo_ms7195_rca_automute(struct hda_codec *codec)
8243{
8244 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02008245
Kailang Yang272a5272007-05-14 11:00:38 +02008246 present = snd_hda_codec_read(codec, 0x14, 0,
8247 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02008248 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8249 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02008250}
Takashi Iwai47fd8302007-08-10 17:11:07 +02008251
Kailang Yang272a5272007-05-14 11:00:38 +02008252static void alc883_lenovo_ms7195_unsol_event(struct hda_codec *codec,
8253 unsigned int res)
8254{
8255 if ((res >> 26) == ALC880_HP_EVENT)
8256 alc888_lenovo_ms7195_front_automute(codec);
8257 if ((res >> 26) == ALC880_FRONT_EVENT)
8258 alc888_lenovo_ms7195_rca_automute(codec);
8259}
8260
8261static struct hda_verb alc883_medion_md2_verbs[] = {
8262 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8263 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8264
8265 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8266
8267 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8268 { } /* end */
8269};
8270
8271/* toggle speaker-output according to the hp-jack state */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008272static void alc883_medion_md2_init_hook(struct hda_codec *codec)
Kailang Yang272a5272007-05-14 11:00:38 +02008273{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008274 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02008275
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008276 spec->autocfg.hp_pins[0] = 0x14;
8277 spec->autocfg.speaker_pins[0] = 0x15;
8278 alc_automute_amp(codec);
Kailang Yang272a5272007-05-14 11:00:38 +02008279}
8280
Kailang Yangccc656c2006-10-17 12:32:26 +02008281/* toggle speaker-output according to the hp-jack state */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008282#define alc883_tagra_init_hook alc882_targa_init_hook
8283#define alc883_tagra_unsol_event alc882_targa_unsol_event
Jiang zhe368c7a92008-03-04 11:20:33 +01008284
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008285static void alc883_clevo_m720_mic_automute(struct hda_codec *codec)
8286{
8287 unsigned int present;
8288
8289 present = snd_hda_codec_read(codec, 0x18, 0,
8290 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
8291 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
8292 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
8293}
8294
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008295static void alc883_clevo_m720_init_hook(struct hda_codec *codec)
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008296{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008297 struct alc_spec *spec = codec->spec;
8298
8299 spec->autocfg.hp_pins[0] = 0x15;
8300 spec->autocfg.speaker_pins[0] = 0x14;
8301 alc_automute_amp(codec);
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008302 alc883_clevo_m720_mic_automute(codec);
8303}
8304
8305static void alc883_clevo_m720_unsol_event(struct hda_codec *codec,
Jiang zhe368c7a92008-03-04 11:20:33 +01008306 unsigned int res)
8307{
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008308 switch (res >> 26) {
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008309 case ALC880_MIC_EVENT:
8310 alc883_clevo_m720_mic_automute(codec);
8311 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008312 default:
8313 alc_automute_amp_unsol_event(codec, res);
8314 break;
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008315 }
Jiang zhe368c7a92008-03-04 11:20:33 +01008316}
8317
Jiang zhefb97dc62008-03-06 11:07:11 +01008318/* toggle speaker-output according to the hp-jack state */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008319static void alc883_2ch_fujitsu_pi2515_init_hook(struct hda_codec *codec)
Jiang zhefb97dc62008-03-06 11:07:11 +01008320{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008321 struct alc_spec *spec = codec->spec;
Jiang zhefb97dc62008-03-06 11:07:11 +01008322
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008323 spec->autocfg.hp_pins[0] = 0x14;
8324 spec->autocfg.speaker_pins[0] = 0x15;
8325 alc_automute_amp(codec);
Jiang zhefb97dc62008-03-06 11:07:11 +01008326}
8327
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008328static void alc883_haier_w66_init_hook(struct hda_codec *codec)
Jiang zhefb97dc62008-03-06 11:07:11 +01008329{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008330 struct alc_spec *spec = codec->spec;
Jiang zhefb97dc62008-03-06 11:07:11 +01008331
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008332 spec->autocfg.hp_pins[0] = 0x1b;
8333 spec->autocfg.speaker_pins[0] = 0x14;
8334 alc_automute_amp(codec);
Kailang Yang189609a2007-08-20 11:31:23 +02008335}
8336
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008337static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
8338{
8339 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008340 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008341
8342 present = snd_hda_codec_read(codec, 0x14, 0,
8343 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02008344 bits = present ? HDA_AMP_MUTE : 0;
8345 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8346 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008347}
8348
8349static void alc883_lenovo_101e_all_automute(struct hda_codec *codec)
8350{
8351 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008352 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008353
8354 present = snd_hda_codec_read(codec, 0x1b, 0,
8355 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02008356 bits = present ? HDA_AMP_MUTE : 0;
8357 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8358 HDA_AMP_MUTE, bits);
8359 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8360 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008361}
8362
8363static void alc883_lenovo_101e_unsol_event(struct hda_codec *codec,
8364 unsigned int res)
8365{
8366 if ((res >> 26) == ALC880_HP_EVENT)
8367 alc883_lenovo_101e_all_automute(codec);
8368 if ((res >> 26) == ALC880_FRONT_EVENT)
8369 alc883_lenovo_101e_ispeaker_automute(codec);
8370}
8371
Takashi Iwai676a9b52007-08-16 15:23:35 +02008372/* toggle speaker-output according to the hp-jack state */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008373static void alc883_acer_aspire_init_hook(struct hda_codec *codec)
Takashi Iwai676a9b52007-08-16 15:23:35 +02008374{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008375 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02008376
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008377 spec->autocfg.hp_pins[0] = 0x14;
8378 spec->autocfg.speaker_pins[0] = 0x15;
8379 spec->autocfg.speaker_pins[1] = 0x16;
8380 alc_automute_amp(codec);
Takashi Iwai676a9b52007-08-16 15:23:35 +02008381}
8382
Kailang Yangd1a991a2007-08-15 16:21:59 +02008383static struct hda_verb alc883_acer_eapd_verbs[] = {
8384 /* HP Pin: output 0 (0x0c) */
8385 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8386 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8387 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8388 /* Front Pin: output 0 (0x0c) */
Takashi Iwai676a9b52007-08-16 15:23:35 +02008389 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8390 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangd1a991a2007-08-15 16:21:59 +02008391 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangd1a991a2007-08-15 16:21:59 +02008392 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
8393 /* eanable EAPD on medion laptop */
8394 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
8395 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
Takashi Iwai676a9b52007-08-16 15:23:35 +02008396 /* enable unsolicited event */
8397 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yangd1a991a2007-08-15 16:21:59 +02008398 { }
8399};
8400
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008401static void alc888_6st_dell_init_hook(struct hda_codec *codec)
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008402{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008403 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02008404
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008405 spec->autocfg.hp_pins[0] = 0x1b;
8406 spec->autocfg.speaker_pins[0] = 0x14;
8407 spec->autocfg.speaker_pins[1] = 0x15;
8408 spec->autocfg.speaker_pins[2] = 0x16;
8409 spec->autocfg.speaker_pins[3] = 0x17;
8410 alc_automute_amp(codec);
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008411}
8412
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008413static void alc888_lenovo_sky_init_hook(struct hda_codec *codec)
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008414{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008415 struct alc_spec *spec = codec->spec;
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008416
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] = 0x15;
8420 spec->autocfg.speaker_pins[2] = 0x16;
8421 spec->autocfg.speaker_pins[3] = 0x17;
8422 spec->autocfg.speaker_pins[4] = 0x1a;
8423 alc_automute_amp(codec);
Kailang Yange2757d52008-08-26 13:17:46 +02008424}
8425
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008426/*
8427 * generic initialization of ADC, input mixers and output mixers
8428 */
8429static struct hda_verb alc883_auto_init_verbs[] = {
8430 /*
8431 * Unmute ADC0-2 and set the default input to mic-in
8432 */
8433 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8434 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8435 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8436 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8437
Takashi Iwaicb53c622007-08-10 17:21:45 +02008438 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008439 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008440 * Note: PASD motherboards uses the Line In 2 as the input for
8441 * front panel mic (mic 2)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008442 */
8443 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02008444 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8445 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8446 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8447 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8448 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008449
8450 /*
8451 * Set up output mixers (0x0c - 0x0f)
8452 */
8453 /* set vol=0 to output mixers */
8454 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8455 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8456 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8457 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8458 /* set up input amps for analog loopback */
8459 /* Amp Indices: DAC = 0, mixer = 1 */
8460 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8461 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8462 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8463 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8464 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8465 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8466 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8467 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8468 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8469 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8470
8471 /* FIXME: use matrix-type input source selection */
8472 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
8473 /* Input mixer1 */
8474 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8475 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8476 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008477 /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, */
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008478 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
8479 /* Input mixer2 */
8480 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8481 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8482 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008483 /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, */
Andy Shevchenkoe3cde642007-12-03 16:50:58 +01008484 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008485
8486 { }
8487};
8488
Kailang Yange2757d52008-08-26 13:17:46 +02008489static struct hda_verb alc888_asus_m90v_verbs[] = {
8490 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8491 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8492 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8493 /* enable unsolicited event */
8494 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8495 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
8496 { } /* end */
8497};
8498
8499static void alc883_nb_mic_automute(struct hda_codec *codec)
8500{
8501 unsigned int present;
8502
8503 present = snd_hda_codec_read(codec, 0x18, 0,
8504 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
8505 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
8506 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
8507 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
8508 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
8509}
8510
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008511static void alc883_M90V_init_hook(struct hda_codec *codec)
Kailang Yange2757d52008-08-26 13:17:46 +02008512{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008513 struct alc_spec *spec = codec->spec;
Kailang Yange2757d52008-08-26 13:17:46 +02008514
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008515 spec->autocfg.hp_pins[0] = 0x1b;
8516 spec->autocfg.speaker_pins[0] = 0x14;
8517 spec->autocfg.speaker_pins[1] = 0x15;
8518 spec->autocfg.speaker_pins[2] = 0x16;
8519 alc_automute_pin(codec);
Kailang Yange2757d52008-08-26 13:17:46 +02008520}
8521
8522static void alc883_mode2_unsol_event(struct hda_codec *codec,
8523 unsigned int res)
8524{
8525 switch (res >> 26) {
Kailang Yange2757d52008-08-26 13:17:46 +02008526 case ALC880_MIC_EVENT:
8527 alc883_nb_mic_automute(codec);
8528 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008529 default:
8530 alc_sku_unsol_event(codec, res);
8531 break;
Kailang Yange2757d52008-08-26 13:17:46 +02008532 }
8533}
8534
8535static void alc883_mode2_inithook(struct hda_codec *codec)
8536{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008537 alc883_M90V_init_hook(codec);
Kailang Yange2757d52008-08-26 13:17:46 +02008538 alc883_nb_mic_automute(codec);
8539}
8540
8541static struct hda_verb alc888_asus_eee1601_verbs[] = {
8542 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8543 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8544 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8545 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8546 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8547 {0x20, AC_VERB_SET_COEF_INDEX, 0x0b},
8548 {0x20, AC_VERB_SET_PROC_COEF, 0x0838},
8549 /* enable unsolicited event */
8550 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8551 { } /* end */
8552};
8553
Kailang Yange2757d52008-08-26 13:17:46 +02008554static void alc883_eee1601_inithook(struct hda_codec *codec)
8555{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008556 struct alc_spec *spec = codec->spec;
8557
8558 spec->autocfg.hp_pins[0] = 0x14;
8559 spec->autocfg.speaker_pins[0] = 0x1b;
8560 alc_automute_pin(codec);
Kailang Yange2757d52008-08-26 13:17:46 +02008561}
8562
Takashi Iwaicb53c622007-08-10 17:21:45 +02008563#ifdef CONFIG_SND_HDA_POWER_SAVE
8564#define alc883_loopbacks alc880_loopbacks
8565#endif
8566
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008567/* pcm configuration: identiacal with ALC880 */
8568#define alc883_pcm_analog_playback alc880_pcm_analog_playback
8569#define alc883_pcm_analog_capture alc880_pcm_analog_capture
Takashi Iwai63300792008-01-24 15:31:36 +01008570#define alc883_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008571#define alc883_pcm_digital_playback alc880_pcm_digital_playback
8572#define alc883_pcm_digital_capture alc880_pcm_digital_capture
8573
8574/*
8575 * configuration and preset
8576 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008577static const char *alc883_models[ALC883_MODEL_LAST] = {
8578 [ALC883_3ST_2ch_DIG] = "3stack-dig",
8579 [ALC883_3ST_6ch_DIG] = "3stack-6ch-dig",
8580 [ALC883_3ST_6ch] = "3stack-6ch",
8581 [ALC883_6ST_DIG] = "6stack-dig",
8582 [ALC883_TARGA_DIG] = "targa-dig",
8583 [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008584 [ALC883_ACER] = "acer",
Tobin Davis2880a862007-08-07 11:50:26 +02008585 [ALC883_ACER_ASPIRE] = "acer-aspire",
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08008586 [ALC888_ACER_ASPIRE_4930G] = "acer-aspire-4930g",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008587 [ALC883_MEDION] = "medion",
Kailang Yang272a5272007-05-14 11:00:38 +02008588 [ALC883_MEDION_MD2] = "medion-md2",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008589 [ALC883_LAPTOP_EAPD] = "laptop-eapd",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008590 [ALC883_LENOVO_101E_2ch] = "lenovo-101e",
Kailang Yang272a5272007-05-14 11:00:38 +02008591 [ALC883_LENOVO_NB0763] = "lenovo-nb0763",
8592 [ALC888_LENOVO_MS7195_DIG] = "lenovo-ms7195-dig",
Kailang Yange2757d52008-08-26 13:17:46 +02008593 [ALC888_LENOVO_SKY] = "lenovo-sky",
Kailang Yang189609a2007-08-20 11:31:23 +02008594 [ALC883_HAIER_W66] = "haier-w66",
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008595 [ALC888_3ST_HP] = "3stack-hp",
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008596 [ALC888_6ST_DELL] = "6stack-dell",
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008597 [ALC883_MITAC] = "mitac",
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008598 [ALC883_CLEVO_M720] = "clevo-m720",
Jiang zhefb97dc62008-03-06 11:07:11 +01008599 [ALC883_FUJITSU_PI2515] = "fujitsu-pi2515",
Vincent Petryef8ef5f2008-11-23 11:31:41 +08008600 [ALC888_FUJITSU_XA3530] = "fujitsu-xa3530",
Jiang zhe17bba1b2008-06-04 12:11:07 +02008601 [ALC883_3ST_6ch_INTEL] = "3stack-6ch-intel",
Wu Fengguang3ab90932008-11-17 09:51:09 +01008602 [ALC1200_ASUS_P5Q] = "asus-p5q",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008603 [ALC883_AUTO] = "auto",
8604};
8605
8606static struct snd_pci_quirk alc883_cfg_tbl[] = {
8607 SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC883_3ST_6ch_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008608 SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE),
Takashi Iwai69e50282008-11-03 10:07:43 +01008609 SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_ACER_ASPIRE),
Takashi Iwai9b6682f2009-03-23 22:50:52 +01008610 SND_PCI_QUIRK(0x1025, 0x010a, "Acer Ferrari 5000", ALC883_ACER_ASPIRE),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008611 SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE),
8612 SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE),
Jaroslav Kysela0b18cb12008-07-28 17:07:07 +02008613 SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_ACER_ASPIRE),
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08008614 SND_PCI_QUIRK(0x1025, 0x013e, "Acer Aspire 4930G",
8615 ALC888_ACER_ASPIRE_4930G),
Lukasz Wojnilowicza8e4f9d2009-01-08 12:00:49 +01008616 SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G",
8617 ALC888_ACER_ASPIRE_4930G),
Takashi Iwaib3bdb302009-02-18 13:16:26 +01008618 SND_PCI_QUIRK(0x1025, 0x0157, "Acer X3200", ALC883_AUTO),
Takashi Iwai94683502009-02-13 09:31:20 +01008619 SND_PCI_QUIRK(0x1025, 0x0158, "Acer AX1700-U3700A", ALC883_AUTO),
Lukasz Wojnilowicza8e4f9d2009-01-08 12:00:49 +01008620 SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G",
8621 ALC888_ACER_ASPIRE_4930G),
Juan Jesus Garcia de Soriacc374c42009-02-23 08:11:59 +01008622 SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G",
8623 ALC888_ACER_ASPIRE_4930G),
Takashi Iwaidea0a502009-02-09 17:14:52 +01008624 /* default Acer */
8625 SND_PCI_QUIRK_VENDOR(0x1025, "Acer laptop", ALC883_ACER),
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008626 SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL),
Tobin Davisfebe3372007-06-12 11:27:46 +02008627 SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008628 SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP),
8629 SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP),
Herton Ronaldo Krzesinski5d85f8d2008-03-20 12:13:46 +01008630 SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG),
Chris Bagwell06bf3e12009-01-01 10:32:08 +01008631 SND_PCI_QUIRK(0x103c, 0x2a66, "HP Acacia", ALC888_3ST_HP),
Herton Ronaldo Krzesinski7ec30f02009-03-04 14:22:52 -03008632 SND_PCI_QUIRK(0x103c, 0x2a72, "HP Educ.ar", ALC888_3ST_HP),
Kailang Yanga01c30c2008-10-15 11:14:58 +02008633 SND_PCI_QUIRK(0x1043, 0x1873, "Asus M90V", ALC888_ASUS_M90V),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008634 SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG),
Mackenzie Morgan44a678d2009-02-10 17:13:43 +01008635 SND_PCI_QUIRK(0x1043, 0x8284, "Asus Z37E", ALC883_6ST_DIG),
Wu Fengguang3ab90932008-11-17 09:51:09 +01008636 SND_PCI_QUIRK(0x1043, 0x82fe, "Asus P5Q-EM HDMI", ALC1200_ASUS_P5Q),
Kailang Yange2757d52008-08-26 13:17:46 +02008637 SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_ASUS_EEE1601),
Travis Place97ec7102008-05-23 18:31:46 +02008638 SND_PCI_QUIRK(0x105b, 0x0ce8, "Foxconn P35AX-S", ALC883_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008639 SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC883_6ST_DIG),
Luke Yelavich2de686d2009-01-16 15:08:02 +11008640 SND_PCI_QUIRK(0x1071, 0x8227, "Mitac 82801H", ALC883_MITAC),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008641 SND_PCI_QUIRK(0x1071, 0x8253, "Mitac 8252d", ALC883_MITAC),
8642 SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD),
Kailang Yange2757d52008-08-26 13:17:46 +02008643 SND_PCI_QUIRK(0x10f1, 0x2350, "TYAN-S2350", ALC888_6ST_DELL),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008644 SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch),
Tobin Davis57b14f22007-04-18 23:05:36 +02008645 SND_PCI_QUIRK(0x1458, 0xa002, "MSI", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008646 SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG),
8647 SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG),
8648 SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG),
Jiang zhe4383fae2008-04-14 12:58:57 +02008649 SND_PCI_QUIRK(0x1462, 0x2fb3, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008650 SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG),
Pascal Terjan82808232008-03-04 11:33:28 +01008651 SND_PCI_QUIRK(0x1462, 0x3783, "NEC S970", ALC883_TARGA_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008652 SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG),
8653 SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG),
8654 SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG),
8655 SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG),
8656 SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG),
8657 SND_PCI_QUIRK(0x1462, 0x3fdf, "MSI", ALC883_TARGA_DIG),
8658 SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG),
8659 SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG),
8660 SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008661 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG),
8662 SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG),
Tobin Davis799f88a2007-05-29 14:29:08 +02008663 SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG),
Takashi Iwaiee095432008-11-25 15:03:38 +01008664 SND_PCI_QUIRK(0x1462, 0x7260, "MSI 7260", ALC883_TARGA_DIG),
Herton Ronaldo Krzesinski86d34b72008-03-18 09:27:59 +01008665 SND_PCI_QUIRK(0x1462, 0x7267, "MSI", ALC883_3ST_6ch_DIG),
Leonard Norrgard2a296cb2007-01-08 11:28:22 +01008666 SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG),
Tobin Davis2dcd5222007-07-10 17:04:57 +02008667 SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008668 SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008669 SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG),
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008670 SND_PCI_QUIRK(0x1558, 0x0721, "Clevo laptop M720R", ALC883_CLEVO_M720),
8671 SND_PCI_QUIRK(0x1558, 0x0722, "Clevo laptop M720SR", ALC883_CLEVO_M720),
Takashi Iwaidea0a502009-02-09 17:14:52 +01008672 SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC883_LAPTOP_EAPD),
Daniel T Chene60623b2007-05-29 03:41:55 -04008673 SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008674 SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION),
Takashi Iwaibfb53032009-04-14 14:51:04 +02008675 SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1100, "FSC AMILO Xi/Pi25xx",
Takashi Iwaif67d8172009-02-04 23:30:19 +01008676 ALC883_FUJITSU_PI2515),
Takashi Iwaibfb53032009-04-14 14:51:04 +02008677 SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1130, "Fujitsu AMILO Xa35xx",
Vincent Petryef8ef5f2008-11-23 11:31:41 +08008678 ALC888_FUJITSU_XA3530),
Kailang Yang272a5272007-05-14 11:00:38 +02008679 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch),
Kailang Yang272a5272007-05-14 11:00:38 +02008680 SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008681 SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763),
8682 SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Kailang Yange2757d52008-08-26 13:17:46 +02008683 SND_PCI_QUIRK(0x17aa, 0x101d, "Lenovo Sky", ALC888_LENOVO_SKY),
Kailang Yang272a5272007-05-14 11:00:38 +02008684 SND_PCI_QUIRK(0x17c0, 0x4071, "MEDION MD2", ALC883_MEDION_MD2),
Takashi Iwai959973b2008-11-05 11:30:56 +01008685 SND_PCI_QUIRK(0x17c0, 0x4085, "MEDION MD96630", ALC888_LENOVO_MS7195_DIG),
Andrew Paprocki0b167bf2008-02-03 10:15:44 +01008686 SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG),
Kailang Yang189609a2007-08-20 11:31:23 +02008687 SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66),
Jiang zhe17bba1b2008-06-04 12:11:07 +02008688 SND_PCI_QUIRK(0x8086, 0x0001, "DG33BUC", ALC883_3ST_6ch_INTEL),
8689 SND_PCI_QUIRK(0x8086, 0x0002, "DG33FBC", ALC883_3ST_6ch_INTEL),
Luke Yelavich2de686d2009-01-16 15:08:02 +11008690 SND_PCI_QUIRK(0x8086, 0x2503, "82801H", ALC883_MITAC),
Wu Fengguang4b558992009-01-12 09:18:58 +08008691 SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC883_3ST_6ch_INTEL),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008692 SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008693 {}
8694};
8695
Wu Fengguangf3cd3f52009-04-02 19:44:18 +08008696static hda_nid_t alc883_slave_dig_outs[] = {
8697 ALC1200_DIGOUT_NID, 0,
8698};
8699
Wu Fengguangb25c9da2009-02-06 15:02:27 +08008700static hda_nid_t alc1200_slave_dig_outs[] = {
8701 ALC883_DIGOUT_NID, 0,
8702};
8703
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008704static struct alc_config_preset alc883_presets[] = {
8705 [ALC883_3ST_2ch_DIG] = {
8706 .mixers = { alc883_3ST_2ch_mixer },
8707 .init_verbs = { alc883_init_verbs },
8708 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8709 .dac_nids = alc883_dac_nids,
8710 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008711 .dig_in_nid = ALC883_DIGIN_NID,
8712 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8713 .channel_mode = alc883_3ST_2ch_modes,
8714 .input_mux = &alc883_capture_source,
8715 },
8716 [ALC883_3ST_6ch_DIG] = {
8717 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
8718 .init_verbs = { alc883_init_verbs },
8719 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8720 .dac_nids = alc883_dac_nids,
8721 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008722 .dig_in_nid = ALC883_DIGIN_NID,
8723 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
8724 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02008725 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008726 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008727 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008728 [ALC883_3ST_6ch] = {
8729 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
8730 .init_verbs = { alc883_init_verbs },
8731 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8732 .dac_nids = alc883_dac_nids,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008733 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
8734 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02008735 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008736 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008737 },
Jiang zhe17bba1b2008-06-04 12:11:07 +02008738 [ALC883_3ST_6ch_INTEL] = {
8739 .mixers = { alc883_3ST_6ch_intel_mixer, alc883_chmode_mixer },
8740 .init_verbs = { alc883_init_verbs },
8741 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8742 .dac_nids = alc883_dac_nids,
8743 .dig_out_nid = ALC883_DIGOUT_NID,
8744 .dig_in_nid = ALC883_DIGIN_NID,
Wu Fengguangf3cd3f52009-04-02 19:44:18 +08008745 .slave_dig_outs = alc883_slave_dig_outs,
Jiang zhe17bba1b2008-06-04 12:11:07 +02008746 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_intel_modes),
8747 .channel_mode = alc883_3ST_6ch_intel_modes,
8748 .need_dac_fix = 1,
8749 .input_mux = &alc883_3stack_6ch_intel,
8750 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008751 [ALC883_6ST_DIG] = {
8752 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
8753 .init_verbs = { alc883_init_verbs },
8754 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8755 .dac_nids = alc883_dac_nids,
8756 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008757 .dig_in_nid = ALC883_DIGIN_NID,
8758 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
8759 .channel_mode = alc883_sixstack_modes,
8760 .input_mux = &alc883_capture_source,
8761 },
Kailang Yangccc656c2006-10-17 12:32:26 +02008762 [ALC883_TARGA_DIG] = {
8763 .mixers = { alc883_tagra_mixer, alc883_chmode_mixer },
8764 .init_verbs = { alc883_init_verbs, alc883_tagra_verbs},
8765 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8766 .dac_nids = alc883_dac_nids,
8767 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +02008768 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
8769 .channel_mode = alc883_3ST_6ch_modes,
8770 .need_dac_fix = 1,
8771 .input_mux = &alc883_capture_source,
8772 .unsol_event = alc883_tagra_unsol_event,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008773 .init_hook = alc883_tagra_init_hook,
Kailang Yangccc656c2006-10-17 12:32:26 +02008774 },
8775 [ALC883_TARGA_2ch_DIG] = {
8776 .mixers = { alc883_tagra_2ch_mixer},
8777 .init_verbs = { alc883_init_verbs, alc883_tagra_verbs},
8778 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8779 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01008780 .adc_nids = alc883_adc_nids_alt,
8781 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Kailang Yangccc656c2006-10-17 12:32:26 +02008782 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +02008783 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8784 .channel_mode = alc883_3ST_2ch_modes,
8785 .input_mux = &alc883_capture_source,
8786 .unsol_event = alc883_tagra_unsol_event,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008787 .init_hook = alc883_tagra_init_hook,
Kailang Yangccc656c2006-10-17 12:32:26 +02008788 },
Vladimir Avdoninbab282b92006-08-22 13:31:58 +02008789 [ALC883_ACER] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02008790 .mixers = { alc883_base_mixer },
Vladimir Avdoninbab282b92006-08-22 13:31:58 +02008791 /* On TravelMate laptops, GPIO 0 enables the internal speaker
8792 * and the headphone jack. Turn this on and rely on the
8793 * standard mute methods whenever the user wants to turn
8794 * these outputs off.
8795 */
8796 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs },
8797 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8798 .dac_nids = alc883_dac_nids,
Vladimir Avdoninbab282b92006-08-22 13:31:58 +02008799 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8800 .channel_mode = alc883_3ST_2ch_modes,
8801 .input_mux = &alc883_capture_source,
8802 },
Tobin Davis2880a862007-08-07 11:50:26 +02008803 [ALC883_ACER_ASPIRE] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02008804 .mixers = { alc883_acer_aspire_mixer },
Kailang Yangd1a991a2007-08-15 16:21:59 +02008805 .init_verbs = { alc883_init_verbs, alc883_acer_eapd_verbs },
Tobin Davis2880a862007-08-07 11:50:26 +02008806 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8807 .dac_nids = alc883_dac_nids,
8808 .dig_out_nid = ALC883_DIGOUT_NID,
Tobin Davis2880a862007-08-07 11:50:26 +02008809 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8810 .channel_mode = alc883_3ST_2ch_modes,
8811 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008812 .unsol_event = alc_automute_amp_unsol_event,
8813 .init_hook = alc883_acer_aspire_init_hook,
Kailang Yangd1a991a2007-08-15 16:21:59 +02008814 },
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08008815 [ALC888_ACER_ASPIRE_4930G] = {
Vincent Petryef8ef5f2008-11-23 11:31:41 +08008816 .mixers = { alc888_base_mixer,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08008817 alc883_chmode_mixer },
8818 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
8819 alc888_acer_aspire_4930g_verbs },
8820 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8821 .dac_nids = alc883_dac_nids,
8822 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
8823 .adc_nids = alc883_adc_nids_rev,
8824 .capsrc_nids = alc883_capsrc_nids_rev,
8825 .dig_out_nid = ALC883_DIGOUT_NID,
8826 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
8827 .channel_mode = alc883_3ST_6ch_modes,
8828 .need_dac_fix = 1,
8829 .num_mux_defs =
Vincent Petryef8ef5f2008-11-23 11:31:41 +08008830 ARRAY_SIZE(alc888_2_capture_sources),
8831 .input_mux = alc888_2_capture_sources,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008832 .unsol_event = alc_automute_amp_unsol_event,
8833 .init_hook = alc888_acer_aspire_4930g_init_hook,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08008834 },
Tobin Davisc07584c2006-10-13 12:32:16 +02008835 [ALC883_MEDION] = {
8836 .mixers = { alc883_fivestack_mixer,
8837 alc883_chmode_mixer },
8838 .init_verbs = { alc883_init_verbs,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008839 alc883_medion_eapd_verbs },
Tobin Davisc07584c2006-10-13 12:32:16 +02008840 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8841 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01008842 .adc_nids = alc883_adc_nids_alt,
8843 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Tobin Davisc07584c2006-10-13 12:32:16 +02008844 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
8845 .channel_mode = alc883_sixstack_modes,
8846 .input_mux = &alc883_capture_source,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008847 },
Kailang Yang272a5272007-05-14 11:00:38 +02008848 [ALC883_MEDION_MD2] = {
8849 .mixers = { alc883_medion_md2_mixer},
8850 .init_verbs = { alc883_init_verbs, alc883_medion_md2_verbs},
8851 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8852 .dac_nids = alc883_dac_nids,
8853 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang272a5272007-05-14 11:00:38 +02008854 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8855 .channel_mode = alc883_3ST_2ch_modes,
8856 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008857 .unsol_event = alc_automute_amp_unsol_event,
8858 .init_hook = alc883_medion_md2_init_hook,
Kailang Yangea1fb292008-08-26 12:58:38 +02008859 },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008860 [ALC883_LAPTOP_EAPD] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02008861 .mixers = { alc883_base_mixer },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008862 .init_verbs = { alc883_init_verbs, alc882_eapd_verbs },
8863 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8864 .dac_nids = alc883_dac_nids,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008865 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8866 .channel_mode = alc883_3ST_2ch_modes,
8867 .input_mux = &alc883_capture_source,
8868 },
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008869 [ALC883_CLEVO_M720] = {
8870 .mixers = { alc883_clevo_m720_mixer },
8871 .init_verbs = { alc883_init_verbs, alc883_clevo_m720_verbs },
Jiang zhe368c7a92008-03-04 11:20:33 +01008872 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8873 .dac_nids = alc883_dac_nids,
8874 .dig_out_nid = ALC883_DIGOUT_NID,
8875 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8876 .channel_mode = alc883_3ST_2ch_modes,
8877 .input_mux = &alc883_capture_source,
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008878 .unsol_event = alc883_clevo_m720_unsol_event,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008879 .init_hook = alc883_clevo_m720_init_hook,
Jiang zhe368c7a92008-03-04 11:20:33 +01008880 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008881 [ALC883_LENOVO_101E_2ch] = {
8882 .mixers = { alc883_lenovo_101e_2ch_mixer},
8883 .init_verbs = { alc883_init_verbs, alc883_lenovo_101e_verbs},
8884 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8885 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01008886 .adc_nids = alc883_adc_nids_alt,
8887 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008888 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8889 .channel_mode = alc883_3ST_2ch_modes,
8890 .input_mux = &alc883_lenovo_101e_capture_source,
8891 .unsol_event = alc883_lenovo_101e_unsol_event,
8892 .init_hook = alc883_lenovo_101e_all_automute,
8893 },
Kailang Yang272a5272007-05-14 11:00:38 +02008894 [ALC883_LENOVO_NB0763] = {
8895 .mixers = { alc883_lenovo_nb0763_mixer },
8896 .init_verbs = { alc883_init_verbs, alc883_lenovo_nb0763_verbs},
8897 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8898 .dac_nids = alc883_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +02008899 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8900 .channel_mode = alc883_3ST_2ch_modes,
8901 .need_dac_fix = 1,
8902 .input_mux = &alc883_lenovo_nb0763_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008903 .unsol_event = alc_automute_amp_unsol_event,
8904 .init_hook = alc883_medion_md2_init_hook,
Kailang Yang272a5272007-05-14 11:00:38 +02008905 },
8906 [ALC888_LENOVO_MS7195_DIG] = {
8907 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
8908 .init_verbs = { alc883_init_verbs, alc888_lenovo_ms7195_verbs},
8909 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8910 .dac_nids = alc883_dac_nids,
8911 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang272a5272007-05-14 11:00:38 +02008912 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
8913 .channel_mode = alc883_3ST_6ch_modes,
8914 .need_dac_fix = 1,
8915 .input_mux = &alc883_capture_source,
8916 .unsol_event = alc883_lenovo_ms7195_unsol_event,
8917 .init_hook = alc888_lenovo_ms7195_front_automute,
Kailang Yang189609a2007-08-20 11:31:23 +02008918 },
8919 [ALC883_HAIER_W66] = {
8920 .mixers = { alc883_tagra_2ch_mixer},
8921 .init_verbs = { alc883_init_verbs, alc883_haier_w66_verbs},
8922 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8923 .dac_nids = alc883_dac_nids,
8924 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang189609a2007-08-20 11:31:23 +02008925 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8926 .channel_mode = alc883_3ST_2ch_modes,
8927 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008928 .unsol_event = alc_automute_amp_unsol_event,
8929 .init_hook = alc883_haier_w66_init_hook,
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +01008930 },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008931 [ALC888_3ST_HP] = {
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +01008932 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008933 .init_verbs = { alc883_init_verbs, alc888_3st_hp_verbs },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008934 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8935 .dac_nids = alc883_dac_nids,
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008936 .num_channel_mode = ARRAY_SIZE(alc888_3st_hp_modes),
8937 .channel_mode = alc888_3st_hp_modes,
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008938 .need_dac_fix = 1,
8939 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008940 .unsol_event = alc_automute_amp_unsol_event,
8941 .init_hook = alc888_3st_hp_init_hook,
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008942 },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008943 [ALC888_6ST_DELL] = {
Herton Ronaldo Krzesinskif24dbdc2008-03-20 12:14:28 +01008944 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008945 .init_verbs = { alc883_init_verbs, alc888_6st_dell_verbs },
8946 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8947 .dac_nids = alc883_dac_nids,
8948 .dig_out_nid = ALC883_DIGOUT_NID,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008949 .dig_in_nid = ALC883_DIGIN_NID,
8950 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
8951 .channel_mode = alc883_sixstack_modes,
8952 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008953 .unsol_event = alc_automute_amp_unsol_event,
8954 .init_hook = alc888_6st_dell_init_hook,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008955 },
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008956 [ALC883_MITAC] = {
8957 .mixers = { alc883_mitac_mixer },
8958 .init_verbs = { alc883_init_verbs, alc883_mitac_verbs },
8959 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8960 .dac_nids = alc883_dac_nids,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008961 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8962 .channel_mode = alc883_3ST_2ch_modes,
8963 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008964 .unsol_event = alc_automute_amp_unsol_event,
8965 .init_hook = alc883_mitac_init_hook,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008966 },
Jiang zhefb97dc62008-03-06 11:07:11 +01008967 [ALC883_FUJITSU_PI2515] = {
8968 .mixers = { alc883_2ch_fujitsu_pi2515_mixer },
8969 .init_verbs = { alc883_init_verbs,
8970 alc883_2ch_fujitsu_pi2515_verbs},
8971 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8972 .dac_nids = alc883_dac_nids,
8973 .dig_out_nid = ALC883_DIGOUT_NID,
8974 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8975 .channel_mode = alc883_3ST_2ch_modes,
8976 .input_mux = &alc883_fujitsu_pi2515_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008977 .unsol_event = alc_automute_amp_unsol_event,
8978 .init_hook = alc883_2ch_fujitsu_pi2515_init_hook,
Jiang zhefb97dc62008-03-06 11:07:11 +01008979 },
Vincent Petryef8ef5f2008-11-23 11:31:41 +08008980 [ALC888_FUJITSU_XA3530] = {
8981 .mixers = { alc888_base_mixer, alc883_chmode_mixer },
8982 .init_verbs = { alc883_init_verbs,
8983 alc888_fujitsu_xa3530_verbs },
8984 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8985 .dac_nids = alc883_dac_nids,
8986 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
8987 .adc_nids = alc883_adc_nids_rev,
8988 .capsrc_nids = alc883_capsrc_nids_rev,
8989 .dig_out_nid = ALC883_DIGOUT_NID,
8990 .num_channel_mode = ARRAY_SIZE(alc888_4ST_8ch_intel_modes),
8991 .channel_mode = alc888_4ST_8ch_intel_modes,
8992 .num_mux_defs =
8993 ARRAY_SIZE(alc888_2_capture_sources),
8994 .input_mux = alc888_2_capture_sources,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008995 .unsol_event = alc_automute_amp_unsol_event,
8996 .init_hook = alc888_fujitsu_xa3530_init_hook,
Vincent Petryef8ef5f2008-11-23 11:31:41 +08008997 },
Kailang Yange2757d52008-08-26 13:17:46 +02008998 [ALC888_LENOVO_SKY] = {
8999 .mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer },
9000 .init_verbs = { alc883_init_verbs, alc888_lenovo_sky_verbs},
9001 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9002 .dac_nids = alc883_dac_nids,
9003 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yange2757d52008-08-26 13:17:46 +02009004 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
9005 .channel_mode = alc883_sixstack_modes,
9006 .need_dac_fix = 1,
9007 .input_mux = &alc883_lenovo_sky_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009008 .unsol_event = alc_automute_amp_unsol_event,
9009 .init_hook = alc888_lenovo_sky_init_hook,
Kailang Yange2757d52008-08-26 13:17:46 +02009010 },
9011 [ALC888_ASUS_M90V] = {
9012 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
9013 .init_verbs = { alc883_init_verbs, alc888_asus_m90v_verbs },
9014 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9015 .dac_nids = alc883_dac_nids,
9016 .dig_out_nid = ALC883_DIGOUT_NID,
9017 .dig_in_nid = ALC883_DIGIN_NID,
9018 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
9019 .channel_mode = alc883_3ST_6ch_modes,
9020 .need_dac_fix = 1,
9021 .input_mux = &alc883_fujitsu_pi2515_capture_source,
9022 .unsol_event = alc883_mode2_unsol_event,
9023 .init_hook = alc883_mode2_inithook,
9024 },
9025 [ALC888_ASUS_EEE1601] = {
9026 .mixers = { alc883_asus_eee1601_mixer },
Takashi Iwaif9e336f2008-10-31 16:37:07 +01009027 .cap_mixer = alc883_asus_eee1601_cap_mixer,
Kailang Yange2757d52008-08-26 13:17:46 +02009028 .init_verbs = { alc883_init_verbs, alc888_asus_eee1601_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,
9033 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9034 .channel_mode = alc883_3ST_2ch_modes,
9035 .need_dac_fix = 1,
9036 .input_mux = &alc883_asus_eee1601_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009037 .unsol_event = alc_sku_unsol_event,
Kailang Yange2757d52008-08-26 13:17:46 +02009038 .init_hook = alc883_eee1601_inithook,
9039 },
Wu Fengguang3ab90932008-11-17 09:51:09 +01009040 [ALC1200_ASUS_P5Q] = {
9041 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
9042 .init_verbs = { alc883_init_verbs },
9043 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9044 .dac_nids = alc883_dac_nids,
9045 .dig_out_nid = ALC1200_DIGOUT_NID,
9046 .dig_in_nid = ALC883_DIGIN_NID,
Wu Fengguangb25c9da2009-02-06 15:02:27 +08009047 .slave_dig_outs = alc1200_slave_dig_outs,
Wu Fengguang3ab90932008-11-17 09:51:09 +01009048 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
9049 .channel_mode = alc883_sixstack_modes,
9050 .input_mux = &alc883_capture_source,
9051 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009052};
9053
9054
9055/*
9056 * BIOS auto configuration
9057 */
9058static void alc883_auto_set_output_and_unmute(struct hda_codec *codec,
9059 hda_nid_t nid, int pin_type,
9060 int dac_idx)
9061{
9062 /* set as output */
9063 struct alc_spec *spec = codec->spec;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009064 int idx;
9065
Takashi Iwaif6c7e542008-02-12 18:32:23 +01009066 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009067 if (spec->multiout.dac_nids[dac_idx] == 0x25)
9068 idx = 4;
9069 else
9070 idx = spec->multiout.dac_nids[dac_idx] - 2;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009071 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
9072
9073}
9074
9075static void alc883_auto_init_multi_out(struct hda_codec *codec)
9076{
9077 struct alc_spec *spec = codec->spec;
9078 int i;
9079
9080 for (i = 0; i <= HDA_SIDE; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009081 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02009082 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009083 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02009084 alc883_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009085 i);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009086 }
9087}
9088
9089static void alc883_auto_init_hp_out(struct hda_codec *codec)
9090{
9091 struct alc_spec *spec = codec->spec;
9092 hda_nid_t pin;
9093
Takashi Iwaieb06ed82006-09-20 17:10:27 +02009094 pin = spec->autocfg.hp_pins[0];
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009095 if (pin) /* connect to front */
9096 /* use dac 0 */
9097 alc883_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01009098 pin = spec->autocfg.speaker_pins[0];
9099 if (pin)
9100 alc883_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009101}
9102
9103#define alc883_is_input_pin(nid) alc880_is_input_pin(nid)
9104#define ALC883_PIN_CD_NID ALC880_PIN_CD_NID
9105
9106static void alc883_auto_init_analog_input(struct hda_codec *codec)
9107{
9108 struct alc_spec *spec = codec->spec;
9109 int i;
9110
9111 for (i = 0; i < AUTO_PIN_LAST; i++) {
9112 hda_nid_t nid = spec->autocfg.input_pins[i];
9113 if (alc883_is_input_pin(nid)) {
Takashi Iwai23f0c042009-02-26 13:03:58 +01009114 alc_set_input_pin(codec, nid, i);
Takashi Iwaie82c0252009-03-23 15:17:38 +01009115 if (nid != ALC883_PIN_CD_NID &&
9116 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009117 snd_hda_codec_write(codec, nid, 0,
9118 AC_VERB_SET_AMP_GAIN_MUTE,
9119 AMP_OUT_MUTE);
9120 }
9121 }
9122}
9123
Takashi Iwaif511b012008-08-15 16:46:42 +02009124#define alc883_auto_init_input_src alc882_auto_init_input_src
9125
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009126/* almost identical with ALC880 parser... */
9127static int alc883_parse_auto_config(struct hda_codec *codec)
9128{
9129 struct alc_spec *spec = codec->spec;
9130 int err = alc880_parse_auto_config(codec);
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02009131 struct auto_pin_cfg *cfg = &spec->autocfg;
9132 int i;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009133
9134 if (err < 0)
9135 return err;
Takashi Iwai776e1842007-08-29 15:07:11 +02009136 else if (!err)
9137 return 0; /* no config found */
9138
9139 err = alc_auto_add_mic_boost(codec);
9140 if (err < 0)
9141 return err;
9142
9143 /* hack - override the init verbs */
9144 spec->init_verbs[0] = alc883_auto_init_verbs;
Takashi Iwai776e1842007-08-29 15:07:11 +02009145
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02009146 /* setup input_mux for ALC889 */
9147 if (codec->vendor_id == 0x10ec0889) {
9148 /* digital-mic input pin is excluded in alc880_auto_create..()
9149 * because it's under 0x18
9150 */
9151 if (cfg->input_pins[AUTO_PIN_MIC] == 0x12 ||
9152 cfg->input_pins[AUTO_PIN_FRONT_MIC] == 0x12) {
9153 struct hda_input_mux *imux = &spec->private_imux[0];
9154 for (i = 1; i < 3; i++)
9155 memcpy(&spec->private_imux[i],
9156 &spec->private_imux[0],
9157 sizeof(spec->private_imux[0]));
9158 imux->items[imux->num_items].label = "Int DMic";
9159 imux->items[imux->num_items].index = 0x0b;
9160 imux->num_items++;
9161 spec->num_mux_defs = 3;
9162 spec->input_mux = spec->private_imux;
9163 }
9164 }
9165
Takashi Iwai776e1842007-08-29 15:07:11 +02009166 return 1; /* config found */
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009167}
9168
9169/* additional initialization for auto-configuration model */
9170static void alc883_auto_init(struct hda_codec *codec)
9171{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01009172 struct alc_spec *spec = codec->spec;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009173 alc883_auto_init_multi_out(codec);
9174 alc883_auto_init_hp_out(codec);
9175 alc883_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +02009176 alc883_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01009177 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02009178 alc_inithook(codec);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009179}
9180
9181static int patch_alc883(struct hda_codec *codec)
9182{
9183 struct alc_spec *spec;
9184 int err, board_config;
9185
9186 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
9187 if (spec == NULL)
9188 return -ENOMEM;
9189
9190 codec->spec = spec;
9191
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02009192 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
9193
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009194 board_config = snd_hda_check_board_config(codec, ALC883_MODEL_LAST,
9195 alc883_models,
9196 alc883_cfg_tbl);
9197 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009198 printk(KERN_INFO "hda_codec: Unknown model for ALC883, "
9199 "trying auto-probe from BIOS...\n");
9200 board_config = ALC883_AUTO;
9201 }
9202
9203 if (board_config == ALC883_AUTO) {
9204 /* automatic parse from the BIOS config */
9205 err = alc883_parse_auto_config(codec);
9206 if (err < 0) {
9207 alc_free(codec);
9208 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009209 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009210 printk(KERN_INFO
9211 "hda_codec: Cannot set up configuration "
9212 "from BIOS. Using base mode...\n");
9213 board_config = ALC883_3ST_2ch_DIG;
9214 }
9215 }
9216
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09009217 err = snd_hda_attach_beep_device(codec, 0x1);
9218 if (err < 0) {
9219 alc_free(codec);
9220 return err;
9221 }
9222
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009223 if (board_config != ALC883_AUTO)
9224 setup_preset(spec, &alc883_presets[board_config]);
9225
Kailang Yang2f893282008-05-27 12:14:47 +02009226 switch (codec->vendor_id) {
9227 case 0x10ec0888:
Kailang Yang44426082008-10-15 11:18:05 +02009228 if (codec->revision_id == 0x100101) {
9229 spec->stream_name_analog = "ALC1200 Analog";
9230 spec->stream_name_digital = "ALC1200 Digital";
9231 } else {
9232 spec->stream_name_analog = "ALC888 Analog";
9233 spec->stream_name_digital = "ALC888 Digital";
9234 }
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02009235 if (!spec->num_adc_nids) {
9236 spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids);
9237 spec->adc_nids = alc883_adc_nids;
9238 }
9239 if (!spec->capsrc_nids)
9240 spec->capsrc_nids = alc883_capsrc_nids;
9241 spec->capture_style = CAPT_MIX; /* matrix-style capture */
Takashi Iwai4a79ba32009-04-22 16:31:35 +02009242 spec->init_amp = ALC_INIT_DEFAULT; /* always initialize */
Kailang Yang2f893282008-05-27 12:14:47 +02009243 break;
9244 case 0x10ec0889:
9245 spec->stream_name_analog = "ALC889 Analog";
9246 spec->stream_name_digital = "ALC889 Digital";
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02009247 if (!spec->num_adc_nids) {
9248 spec->num_adc_nids = ARRAY_SIZE(alc889_adc_nids);
9249 spec->adc_nids = alc889_adc_nids;
9250 }
9251 if (!spec->capsrc_nids)
9252 spec->capsrc_nids = alc889_capsrc_nids;
9253 spec->capture_style = CAPT_1MUX_MIX; /* 1mux/Nmix-style
9254 capture */
Kailang Yang2f893282008-05-27 12:14:47 +02009255 break;
9256 default:
9257 spec->stream_name_analog = "ALC883 Analog";
9258 spec->stream_name_digital = "ALC883 Digital";
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02009259 if (!spec->num_adc_nids) {
9260 spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids);
9261 spec->adc_nids = alc883_adc_nids;
9262 }
9263 if (!spec->capsrc_nids)
9264 spec->capsrc_nids = alc883_capsrc_nids;
9265 spec->capture_style = CAPT_MIX; /* matrix-style capture */
Kailang Yang2f893282008-05-27 12:14:47 +02009266 break;
9267 }
9268
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009269 spec->stream_analog_playback = &alc883_pcm_analog_playback;
9270 spec->stream_analog_capture = &alc883_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01009271 spec->stream_analog_alt_capture = &alc883_pcm_analog_alt_capture;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009272
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009273 spec->stream_digital_playback = &alc883_pcm_digital_playback;
9274 spec->stream_digital_capture = &alc883_pcm_digital_capture;
9275
Takashi Iwaif9e336f2008-10-31 16:37:07 +01009276 if (!spec->cap_mixer)
9277 set_capture_mixer(spec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01009278 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009279
Takashi Iwai2134ea42008-01-10 16:53:55 +01009280 spec->vmaster_nid = 0x0c;
9281
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009282 codec->patch_ops = alc_patch_ops;
9283 if (board_config == ALC883_AUTO)
9284 spec->init_hook = alc883_auto_init;
Kailang Yangf9423e72008-05-27 12:32:25 +02009285
Takashi Iwaicb53c622007-08-10 17:21:45 +02009286#ifdef CONFIG_SND_HDA_POWER_SAVE
9287 if (!spec->loopback.amplist)
9288 spec->loopback.amplist = alc883_loopbacks;
9289#endif
Takashi Iwaidaead532008-11-28 12:55:36 +01009290 codec->proc_widget_hook = print_realtek_coef;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009291
9292 return 0;
9293}
9294
9295/*
Kailang Yangdf694da2005-12-05 19:42:22 +01009296 * ALC262 support
9297 */
9298
9299#define ALC262_DIGOUT_NID ALC880_DIGOUT_NID
9300#define ALC262_DIGIN_NID ALC880_DIGIN_NID
9301
9302#define alc262_dac_nids alc260_dac_nids
9303#define alc262_adc_nids alc882_adc_nids
9304#define alc262_adc_nids_alt alc882_adc_nids_alt
Takashi Iwai88c71a92008-02-14 17:27:17 +01009305#define alc262_capsrc_nids alc882_capsrc_nids
9306#define alc262_capsrc_nids_alt alc882_capsrc_nids_alt
Kailang Yangdf694da2005-12-05 19:42:22 +01009307
9308#define alc262_modes alc260_modes
Takashi Iwaic5f2ea02005-12-06 18:54:31 +01009309#define alc262_capture_source alc882_capture_source
Kailang Yangdf694da2005-12-05 19:42:22 +01009310
Kailang Yang4e555fe2008-08-26 13:05:55 +02009311static hda_nid_t alc262_dmic_adc_nids[1] = {
9312 /* ADC0 */
9313 0x09
9314};
9315
9316static hda_nid_t alc262_dmic_capsrc_nids[1] = { 0x22 };
9317
Kailang Yangdf694da2005-12-05 19:42:22 +01009318static struct snd_kcontrol_new alc262_base_mixer[] = {
9319 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9320 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9321 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9322 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9323 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9324 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9325 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9326 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01009327 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01009328 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
9329 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01009330 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01009331 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),
9332 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9333 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
9334 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01009335 { } /* end */
Takashi Iwai834be882006-03-01 14:16:17 +01009336};
9337
Takashi Iwaice875f02008-01-28 18:17:43 +01009338/* update HP, line and mono-out pins according to the master switch */
9339static void alc262_hp_master_update(struct hda_codec *codec)
9340{
9341 struct alc_spec *spec = codec->spec;
9342 int val = spec->master_sw;
9343
9344 /* HP & line-out */
9345 snd_hda_codec_write_cache(codec, 0x1b, 0,
9346 AC_VERB_SET_PIN_WIDGET_CONTROL,
9347 val ? PIN_HP : 0);
9348 snd_hda_codec_write_cache(codec, 0x15, 0,
9349 AC_VERB_SET_PIN_WIDGET_CONTROL,
9350 val ? PIN_HP : 0);
9351 /* mono (speaker) depending on the HP jack sense */
9352 val = val && !spec->jack_present;
9353 snd_hda_codec_write_cache(codec, 0x16, 0,
9354 AC_VERB_SET_PIN_WIDGET_CONTROL,
9355 val ? PIN_OUT : 0);
9356}
9357
9358static void alc262_hp_bpc_automute(struct hda_codec *codec)
9359{
9360 struct alc_spec *spec = codec->spec;
9361 unsigned int presence;
9362 presence = snd_hda_codec_read(codec, 0x1b, 0,
9363 AC_VERB_GET_PIN_SENSE, 0);
9364 spec->jack_present = !!(presence & AC_PINSENSE_PRESENCE);
9365 alc262_hp_master_update(codec);
9366}
9367
9368static void alc262_hp_bpc_unsol_event(struct hda_codec *codec, unsigned int res)
9369{
9370 if ((res >> 26) != ALC880_HP_EVENT)
9371 return;
9372 alc262_hp_bpc_automute(codec);
9373}
9374
9375static void alc262_hp_wildwest_automute(struct hda_codec *codec)
9376{
9377 struct alc_spec *spec = codec->spec;
9378 unsigned int presence;
9379 presence = snd_hda_codec_read(codec, 0x15, 0,
9380 AC_VERB_GET_PIN_SENSE, 0);
9381 spec->jack_present = !!(presence & AC_PINSENSE_PRESENCE);
9382 alc262_hp_master_update(codec);
9383}
9384
9385static void alc262_hp_wildwest_unsol_event(struct hda_codec *codec,
9386 unsigned int res)
9387{
9388 if ((res >> 26) != ALC880_HP_EVENT)
9389 return;
9390 alc262_hp_wildwest_automute(codec);
9391}
9392
Takashi Iwaib72519b2009-05-08 14:31:55 +02009393#define alc262_hp_master_sw_get alc260_hp_master_sw_get
Takashi Iwaice875f02008-01-28 18:17:43 +01009394
9395static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol,
9396 struct snd_ctl_elem_value *ucontrol)
9397{
9398 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
9399 struct alc_spec *spec = codec->spec;
9400 int val = !!*ucontrol->value.integer.value;
9401
9402 if (val == spec->master_sw)
9403 return 0;
9404 spec->master_sw = val;
9405 alc262_hp_master_update(codec);
9406 return 1;
9407}
9408
Takashi Iwaib72519b2009-05-08 14:31:55 +02009409#define ALC262_HP_MASTER_SWITCH \
9410 { \
9411 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
9412 .name = "Master Playback Switch", \
9413 .info = snd_ctl_boolean_mono_info, \
9414 .get = alc262_hp_master_sw_get, \
9415 .put = alc262_hp_master_sw_put, \
9416 }
9417
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009418static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
Takashi Iwaib72519b2009-05-08 14:31:55 +02009419 ALC262_HP_MASTER_SWITCH,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009420 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9421 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9422 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +01009423 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
9424 HDA_OUTPUT),
9425 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
9426 HDA_OUTPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009427 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9428 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01009429 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009430 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
9431 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01009432 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009433 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9434 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9435 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9436 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009437 HDA_CODEC_VOLUME("AUX IN Playback Volume", 0x0b, 0x06, HDA_INPUT),
9438 HDA_CODEC_MUTE("AUX IN Playback Switch", 0x0b, 0x06, HDA_INPUT),
9439 { } /* end */
9440};
9441
Kailang Yangcd7509a2007-01-26 18:33:17 +01009442static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = {
Takashi Iwaib72519b2009-05-08 14:31:55 +02009443 ALC262_HP_MASTER_SWITCH,
Kailang Yangcd7509a2007-01-26 18:33:17 +01009444 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9445 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
9446 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
9447 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +01009448 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
9449 HDA_OUTPUT),
9450 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
9451 HDA_OUTPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +01009452 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT),
9453 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01009454 HDA_CODEC_VOLUME("Front Mic Boost", 0x1a, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +01009455 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
9456 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
9457 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9458 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +01009459 { } /* end */
9460};
9461
9462static struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = {
9463 HDA_CODEC_VOLUME("Rear Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9464 HDA_CODEC_MUTE("Rear Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01009465 HDA_CODEC_VOLUME("Rear Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +01009466 { } /* end */
9467};
9468
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009469/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009470static void alc262_hp_t5735_init_hook(struct hda_codec *codec)
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009471{
9472 struct alc_spec *spec = codec->spec;
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009473
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009474 spec->autocfg.hp_pins[0] = 0x15;
9475 spec->autocfg.speaker_pins[0] = 0x0c; /* HACK: not actually a pin */
9476 alc_automute_amp(codec);
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009477}
9478
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009479static struct snd_kcontrol_new alc262_hp_t5735_mixer[] = {
Takashi Iwai86cd9292008-01-28 18:09:56 +01009480 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9481 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009482 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
9483 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9484 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9485 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9486 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9487 { } /* end */
9488};
9489
9490static struct hda_verb alc262_hp_t5735_verbs[] = {
9491 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9492 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9493
9494 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9495 { }
9496};
9497
Kailang Yang8c427222008-01-10 13:03:59 +01009498static struct snd_kcontrol_new alc262_hp_rp5700_mixer[] = {
Takashi Iwaif2f48e12008-01-28 18:14:43 +01009499 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9500 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01009501 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
9502 HDA_CODEC_MUTE("Speaker Playback Switch", 0x16, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +01009503 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
9504 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
9505 { } /* end */
9506};
9507
9508static struct hda_verb alc262_hp_rp5700_verbs[] = {
9509 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9510 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9511 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9512 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9513 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
9514 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
9515 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
9516 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
9517 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
9518 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
9519 {}
9520};
9521
9522static struct hda_input_mux alc262_hp_rp5700_capture_source = {
9523 .num_items = 1,
9524 .items = {
9525 { "Line", 0x1 },
9526 },
9527};
9528
Takashi Iwai42171c12009-05-08 14:11:43 +02009529/* bind hp and internal speaker mute (with plug check) as master switch */
9530static void alc262_hippo_master_update(struct hda_codec *codec)
9531{
9532 struct alc_spec *spec = codec->spec;
9533 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
9534 hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
9535 hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
9536 unsigned int mute;
9537
9538 /* HP */
9539 mute = spec->master_sw ? 0 : HDA_AMP_MUTE;
9540 snd_hda_codec_amp_stereo(codec, hp_nid, HDA_OUTPUT, 0,
9541 HDA_AMP_MUTE, mute);
9542 /* mute internal speaker per jack sense */
9543 if (spec->jack_present)
9544 mute = HDA_AMP_MUTE;
9545 if (line_nid)
9546 snd_hda_codec_amp_stereo(codec, line_nid, HDA_OUTPUT, 0,
9547 HDA_AMP_MUTE, mute);
9548 if (speaker_nid && speaker_nid != line_nid)
9549 snd_hda_codec_amp_stereo(codec, speaker_nid, HDA_OUTPUT, 0,
9550 HDA_AMP_MUTE, mute);
9551}
9552
9553#define alc262_hippo_master_sw_get alc262_hp_master_sw_get
9554
9555static int alc262_hippo_master_sw_put(struct snd_kcontrol *kcontrol,
9556 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai0724ea22007-08-23 00:31:43 +02009557{
9558 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
Takashi Iwai42171c12009-05-08 14:11:43 +02009559 struct alc_spec *spec = codec->spec;
9560 int val = !!*ucontrol->value.integer.value;
Takashi Iwai0724ea22007-08-23 00:31:43 +02009561
Takashi Iwai42171c12009-05-08 14:11:43 +02009562 if (val == spec->master_sw)
9563 return 0;
9564 spec->master_sw = val;
9565 alc262_hippo_master_update(codec);
9566 return 1;
Takashi Iwai0724ea22007-08-23 00:31:43 +02009567}
Takashi Iwai5b319542007-07-26 11:49:22 +02009568
Takashi Iwai42171c12009-05-08 14:11:43 +02009569#define ALC262_HIPPO_MASTER_SWITCH \
9570 { \
9571 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
9572 .name = "Master Playback Switch", \
9573 .info = snd_ctl_boolean_mono_info, \
9574 .get = alc262_hippo_master_sw_get, \
9575 .put = alc262_hippo_master_sw_put, \
9576 }
9577
9578static struct snd_kcontrol_new alc262_hippo_mixer[] = {
9579 ALC262_HIPPO_MASTER_SWITCH,
9580 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9581 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9582 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9583 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9584 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9585 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9586 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9587 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9588 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
9589 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
9590 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
9591 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
9592 { } /* end */
9593};
9594
9595static struct snd_kcontrol_new alc262_hippo1_mixer[] = {
9596 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9597 ALC262_HIPPO_MASTER_SWITCH,
9598 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9599 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9600 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9601 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9602 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9603 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9604 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9605 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
9606 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
9607 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
9608 { } /* end */
9609};
9610
9611/* mute/unmute internal speaker according to the hp jack and mute state */
9612static void alc262_hippo_automute(struct hda_codec *codec)
9613{
9614 struct alc_spec *spec = codec->spec;
9615 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
9616 unsigned int present;
9617
9618 /* need to execute and sync at first */
9619 snd_hda_codec_read(codec, hp_nid, 0, AC_VERB_SET_PIN_SENSE, 0);
9620 present = snd_hda_codec_read(codec, hp_nid, 0,
9621 AC_VERB_GET_PIN_SENSE, 0);
9622 spec->jack_present = (present & 0x80000000) != 0;
9623 alc262_hippo_master_update(codec);
9624}
9625
9626static void alc262_hippo_unsol_event(struct hda_codec *codec, unsigned int res)
9627{
9628 if ((res >> 26) != ALC880_HP_EVENT)
9629 return;
9630 alc262_hippo_automute(codec);
9631}
9632
9633static void alc262_hippo_init_hook(struct hda_codec *codec)
9634{
9635 struct alc_spec *spec = codec->spec;
9636
9637 spec->autocfg.hp_pins[0] = 0x15;
9638 spec->autocfg.speaker_pins[0] = 0x14;
9639 alc262_hippo_automute(codec);
9640}
9641
9642static void alc262_hippo1_init_hook(struct hda_codec *codec)
9643{
9644 struct alc_spec *spec = codec->spec;
9645
9646 spec->autocfg.hp_pins[0] = 0x1b;
9647 spec->autocfg.speaker_pins[0] = 0x14;
9648 alc262_hippo_automute(codec);
9649}
9650
9651
Kailang Yang272a5272007-05-14 11:00:38 +02009652static struct snd_kcontrol_new alc262_sony_mixer[] = {
Takashi Iwai0724ea22007-08-23 00:31:43 +02009653 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +02009654 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yang272a5272007-05-14 11:00:38 +02009655 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9656 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9657 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
9658 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
9659 { } /* end */
9660};
9661
Kailang Yang83c34212007-07-05 11:43:05 +02009662static struct snd_kcontrol_new alc262_benq_t31_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +02009663 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9664 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yang83c34212007-07-05 11:43:05 +02009665 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9666 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9667 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9668 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
9669 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
9670 { } /* end */
9671};
Kailang Yang272a5272007-05-14 11:00:38 +02009672
Tony Vroonba340e82009-02-02 19:01:30 +00009673static struct snd_kcontrol_new alc262_tyan_mixer[] = {
9674 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9675 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
9676 HDA_CODEC_VOLUME("Aux Playback Volume", 0x0b, 0x06, HDA_INPUT),
9677 HDA_CODEC_MUTE("Aux Playback Switch", 0x0b, 0x06, HDA_INPUT),
9678 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9679 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9680 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9681 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9682 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9683 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
9684 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
9685 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
9686 { } /* end */
9687};
9688
9689static struct hda_verb alc262_tyan_verbs[] = {
9690 /* Headphone automute */
9691 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
9692 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9693 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9694
9695 /* P11 AUX_IN, white 4-pin connector */
9696 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
9697 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_1, 0xe1},
9698 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_2, 0x93},
9699 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0x19},
9700
9701 {}
9702};
9703
9704/* unsolicited event for HP jack sensing */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009705static void alc262_tyan_init_hook(struct hda_codec *codec)
Tony Vroonba340e82009-02-02 19:01:30 +00009706{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009707 struct alc_spec *spec = codec->spec;
Tony Vroonba340e82009-02-02 19:01:30 +00009708
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009709 spec->autocfg.hp_pins[0] = 0x1b;
9710 spec->autocfg.speaker_pins[0] = 0x15;
9711 alc_automute_amp(codec);
Tony Vroonba340e82009-02-02 19:01:30 +00009712}
9713
Tony Vroonba340e82009-02-02 19:01:30 +00009714
Kailang Yangdf694da2005-12-05 19:42:22 +01009715#define alc262_capture_mixer alc882_capture_mixer
9716#define alc262_capture_alt_mixer alc882_capture_alt_mixer
9717
9718/*
9719 * generic initialization of ADC, input mixers and output mixers
9720 */
9721static struct hda_verb alc262_init_verbs[] = {
9722 /*
9723 * Unmute ADC0-2 and set the default input to mic-in
9724 */
9725 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
9726 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9727 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
9728 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9729 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
9730 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9731
Takashi Iwaicb53c622007-08-10 17:21:45 +02009732 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +01009733 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009734 * Note: PASD motherboards uses the Line In 2 as the input for
9735 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01009736 */
9737 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02009738 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9739 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
9740 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
9741 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
9742 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01009743
9744 /*
9745 * Set up output mixers (0x0c - 0x0e)
9746 */
9747 /* set vol=0 to output mixers */
9748 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9749 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9750 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9751 /* set up input amps for analog loopback */
9752 /* Amp Indices: DAC = 0, mixer = 1 */
9753 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9754 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9755 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9756 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9757 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9758 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9759
9760 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
9761 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
9762 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
9763 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9764 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9765 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9766
9767 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
9768 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
9769 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
9770 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
9771 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Kailang Yangea1fb292008-08-26 12:58:38 +02009772
Kailang Yangdf694da2005-12-05 19:42:22 +01009773 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
9774 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Kailang Yangea1fb292008-08-26 12:58:38 +02009775
Kailang Yangdf694da2005-12-05 19:42:22 +01009776 /* FIXME: use matrix-type input source selection */
9777 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
9778 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
9779 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9780 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
9781 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
9782 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
9783 /* Input mixer2 */
9784 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9785 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
9786 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
9787 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
9788 /* Input mixer3 */
9789 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9790 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
9791 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009792 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
Kailang Yangdf694da2005-12-05 19:42:22 +01009793
9794 { }
9795};
9796
Kailang Yang4e555fe2008-08-26 13:05:55 +02009797static struct hda_verb alc262_eapd_verbs[] = {
9798 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
9799 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
9800 { }
9801};
9802
Kailang Yangccc656c2006-10-17 12:32:26 +02009803static struct hda_verb alc262_hippo_unsol_verbs[] = {
9804 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
9805 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9806 {}
9807};
9808
9809static struct hda_verb alc262_hippo1_unsol_verbs[] = {
9810 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
9811 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
9812 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
9813
9814 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
9815 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9816 {}
9817};
9818
Kailang Yang272a5272007-05-14 11:00:38 +02009819static struct hda_verb alc262_sony_unsol_verbs[] = {
9820 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
9821 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9822 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, // Front Mic
9823
9824 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
9825 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Akio Idehara7b1e8792008-06-09 22:46:07 +09009826 {}
Kailang Yang272a5272007-05-14 11:00:38 +02009827};
9828
Kailang Yang4e555fe2008-08-26 13:05:55 +02009829static struct hda_input_mux alc262_dmic_capture_source = {
9830 .num_items = 2,
9831 .items = {
9832 { "Int DMic", 0x9 },
9833 { "Mic", 0x0 },
9834 },
9835};
9836
9837static struct snd_kcontrol_new alc262_toshiba_s06_mixer[] = {
9838 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9839 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9840 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9841 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9842 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang4e555fe2008-08-26 13:05:55 +02009843 { } /* end */
9844};
9845
9846static struct hda_verb alc262_toshiba_s06_verbs[] = {
9847 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
9848 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9849 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9850 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9851 {0x22, AC_VERB_SET_CONNECT_SEL, 0x09},
9852 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9853 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
9854 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
9855 {}
9856};
9857
9858static void alc262_dmic_automute(struct hda_codec *codec)
9859{
9860 unsigned int present;
9861
9862 present = snd_hda_codec_read(codec, 0x18, 0,
9863 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
9864 snd_hda_codec_write(codec, 0x22, 0,
9865 AC_VERB_SET_CONNECT_SEL, present ? 0x0 : 0x09);
9866}
9867
Kailang Yang4e555fe2008-08-26 13:05:55 +02009868
9869/* unsolicited event for HP jack sensing */
9870static void alc262_toshiba_s06_unsol_event(struct hda_codec *codec,
9871 unsigned int res)
9872{
Kailang Yang4e555fe2008-08-26 13:05:55 +02009873 if ((res >> 26) == ALC880_MIC_EVENT)
9874 alc262_dmic_automute(codec);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009875 else
9876 alc_sku_unsol_event(codec, res);
Kailang Yang4e555fe2008-08-26 13:05:55 +02009877}
9878
9879static void alc262_toshiba_s06_init_hook(struct hda_codec *codec)
9880{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009881 struct alc_spec *spec = codec->spec;
9882
9883 spec->autocfg.hp_pins[0] = 0x15;
9884 spec->autocfg.speaker_pins[0] = 0x14;
9885 alc_automute_pin(codec);
Kailang Yang4e555fe2008-08-26 13:05:55 +02009886 alc262_dmic_automute(codec);
9887}
9888
Takashi Iwai834be882006-03-01 14:16:17 +01009889/*
Pascal Terjane8f9ae22008-08-04 14:36:05 +02009890 * nec model
9891 * 0x15 = headphone
9892 * 0x16 = internal speaker
9893 * 0x18 = external mic
9894 */
9895
9896static struct snd_kcontrol_new alc262_nec_mixer[] = {
9897 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
9898 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 0, 0x0, HDA_OUTPUT),
9899
9900 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9901 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9902 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9903
9904 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
9905 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9906 { } /* end */
9907};
9908
9909static struct hda_verb alc262_nec_verbs[] = {
9910 /* Unmute Speaker */
9911 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9912
9913 /* Headphone */
9914 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
9915 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9916
9917 /* External mic to headphone */
9918 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9919 /* External mic to speaker */
9920 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9921 {}
9922};
9923
9924/*
Takashi Iwai834be882006-03-01 14:16:17 +01009925 * fujitsu model
Tony Vroon5d9fab22008-03-14 17:09:18 +01009926 * 0x14 = headphone/spdif-out, 0x15 = internal speaker,
9927 * 0x1b = port replicator headphone out
Takashi Iwai834be882006-03-01 14:16:17 +01009928 */
9929
9930#define ALC_HP_EVENT 0x37
9931
9932static struct hda_verb alc262_fujitsu_unsol_verbs[] = {
9933 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
9934 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Tony Vroon5d9fab22008-03-14 17:09:18 +01009935 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
9936 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai834be882006-03-01 14:16:17 +01009937 {}
9938};
9939
Jiang zhe0e31daf2008-03-20 12:12:39 +01009940static struct hda_verb alc262_lenovo_3000_unsol_verbs[] = {
9941 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
9942 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9943 {}
9944};
9945
Takashi Iwai834be882006-03-01 14:16:17 +01009946static struct hda_input_mux alc262_fujitsu_capture_source = {
Takashi Iwai39d3ed32007-10-12 15:03:48 +02009947 .num_items = 3,
Takashi Iwai834be882006-03-01 14:16:17 +01009948 .items = {
9949 { "Mic", 0x0 },
Takashi Iwai39d3ed32007-10-12 15:03:48 +02009950 { "Int Mic", 0x1 },
Takashi Iwai834be882006-03-01 14:16:17 +01009951 { "CD", 0x4 },
9952 },
9953};
9954
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009955static struct hda_input_mux alc262_HP_capture_source = {
9956 .num_items = 5,
9957 .items = {
9958 { "Mic", 0x0 },
zhejiangaccbe492007-08-31 12:36:05 +02009959 { "Front Mic", 0x1 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009960 { "Line", 0x2 },
9961 { "CD", 0x4 },
9962 { "AUX IN", 0x6 },
9963 },
9964};
9965
zhejiangaccbe492007-08-31 12:36:05 +02009966static struct hda_input_mux alc262_HP_D7000_capture_source = {
9967 .num_items = 4,
9968 .items = {
9969 { "Mic", 0x0 },
9970 { "Front Mic", 0x2 },
9971 { "Line", 0x1 },
9972 { "CD", 0x4 },
9973 },
9974};
9975
Takashi Iwaiebc7a402008-05-20 09:23:05 +02009976/* mute/unmute internal speaker according to the hp jacks and mute state */
Takashi Iwai834be882006-03-01 14:16:17 +01009977static void alc262_fujitsu_automute(struct hda_codec *codec, int force)
9978{
9979 struct alc_spec *spec = codec->spec;
9980 unsigned int mute;
9981
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009982 if (force || !spec->sense_updated) {
Takashi Iwaiebc7a402008-05-20 09:23:05 +02009983 unsigned int present;
Takashi Iwai834be882006-03-01 14:16:17 +01009984 /* need to execute and sync at first */
9985 snd_hda_codec_read(codec, 0x14, 0, AC_VERB_SET_PIN_SENSE, 0);
Takashi Iwaiebc7a402008-05-20 09:23:05 +02009986 /* check laptop HP jack */
9987 present = snd_hda_codec_read(codec, 0x14, 0,
9988 AC_VERB_GET_PIN_SENSE, 0);
9989 /* need to execute and sync at first */
9990 snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
9991 /* check docking HP jack */
9992 present |= snd_hda_codec_read(codec, 0x1b, 0,
9993 AC_VERB_GET_PIN_SENSE, 0);
9994 if (present & AC_PINSENSE_PRESENCE)
9995 spec->jack_present = 1;
9996 else
9997 spec->jack_present = 0;
Takashi Iwai834be882006-03-01 14:16:17 +01009998 spec->sense_updated = 1;
9999 }
Takashi Iwaiebc7a402008-05-20 09:23:05 +020010000 /* unmute internal speaker only if both HPs are unplugged and
10001 * master switch is on
10002 */
10003 if (spec->jack_present)
10004 mute = HDA_AMP_MUTE;
10005 else
Takashi Iwai834be882006-03-01 14:16:17 +010010006 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
Takashi Iwaiebc7a402008-05-20 09:23:05 +020010007 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
10008 HDA_AMP_MUTE, mute);
Takashi Iwai834be882006-03-01 14:16:17 +010010009}
10010
10011/* unsolicited event for HP jack sensing */
10012static void alc262_fujitsu_unsol_event(struct hda_codec *codec,
10013 unsigned int res)
10014{
10015 if ((res >> 26) != ALC_HP_EVENT)
10016 return;
10017 alc262_fujitsu_automute(codec, 1);
10018}
10019
Takashi Iwaiebc7a402008-05-20 09:23:05 +020010020static void alc262_fujitsu_init_hook(struct hda_codec *codec)
10021{
10022 alc262_fujitsu_automute(codec, 1);
10023}
10024
Takashi Iwai834be882006-03-01 14:16:17 +010010025/* bind volumes of both NID 0x0c and 0x0d */
Takashi Iwaicca3b372007-08-10 17:12:15 +020010026static struct hda_bind_ctls alc262_fujitsu_bind_master_vol = {
10027 .ops = &snd_hda_bind_vol,
10028 .values = {
10029 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT),
10030 HDA_COMPOSE_AMP_VAL(0x0d, 3, 0, HDA_OUTPUT),
10031 0
10032 },
10033};
Takashi Iwai834be882006-03-01 14:16:17 +010010034
Jiang zhe0e31daf2008-03-20 12:12:39 +010010035/* mute/unmute internal speaker according to the hp jack and mute state */
10036static void alc262_lenovo_3000_automute(struct hda_codec *codec, int force)
10037{
10038 struct alc_spec *spec = codec->spec;
10039 unsigned int mute;
10040
10041 if (force || !spec->sense_updated) {
10042 unsigned int present_int_hp;
10043 /* need to execute and sync at first */
10044 snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
10045 present_int_hp = snd_hda_codec_read(codec, 0x1b, 0,
10046 AC_VERB_GET_PIN_SENSE, 0);
10047 spec->jack_present = (present_int_hp & 0x80000000) != 0;
10048 spec->sense_updated = 1;
10049 }
10050 if (spec->jack_present) {
10051 /* mute internal speaker */
10052 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
10053 HDA_AMP_MUTE, HDA_AMP_MUTE);
10054 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
10055 HDA_AMP_MUTE, HDA_AMP_MUTE);
10056 } else {
10057 /* unmute internal speaker if necessary */
10058 mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
10059 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
10060 HDA_AMP_MUTE, mute);
10061 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
10062 HDA_AMP_MUTE, mute);
10063 }
10064}
10065
10066/* unsolicited event for HP jack sensing */
10067static void alc262_lenovo_3000_unsol_event(struct hda_codec *codec,
10068 unsigned int res)
10069{
10070 if ((res >> 26) != ALC_HP_EVENT)
10071 return;
10072 alc262_lenovo_3000_automute(codec, 1);
10073}
10074
Takashi Iwai834be882006-03-01 14:16:17 +010010075/* bind hp and internal speaker mute (with plug check) */
10076static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol,
10077 struct snd_ctl_elem_value *ucontrol)
10078{
10079 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
10080 long *valp = ucontrol->value.integer.value;
10081 int change;
10082
Tony Vroon5d9fab22008-03-14 17:09:18 +010010083 change = snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
10084 HDA_AMP_MUTE,
10085 valp ? 0 : HDA_AMP_MUTE);
10086 change |= snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
10087 HDA_AMP_MUTE,
10088 valp ? 0 : HDA_AMP_MUTE);
10089
Takashi Iwai82beb8f2007-08-10 17:09:26 +020010090 if (change)
10091 alc262_fujitsu_automute(codec, 0);
Takashi Iwai834be882006-03-01 14:16:17 +010010092 return change;
10093}
10094
10095static struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +020010096 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
Takashi Iwai834be882006-03-01 14:16:17 +010010097 {
10098 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10099 .name = "Master Playback Switch",
10100 .info = snd_hda_mixer_amp_switch_info,
10101 .get = snd_hda_mixer_amp_switch_get,
10102 .put = alc262_fujitsu_master_sw_put,
10103 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
10104 },
10105 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
10106 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
10107 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10108 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10109 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai39d3ed32007-10-12 15:03:48 +020010110 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
10111 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
10112 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai834be882006-03-01 14:16:17 +010010113 { } /* end */
10114};
10115
Jiang zhe0e31daf2008-03-20 12:12:39 +010010116/* bind hp and internal speaker mute (with plug check) */
10117static int alc262_lenovo_3000_master_sw_put(struct snd_kcontrol *kcontrol,
10118 struct snd_ctl_elem_value *ucontrol)
10119{
10120 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
10121 long *valp = ucontrol->value.integer.value;
10122 int change;
10123
10124 change = snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
10125 HDA_AMP_MUTE,
10126 valp ? 0 : HDA_AMP_MUTE);
10127
10128 if (change)
10129 alc262_lenovo_3000_automute(codec, 0);
10130 return change;
10131}
10132
10133static struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = {
10134 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
10135 {
10136 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10137 .name = "Master Playback Switch",
10138 .info = snd_hda_mixer_amp_switch_info,
10139 .get = snd_hda_mixer_amp_switch_get,
10140 .put = alc262_lenovo_3000_master_sw_put,
10141 .private_value = HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
10142 },
10143 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
10144 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
10145 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10146 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10147 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
10148 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
10149 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
10150 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
10151 { } /* end */
10152};
10153
Hiroshi Miura9f99a632008-08-28 16:09:06 +020010154static struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = {
10155 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
Takashi Iwai42171c12009-05-08 14:11:43 +020010156 ALC262_HIPPO_MASTER_SWITCH,
Hiroshi Miura9f99a632008-08-28 16:09:06 +020010157 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10158 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
10159 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10160 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
10161 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
10162 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
10163 { } /* end */
10164};
10165
Takashi Iwai304dcaa2006-07-25 14:51:16 +020010166/* additional init verbs for Benq laptops */
10167static struct hda_verb alc262_EAPD_verbs[] = {
10168 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
10169 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
10170 {}
10171};
10172
Kailang Yang83c34212007-07-05 11:43:05 +020010173static struct hda_verb alc262_benq_t31_EAPD_verbs[] = {
10174 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
10175 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
10176
10177 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
10178 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
10179 {}
10180};
10181
Tobin Davisf651b502007-10-26 12:40:47 +020010182/* Samsung Q1 Ultra Vista model setup */
10183static struct snd_kcontrol_new alc262_ultra_mixer[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010184 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
10185 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +020010186 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
10187 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
10188 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010189 HDA_CODEC_VOLUME("Headphone Mic Boost", 0x15, 0, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +020010190 { } /* end */
10191};
10192
10193static struct hda_verb alc262_ultra_verbs[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010194 /* output mixer */
10195 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
10196 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10197 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10198 /* speaker */
10199 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
10200 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10201 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10202 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
10203 /* HP */
Tobin Davisf651b502007-10-26 12:40:47 +020010204 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010205 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10206 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10207 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
10208 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
10209 /* internal mic */
10210 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
10211 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10212 /* ADC, choose mic */
10213 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
10214 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
10215 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10216 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
10217 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
10218 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
10219 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
10220 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
10221 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
10222 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(8)},
Tobin Davisf651b502007-10-26 12:40:47 +020010223 {}
10224};
10225
Tobin Davisf651b502007-10-26 12:40:47 +020010226/* mute/unmute internal speaker according to the hp jack and mute state */
10227static void alc262_ultra_automute(struct hda_codec *codec)
10228{
10229 struct alc_spec *spec = codec->spec;
10230 unsigned int mute;
Tobin Davisf651b502007-10-26 12:40:47 +020010231
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010232 mute = 0;
10233 /* auto-mute only when HP is used as HP */
10234 if (!spec->cur_mux[0]) {
10235 unsigned int present;
10236 /* need to execute and sync at first */
10237 snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0);
10238 present = snd_hda_codec_read(codec, 0x15, 0,
10239 AC_VERB_GET_PIN_SENSE, 0);
10240 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
10241 if (spec->jack_present)
10242 mute = HDA_AMP_MUTE;
Tobin Davisf651b502007-10-26 12:40:47 +020010243 }
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010244 /* mute/unmute internal speaker */
10245 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
10246 HDA_AMP_MUTE, mute);
10247 /* mute/unmute HP */
10248 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
10249 HDA_AMP_MUTE, mute ? 0 : HDA_AMP_MUTE);
Tobin Davisf651b502007-10-26 12:40:47 +020010250}
10251
10252/* unsolicited event for HP jack sensing */
10253static void alc262_ultra_unsol_event(struct hda_codec *codec,
10254 unsigned int res)
10255{
10256 if ((res >> 26) != ALC880_HP_EVENT)
10257 return;
10258 alc262_ultra_automute(codec);
10259}
10260
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010261static struct hda_input_mux alc262_ultra_capture_source = {
10262 .num_items = 2,
10263 .items = {
10264 { "Mic", 0x1 },
10265 { "Headphone", 0x7 },
10266 },
10267};
10268
10269static int alc262_ultra_mux_enum_put(struct snd_kcontrol *kcontrol,
10270 struct snd_ctl_elem_value *ucontrol)
10271{
10272 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
10273 struct alc_spec *spec = codec->spec;
10274 int ret;
10275
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010010276 ret = alc_mux_enum_put(kcontrol, ucontrol);
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010277 if (!ret)
10278 return 0;
10279 /* reprogram the HP pin as mic or HP according to the input source */
10280 snd_hda_codec_write_cache(codec, 0x15, 0,
10281 AC_VERB_SET_PIN_WIDGET_CONTROL,
10282 spec->cur_mux[0] ? PIN_VREF80 : PIN_HP);
10283 alc262_ultra_automute(codec); /* mute/unmute HP */
10284 return ret;
10285}
10286
10287static struct snd_kcontrol_new alc262_ultra_capture_mixer[] = {
10288 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
10289 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
10290 {
10291 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10292 .name = "Capture Source",
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010010293 .info = alc_mux_enum_info,
10294 .get = alc_mux_enum_get,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010295 .put = alc262_ultra_mux_enum_put,
10296 },
10297 { } /* end */
10298};
10299
Kailang Yangdf694da2005-12-05 19:42:22 +010010300/* add playback controls from the parsed DAC table */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010301static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
10302 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010010303{
10304 hda_nid_t nid;
10305 int err;
10306
10307 spec->multiout.num_dacs = 1; /* only use one dac */
10308 spec->multiout.dac_nids = spec->private_dac_nids;
10309 spec->multiout.dac_nids[0] = 2;
10310
10311 nid = cfg->line_out_pins[0];
10312 if (nid) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010313 err = add_control(spec, ALC_CTL_WIDGET_VOL,
10314 "Front Playback Volume",
10315 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT));
10316 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010317 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010318 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10319 "Front Playback Switch",
10320 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
10321 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010322 return err;
10323 }
10324
Takashi Iwai82bc9552006-03-21 11:24:42 +010010325 nid = cfg->speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010010326 if (nid) {
10327 if (nid == 0x16) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010328 err = add_control(spec, ALC_CTL_WIDGET_VOL,
10329 "Speaker Playback Volume",
10330 HDA_COMPOSE_AMP_VAL(0x0e, 2, 0,
10331 HDA_OUTPUT));
10332 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010333 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010334 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10335 "Speaker Playback Switch",
10336 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
10337 HDA_OUTPUT));
10338 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010339 return err;
10340 } else {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010341 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10342 "Speaker Playback Switch",
10343 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
10344 HDA_OUTPUT));
10345 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010346 return err;
10347 }
10348 }
Takashi Iwaieb06ed82006-09-20 17:10:27 +020010349 nid = cfg->hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010010350 if (nid) {
10351 /* spec->multiout.hp_nid = 2; */
10352 if (nid == 0x16) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010353 err = add_control(spec, ALC_CTL_WIDGET_VOL,
10354 "Headphone Playback Volume",
10355 HDA_COMPOSE_AMP_VAL(0x0e, 2, 0,
10356 HDA_OUTPUT));
10357 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010358 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010359 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10360 "Headphone Playback Switch",
10361 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
10362 HDA_OUTPUT));
10363 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010364 return err;
10365 } else {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010366 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10367 "Headphone Playback Switch",
10368 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
10369 HDA_OUTPUT));
10370 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010371 return err;
10372 }
10373 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010374 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +010010375}
10376
10377/* identical with ALC880 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010378#define alc262_auto_create_analog_input_ctls \
10379 alc880_auto_create_analog_input_ctls
Kailang Yangdf694da2005-12-05 19:42:22 +010010380
10381/*
10382 * generic initialization of ADC, input mixers and output mixers
10383 */
10384static struct hda_verb alc262_volume_init_verbs[] = {
10385 /*
10386 * Unmute ADC0-2 and set the default input to mic-in
10387 */
10388 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
10389 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10390 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
10391 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10392 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
10393 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10394
Takashi Iwaicb53c622007-08-10 17:21:45 +020010395 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +010010396 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010397 * Note: PASD motherboards uses the Line In 2 as the input for
10398 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +010010399 */
10400 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020010401 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
10402 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10403 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
10404 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
10405 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +010010406
10407 /*
10408 * Set up output mixers (0x0c - 0x0f)
10409 */
10410 /* set vol=0 to output mixers */
10411 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10412 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10413 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yangea1fb292008-08-26 12:58:38 +020010414
Kailang Yangdf694da2005-12-05 19:42:22 +010010415 /* set up input amps for analog loopback */
10416 /* Amp Indices: DAC = 0, mixer = 1 */
10417 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10418 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10419 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10420 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10421 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10422 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10423
10424 /* FIXME: use matrix-type input source selection */
10425 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
10426 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
10427 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10428 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
10429 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
10430 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
10431 /* Input mixer2 */
10432 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10433 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
10434 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
10435 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
10436 /* Input mixer3 */
10437 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10438 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
10439 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
10440 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
10441
10442 { }
10443};
10444
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010445static struct hda_verb alc262_HP_BPC_init_verbs[] = {
10446 /*
10447 * Unmute ADC0-2 and set the default input to mic-in
10448 */
10449 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
10450 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10451 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
10452 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10453 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
10454 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10455
Takashi Iwaicb53c622007-08-10 17:21:45 +020010456 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010457 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010458 * Note: PASD motherboards uses the Line In 2 as the input for
10459 * front panel mic (mic 2)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010460 */
10461 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020010462 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
10463 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10464 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
10465 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
10466 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
10467 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
10468 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
Kailang Yangea1fb292008-08-26 12:58:38 +020010469
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010470 /*
10471 * Set up output mixers (0x0c - 0x0e)
10472 */
10473 /* set vol=0 to output mixers */
10474 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10475 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10476 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10477
10478 /* set up input amps for analog loopback */
10479 /* Amp Indices: DAC = 0, mixer = 1 */
10480 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10481 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10482 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10483 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10484 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10485 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10486
Takashi Iwaice875f02008-01-28 18:17:43 +010010487 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010488 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
10489 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
10490
10491 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
10492 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
10493
10494 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
10495 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
10496
10497 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10498 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
10499 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
10500 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10501 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10502
10503 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
10504 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10505 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10506 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
10507 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10508 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10509
10510
10511 /* FIXME: use matrix-type input source selection */
10512 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
10513 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
10514 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10515 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
10516 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
10517 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
10518 /* Input mixer2 */
10519 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10520 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
10521 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
10522 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
10523 /* Input mixer3 */
10524 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10525 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
10526 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
10527 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
10528
Takashi Iwaice875f02008-01-28 18:17:43 +010010529 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
10530
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010531 { }
10532};
10533
Kailang Yangcd7509a2007-01-26 18:33:17 +010010534static struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = {
10535 /*
10536 * Unmute ADC0-2 and set the default input to mic-in
10537 */
10538 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
10539 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10540 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
10541 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10542 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
10543 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10544
Takashi Iwaicb53c622007-08-10 17:21:45 +020010545 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangcd7509a2007-01-26 18:33:17 +010010546 * mixer widget
10547 * Note: PASD motherboards uses the Line In 2 as the input for front
10548 * panel mic (mic 2)
10549 */
10550 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020010551 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
10552 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10553 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
10554 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
10555 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
10556 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
10557 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
10558 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Kailang Yangcd7509a2007-01-26 18:33:17 +010010559 /*
10560 * Set up output mixers (0x0c - 0x0e)
10561 */
10562 /* set vol=0 to output mixers */
10563 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10564 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10565 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10566
10567 /* set up input amps for analog loopback */
10568 /* Amp Indices: DAC = 0, mixer = 1 */
10569 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10570 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10571 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10572 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10573 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10574 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10575
10576
10577 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP */
10578 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Mono */
10579 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* rear MIC */
10580 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* Line in */
10581 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
10582 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Line out */
10583 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD in */
10584
10585 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
10586 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
10587
10588 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
10589 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
10590
10591 /* {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, */
10592 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10593 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10594 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
10595 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10596 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10597
10598 /* FIXME: use matrix-type input source selection */
10599 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
10600 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
10601 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, /*rear MIC*/
10602 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, /*Line in*/
10603 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, /*F MIC*/
10604 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, /*Front*/
10605 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, /*CD*/
10606 /* {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
10607 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, /*HP*/
10608 /* Input mixer2 */
10609 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10610 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
10611 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
10612 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
10613 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
10614 /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
10615 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
10616 /* Input mixer3 */
10617 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10618 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
10619 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
10620 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
10621 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
10622 /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
10623 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
10624
Takashi Iwaice875f02008-01-28 18:17:43 +010010625 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
10626
Kailang Yangcd7509a2007-01-26 18:33:17 +010010627 { }
10628};
10629
Hiroshi Miura9f99a632008-08-28 16:09:06 +020010630static struct hda_verb alc262_toshiba_rx1_unsol_verbs[] = {
10631
10632 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Front Speaker */
10633 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
10634 {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
10635
10636 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* MIC jack */
10637 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
10638 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
10639 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
10640
10641 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP jack */
10642 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
10643 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
10644 {}
10645};
10646
10647
Takashi Iwaicb53c622007-08-10 17:21:45 +020010648#ifdef CONFIG_SND_HDA_POWER_SAVE
10649#define alc262_loopbacks alc880_loopbacks
10650#endif
10651
Kailang Yangdf694da2005-12-05 19:42:22 +010010652/* pcm configuration: identiacal with ALC880 */
10653#define alc262_pcm_analog_playback alc880_pcm_analog_playback
10654#define alc262_pcm_analog_capture alc880_pcm_analog_capture
10655#define alc262_pcm_digital_playback alc880_pcm_digital_playback
10656#define alc262_pcm_digital_capture alc880_pcm_digital_capture
10657
10658/*
10659 * BIOS auto configuration
10660 */
10661static int alc262_parse_auto_config(struct hda_codec *codec)
10662{
10663 struct alc_spec *spec = codec->spec;
10664 int err;
10665 static hda_nid_t alc262_ignore[] = { 0x1d, 0 };
10666
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010667 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
10668 alc262_ignore);
10669 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010670 return err;
Takashi Iwaie64f14f2009-01-20 18:32:55 +010010671 if (!spec->autocfg.line_outs) {
Takashi Iwai0852d7a2009-02-11 11:35:15 +010010672 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
Takashi Iwaie64f14f2009-01-20 18:32:55 +010010673 spec->multiout.max_channels = 2;
10674 spec->no_analog = 1;
10675 goto dig_only;
10676 }
Kailang Yangdf694da2005-12-05 19:42:22 +010010677 return 0; /* can't find valid BIOS pin config */
Takashi Iwaie64f14f2009-01-20 18:32:55 +010010678 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010679 err = alc262_auto_create_multi_out_ctls(spec, &spec->autocfg);
10680 if (err < 0)
10681 return err;
10682 err = alc262_auto_create_analog_input_ctls(spec, &spec->autocfg);
10683 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010684 return err;
10685
10686 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
10687
Takashi Iwaie64f14f2009-01-20 18:32:55 +010010688 dig_only:
Takashi Iwai0852d7a2009-02-11 11:35:15 +010010689 if (spec->autocfg.dig_outs) {
Kailang Yangdf694da2005-12-05 19:42:22 +010010690 spec->multiout.dig_out_nid = ALC262_DIGOUT_NID;
Takashi Iwai0852d7a2009-02-11 11:35:15 +010010691 spec->dig_out_type = spec->autocfg.dig_out_type[0];
Takashi Iwaie64f14f2009-01-20 18:32:55 +010010692 }
Kailang Yangdf694da2005-12-05 19:42:22 +010010693 if (spec->autocfg.dig_in_pin)
10694 spec->dig_in_nid = ALC262_DIGIN_NID;
10695
Takashi Iwai603c4012008-07-30 15:01:44 +020010696 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010010697 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +010010698
Takashi Iwaid88897e2008-10-31 15:01:37 +010010699 add_verb(spec, alc262_volume_init_verbs);
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020010700 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020010701 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010010702
Takashi Iwai776e1842007-08-29 15:07:11 +020010703 err = alc_auto_add_mic_boost(codec);
10704 if (err < 0)
10705 return err;
10706
Takashi Iwai4a79ba32009-04-22 16:31:35 +020010707 alc_ssid_check(codec, 0x15, 0x14, 0x1b);
10708
Kailang Yangdf694da2005-12-05 19:42:22 +010010709 return 1;
10710}
10711
10712#define alc262_auto_init_multi_out alc882_auto_init_multi_out
10713#define alc262_auto_init_hp_out alc882_auto_init_hp_out
10714#define alc262_auto_init_analog_input alc882_auto_init_analog_input
Takashi Iwaif511b012008-08-15 16:46:42 +020010715#define alc262_auto_init_input_src alc882_auto_init_input_src
Kailang Yangdf694da2005-12-05 19:42:22 +010010716
10717
10718/* init callback for auto-configuration model -- overriding the default init */
Takashi Iwaiae6b8132006-03-03 16:47:17 +010010719static void alc262_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010010720{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010721 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010010722 alc262_auto_init_multi_out(codec);
10723 alc262_auto_init_hp_out(codec);
10724 alc262_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020010725 alc262_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010726 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020010727 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010010728}
10729
10730/*
10731 * configuration and preset
10732 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010733static const char *alc262_models[ALC262_MODEL_LAST] = {
10734 [ALC262_BASIC] = "basic",
10735 [ALC262_HIPPO] = "hippo",
10736 [ALC262_HIPPO_1] = "hippo_1",
10737 [ALC262_FUJITSU] = "fujitsu",
10738 [ALC262_HP_BPC] = "hp-bpc",
Kailang Yangcd7509a2007-01-26 18:33:17 +010010739 [ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000",
Takashi Iwai61dc35d2007-11-14 12:26:44 +010010740 [ALC262_HP_TC_T5735] = "hp-tc-t5735",
Kailang Yang8c427222008-01-10 13:03:59 +010010741 [ALC262_HP_RP5700] = "hp-rp5700",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010742 [ALC262_BENQ_ED8] = "benq",
Takashi Iwai0f405022007-07-06 12:24:11 +020010743 [ALC262_BENQ_T31] = "benq-t31",
10744 [ALC262_SONY_ASSAMD] = "sony-assamd",
Takashi Iwai2922c9a2008-08-27 18:12:42 +020010745 [ALC262_TOSHIBA_S06] = "toshiba-s06",
Hiroshi Miura9f99a632008-08-28 16:09:06 +020010746 [ALC262_TOSHIBA_RX1] = "toshiba-rx1",
Tobin Davisf651b502007-10-26 12:40:47 +020010747 [ALC262_ULTRA] = "ultra",
Jiang zhe0e31daf2008-03-20 12:12:39 +010010748 [ALC262_LENOVO_3000] = "lenovo-3000",
Pascal Terjane8f9ae22008-08-04 14:36:05 +020010749 [ALC262_NEC] = "nec",
Tony Vroonba340e82009-02-02 19:01:30 +000010750 [ALC262_TYAN] = "tyan",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010751 [ALC262_AUTO] = "auto",
10752};
10753
10754static struct snd_pci_quirk alc262_cfg_tbl[] = {
10755 SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO),
Pascal Terjane8f9ae22008-08-04 14:36:05 +020010756 SND_PCI_QUIRK(0x1033, 0x8895, "NEC Versa S9100", ALC262_NEC),
Takashi Iwaidea0a502009-02-09 17:14:52 +010010757 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1200, "HP xw series",
10758 ALC262_HP_BPC),
10759 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1300, "HP xw series",
10760 ALC262_HP_BPC),
Takashi Iwai53eff7e2009-02-27 17:49:44 +010010761 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1700, "HP xw series",
10762 ALC262_HP_BPC),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010763 SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010764 SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010765 SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010766 SND_PCI_QUIRK(0x103c, 0x2803, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010767 SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010768 SND_PCI_QUIRK(0x103c, 0x2805, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010769 SND_PCI_QUIRK(0x103c, 0x2806, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010770 SND_PCI_QUIRK(0x103c, 0x2807, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010771 SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC),
10772 SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC),
10773 SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC),
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010774 SND_PCI_QUIRK(0x103c, 0x302f, "HP Thin Client T5735",
10775 ALC262_HP_TC_T5735),
Kailang Yang8c427222008-01-10 13:03:59 +010010776 SND_PCI_QUIRK(0x103c, 0x2817, "HP RP5700", ALC262_HP_RP5700),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010777 SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010778 SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010779 SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD),
Takashi Iwaibd6afe32009-03-04 11:30:25 +010010780 SND_PCI_QUIRK(0x104d, 0x9016, "Sony VAIO", ALC262_AUTO), /* dig-only */
Takashi Iwaif872a912009-02-26 00:57:01 +010010781 SND_PCI_QUIRK_MASK(0x104d, 0xff00, 0x9000, "Sony VAIO",
10782 ALC262_SONY_ASSAMD),
Akio Idehara36ca6e12008-06-09 22:57:40 +090010783 SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1",
Hiroshi Miura9f99a632008-08-28 16:09:06 +020010784 ALC262_TOSHIBA_RX1),
Kailang Yang80ffe862008-10-15 11:23:27 +020010785 SND_PCI_QUIRK(0x1179, 0xff7b, "Toshiba S06", ALC262_TOSHIBA_S06),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010786 SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU),
Tony Vroon3f1eeae2008-02-25 16:44:13 +010010787 SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU),
Tony Vroonba340e82009-02-02 19:01:30 +000010788 SND_PCI_QUIRK(0x10f1, 0x2915, "Tyan Thunder n6650W", ALC262_TYAN),
Takashi Iwaidea0a502009-02-09 17:14:52 +010010789 SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc032, "Samsung Q1",
10790 ALC262_ULTRA),
Luke Yelavich3e420e72008-12-16 12:37:47 +110010791 SND_PCI_QUIRK(0x144d, 0xc510, "Samsung Q45", ALC262_HIPPO),
Jiang zhe0e31daf2008-03-20 12:12:39 +010010792 SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 y410", ALC262_LENOVO_3000),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010793 SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8),
Kailang Yang83c34212007-07-05 11:43:05 +020010794 SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010795 SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1),
Kailang Yangdf694da2005-12-05 19:42:22 +010010796 {}
10797};
10798
10799static struct alc_config_preset alc262_presets[] = {
10800 [ALC262_BASIC] = {
10801 .mixers = { alc262_base_mixer },
10802 .init_verbs = { alc262_init_verbs },
10803 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10804 .dac_nids = alc262_dac_nids,
10805 .hp_nid = 0x03,
10806 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10807 .channel_mode = alc262_modes,
Takashi Iwaia3bcba32005-12-06 19:05:29 +010010808 .input_mux = &alc262_capture_source,
Kailang Yangdf694da2005-12-05 19:42:22 +010010809 },
Kailang Yangccc656c2006-10-17 12:32:26 +020010810 [ALC262_HIPPO] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020010811 .mixers = { alc262_hippo_mixer },
Kailang Yangccc656c2006-10-17 12:32:26 +020010812 .init_verbs = { alc262_init_verbs, alc262_hippo_unsol_verbs},
10813 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10814 .dac_nids = alc262_dac_nids,
10815 .hp_nid = 0x03,
10816 .dig_out_nid = ALC262_DIGOUT_NID,
10817 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10818 .channel_mode = alc262_modes,
10819 .input_mux = &alc262_capture_source,
10820 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai42171c12009-05-08 14:11:43 +020010821 .init_hook = alc262_hippo_init_hook,
Kailang Yangccc656c2006-10-17 12:32:26 +020010822 },
10823 [ALC262_HIPPO_1] = {
10824 .mixers = { alc262_hippo1_mixer },
10825 .init_verbs = { alc262_init_verbs, alc262_hippo1_unsol_verbs},
10826 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10827 .dac_nids = alc262_dac_nids,
10828 .hp_nid = 0x02,
10829 .dig_out_nid = ALC262_DIGOUT_NID,
10830 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10831 .channel_mode = alc262_modes,
10832 .input_mux = &alc262_capture_source,
Takashi Iwai42171c12009-05-08 14:11:43 +020010833 .unsol_event = alc262_hippo_unsol_event,
10834 .init_hook = alc262_hippo1_init_hook,
Kailang Yangccc656c2006-10-17 12:32:26 +020010835 },
Takashi Iwai834be882006-03-01 14:16:17 +010010836 [ALC262_FUJITSU] = {
10837 .mixers = { alc262_fujitsu_mixer },
Takashi Iwai39d3ed32007-10-12 15:03:48 +020010838 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
10839 alc262_fujitsu_unsol_verbs },
Takashi Iwai834be882006-03-01 14:16:17 +010010840 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10841 .dac_nids = alc262_dac_nids,
10842 .hp_nid = 0x03,
10843 .dig_out_nid = ALC262_DIGOUT_NID,
10844 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10845 .channel_mode = alc262_modes,
10846 .input_mux = &alc262_fujitsu_capture_source,
Takashi Iwaiae6b8132006-03-03 16:47:17 +010010847 .unsol_event = alc262_fujitsu_unsol_event,
Takashi Iwaiebc7a402008-05-20 09:23:05 +020010848 .init_hook = alc262_fujitsu_init_hook,
Takashi Iwai834be882006-03-01 14:16:17 +010010849 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010850 [ALC262_HP_BPC] = {
10851 .mixers = { alc262_HP_BPC_mixer },
10852 .init_verbs = { alc262_HP_BPC_init_verbs },
10853 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10854 .dac_nids = alc262_dac_nids,
10855 .hp_nid = 0x03,
10856 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10857 .channel_mode = alc262_modes,
10858 .input_mux = &alc262_HP_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010010859 .unsol_event = alc262_hp_bpc_unsol_event,
10860 .init_hook = alc262_hp_bpc_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010861 },
Kailang Yangcd7509a2007-01-26 18:33:17 +010010862 [ALC262_HP_BPC_D7000_WF] = {
10863 .mixers = { alc262_HP_BPC_WildWest_mixer },
10864 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
10865 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10866 .dac_nids = alc262_dac_nids,
10867 .hp_nid = 0x03,
10868 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10869 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +020010870 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010010871 .unsol_event = alc262_hp_wildwest_unsol_event,
10872 .init_hook = alc262_hp_wildwest_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010873 },
Kailang Yangcd7509a2007-01-26 18:33:17 +010010874 [ALC262_HP_BPC_D7000_WL] = {
10875 .mixers = { alc262_HP_BPC_WildWest_mixer,
10876 alc262_HP_BPC_WildWest_option_mixer },
10877 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
10878 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10879 .dac_nids = alc262_dac_nids,
10880 .hp_nid = 0x03,
10881 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10882 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +020010883 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010010884 .unsol_event = alc262_hp_wildwest_unsol_event,
10885 .init_hook = alc262_hp_wildwest_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010886 },
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010887 [ALC262_HP_TC_T5735] = {
10888 .mixers = { alc262_hp_t5735_mixer },
10889 .init_verbs = { alc262_init_verbs, alc262_hp_t5735_verbs },
10890 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10891 .dac_nids = alc262_dac_nids,
10892 .hp_nid = 0x03,
10893 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10894 .channel_mode = alc262_modes,
10895 .input_mux = &alc262_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010896 .unsol_event = alc_automute_amp_unsol_event,
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010897 .init_hook = alc262_hp_t5735_init_hook,
Kailang Yang8c427222008-01-10 13:03:59 +010010898 },
10899 [ALC262_HP_RP5700] = {
10900 .mixers = { alc262_hp_rp5700_mixer },
10901 .init_verbs = { alc262_init_verbs, alc262_hp_rp5700_verbs },
10902 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10903 .dac_nids = alc262_dac_nids,
10904 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10905 .channel_mode = alc262_modes,
10906 .input_mux = &alc262_hp_rp5700_capture_source,
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010907 },
Takashi Iwai304dcaa2006-07-25 14:51:16 +020010908 [ALC262_BENQ_ED8] = {
10909 .mixers = { alc262_base_mixer },
10910 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs },
10911 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10912 .dac_nids = alc262_dac_nids,
10913 .hp_nid = 0x03,
10914 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10915 .channel_mode = alc262_modes,
10916 .input_mux = &alc262_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010917 },
Kailang Yang272a5272007-05-14 11:00:38 +020010918 [ALC262_SONY_ASSAMD] = {
10919 .mixers = { alc262_sony_mixer },
10920 .init_verbs = { alc262_init_verbs, alc262_sony_unsol_verbs},
10921 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10922 .dac_nids = alc262_dac_nids,
10923 .hp_nid = 0x02,
10924 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10925 .channel_mode = alc262_modes,
10926 .input_mux = &alc262_capture_source,
10927 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai42171c12009-05-08 14:11:43 +020010928 .init_hook = alc262_hippo_init_hook,
Kailang Yang83c34212007-07-05 11:43:05 +020010929 },
10930 [ALC262_BENQ_T31] = {
10931 .mixers = { alc262_benq_t31_mixer },
10932 .init_verbs = { alc262_init_verbs, alc262_benq_t31_EAPD_verbs, alc262_hippo_unsol_verbs },
10933 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10934 .dac_nids = alc262_dac_nids,
10935 .hp_nid = 0x03,
10936 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10937 .channel_mode = alc262_modes,
10938 .input_mux = &alc262_capture_source,
10939 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai42171c12009-05-08 14:11:43 +020010940 .init_hook = alc262_hippo_init_hook,
Kailang Yangea1fb292008-08-26 12:58:38 +020010941 },
Tobin Davisf651b502007-10-26 12:40:47 +020010942 [ALC262_ULTRA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010943 .mixers = { alc262_ultra_mixer },
10944 .cap_mixer = alc262_ultra_capture_mixer,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010945 .init_verbs = { alc262_ultra_verbs },
Tobin Davisf651b502007-10-26 12:40:47 +020010946 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10947 .dac_nids = alc262_dac_nids,
Tobin Davisf651b502007-10-26 12:40:47 +020010948 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10949 .channel_mode = alc262_modes,
10950 .input_mux = &alc262_ultra_capture_source,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010951 .adc_nids = alc262_adc_nids, /* ADC0 */
10952 .capsrc_nids = alc262_capsrc_nids,
10953 .num_adc_nids = 1, /* single ADC */
Tobin Davisf651b502007-10-26 12:40:47 +020010954 .unsol_event = alc262_ultra_unsol_event,
10955 .init_hook = alc262_ultra_automute,
10956 },
Jiang zhe0e31daf2008-03-20 12:12:39 +010010957 [ALC262_LENOVO_3000] = {
10958 .mixers = { alc262_lenovo_3000_mixer },
10959 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
10960 alc262_lenovo_3000_unsol_verbs },
10961 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10962 .dac_nids = alc262_dac_nids,
10963 .hp_nid = 0x03,
10964 .dig_out_nid = ALC262_DIGOUT_NID,
10965 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10966 .channel_mode = alc262_modes,
10967 .input_mux = &alc262_fujitsu_capture_source,
10968 .unsol_event = alc262_lenovo_3000_unsol_event,
10969 },
Pascal Terjane8f9ae22008-08-04 14:36:05 +020010970 [ALC262_NEC] = {
10971 .mixers = { alc262_nec_mixer },
10972 .init_verbs = { alc262_nec_verbs },
10973 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10974 .dac_nids = alc262_dac_nids,
10975 .hp_nid = 0x03,
10976 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10977 .channel_mode = alc262_modes,
10978 .input_mux = &alc262_capture_source,
10979 },
Kailang Yang4e555fe2008-08-26 13:05:55 +020010980 [ALC262_TOSHIBA_S06] = {
10981 .mixers = { alc262_toshiba_s06_mixer },
10982 .init_verbs = { alc262_init_verbs, alc262_toshiba_s06_verbs,
10983 alc262_eapd_verbs },
10984 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10985 .capsrc_nids = alc262_dmic_capsrc_nids,
10986 .dac_nids = alc262_dac_nids,
10987 .adc_nids = alc262_dmic_adc_nids, /* ADC0 */
10988 .dig_out_nid = ALC262_DIGOUT_NID,
10989 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10990 .channel_mode = alc262_modes,
10991 .input_mux = &alc262_dmic_capture_source,
10992 .unsol_event = alc262_toshiba_s06_unsol_event,
10993 .init_hook = alc262_toshiba_s06_init_hook,
10994 },
Hiroshi Miura9f99a632008-08-28 16:09:06 +020010995 [ALC262_TOSHIBA_RX1] = {
10996 .mixers = { alc262_toshiba_rx1_mixer },
10997 .init_verbs = { alc262_init_verbs, alc262_toshiba_rx1_unsol_verbs },
10998 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10999 .dac_nids = alc262_dac_nids,
11000 .hp_nid = 0x03,
11001 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11002 .channel_mode = alc262_modes,
11003 .input_mux = &alc262_capture_source,
11004 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai42171c12009-05-08 14:11:43 +020011005 .init_hook = alc262_hippo_init_hook,
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011006 },
Tony Vroonba340e82009-02-02 19:01:30 +000011007 [ALC262_TYAN] = {
11008 .mixers = { alc262_tyan_mixer },
11009 .init_verbs = { alc262_init_verbs, alc262_tyan_verbs},
11010 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11011 .dac_nids = alc262_dac_nids,
11012 .hp_nid = 0x02,
11013 .dig_out_nid = ALC262_DIGOUT_NID,
11014 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11015 .channel_mode = alc262_modes,
11016 .input_mux = &alc262_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011017 .unsol_event = alc_automute_amp_unsol_event,
11018 .init_hook = alc262_tyan_init_hook,
Tony Vroonba340e82009-02-02 19:01:30 +000011019 },
Kailang Yangdf694da2005-12-05 19:42:22 +010011020};
11021
11022static int patch_alc262(struct hda_codec *codec)
11023{
11024 struct alc_spec *spec;
11025 int board_config;
11026 int err;
11027
Robert P. J. Daydc041e02006-12-19 14:44:15 +010011028 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010011029 if (spec == NULL)
11030 return -ENOMEM;
11031
11032 codec->spec = spec;
11033#if 0
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011034 /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is
11035 * under-run
11036 */
Kailang Yangdf694da2005-12-05 19:42:22 +010011037 {
11038 int tmp;
11039 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
11040 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
11041 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
11042 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80);
11043 }
11044#endif
11045
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020011046 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
11047
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011048 board_config = snd_hda_check_board_config(codec, ALC262_MODEL_LAST,
11049 alc262_models,
11050 alc262_cfg_tbl);
Kailang Yangcd7509a2007-01-26 18:33:17 +010011051
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011052 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011053 printk(KERN_INFO "hda_codec: Unknown model for ALC262, "
11054 "trying auto-probe from BIOS...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010011055 board_config = ALC262_AUTO;
11056 }
11057
11058 if (board_config == ALC262_AUTO) {
11059 /* automatic parse from the BIOS config */
11060 err = alc262_parse_auto_config(codec);
11061 if (err < 0) {
11062 alc_free(codec);
11063 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011064 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011065 printk(KERN_INFO
11066 "hda_codec: Cannot set up configuration "
11067 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010011068 board_config = ALC262_BASIC;
11069 }
11070 }
11071
Takashi Iwai07eba612009-02-19 08:06:35 +010011072 if (!spec->no_analog) {
11073 err = snd_hda_attach_beep_device(codec, 0x1);
11074 if (err < 0) {
11075 alc_free(codec);
11076 return err;
11077 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090011078 }
11079
Kailang Yangdf694da2005-12-05 19:42:22 +010011080 if (board_config != ALC262_AUTO)
11081 setup_preset(spec, &alc262_presets[board_config]);
11082
11083 spec->stream_name_analog = "ALC262 Analog";
11084 spec->stream_analog_playback = &alc262_pcm_analog_playback;
11085 spec->stream_analog_capture = &alc262_pcm_analog_capture;
Kailang Yangea1fb292008-08-26 12:58:38 +020011086
Kailang Yangdf694da2005-12-05 19:42:22 +010011087 spec->stream_name_digital = "ALC262 Digital";
11088 spec->stream_digital_playback = &alc262_pcm_digital_playback;
11089 spec->stream_digital_capture = &alc262_pcm_digital_capture;
11090
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020011091 spec->capture_style = CAPT_MIX;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011092 if (!spec->adc_nids && spec->input_mux) {
Kailang Yangdf694da2005-12-05 19:42:22 +010011093 /* check whether NID 0x07 is valid */
Takashi Iwai4a471b72005-12-07 13:56:29 +010011094 unsigned int wcap = get_wcaps(codec, 0x07);
11095
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011096 /* get type */
11097 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Kailang Yangdf694da2005-12-05 19:42:22 +010011098 if (wcap != AC_WID_AUD_IN) {
11099 spec->adc_nids = alc262_adc_nids_alt;
11100 spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids_alt);
Takashi Iwai88c71a92008-02-14 17:27:17 +010011101 spec->capsrc_nids = alc262_capsrc_nids_alt;
Kailang Yangdf694da2005-12-05 19:42:22 +010011102 } else {
11103 spec->adc_nids = alc262_adc_nids;
11104 spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids);
Takashi Iwai88c71a92008-02-14 17:27:17 +010011105 spec->capsrc_nids = alc262_capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +010011106 }
11107 }
Takashi Iwaie64f14f2009-01-20 18:32:55 +010011108 if (!spec->cap_mixer && !spec->no_analog)
Takashi Iwaif9e336f2008-10-31 16:37:07 +010011109 set_capture_mixer(spec);
Takashi Iwai07eba612009-02-19 08:06:35 +010011110 if (!spec->no_analog)
11111 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Kailang Yangdf694da2005-12-05 19:42:22 +010011112
Takashi Iwai2134ea42008-01-10 16:53:55 +010011113 spec->vmaster_nid = 0x0c;
11114
Kailang Yangdf694da2005-12-05 19:42:22 +010011115 codec->patch_ops = alc_patch_ops;
11116 if (board_config == ALC262_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +010011117 spec->init_hook = alc262_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020011118#ifdef CONFIG_SND_HDA_POWER_SAVE
11119 if (!spec->loopback.amplist)
11120 spec->loopback.amplist = alc262_loopbacks;
11121#endif
Takashi Iwaidaead532008-11-28 12:55:36 +010011122 codec->proc_widget_hook = print_realtek_coef;
Kailang Yangea1fb292008-08-26 12:58:38 +020011123
Kailang Yangdf694da2005-12-05 19:42:22 +010011124 return 0;
11125}
11126
Kailang Yangdf694da2005-12-05 19:42:22 +010011127/*
Kailang Yanga361d842007-06-05 12:30:55 +020011128 * ALC268 channel source setting (2 channel)
11129 */
11130#define ALC268_DIGOUT_NID ALC880_DIGOUT_NID
11131#define alc268_modes alc260_modes
Kailang Yangea1fb292008-08-26 12:58:38 +020011132
Kailang Yanga361d842007-06-05 12:30:55 +020011133static hda_nid_t alc268_dac_nids[2] = {
11134 /* front, hp */
11135 0x02, 0x03
11136};
11137
11138static hda_nid_t alc268_adc_nids[2] = {
11139 /* ADC0-1 */
11140 0x08, 0x07
11141};
11142
11143static hda_nid_t alc268_adc_nids_alt[1] = {
11144 /* ADC0 */
11145 0x08
11146};
11147
Takashi Iwaie1406342008-02-11 18:32:32 +010011148static hda_nid_t alc268_capsrc_nids[2] = { 0x23, 0x24 };
11149
Kailang Yanga361d842007-06-05 12:30:55 +020011150static struct snd_kcontrol_new alc268_base_mixer[] = {
11151 /* output mixer control */
11152 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
11153 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11154 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
11155 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai33bf17a2007-08-21 11:51:42 +020011156 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11157 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
11158 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
Kailang Yanga361d842007-06-05 12:30:55 +020011159 { }
11160};
11161
Takashi Iwai42171c12009-05-08 14:11:43 +020011162static struct snd_kcontrol_new alc268_toshiba_mixer[] = {
11163 /* output mixer control */
11164 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
11165 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
11166 ALC262_HIPPO_MASTER_SWITCH,
11167 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11168 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
11169 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
11170 { }
11171};
11172
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011173/* bind Beep switches of both NID 0x0f and 0x10 */
11174static struct hda_bind_ctls alc268_bind_beep_sw = {
11175 .ops = &snd_hda_bind_sw,
11176 .values = {
11177 HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT),
11178 HDA_COMPOSE_AMP_VAL(0x10, 3, 1, HDA_INPUT),
11179 0
11180 },
11181};
11182
11183static struct snd_kcontrol_new alc268_beep_mixer[] = {
11184 HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT),
11185 HDA_BIND_SW("Beep Playback Switch", &alc268_bind_beep_sw),
11186 { }
11187};
11188
Kailang Yangd1a991a2007-08-15 16:21:59 +020011189static struct hda_verb alc268_eapd_verbs[] = {
11190 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
11191 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
11192 { }
11193};
11194
Takashi Iwaid2738092007-08-16 14:59:45 +020011195/* Toshiba specific */
Takashi Iwaid2738092007-08-16 14:59:45 +020011196static struct hda_verb alc268_toshiba_verbs[] = {
11197 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
11198 { } /* end */
11199};
11200
Kailang Yang8ef355d2008-08-26 13:10:22 +020011201static struct hda_input_mux alc268_acer_lc_capture_source = {
11202 .num_items = 2,
11203 .items = {
11204 { "i-Mic", 0x6 },
11205 { "E-Mic", 0x0 },
11206 },
11207};
11208
Takashi Iwaid2738092007-08-16 14:59:45 +020011209/* Acer specific */
Takashi Iwai889c4392007-08-23 18:56:52 +020011210/* bind volumes of both NID 0x02 and 0x03 */
Takashi Iwai6bc96852007-08-17 09:02:12 +020011211static struct hda_bind_ctls alc268_acer_bind_master_vol = {
11212 .ops = &snd_hda_bind_vol,
11213 .values = {
11214 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
11215 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
11216 0
11217 },
11218};
11219
Takashi Iwai889c4392007-08-23 18:56:52 +020011220/* mute/unmute internal speaker according to the hp jack and mute state */
11221static void alc268_acer_automute(struct hda_codec *codec, int force)
11222{
11223 struct alc_spec *spec = codec->spec;
11224 unsigned int mute;
11225
11226 if (force || !spec->sense_updated) {
11227 unsigned int present;
11228 present = snd_hda_codec_read(codec, 0x14, 0,
11229 AC_VERB_GET_PIN_SENSE, 0);
11230 spec->jack_present = (present & 0x80000000) != 0;
11231 spec->sense_updated = 1;
11232 }
11233 if (spec->jack_present)
11234 mute = HDA_AMP_MUTE; /* mute internal speaker */
11235 else /* unmute internal speaker if necessary */
11236 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
11237 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
11238 HDA_AMP_MUTE, mute);
11239}
11240
11241
11242/* bind hp and internal speaker mute (with plug check) */
11243static int alc268_acer_master_sw_put(struct snd_kcontrol *kcontrol,
11244 struct snd_ctl_elem_value *ucontrol)
11245{
11246 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
11247 long *valp = ucontrol->value.integer.value;
11248 int change;
11249
11250 change = snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0,
11251 HDA_AMP_MUTE,
11252 valp[0] ? 0 : HDA_AMP_MUTE);
11253 change |= snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0,
11254 HDA_AMP_MUTE,
11255 valp[1] ? 0 : HDA_AMP_MUTE);
11256 if (change)
11257 alc268_acer_automute(codec, 0);
11258 return change;
11259}
Takashi Iwaid2738092007-08-16 14:59:45 +020011260
Kailang Yang8ef355d2008-08-26 13:10:22 +020011261static struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = {
11262 /* output mixer control */
11263 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
11264 {
11265 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11266 .name = "Master Playback Switch",
11267 .info = snd_hda_mixer_amp_switch_info,
11268 .get = snd_hda_mixer_amp_switch_get,
11269 .put = alc268_acer_master_sw_put,
11270 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
11271 },
11272 HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x18, 0, HDA_INPUT),
11273 { }
11274};
11275
Takashi Iwaid2738092007-08-16 14:59:45 +020011276static struct snd_kcontrol_new alc268_acer_mixer[] = {
11277 /* output mixer control */
11278 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
11279 {
11280 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11281 .name = "Master Playback Switch",
11282 .info = snd_hda_mixer_amp_switch_info,
11283 .get = snd_hda_mixer_amp_switch_get,
11284 .put = alc268_acer_master_sw_put,
11285 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
11286 },
Takashi Iwai33bf17a2007-08-21 11:51:42 +020011287 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11288 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
11289 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
Takashi Iwaid2738092007-08-16 14:59:45 +020011290 { }
11291};
11292
Takashi Iwaic238b4f2008-11-05 14:57:20 +010011293static struct snd_kcontrol_new alc268_acer_dmic_mixer[] = {
11294 /* output mixer control */
11295 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
11296 {
11297 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11298 .name = "Master Playback Switch",
11299 .info = snd_hda_mixer_amp_switch_info,
11300 .get = snd_hda_mixer_amp_switch_get,
11301 .put = alc268_acer_master_sw_put,
11302 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
11303 },
11304 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11305 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
11306 { }
11307};
11308
Kailang Yang8ef355d2008-08-26 13:10:22 +020011309static struct hda_verb alc268_acer_aspire_one_verbs[] = {
11310 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11311 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11312 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
11313 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
11314 {0x23, AC_VERB_SET_CONNECT_SEL, 0x06},
11315 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, 0xa017},
11316 { }
11317};
11318
Takashi Iwaid2738092007-08-16 14:59:45 +020011319static struct hda_verb alc268_acer_verbs[] = {
Takashi Iwai0ccb5412008-03-06 16:58:35 +010011320 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* internal dmic? */
11321 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaid2738092007-08-16 14:59:45 +020011322 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11323 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai0ccb5412008-03-06 16:58:35 +010011324 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
11325 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaid2738092007-08-16 14:59:45 +020011326 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
11327 { }
11328};
11329
11330/* unsolicited event for HP jack sensing */
Takashi Iwai42171c12009-05-08 14:11:43 +020011331#define alc268_toshiba_unsol_event alc262_hippo_unsol_event
11332#define alc268_toshiba_init_hook alc262_hippo_init_hook
Takashi Iwaid2738092007-08-16 14:59:45 +020011333
11334static void alc268_acer_unsol_event(struct hda_codec *codec,
11335 unsigned int res)
11336{
Takashi Iwai889c4392007-08-23 18:56:52 +020011337 if ((res >> 26) != ALC880_HP_EVENT)
Takashi Iwaid2738092007-08-16 14:59:45 +020011338 return;
11339 alc268_acer_automute(codec, 1);
11340}
11341
Takashi Iwai889c4392007-08-23 18:56:52 +020011342static void alc268_acer_init_hook(struct hda_codec *codec)
11343{
11344 alc268_acer_automute(codec, 1);
11345}
11346
Kailang Yang8ef355d2008-08-26 13:10:22 +020011347/* toggle speaker-output according to the hp-jack state */
11348static void alc268_aspire_one_speaker_automute(struct hda_codec *codec)
11349{
11350 unsigned int present;
11351 unsigned char bits;
11352
11353 present = snd_hda_codec_read(codec, 0x15, 0,
11354 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
11355 bits = present ? AMP_IN_MUTE(0) : 0;
11356 snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 0,
11357 AMP_IN_MUTE(0), bits);
11358 snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 1,
11359 AMP_IN_MUTE(0), bits);
11360}
11361
11362
11363static void alc268_acer_mic_automute(struct hda_codec *codec)
11364{
11365 unsigned int present;
11366
11367 present = snd_hda_codec_read(codec, 0x18, 0,
11368 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
11369 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_CONNECT_SEL,
11370 present ? 0x0 : 0x6);
11371}
11372
11373static void alc268_acer_lc_unsol_event(struct hda_codec *codec,
11374 unsigned int res)
11375{
11376 if ((res >> 26) == ALC880_HP_EVENT)
11377 alc268_aspire_one_speaker_automute(codec);
11378 if ((res >> 26) == ALC880_MIC_EVENT)
11379 alc268_acer_mic_automute(codec);
11380}
11381
11382static void alc268_acer_lc_init_hook(struct hda_codec *codec)
11383{
11384 alc268_aspire_one_speaker_automute(codec);
11385 alc268_acer_mic_automute(codec);
11386}
11387
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011388static struct snd_kcontrol_new alc268_dell_mixer[] = {
11389 /* output mixer control */
11390 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
11391 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11392 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
11393 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11394 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11395 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
11396 { }
11397};
11398
11399static struct hda_verb alc268_dell_verbs[] = {
11400 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11401 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11402 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
11403 { }
11404};
11405
11406/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011407static void alc268_dell_init_hook(struct hda_codec *codec)
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011408{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011409 struct alc_spec *spec = codec->spec;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011410
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011411 spec->autocfg.hp_pins[0] = 0x15;
11412 spec->autocfg.speaker_pins[0] = 0x14;
11413 alc_automute_pin(codec);
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011414}
11415
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020011416static struct snd_kcontrol_new alc267_quanta_il1_mixer[] = {
11417 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x2, 0x0, HDA_OUTPUT),
11418 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11419 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
11420 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11421 HDA_CODEC_VOLUME("Mic Capture Volume", 0x23, 0x0, HDA_OUTPUT),
11422 HDA_BIND_MUTE("Mic Capture Switch", 0x23, 2, HDA_OUTPUT),
11423 HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
11424 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
11425 { }
11426};
11427
11428static struct hda_verb alc267_quanta_il1_verbs[] = {
11429 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
11430 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
11431 { }
11432};
11433
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020011434static void alc267_quanta_il1_mic_automute(struct hda_codec *codec)
11435{
11436 unsigned int present;
11437
11438 present = snd_hda_codec_read(codec, 0x18, 0,
11439 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
11440 snd_hda_codec_write(codec, 0x23, 0,
11441 AC_VERB_SET_CONNECT_SEL,
11442 present ? 0x00 : 0x01);
11443}
11444
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011445static void alc267_quanta_il1_init_hook(struct hda_codec *codec)
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020011446{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011447 struct alc_spec *spec = codec->spec;
11448
11449 spec->autocfg.hp_pins[0] = 0x15;
11450 spec->autocfg.speaker_pins[0] = 0x14;
11451 alc_automute_pin(codec);
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020011452 alc267_quanta_il1_mic_automute(codec);
11453}
11454
11455static void alc267_quanta_il1_unsol_event(struct hda_codec *codec,
11456 unsigned int res)
11457{
11458 switch (res >> 26) {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020011459 case ALC880_MIC_EVENT:
11460 alc267_quanta_il1_mic_automute(codec);
11461 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011462 default:
11463 alc_sku_unsol_event(codec, res);
11464 break;
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020011465 }
11466}
11467
Kailang Yanga361d842007-06-05 12:30:55 +020011468/*
11469 * generic initialization of ADC, input mixers and output mixers
11470 */
11471static struct hda_verb alc268_base_init_verbs[] = {
11472 /* Unmute DAC0-1 and set vol = 0 */
11473 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020011474 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020011475
11476 /*
11477 * Set up output mixers (0x0c - 0x0e)
11478 */
11479 /* set vol=0 to output mixers */
11480 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yanga361d842007-06-05 12:30:55 +020011481 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
11482
11483 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11484 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11485
11486 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
11487 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
11488 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
11489 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11490 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11491 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11492 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11493 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11494
11495 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11496 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11497 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11498 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020011499 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011500
11501 /* set PCBEEP vol = 0, mute connections */
11502 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11503 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11504 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020011505
Jiang Zhea9b3aa82007-12-20 13:13:13 +010011506 /* Unmute Selector 23h,24h and set the default input to mic-in */
Kailang Yangea1fb292008-08-26 12:58:38 +020011507
Jiang Zhea9b3aa82007-12-20 13:13:13 +010011508 {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
11509 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11510 {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
11511 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020011512
Kailang Yanga361d842007-06-05 12:30:55 +020011513 { }
11514};
11515
11516/*
11517 * generic initialization of ADC, input mixers and output mixers
11518 */
11519static struct hda_verb alc268_volume_init_verbs[] = {
11520 /* set output DAC */
Takashi Iwai4cfb91c2009-01-23 12:53:09 +010011521 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11522 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020011523
11524 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11525 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11526 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11527 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11528 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11529
Kailang Yanga361d842007-06-05 12:30:55 +020011530 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yanga361d842007-06-05 12:30:55 +020011531 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11532 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11533
11534 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020011535 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020011536
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011537 /* set PCBEEP vol = 0, mute connections */
11538 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11539 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11540 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020011541
11542 { }
11543};
11544
Kailang Yanga361d842007-06-05 12:30:55 +020011545static struct snd_kcontrol_new alc268_capture_alt_mixer[] = {
11546 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
11547 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
11548 {
11549 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11550 /* The multiple "Capture Source" controls confuse alsamixer
11551 * So call somewhat different..
Kailang Yanga361d842007-06-05 12:30:55 +020011552 */
11553 /* .name = "Capture Source", */
11554 .name = "Input Source",
11555 .count = 1,
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010011556 .info = alc_mux_enum_info,
11557 .get = alc_mux_enum_get,
11558 .put = alc_mux_enum_put,
Kailang Yanga361d842007-06-05 12:30:55 +020011559 },
11560 { } /* end */
11561};
11562
11563static struct snd_kcontrol_new alc268_capture_mixer[] = {
11564 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
11565 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
11566 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x24, 0x0, HDA_OUTPUT),
11567 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x24, 0x0, HDA_OUTPUT),
11568 {
11569 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11570 /* The multiple "Capture Source" controls confuse alsamixer
11571 * So call somewhat different..
Kailang Yanga361d842007-06-05 12:30:55 +020011572 */
11573 /* .name = "Capture Source", */
11574 .name = "Input Source",
11575 .count = 2,
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010011576 .info = alc_mux_enum_info,
11577 .get = alc_mux_enum_get,
11578 .put = alc_mux_enum_put,
Kailang Yanga361d842007-06-05 12:30:55 +020011579 },
11580 { } /* end */
11581};
11582
11583static struct hda_input_mux alc268_capture_source = {
11584 .num_items = 4,
11585 .items = {
11586 { "Mic", 0x0 },
11587 { "Front Mic", 0x1 },
11588 { "Line", 0x2 },
11589 { "CD", 0x3 },
11590 },
11591};
11592
Takashi Iwai0ccb5412008-03-06 16:58:35 +010011593static struct hda_input_mux alc268_acer_capture_source = {
11594 .num_items = 3,
11595 .items = {
11596 { "Mic", 0x0 },
Takashi Iwaic238b4f2008-11-05 14:57:20 +010011597 { "Internal Mic", 0x1 },
11598 { "Line", 0x2 },
11599 },
11600};
11601
11602static struct hda_input_mux alc268_acer_dmic_capture_source = {
11603 .num_items = 3,
11604 .items = {
11605 { "Mic", 0x0 },
Takashi Iwai0ccb5412008-03-06 16:58:35 +010011606 { "Internal Mic", 0x6 },
11607 { "Line", 0x2 },
11608 },
11609};
11610
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010011611#ifdef CONFIG_SND_DEBUG
11612static struct snd_kcontrol_new alc268_test_mixer[] = {
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010011613 /* Volume widgets */
11614 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x02, 0x0, HDA_OUTPUT),
11615 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x03, 0x0, HDA_OUTPUT),
11616 HDA_BIND_MUTE_MONO("Mono sum Playback Switch", 0x0e, 1, 2, HDA_INPUT),
11617 HDA_BIND_MUTE("LINE-OUT sum Playback Switch", 0x0f, 2, HDA_INPUT),
11618 HDA_BIND_MUTE("HP-OUT sum Playback Switch", 0x10, 2, HDA_INPUT),
11619 HDA_BIND_MUTE("LINE-OUT Playback Switch", 0x14, 2, HDA_OUTPUT),
11620 HDA_BIND_MUTE("HP-OUT Playback Switch", 0x15, 2, HDA_OUTPUT),
11621 HDA_BIND_MUTE("Mono Playback Switch", 0x16, 2, HDA_OUTPUT),
11622 HDA_CODEC_VOLUME("MIC1 Capture Volume", 0x18, 0x0, HDA_INPUT),
11623 HDA_BIND_MUTE("MIC1 Capture Switch", 0x18, 2, HDA_OUTPUT),
11624 HDA_CODEC_VOLUME("MIC2 Capture Volume", 0x19, 0x0, HDA_INPUT),
11625 HDA_CODEC_VOLUME("LINE1 Capture Volume", 0x1a, 0x0, HDA_INPUT),
11626 HDA_BIND_MUTE("LINE1 Capture Switch", 0x1a, 2, HDA_OUTPUT),
Takashi Iwaif0747ee2008-01-15 11:41:41 +010011627 /* The below appears problematic on some hardwares */
11628 /*HDA_CODEC_VOLUME("PCBEEP Playback Volume", 0x1d, 0x0, HDA_INPUT),*/
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010011629 HDA_CODEC_VOLUME("PCM-IN1 Capture Volume", 0x23, 0x0, HDA_OUTPUT),
11630 HDA_BIND_MUTE("PCM-IN1 Capture Switch", 0x23, 2, HDA_OUTPUT),
11631 HDA_CODEC_VOLUME("PCM-IN2 Capture Volume", 0x24, 0x0, HDA_OUTPUT),
11632 HDA_BIND_MUTE("PCM-IN2 Capture Switch", 0x24, 2, HDA_OUTPUT),
11633
11634 /* Modes for retasking pin widgets */
11635 ALC_PIN_MODE("LINE-OUT pin mode", 0x14, ALC_PIN_DIR_INOUT),
11636 ALC_PIN_MODE("HP-OUT pin mode", 0x15, ALC_PIN_DIR_INOUT),
11637 ALC_PIN_MODE("MIC1 pin mode", 0x18, ALC_PIN_DIR_INOUT),
11638 ALC_PIN_MODE("LINE1 pin mode", 0x1a, ALC_PIN_DIR_INOUT),
11639
11640 /* Controls for GPIO pins, assuming they are configured as outputs */
11641 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
11642 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
11643 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
11644 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
11645
11646 /* Switches to allow the digital SPDIF output pin to be enabled.
11647 * The ALC268 does not have an SPDIF input.
11648 */
11649 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x06, 0x01),
11650
11651 /* A switch allowing EAPD to be enabled. Some laptops seem to use
11652 * this output to turn on an external amplifier.
11653 */
11654 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
11655 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
11656
11657 { } /* end */
11658};
11659#endif
11660
Kailang Yanga361d842007-06-05 12:30:55 +020011661/* create input playback/capture controls for the given pin */
11662static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
11663 const char *ctlname, int idx)
11664{
11665 char name[32];
11666 int err;
11667
11668 sprintf(name, "%s Playback Volume", ctlname);
11669 if (nid == 0x14) {
11670 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
11671 HDA_COMPOSE_AMP_VAL(0x02, 3, idx,
11672 HDA_OUTPUT));
11673 if (err < 0)
11674 return err;
11675 } else if (nid == 0x15) {
11676 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
11677 HDA_COMPOSE_AMP_VAL(0x03, 3, idx,
11678 HDA_OUTPUT));
11679 if (err < 0)
11680 return err;
11681 } else
11682 return -1;
11683 sprintf(name, "%s Playback Switch", ctlname);
11684 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
11685 HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
11686 if (err < 0)
11687 return err;
11688 return 0;
11689}
11690
11691/* add playback controls from the parsed DAC table */
11692static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
11693 const struct auto_pin_cfg *cfg)
11694{
11695 hda_nid_t nid;
11696 int err;
11697
11698 spec->multiout.num_dacs = 2; /* only use one dac */
11699 spec->multiout.dac_nids = spec->private_dac_nids;
11700 spec->multiout.dac_nids[0] = 2;
11701 spec->multiout.dac_nids[1] = 3;
11702
11703 nid = cfg->line_out_pins[0];
11704 if (nid)
Kailang Yangea1fb292008-08-26 12:58:38 +020011705 alc268_new_analog_output(spec, nid, "Front", 0);
Kailang Yanga361d842007-06-05 12:30:55 +020011706
11707 nid = cfg->speaker_pins[0];
11708 if (nid == 0x1d) {
11709 err = add_control(spec, ALC_CTL_WIDGET_VOL,
11710 "Speaker Playback Volume",
11711 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
11712 if (err < 0)
11713 return err;
11714 }
11715 nid = cfg->hp_pins[0];
11716 if (nid)
11717 alc268_new_analog_output(spec, nid, "Headphone", 0);
11718
11719 nid = cfg->line_out_pins[1] | cfg->line_out_pins[2];
11720 if (nid == 0x16) {
11721 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
11722 "Mono Playback Switch",
11723 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_INPUT));
11724 if (err < 0)
11725 return err;
11726 }
Kailang Yangea1fb292008-08-26 12:58:38 +020011727 return 0;
Kailang Yanga361d842007-06-05 12:30:55 +020011728}
11729
11730/* create playback/capture controls for input pins */
11731static int alc268_auto_create_analog_input_ctls(struct alc_spec *spec,
11732 const struct auto_pin_cfg *cfg)
11733{
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020011734 struct hda_input_mux *imux = &spec->private_imux[0];
Kailang Yanga361d842007-06-05 12:30:55 +020011735 int i, idx1;
11736
11737 for (i = 0; i < AUTO_PIN_LAST; i++) {
11738 switch(cfg->input_pins[i]) {
11739 case 0x18:
11740 idx1 = 0; /* Mic 1 */
11741 break;
11742 case 0x19:
11743 idx1 = 1; /* Mic 2 */
11744 break;
11745 case 0x1a:
11746 idx1 = 2; /* Line In */
11747 break;
Kailang Yangea1fb292008-08-26 12:58:38 +020011748 case 0x1c:
Kailang Yanga361d842007-06-05 12:30:55 +020011749 idx1 = 3; /* CD */
11750 break;
Takashi Iwai7194cae2008-03-06 16:58:17 +010011751 case 0x12:
11752 case 0x13:
11753 idx1 = 6; /* digital mics */
11754 break;
Kailang Yanga361d842007-06-05 12:30:55 +020011755 default:
11756 continue;
11757 }
11758 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
11759 imux->items[imux->num_items].index = idx1;
Kailang Yangea1fb292008-08-26 12:58:38 +020011760 imux->num_items++;
Kailang Yanga361d842007-06-05 12:30:55 +020011761 }
11762 return 0;
11763}
11764
11765static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec)
11766{
11767 struct alc_spec *spec = codec->spec;
11768 hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
11769 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
11770 hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
11771 unsigned int dac_vol1, dac_vol2;
11772
11773 if (speaker_nid) {
11774 snd_hda_codec_write(codec, speaker_nid, 0,
11775 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
11776 snd_hda_codec_write(codec, 0x0f, 0,
11777 AC_VERB_SET_AMP_GAIN_MUTE,
11778 AMP_IN_UNMUTE(1));
11779 snd_hda_codec_write(codec, 0x10, 0,
11780 AC_VERB_SET_AMP_GAIN_MUTE,
11781 AMP_IN_UNMUTE(1));
11782 } else {
11783 snd_hda_codec_write(codec, 0x0f, 0,
11784 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
11785 snd_hda_codec_write(codec, 0x10, 0,
11786 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
11787 }
11788
11789 dac_vol1 = dac_vol2 = 0xb000 | 0x40; /* set max volume */
Kailang Yangea1fb292008-08-26 12:58:38 +020011790 if (line_nid == 0x14)
Kailang Yanga361d842007-06-05 12:30:55 +020011791 dac_vol2 = AMP_OUT_ZERO;
11792 else if (line_nid == 0x15)
11793 dac_vol1 = AMP_OUT_ZERO;
Kailang Yangea1fb292008-08-26 12:58:38 +020011794 if (hp_nid == 0x14)
Kailang Yanga361d842007-06-05 12:30:55 +020011795 dac_vol2 = AMP_OUT_ZERO;
11796 else if (hp_nid == 0x15)
11797 dac_vol1 = AMP_OUT_ZERO;
11798 if (line_nid != 0x16 || hp_nid != 0x16 ||
11799 spec->autocfg.line_out_pins[1] != 0x16 ||
11800 spec->autocfg.line_out_pins[2] != 0x16)
11801 dac_vol1 = dac_vol2 = AMP_OUT_ZERO;
11802
11803 snd_hda_codec_write(codec, 0x02, 0,
11804 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol1);
11805 snd_hda_codec_write(codec, 0x03, 0,
11806 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol2);
11807}
11808
11809/* pcm configuration: identiacal with ALC880 */
11810#define alc268_pcm_analog_playback alc880_pcm_analog_playback
11811#define alc268_pcm_analog_capture alc880_pcm_analog_capture
Takashi Iwai63300792008-01-24 15:31:36 +010011812#define alc268_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
Kailang Yanga361d842007-06-05 12:30:55 +020011813#define alc268_pcm_digital_playback alc880_pcm_digital_playback
11814
11815/*
11816 * BIOS auto configuration
11817 */
11818static int alc268_parse_auto_config(struct hda_codec *codec)
11819{
11820 struct alc_spec *spec = codec->spec;
11821 int err;
11822 static hda_nid_t alc268_ignore[] = { 0 };
11823
11824 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
11825 alc268_ignore);
11826 if (err < 0)
11827 return err;
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010011828 if (!spec->autocfg.line_outs) {
11829 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
11830 spec->multiout.max_channels = 2;
11831 spec->no_analog = 1;
11832 goto dig_only;
11833 }
Kailang Yanga361d842007-06-05 12:30:55 +020011834 return 0; /* can't find valid BIOS pin config */
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010011835 }
Kailang Yanga361d842007-06-05 12:30:55 +020011836 err = alc268_auto_create_multi_out_ctls(spec, &spec->autocfg);
11837 if (err < 0)
11838 return err;
11839 err = alc268_auto_create_analog_input_ctls(spec, &spec->autocfg);
11840 if (err < 0)
11841 return err;
11842
11843 spec->multiout.max_channels = 2;
11844
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010011845 dig_only:
Kailang Yanga361d842007-06-05 12:30:55 +020011846 /* digital only support output */
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010011847 if (spec->autocfg.dig_outs) {
Kailang Yanga361d842007-06-05 12:30:55 +020011848 spec->multiout.dig_out_nid = ALC268_DIGOUT_NID;
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010011849 spec->dig_out_type = spec->autocfg.dig_out_type[0];
11850 }
Takashi Iwai603c4012008-07-30 15:01:44 +020011851 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010011852 add_mixer(spec, spec->kctls.list);
Kailang Yanga361d842007-06-05 12:30:55 +020011853
Takashi Iwai892981f2009-03-02 08:04:35 +010011854 if (!spec->no_analog && spec->autocfg.speaker_pins[0] != 0x1d)
Takashi Iwaid88897e2008-10-31 15:01:37 +010011855 add_mixer(spec, alc268_beep_mixer);
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011856
Takashi Iwaid88897e2008-10-31 15:01:37 +010011857 add_verb(spec, alc268_volume_init_verbs);
Kailang Yanga361d842007-06-05 12:30:55 +020011858 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020011859 spec->input_mux = &spec->private_imux[0];
Kailang Yanga361d842007-06-05 12:30:55 +020011860
Takashi Iwai776e1842007-08-29 15:07:11 +020011861 err = alc_auto_add_mic_boost(codec);
11862 if (err < 0)
11863 return err;
11864
Kailang Yanga361d842007-06-05 12:30:55 +020011865 return 1;
11866}
11867
11868#define alc268_auto_init_multi_out alc882_auto_init_multi_out
11869#define alc268_auto_init_hp_out alc882_auto_init_hp_out
11870#define alc268_auto_init_analog_input alc882_auto_init_analog_input
11871
11872/* init callback for auto-configuration model -- overriding the default init */
11873static void alc268_auto_init(struct hda_codec *codec)
11874{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010011875 struct alc_spec *spec = codec->spec;
Kailang Yanga361d842007-06-05 12:30:55 +020011876 alc268_auto_init_multi_out(codec);
11877 alc268_auto_init_hp_out(codec);
11878 alc268_auto_init_mono_speaker_out(codec);
11879 alc268_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010011880 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020011881 alc_inithook(codec);
Kailang Yanga361d842007-06-05 12:30:55 +020011882}
11883
11884/*
11885 * configuration and preset
11886 */
11887static const char *alc268_models[ALC268_MODEL_LAST] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020011888 [ALC267_QUANTA_IL1] = "quanta-il1",
Kailang Yanga361d842007-06-05 12:30:55 +020011889 [ALC268_3ST] = "3stack",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020011890 [ALC268_TOSHIBA] = "toshiba",
Takashi Iwaid2738092007-08-16 14:59:45 +020011891 [ALC268_ACER] = "acer",
Takashi Iwaic238b4f2008-11-05 14:57:20 +010011892 [ALC268_ACER_DMIC] = "acer-dmic",
Kailang Yang8ef355d2008-08-26 13:10:22 +020011893 [ALC268_ACER_ASPIRE_ONE] = "acer-aspire",
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011894 [ALC268_DELL] = "dell",
Mirco Tischlerf12462c2008-02-04 12:33:59 +010011895 [ALC268_ZEPTO] = "zepto",
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010011896#ifdef CONFIG_SND_DEBUG
11897 [ALC268_TEST] = "test",
11898#endif
Kailang Yanga361d842007-06-05 12:30:55 +020011899 [ALC268_AUTO] = "auto",
11900};
11901
11902static struct snd_pci_quirk alc268_cfg_tbl[] = {
Takashi Iwaia0b8f7d2008-04-22 19:39:49 +020011903 SND_PCI_QUIRK(0x1025, 0x011e, "Acer Aspire 5720z", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011904 SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER),
Andy Shevchenkodafc8352008-01-25 11:53:50 +010011905 SND_PCI_QUIRK(0x1025, 0x012e, "Acer Aspire 5310", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011906 SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER),
Andy Shevchenko29a52c22008-01-24 17:29:00 +010011907 SND_PCI_QUIRK(0x1025, 0x0136, "Acer Aspire 5315", ALC268_ACER),
Kailang Yang8ef355d2008-08-26 13:10:22 +020011908 SND_PCI_QUIRK(0x1025, 0x015b, "Acer Aspire One",
11909 ALC268_ACER_ASPIRE_ONE),
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011910 SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL),
Takashi Iwai57d13922009-01-08 15:52:09 +010011911 SND_PCI_QUIRK(0x1028, 0x02b0, "Dell Inspiron Mini9", ALC268_DELL),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011912 SND_PCI_QUIRK(0x103c, 0x30cc, "TOSHIBA", ALC268_TOSHIBA),
Kailang Yanga361d842007-06-05 12:30:55 +020011913 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST),
Kailang Yangd1a991a2007-08-15 16:21:59 +020011914 SND_PCI_QUIRK(0x1179, 0xff10, "TOSHIBA A205", ALC268_TOSHIBA),
Takashi Iwai8e7f00f2007-09-07 10:58:58 +020011915 SND_PCI_QUIRK(0x1179, 0xff50, "TOSHIBA A305", ALC268_TOSHIBA),
Travis Place2346d0c2008-09-01 08:24:00 +020011916 SND_PCI_QUIRK(0x1179, 0xff64, "TOSHIBA L305", ALC268_TOSHIBA),
Tony Vroon378bd6a2008-06-04 12:08:30 +020011917 SND_PCI_QUIRK(0x14c0, 0x0025, "COMPAL IFL90/JFL-92", ALC268_TOSHIBA),
Takashi Iwaib875bf32007-09-06 15:00:27 +020011918 SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER),
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020011919 SND_PCI_QUIRK(0x152d, 0x0771, "Quanta IL1", ALC267_QUANTA_IL1),
Mirco Tischlerf12462c2008-02-04 12:33:59 +010011920 SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO),
Kailang Yanga361d842007-06-05 12:30:55 +020011921 {}
11922};
11923
11924static struct alc_config_preset alc268_presets[] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020011925 [ALC267_QUANTA_IL1] = {
Takashi Iwai22971e32009-02-10 11:56:44 +010011926 .mixers = { alc267_quanta_il1_mixer, alc268_beep_mixer },
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020011927 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
11928 alc267_quanta_il1_verbs },
11929 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11930 .dac_nids = alc268_dac_nids,
11931 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
11932 .adc_nids = alc268_adc_nids_alt,
11933 .hp_nid = 0x03,
11934 .num_channel_mode = ARRAY_SIZE(alc268_modes),
11935 .channel_mode = alc268_modes,
11936 .input_mux = &alc268_capture_source,
11937 .unsol_event = alc267_quanta_il1_unsol_event,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011938 .init_hook = alc267_quanta_il1_init_hook,
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020011939 },
Kailang Yanga361d842007-06-05 12:30:55 +020011940 [ALC268_3ST] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011941 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
11942 alc268_beep_mixer },
Kailang Yanga361d842007-06-05 12:30:55 +020011943 .init_verbs = { alc268_base_init_verbs },
11944 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11945 .dac_nids = alc268_dac_nids,
11946 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
11947 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010011948 .capsrc_nids = alc268_capsrc_nids,
Kailang Yanga361d842007-06-05 12:30:55 +020011949 .hp_nid = 0x03,
11950 .dig_out_nid = ALC268_DIGOUT_NID,
11951 .num_channel_mode = ARRAY_SIZE(alc268_modes),
11952 .channel_mode = alc268_modes,
11953 .input_mux = &alc268_capture_source,
11954 },
Kailang Yangd1a991a2007-08-15 16:21:59 +020011955 [ALC268_TOSHIBA] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020011956 .mixers = { alc268_toshiba_mixer, alc268_capture_alt_mixer,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011957 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020011958 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
11959 alc268_toshiba_verbs },
Kailang Yangd1a991a2007-08-15 16:21:59 +020011960 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11961 .dac_nids = alc268_dac_nids,
11962 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
11963 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010011964 .capsrc_nids = alc268_capsrc_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020011965 .hp_nid = 0x03,
11966 .num_channel_mode = ARRAY_SIZE(alc268_modes),
11967 .channel_mode = alc268_modes,
11968 .input_mux = &alc268_capture_source,
Takashi Iwaid2738092007-08-16 14:59:45 +020011969 .unsol_event = alc268_toshiba_unsol_event,
Takashi Iwai42171c12009-05-08 14:11:43 +020011970 .init_hook = alc268_toshiba_init_hook,
Takashi Iwaid2738092007-08-16 14:59:45 +020011971 },
11972 [ALC268_ACER] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011973 .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer,
11974 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020011975 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
11976 alc268_acer_verbs },
11977 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11978 .dac_nids = alc268_dac_nids,
11979 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
11980 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010011981 .capsrc_nids = alc268_capsrc_nids,
Takashi Iwaid2738092007-08-16 14:59:45 +020011982 .hp_nid = 0x02,
11983 .num_channel_mode = ARRAY_SIZE(alc268_modes),
11984 .channel_mode = alc268_modes,
Takashi Iwai0ccb5412008-03-06 16:58:35 +010011985 .input_mux = &alc268_acer_capture_source,
Takashi Iwaid2738092007-08-16 14:59:45 +020011986 .unsol_event = alc268_acer_unsol_event,
Takashi Iwai889c4392007-08-23 18:56:52 +020011987 .init_hook = alc268_acer_init_hook,
Kailang Yangd1a991a2007-08-15 16:21:59 +020011988 },
Takashi Iwaic238b4f2008-11-05 14:57:20 +010011989 [ALC268_ACER_DMIC] = {
11990 .mixers = { alc268_acer_dmic_mixer, alc268_capture_alt_mixer,
11991 alc268_beep_mixer },
11992 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
11993 alc268_acer_verbs },
11994 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11995 .dac_nids = alc268_dac_nids,
11996 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
11997 .adc_nids = alc268_adc_nids_alt,
11998 .capsrc_nids = alc268_capsrc_nids,
11999 .hp_nid = 0x02,
12000 .num_channel_mode = ARRAY_SIZE(alc268_modes),
12001 .channel_mode = alc268_modes,
12002 .input_mux = &alc268_acer_dmic_capture_source,
12003 .unsol_event = alc268_acer_unsol_event,
12004 .init_hook = alc268_acer_init_hook,
12005 },
Kailang Yang8ef355d2008-08-26 13:10:22 +020012006 [ALC268_ACER_ASPIRE_ONE] = {
12007 .mixers = { alc268_acer_aspire_one_mixer,
Takashi Iwai22971e32009-02-10 11:56:44 +010012008 alc268_beep_mixer,
12009 alc268_capture_alt_mixer },
Kailang Yang8ef355d2008-08-26 13:10:22 +020012010 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
12011 alc268_acer_aspire_one_verbs },
12012 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
12013 .dac_nids = alc268_dac_nids,
12014 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
12015 .adc_nids = alc268_adc_nids_alt,
12016 .capsrc_nids = alc268_capsrc_nids,
12017 .hp_nid = 0x03,
12018 .num_channel_mode = ARRAY_SIZE(alc268_modes),
12019 .channel_mode = alc268_modes,
12020 .input_mux = &alc268_acer_lc_capture_source,
12021 .unsol_event = alc268_acer_lc_unsol_event,
12022 .init_hook = alc268_acer_lc_init_hook,
12023 },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012024 [ALC268_DELL] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012025 .mixers = { alc268_dell_mixer, alc268_beep_mixer },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012026 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
12027 alc268_dell_verbs },
12028 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
12029 .dac_nids = alc268_dac_nids,
12030 .hp_nid = 0x02,
12031 .num_channel_mode = ARRAY_SIZE(alc268_modes),
12032 .channel_mode = alc268_modes,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020012033 .unsol_event = alc_sku_unsol_event,
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012034 .init_hook = alc268_dell_init_hook,
12035 .input_mux = &alc268_capture_source,
12036 },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010012037 [ALC268_ZEPTO] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012038 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
12039 alc268_beep_mixer },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010012040 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
12041 alc268_toshiba_verbs },
12042 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
12043 .dac_nids = alc268_dac_nids,
12044 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
12045 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010012046 .capsrc_nids = alc268_capsrc_nids,
Mirco Tischlerf12462c2008-02-04 12:33:59 +010012047 .hp_nid = 0x03,
12048 .dig_out_nid = ALC268_DIGOUT_NID,
12049 .num_channel_mode = ARRAY_SIZE(alc268_modes),
12050 .channel_mode = alc268_modes,
12051 .input_mux = &alc268_capture_source,
12052 .unsol_event = alc268_toshiba_unsol_event,
Takashi Iwai42171c12009-05-08 14:11:43 +020012053 .init_hook = alc268_toshiba_init_hook
Mirco Tischlerf12462c2008-02-04 12:33:59 +010012054 },
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010012055#ifdef CONFIG_SND_DEBUG
12056 [ALC268_TEST] = {
12057 .mixers = { alc268_test_mixer, alc268_capture_mixer },
12058 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
12059 alc268_volume_init_verbs },
12060 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
12061 .dac_nids = alc268_dac_nids,
12062 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
12063 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010012064 .capsrc_nids = alc268_capsrc_nids,
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010012065 .hp_nid = 0x03,
12066 .dig_out_nid = ALC268_DIGOUT_NID,
12067 .num_channel_mode = ARRAY_SIZE(alc268_modes),
12068 .channel_mode = alc268_modes,
12069 .input_mux = &alc268_capture_source,
12070 },
12071#endif
Kailang Yanga361d842007-06-05 12:30:55 +020012072};
12073
12074static int patch_alc268(struct hda_codec *codec)
12075{
12076 struct alc_spec *spec;
12077 int board_config;
Takashi Iwai22971e32009-02-10 11:56:44 +010012078 int i, has_beep, err;
Kailang Yanga361d842007-06-05 12:30:55 +020012079
12080 spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
12081 if (spec == NULL)
12082 return -ENOMEM;
12083
12084 codec->spec = spec;
12085
12086 board_config = snd_hda_check_board_config(codec, ALC268_MODEL_LAST,
12087 alc268_models,
12088 alc268_cfg_tbl);
12089
12090 if (board_config < 0 || board_config >= ALC268_MODEL_LAST) {
12091 printk(KERN_INFO "hda_codec: Unknown model for ALC268, "
12092 "trying auto-probe from BIOS...\n");
12093 board_config = ALC268_AUTO;
12094 }
12095
12096 if (board_config == ALC268_AUTO) {
12097 /* automatic parse from the BIOS config */
12098 err = alc268_parse_auto_config(codec);
12099 if (err < 0) {
12100 alc_free(codec);
12101 return err;
12102 } else if (!err) {
12103 printk(KERN_INFO
12104 "hda_codec: Cannot set up configuration "
12105 "from BIOS. Using base mode...\n");
12106 board_config = ALC268_3ST;
12107 }
12108 }
12109
12110 if (board_config != ALC268_AUTO)
12111 setup_preset(spec, &alc268_presets[board_config]);
12112
Kailang Yang2f893282008-05-27 12:14:47 +020012113 if (codec->vendor_id == 0x10ec0267) {
12114 spec->stream_name_analog = "ALC267 Analog";
12115 spec->stream_name_digital = "ALC267 Digital";
12116 } else {
12117 spec->stream_name_analog = "ALC268 Analog";
12118 spec->stream_name_digital = "ALC268 Digital";
12119 }
12120
Kailang Yanga361d842007-06-05 12:30:55 +020012121 spec->stream_analog_playback = &alc268_pcm_analog_playback;
12122 spec->stream_analog_capture = &alc268_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +010012123 spec->stream_analog_alt_capture = &alc268_pcm_analog_alt_capture;
Kailang Yanga361d842007-06-05 12:30:55 +020012124
Kailang Yanga361d842007-06-05 12:30:55 +020012125 spec->stream_digital_playback = &alc268_pcm_digital_playback;
12126
Takashi Iwai22971e32009-02-10 11:56:44 +010012127 has_beep = 0;
12128 for (i = 0; i < spec->num_mixers; i++) {
12129 if (spec->mixers[i] == alc268_beep_mixer) {
12130 has_beep = 1;
12131 break;
12132 }
12133 }
12134
12135 if (has_beep) {
12136 err = snd_hda_attach_beep_device(codec, 0x1);
12137 if (err < 0) {
12138 alc_free(codec);
12139 return err;
12140 }
12141 if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
12142 /* override the amp caps for beep generator */
12143 snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012144 (0x0c << AC_AMPCAP_OFFSET_SHIFT) |
12145 (0x0c << AC_AMPCAP_NUM_STEPS_SHIFT) |
12146 (0x07 << AC_AMPCAP_STEP_SIZE_SHIFT) |
12147 (0 << AC_AMPCAP_MUTE_SHIFT));
Takashi Iwai22971e32009-02-10 11:56:44 +010012148 }
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012149
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010012150 if (!spec->no_analog && !spec->adc_nids && spec->input_mux) {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012151 /* check whether NID 0x07 is valid */
12152 unsigned int wcap = get_wcaps(codec, 0x07);
Takashi Iwai85860c02008-02-19 15:00:15 +010012153 int i;
Kailang Yanga361d842007-06-05 12:30:55 +020012154
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012155 /* get type */
12156 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Takashi Iwai67ebcb02008-02-19 15:03:57 +010012157 if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012158 spec->adc_nids = alc268_adc_nids_alt;
12159 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt);
Takashi Iwaid88897e2008-10-31 15:01:37 +010012160 add_mixer(spec, alc268_capture_alt_mixer);
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012161 } else {
12162 spec->adc_nids = alc268_adc_nids;
12163 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids);
Takashi Iwaid88897e2008-10-31 15:01:37 +010012164 add_mixer(spec, alc268_capture_mixer);
Kailang Yanga361d842007-06-05 12:30:55 +020012165 }
Takashi Iwaie1406342008-02-11 18:32:32 +010012166 spec->capsrc_nids = alc268_capsrc_nids;
Takashi Iwai85860c02008-02-19 15:00:15 +010012167 /* set default input source */
12168 for (i = 0; i < spec->num_adc_nids; i++)
12169 snd_hda_codec_write_cache(codec, alc268_capsrc_nids[i],
12170 0, AC_VERB_SET_CONNECT_SEL,
12171 spec->input_mux->items[0].index);
Kailang Yanga361d842007-06-05 12:30:55 +020012172 }
Takashi Iwai2134ea42008-01-10 16:53:55 +010012173
12174 spec->vmaster_nid = 0x02;
12175
Kailang Yanga361d842007-06-05 12:30:55 +020012176 codec->patch_ops = alc_patch_ops;
12177 if (board_config == ALC268_AUTO)
12178 spec->init_hook = alc268_auto_init;
Kailang Yangea1fb292008-08-26 12:58:38 +020012179
Takashi Iwaidaead532008-11-28 12:55:36 +010012180 codec->proc_widget_hook = print_realtek_coef;
12181
Kailang Yanga361d842007-06-05 12:30:55 +020012182 return 0;
12183}
12184
12185/*
Kailang Yangf6a92242007-12-13 16:52:54 +010012186 * ALC269 channel source setting (2 channel)
12187 */
12188#define ALC269_DIGOUT_NID ALC880_DIGOUT_NID
12189
12190#define alc269_dac_nids alc260_dac_nids
12191
12192static hda_nid_t alc269_adc_nids[1] = {
12193 /* ADC1 */
Kailang Yangf53281e2008-07-18 12:36:43 +020012194 0x08,
12195};
12196
Takashi Iwaie01bf502008-08-21 16:25:07 +020012197static hda_nid_t alc269_capsrc_nids[1] = {
12198 0x23,
12199};
12200
12201/* NOTE: ADC2 (0x07) is connected from a recording *MIXER* (0x24),
12202 * not a mux!
12203 */
12204
Kailang Yangf53281e2008-07-18 12:36:43 +020012205static struct hda_input_mux alc269_eeepc_dmic_capture_source = {
12206 .num_items = 2,
12207 .items = {
12208 { "i-Mic", 0x5 },
12209 { "e-Mic", 0x0 },
12210 },
12211};
12212
12213static struct hda_input_mux alc269_eeepc_amic_capture_source = {
12214 .num_items = 2,
12215 .items = {
12216 { "i-Mic", 0x1 },
12217 { "e-Mic", 0x0 },
12218 },
Kailang Yangf6a92242007-12-13 16:52:54 +010012219};
12220
12221#define alc269_modes alc260_modes
12222#define alc269_capture_source alc880_lg_lw_capture_source
12223
12224static struct snd_kcontrol_new alc269_base_mixer[] = {
12225 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
12226 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
12227 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
12228 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
12229 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
12230 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
12231 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12232 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
12233 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
12234 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
12235 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
12236 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
12237 { } /* end */
12238};
12239
Kailang Yang60db6b52008-08-26 13:13:00 +020012240static struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = {
12241 /* output mixer control */
12242 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
12243 {
12244 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12245 .name = "Master Playback Switch",
12246 .info = snd_hda_mixer_amp_switch_info,
12247 .get = snd_hda_mixer_amp_switch_get,
12248 .put = alc268_acer_master_sw_put,
12249 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
12250 },
12251 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
12252 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
12253 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12254 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
12255 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
12256 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yang60db6b52008-08-26 13:13:00 +020012257 { }
12258};
12259
Tony Vroon64154832008-11-06 15:08:49 +000012260static struct snd_kcontrol_new alc269_lifebook_mixer[] = {
12261 /* output mixer control */
12262 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
12263 {
12264 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12265 .name = "Master Playback Switch",
12266 .info = snd_hda_mixer_amp_switch_info,
12267 .get = snd_hda_mixer_amp_switch_get,
12268 .put = alc268_acer_master_sw_put,
12269 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
12270 },
12271 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
12272 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
12273 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12274 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
12275 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
12276 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
12277 HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x0b, 0x03, HDA_INPUT),
12278 HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x0b, 0x03, HDA_INPUT),
12279 HDA_CODEC_VOLUME("Dock Mic Boost", 0x1b, 0, HDA_INPUT),
Tony Vroon64154832008-11-06 15:08:49 +000012280 { }
12281};
12282
Kailang Yangf53281e2008-07-18 12:36:43 +020012283/* bind volumes of both NID 0x0c and 0x0d */
12284static struct hda_bind_ctls alc269_epc_bind_vol = {
12285 .ops = &snd_hda_bind_vol,
12286 .values = {
12287 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
12288 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
12289 0
12290 },
12291};
12292
12293static struct snd_kcontrol_new alc269_eeepc_mixer[] = {
12294 HDA_CODEC_MUTE("iSpeaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
12295 HDA_BIND_VOL("LineOut Playback Volume", &alc269_epc_bind_vol),
12296 HDA_CODEC_MUTE("LineOut Playback Switch", 0x15, 0x0, HDA_OUTPUT),
12297 { } /* end */
12298};
12299
Kailang Yangf6a92242007-12-13 16:52:54 +010012300/* capture mixer elements */
Kailang Yangf53281e2008-07-18 12:36:43 +020012301static struct snd_kcontrol_new alc269_epc_capture_mixer[] = {
12302 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
12303 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
Takashi Iwai26f5df22008-11-03 17:39:46 +010012304 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12305 { } /* end */
12306};
12307
12308/* FSC amilo */
12309static struct snd_kcontrol_new alc269_fujitsu_mixer[] = {
12310 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
12311 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
12312 HDA_BIND_VOL("PCM Playback Volume", &alc269_epc_bind_vol),
Kailang Yangf53281e2008-07-18 12:36:43 +020012313 { } /* end */
12314};
12315
Kailang Yang60db6b52008-08-26 13:13:00 +020012316static struct hda_verb alc269_quanta_fl1_verbs[] = {
12317 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
12318 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12319 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12320 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12321 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
12322 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12323 { }
12324};
12325
Tony Vroon64154832008-11-06 15:08:49 +000012326static struct hda_verb alc269_lifebook_verbs[] = {
12327 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
12328 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
12329 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12330 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12331 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12332 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12333 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12334 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12335 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
12336 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12337 { }
12338};
12339
Kailang Yang60db6b52008-08-26 13:13:00 +020012340/* toggle speaker-output according to the hp-jack state */
12341static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec)
12342{
12343 unsigned int present;
12344 unsigned char bits;
12345
12346 present = snd_hda_codec_read(codec, 0x15, 0,
12347 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
12348 bits = present ? AMP_IN_MUTE(0) : 0;
12349 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
12350 AMP_IN_MUTE(0), bits);
12351 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
12352 AMP_IN_MUTE(0), bits);
12353
12354 snd_hda_codec_write(codec, 0x20, 0,
12355 AC_VERB_SET_COEF_INDEX, 0x0c);
12356 snd_hda_codec_write(codec, 0x20, 0,
12357 AC_VERB_SET_PROC_COEF, 0x680);
12358
12359 snd_hda_codec_write(codec, 0x20, 0,
12360 AC_VERB_SET_COEF_INDEX, 0x0c);
12361 snd_hda_codec_write(codec, 0x20, 0,
12362 AC_VERB_SET_PROC_COEF, 0x480);
12363}
12364
Tony Vroon64154832008-11-06 15:08:49 +000012365/* toggle speaker-output according to the hp-jacks state */
12366static void alc269_lifebook_speaker_automute(struct hda_codec *codec)
12367{
12368 unsigned int present;
12369 unsigned char bits;
12370
12371 /* Check laptop headphone socket */
12372 present = snd_hda_codec_read(codec, 0x15, 0,
12373 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
12374
12375 /* Check port replicator headphone socket */
12376 present |= snd_hda_codec_read(codec, 0x1a, 0,
12377 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
12378
12379 bits = present ? AMP_IN_MUTE(0) : 0;
12380 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
12381 AMP_IN_MUTE(0), bits);
12382 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
12383 AMP_IN_MUTE(0), bits);
12384
12385 snd_hda_codec_write(codec, 0x20, 0,
12386 AC_VERB_SET_COEF_INDEX, 0x0c);
12387 snd_hda_codec_write(codec, 0x20, 0,
12388 AC_VERB_SET_PROC_COEF, 0x680);
12389
12390 snd_hda_codec_write(codec, 0x20, 0,
12391 AC_VERB_SET_COEF_INDEX, 0x0c);
12392 snd_hda_codec_write(codec, 0x20, 0,
12393 AC_VERB_SET_PROC_COEF, 0x480);
12394}
12395
Kailang Yang60db6b52008-08-26 13:13:00 +020012396static void alc269_quanta_fl1_mic_automute(struct hda_codec *codec)
12397{
12398 unsigned int present;
12399
12400 present = snd_hda_codec_read(codec, 0x18, 0,
12401 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
12402 snd_hda_codec_write(codec, 0x23, 0,
12403 AC_VERB_SET_CONNECT_SEL, present ? 0x0 : 0x1);
12404}
12405
Tony Vroon64154832008-11-06 15:08:49 +000012406static void alc269_lifebook_mic_autoswitch(struct hda_codec *codec)
12407{
12408 unsigned int present_laptop;
12409 unsigned int present_dock;
12410
12411 present_laptop = snd_hda_codec_read(codec, 0x18, 0,
12412 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
12413
12414 present_dock = snd_hda_codec_read(codec, 0x1b, 0,
12415 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
12416
12417 /* Laptop mic port overrides dock mic port, design decision */
12418 if (present_dock)
12419 snd_hda_codec_write(codec, 0x23, 0,
12420 AC_VERB_SET_CONNECT_SEL, 0x3);
12421 if (present_laptop)
12422 snd_hda_codec_write(codec, 0x23, 0,
12423 AC_VERB_SET_CONNECT_SEL, 0x0);
12424 if (!present_dock && !present_laptop)
12425 snd_hda_codec_write(codec, 0x23, 0,
12426 AC_VERB_SET_CONNECT_SEL, 0x1);
12427}
12428
Kailang Yang60db6b52008-08-26 13:13:00 +020012429static void alc269_quanta_fl1_unsol_event(struct hda_codec *codec,
12430 unsigned int res)
12431{
12432 if ((res >> 26) == ALC880_HP_EVENT)
12433 alc269_quanta_fl1_speaker_automute(codec);
12434 if ((res >> 26) == ALC880_MIC_EVENT)
12435 alc269_quanta_fl1_mic_automute(codec);
12436}
12437
Tony Vroon64154832008-11-06 15:08:49 +000012438static void alc269_lifebook_unsol_event(struct hda_codec *codec,
12439 unsigned int res)
12440{
12441 if ((res >> 26) == ALC880_HP_EVENT)
12442 alc269_lifebook_speaker_automute(codec);
12443 if ((res >> 26) == ALC880_MIC_EVENT)
12444 alc269_lifebook_mic_autoswitch(codec);
12445}
12446
Kailang Yang60db6b52008-08-26 13:13:00 +020012447static void alc269_quanta_fl1_init_hook(struct hda_codec *codec)
12448{
12449 alc269_quanta_fl1_speaker_automute(codec);
12450 alc269_quanta_fl1_mic_automute(codec);
12451}
12452
Tony Vroon64154832008-11-06 15:08:49 +000012453static void alc269_lifebook_init_hook(struct hda_codec *codec)
12454{
12455 alc269_lifebook_speaker_automute(codec);
12456 alc269_lifebook_mic_autoswitch(codec);
12457}
12458
Kailang Yang60db6b52008-08-26 13:13:00 +020012459static struct hda_verb alc269_eeepc_dmic_init_verbs[] = {
12460 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
12461 {0x23, AC_VERB_SET_CONNECT_SEL, 0x05},
12462 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
12463 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
12464 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12465 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
12466 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
12467 {}
12468};
12469
12470static struct hda_verb alc269_eeepc_amic_init_verbs[] = {
12471 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
12472 {0x23, AC_VERB_SET_CONNECT_SEL, 0x01},
12473 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
12474 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x701b | (0x00 << 8))},
12475 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
12476 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
12477 {}
12478};
12479
12480/* toggle speaker-output according to the hp-jack state */
12481static void alc269_speaker_automute(struct hda_codec *codec)
12482{
12483 unsigned int present;
12484 unsigned char bits;
12485
12486 present = snd_hda_codec_read(codec, 0x15, 0,
12487 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
12488 bits = present ? AMP_IN_MUTE(0) : 0;
12489 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
12490 AMP_IN_MUTE(0), bits);
12491 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
12492 AMP_IN_MUTE(0), bits);
12493}
12494
12495static void alc269_eeepc_dmic_automute(struct hda_codec *codec)
12496{
12497 unsigned int present;
12498
12499 present = snd_hda_codec_read(codec, 0x18, 0,
12500 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
12501 snd_hda_codec_write(codec, 0x23, 0,
12502 AC_VERB_SET_CONNECT_SEL, (present ? 0 : 5));
12503}
12504
12505static void alc269_eeepc_amic_automute(struct hda_codec *codec)
12506{
12507 unsigned int present;
12508
12509 present = snd_hda_codec_read(codec, 0x18, 0,
12510 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
12511 snd_hda_codec_write(codec, 0x24, 0, AC_VERB_SET_AMP_GAIN_MUTE,
12512 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
12513 snd_hda_codec_write(codec, 0x24, 0, AC_VERB_SET_AMP_GAIN_MUTE,
12514 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
12515}
12516
12517/* unsolicited event for HP jack sensing */
12518static void alc269_eeepc_dmic_unsol_event(struct hda_codec *codec,
12519 unsigned int res)
12520{
12521 if ((res >> 26) == ALC880_HP_EVENT)
12522 alc269_speaker_automute(codec);
12523
12524 if ((res >> 26) == ALC880_MIC_EVENT)
12525 alc269_eeepc_dmic_automute(codec);
12526}
12527
12528static void alc269_eeepc_dmic_inithook(struct hda_codec *codec)
12529{
12530 alc269_speaker_automute(codec);
12531 alc269_eeepc_dmic_automute(codec);
12532}
12533
12534/* unsolicited event for HP jack sensing */
12535static void alc269_eeepc_amic_unsol_event(struct hda_codec *codec,
12536 unsigned int res)
12537{
12538 if ((res >> 26) == ALC880_HP_EVENT)
12539 alc269_speaker_automute(codec);
12540
12541 if ((res >> 26) == ALC880_MIC_EVENT)
12542 alc269_eeepc_amic_automute(codec);
12543}
12544
12545static void alc269_eeepc_amic_inithook(struct hda_codec *codec)
12546{
12547 alc269_speaker_automute(codec);
12548 alc269_eeepc_amic_automute(codec);
12549}
12550
Kailang Yangf6a92242007-12-13 16:52:54 +010012551/*
12552 * generic initialization of ADC, input mixers and output mixers
12553 */
12554static struct hda_verb alc269_init_verbs[] = {
12555 /*
12556 * Unmute ADC0 and set the default input to mic-in
12557 */
Kailang Yang60db6b52008-08-26 13:13:00 +020012558 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangf6a92242007-12-13 16:52:54 +010012559
12560 /* Mute input amps (PCBeep, Line In, Mic 1 & Mic 2) of the
12561 * analog-loopback mixer widget
12562 * Note: PASD motherboards uses the Line In 2 as the input for
12563 * front panel mic (mic 2)
12564 */
12565 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
12566 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12567 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12568 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12569 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12570 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
12571
12572 /*
12573 * Set up output mixers (0x0c - 0x0e)
12574 */
12575 /* set vol=0 to output mixers */
12576 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12577 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12578
12579 /* set up input amps for analog loopback */
12580 /* Amp Indices: DAC = 0, mixer = 1 */
12581 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12582 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12583 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12584 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12585 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12586 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12587
12588 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12589 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12590 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12591 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
12592 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
12593 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12594 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12595
12596 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12597 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12598 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12599 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12600 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12601 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12602 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12603
12604 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
12605 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
12606
12607 /* FIXME: use matrix-type input source selection */
12608 /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
12609 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yang60db6b52008-08-26 13:13:00 +020012610 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12611 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangf6a92242007-12-13 16:52:54 +010012612 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12613 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12614
12615 /* set EAPD */
12616 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
12617 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
12618 { }
12619};
12620
12621/* add playback controls from the parsed DAC table */
12622static int alc269_auto_create_multi_out_ctls(struct alc_spec *spec,
12623 const struct auto_pin_cfg *cfg)
12624{
12625 hda_nid_t nid;
12626 int err;
12627
12628 spec->multiout.num_dacs = 1; /* only use one dac */
12629 spec->multiout.dac_nids = spec->private_dac_nids;
12630 spec->multiout.dac_nids[0] = 2;
12631
12632 nid = cfg->line_out_pins[0];
12633 if (nid) {
12634 err = add_control(spec, ALC_CTL_WIDGET_VOL,
12635 "Front Playback Volume",
12636 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT));
12637 if (err < 0)
12638 return err;
12639 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
12640 "Front Playback Switch",
12641 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
12642 if (err < 0)
12643 return err;
12644 }
12645
12646 nid = cfg->speaker_pins[0];
12647 if (nid) {
12648 if (!cfg->line_out_pins[0]) {
12649 err = add_control(spec, ALC_CTL_WIDGET_VOL,
12650 "Speaker Playback Volume",
12651 HDA_COMPOSE_AMP_VAL(0x02, 3, 0,
12652 HDA_OUTPUT));
12653 if (err < 0)
12654 return err;
12655 }
12656 if (nid == 0x16) {
12657 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
12658 "Speaker Playback Switch",
12659 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
12660 HDA_OUTPUT));
12661 if (err < 0)
12662 return err;
12663 } else {
12664 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
12665 "Speaker Playback Switch",
12666 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
12667 HDA_OUTPUT));
12668 if (err < 0)
12669 return err;
12670 }
12671 }
12672 nid = cfg->hp_pins[0];
12673 if (nid) {
12674 /* spec->multiout.hp_nid = 2; */
12675 if (!cfg->line_out_pins[0] && !cfg->speaker_pins[0]) {
12676 err = add_control(spec, ALC_CTL_WIDGET_VOL,
12677 "Headphone Playback Volume",
12678 HDA_COMPOSE_AMP_VAL(0x02, 3, 0,
12679 HDA_OUTPUT));
12680 if (err < 0)
12681 return err;
12682 }
12683 if (nid == 0x16) {
12684 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
12685 "Headphone Playback Switch",
12686 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
12687 HDA_OUTPUT));
12688 if (err < 0)
12689 return err;
12690 } else {
12691 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
12692 "Headphone Playback Switch",
12693 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
12694 HDA_OUTPUT));
12695 if (err < 0)
12696 return err;
12697 }
12698 }
12699 return 0;
12700}
12701
Takashi Iwaiee956e02008-10-31 17:16:31 +010012702static int alc269_auto_create_analog_input_ctls(struct alc_spec *spec,
12703 const struct auto_pin_cfg *cfg)
12704{
12705 int err;
12706
12707 err = alc880_auto_create_analog_input_ctls(spec, cfg);
12708 if (err < 0)
12709 return err;
12710 /* digital-mic input pin is excluded in alc880_auto_create..()
12711 * because it's under 0x18
12712 */
12713 if (cfg->input_pins[AUTO_PIN_MIC] == 0x12 ||
12714 cfg->input_pins[AUTO_PIN_FRONT_MIC] == 0x12) {
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020012715 struct hda_input_mux *imux = &spec->private_imux[0];
Takashi Iwaiee956e02008-10-31 17:16:31 +010012716 imux->items[imux->num_items].label = "Int Mic";
12717 imux->items[imux->num_items].index = 0x05;
12718 imux->num_items++;
12719 }
12720 return 0;
12721}
Kailang Yangf6a92242007-12-13 16:52:54 +010012722
12723#ifdef CONFIG_SND_HDA_POWER_SAVE
12724#define alc269_loopbacks alc880_loopbacks
12725#endif
12726
12727/* pcm configuration: identiacal with ALC880 */
12728#define alc269_pcm_analog_playback alc880_pcm_analog_playback
12729#define alc269_pcm_analog_capture alc880_pcm_analog_capture
12730#define alc269_pcm_digital_playback alc880_pcm_digital_playback
12731#define alc269_pcm_digital_capture alc880_pcm_digital_capture
12732
Takashi Iwaif03d3112009-03-05 14:18:16 +010012733static struct hda_pcm_stream alc269_44k_pcm_analog_playback = {
12734 .substreams = 1,
12735 .channels_min = 2,
12736 .channels_max = 8,
12737 .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
12738 /* NID is set in alc_build_pcms */
12739 .ops = {
12740 .open = alc880_playback_pcm_open,
12741 .prepare = alc880_playback_pcm_prepare,
12742 .cleanup = alc880_playback_pcm_cleanup
12743 },
12744};
12745
12746static struct hda_pcm_stream alc269_44k_pcm_analog_capture = {
12747 .substreams = 1,
12748 .channels_min = 2,
12749 .channels_max = 2,
12750 .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
12751 /* NID is set in alc_build_pcms */
12752};
12753
Kailang Yangf6a92242007-12-13 16:52:54 +010012754/*
12755 * BIOS auto configuration
12756 */
12757static int alc269_parse_auto_config(struct hda_codec *codec)
12758{
12759 struct alc_spec *spec = codec->spec;
Takashi Iwaicfb9fb52009-02-06 17:34:03 +010012760 int err;
Kailang Yangf6a92242007-12-13 16:52:54 +010012761 static hda_nid_t alc269_ignore[] = { 0x1d, 0 };
12762
12763 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
12764 alc269_ignore);
12765 if (err < 0)
12766 return err;
12767
12768 err = alc269_auto_create_multi_out_ctls(spec, &spec->autocfg);
12769 if (err < 0)
12770 return err;
12771 err = alc269_auto_create_analog_input_ctls(spec, &spec->autocfg);
12772 if (err < 0)
12773 return err;
12774
12775 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
12776
Takashi Iwai0852d7a2009-02-11 11:35:15 +010012777 if (spec->autocfg.dig_outs)
Kailang Yangf6a92242007-12-13 16:52:54 +010012778 spec->multiout.dig_out_nid = ALC269_DIGOUT_NID;
12779
Takashi Iwai603c4012008-07-30 15:01:44 +020012780 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010012781 add_mixer(spec, spec->kctls.list);
Kailang Yangf6a92242007-12-13 16:52:54 +010012782
Takashi Iwaid88897e2008-10-31 15:01:37 +010012783 add_verb(spec, alc269_init_verbs);
Kailang Yangf6a92242007-12-13 16:52:54 +010012784 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020012785 spec->input_mux = &spec->private_imux[0];
Takashi Iwaie01bf502008-08-21 16:25:07 +020012786 /* set default input source */
12787 snd_hda_codec_write_cache(codec, alc269_capsrc_nids[0],
12788 0, AC_VERB_SET_CONNECT_SEL,
12789 spec->input_mux->items[0].index);
Kailang Yangf6a92242007-12-13 16:52:54 +010012790
12791 err = alc_auto_add_mic_boost(codec);
12792 if (err < 0)
12793 return err;
12794
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010012795 if (!spec->cap_mixer && !spec->no_analog)
Takashi Iwaif9e336f2008-10-31 16:37:07 +010012796 set_capture_mixer(spec);
Kailang Yangf53281e2008-07-18 12:36:43 +020012797
Kailang Yangf6a92242007-12-13 16:52:54 +010012798 return 1;
12799}
12800
12801#define alc269_auto_init_multi_out alc882_auto_init_multi_out
12802#define alc269_auto_init_hp_out alc882_auto_init_hp_out
12803#define alc269_auto_init_analog_input alc882_auto_init_analog_input
12804
12805
12806/* init callback for auto-configuration model -- overriding the default init */
12807static void alc269_auto_init(struct hda_codec *codec)
12808{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012809 struct alc_spec *spec = codec->spec;
Kailang Yangf6a92242007-12-13 16:52:54 +010012810 alc269_auto_init_multi_out(codec);
12811 alc269_auto_init_hp_out(codec);
12812 alc269_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012813 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020012814 alc_inithook(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010012815}
12816
12817/*
12818 * configuration and preset
12819 */
12820static const char *alc269_models[ALC269_MODEL_LAST] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020012821 [ALC269_BASIC] = "basic",
Takashi Iwai2922c9a2008-08-27 18:12:42 +020012822 [ALC269_QUANTA_FL1] = "quanta",
12823 [ALC269_ASUS_EEEPC_P703] = "eeepc-p703",
Takashi Iwai26f5df22008-11-03 17:39:46 +010012824 [ALC269_ASUS_EEEPC_P901] = "eeepc-p901",
Tony Vroon64154832008-11-06 15:08:49 +000012825 [ALC269_FUJITSU] = "fujitsu",
12826 [ALC269_LIFEBOOK] = "lifebook"
Kailang Yangf6a92242007-12-13 16:52:54 +010012827};
12828
12829static struct snd_pci_quirk alc269_cfg_tbl[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020012830 SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_QUANTA_FL1),
Kailang Yangf53281e2008-07-18 12:36:43 +020012831 SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A",
12832 ALC269_ASUS_EEEPC_P703),
Kailang Yang622e84c2009-04-21 07:39:04 +020012833 SND_PCI_QUIRK(0x1043, 0x1883, "ASUS F81Se", ALC269_ASUS_EEEPC_P703),
12834 SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS F5Q", ALC269_ASUS_EEEPC_P703),
12835 SND_PCI_QUIRK(0x1043, 0x1723, "ASUS P80", ALC269_ASUS_EEEPC_P703),
12836 SND_PCI_QUIRK(0x1043, 0x1773, "ASUS U20A", ALC269_ASUS_EEEPC_P703),
12837 SND_PCI_QUIRK(0x1043, 0x1743, "ASUS U80", ALC269_ASUS_EEEPC_P703),
12838 SND_PCI_QUIRK(0x1043, 0x1653, "ASUS U50", ALC269_ASUS_EEEPC_P703),
Kailang Yangf53281e2008-07-18 12:36:43 +020012839 SND_PCI_QUIRK(0x1043, 0x831a, "ASUS Eeepc P901",
12840 ALC269_ASUS_EEEPC_P901),
Kailang Yang60db6b52008-08-26 13:13:00 +020012841 SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101",
12842 ALC269_ASUS_EEEPC_P901),
Kailang Yang622e84c2009-04-21 07:39:04 +020012843 SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_ASUS_EEEPC_P901),
Takashi Iwai26f5df22008-11-03 17:39:46 +010012844 SND_PCI_QUIRK(0x1734, 0x115d, "FSC Amilo", ALC269_FUJITSU),
Tony Vroon64154832008-11-06 15:08:49 +000012845 SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook ICH9M-based", ALC269_LIFEBOOK),
Kailang Yangf6a92242007-12-13 16:52:54 +010012846 {}
12847};
12848
12849static struct alc_config_preset alc269_presets[] = {
12850 [ALC269_BASIC] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010012851 .mixers = { alc269_base_mixer },
Kailang Yangf6a92242007-12-13 16:52:54 +010012852 .init_verbs = { alc269_init_verbs },
12853 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
12854 .dac_nids = alc269_dac_nids,
12855 .hp_nid = 0x03,
12856 .num_channel_mode = ARRAY_SIZE(alc269_modes),
12857 .channel_mode = alc269_modes,
12858 .input_mux = &alc269_capture_source,
12859 },
Kailang Yang60db6b52008-08-26 13:13:00 +020012860 [ALC269_QUANTA_FL1] = {
12861 .mixers = { alc269_quanta_fl1_mixer },
12862 .init_verbs = { alc269_init_verbs, alc269_quanta_fl1_verbs },
12863 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
12864 .dac_nids = alc269_dac_nids,
12865 .hp_nid = 0x03,
12866 .num_channel_mode = ARRAY_SIZE(alc269_modes),
12867 .channel_mode = alc269_modes,
12868 .input_mux = &alc269_capture_source,
12869 .unsol_event = alc269_quanta_fl1_unsol_event,
12870 .init_hook = alc269_quanta_fl1_init_hook,
12871 },
Kailang Yangf53281e2008-07-18 12:36:43 +020012872 [ALC269_ASUS_EEEPC_P703] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010012873 .mixers = { alc269_eeepc_mixer },
12874 .cap_mixer = alc269_epc_capture_mixer,
Kailang Yangf53281e2008-07-18 12:36:43 +020012875 .init_verbs = { alc269_init_verbs,
12876 alc269_eeepc_amic_init_verbs },
12877 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
12878 .dac_nids = alc269_dac_nids,
12879 .hp_nid = 0x03,
12880 .num_channel_mode = ARRAY_SIZE(alc269_modes),
12881 .channel_mode = alc269_modes,
12882 .input_mux = &alc269_eeepc_amic_capture_source,
12883 .unsol_event = alc269_eeepc_amic_unsol_event,
12884 .init_hook = alc269_eeepc_amic_inithook,
12885 },
12886 [ALC269_ASUS_EEEPC_P901] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010012887 .mixers = { alc269_eeepc_mixer },
12888 .cap_mixer = alc269_epc_capture_mixer,
Kailang Yangf53281e2008-07-18 12:36:43 +020012889 .init_verbs = { alc269_init_verbs,
12890 alc269_eeepc_dmic_init_verbs },
12891 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
12892 .dac_nids = alc269_dac_nids,
12893 .hp_nid = 0x03,
12894 .num_channel_mode = ARRAY_SIZE(alc269_modes),
12895 .channel_mode = alc269_modes,
12896 .input_mux = &alc269_eeepc_dmic_capture_source,
12897 .unsol_event = alc269_eeepc_dmic_unsol_event,
12898 .init_hook = alc269_eeepc_dmic_inithook,
12899 },
Takashi Iwai26f5df22008-11-03 17:39:46 +010012900 [ALC269_FUJITSU] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010012901 .mixers = { alc269_fujitsu_mixer },
Takashi Iwai26f5df22008-11-03 17:39:46 +010012902 .cap_mixer = alc269_epc_capture_mixer,
12903 .init_verbs = { alc269_init_verbs,
12904 alc269_eeepc_dmic_init_verbs },
12905 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
12906 .dac_nids = alc269_dac_nids,
12907 .hp_nid = 0x03,
12908 .num_channel_mode = ARRAY_SIZE(alc269_modes),
12909 .channel_mode = alc269_modes,
12910 .input_mux = &alc269_eeepc_dmic_capture_source,
12911 .unsol_event = alc269_eeepc_dmic_unsol_event,
12912 .init_hook = alc269_eeepc_dmic_inithook,
12913 },
Tony Vroon64154832008-11-06 15:08:49 +000012914 [ALC269_LIFEBOOK] = {
12915 .mixers = { alc269_lifebook_mixer },
12916 .init_verbs = { alc269_init_verbs, alc269_lifebook_verbs },
12917 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
12918 .dac_nids = alc269_dac_nids,
12919 .hp_nid = 0x03,
12920 .num_channel_mode = ARRAY_SIZE(alc269_modes),
12921 .channel_mode = alc269_modes,
12922 .input_mux = &alc269_capture_source,
12923 .unsol_event = alc269_lifebook_unsol_event,
12924 .init_hook = alc269_lifebook_init_hook,
12925 },
Kailang Yangf6a92242007-12-13 16:52:54 +010012926};
12927
12928static int patch_alc269(struct hda_codec *codec)
12929{
12930 struct alc_spec *spec;
12931 int board_config;
12932 int err;
12933
12934 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
12935 if (spec == NULL)
12936 return -ENOMEM;
12937
12938 codec->spec = spec;
12939
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020012940 alc_fix_pll_init(codec, 0x20, 0x04, 15);
12941
Kailang Yangf6a92242007-12-13 16:52:54 +010012942 board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST,
12943 alc269_models,
12944 alc269_cfg_tbl);
12945
12946 if (board_config < 0) {
12947 printk(KERN_INFO "hda_codec: Unknown model for ALC269, "
12948 "trying auto-probe from BIOS...\n");
12949 board_config = ALC269_AUTO;
12950 }
12951
12952 if (board_config == ALC269_AUTO) {
12953 /* automatic parse from the BIOS config */
12954 err = alc269_parse_auto_config(codec);
12955 if (err < 0) {
12956 alc_free(codec);
12957 return err;
12958 } else if (!err) {
12959 printk(KERN_INFO
12960 "hda_codec: Cannot set up configuration "
12961 "from BIOS. Using base mode...\n");
12962 board_config = ALC269_BASIC;
12963 }
12964 }
12965
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090012966 err = snd_hda_attach_beep_device(codec, 0x1);
12967 if (err < 0) {
12968 alc_free(codec);
12969 return err;
12970 }
12971
Kailang Yangf6a92242007-12-13 16:52:54 +010012972 if (board_config != ALC269_AUTO)
12973 setup_preset(spec, &alc269_presets[board_config]);
12974
12975 spec->stream_name_analog = "ALC269 Analog";
Takashi Iwaif03d3112009-03-05 14:18:16 +010012976 if (codec->subsystem_id == 0x17aa3bf8) {
12977 /* Due to a hardware problem on Lenovo Ideadpad, we need to
12978 * fix the sample rate of analog I/O to 44.1kHz
12979 */
12980 spec->stream_analog_playback = &alc269_44k_pcm_analog_playback;
12981 spec->stream_analog_capture = &alc269_44k_pcm_analog_capture;
12982 } else {
12983 spec->stream_analog_playback = &alc269_pcm_analog_playback;
12984 spec->stream_analog_capture = &alc269_pcm_analog_capture;
12985 }
Kailang Yangf6a92242007-12-13 16:52:54 +010012986 spec->stream_name_digital = "ALC269 Digital";
12987 spec->stream_digital_playback = &alc269_pcm_digital_playback;
12988 spec->stream_digital_capture = &alc269_pcm_digital_capture;
12989
12990 spec->adc_nids = alc269_adc_nids;
12991 spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids);
Takashi Iwaie01bf502008-08-21 16:25:07 +020012992 spec->capsrc_nids = alc269_capsrc_nids;
Takashi Iwaif9e336f2008-10-31 16:37:07 +010012993 if (!spec->cap_mixer)
12994 set_capture_mixer(spec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010012995 set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
Kailang Yangf6a92242007-12-13 16:52:54 +010012996
12997 codec->patch_ops = alc_patch_ops;
12998 if (board_config == ALC269_AUTO)
12999 spec->init_hook = alc269_auto_init;
13000#ifdef CONFIG_SND_HDA_POWER_SAVE
13001 if (!spec->loopback.amplist)
13002 spec->loopback.amplist = alc269_loopbacks;
13003#endif
Takashi Iwaidaead532008-11-28 12:55:36 +010013004 codec->proc_widget_hook = print_realtek_coef;
Kailang Yangf6a92242007-12-13 16:52:54 +010013005
13006 return 0;
13007}
13008
13009/*
Kailang Yangdf694da2005-12-05 19:42:22 +010013010 * ALC861 channel source setting (2/6 channel selection for 3-stack)
13011 */
13012
13013/*
13014 * set the path ways for 2 channel output
13015 * need to set the codec line out and mic 1 pin widgets to inputs
13016 */
13017static struct hda_verb alc861_threestack_ch2_init[] = {
13018 /* set pin widget 1Ah (line in) for input */
13019 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013020 /* set pin widget 18h (mic1/2) for input, for mic also enable
13021 * the vref
13022 */
Kailang Yangdf694da2005-12-05 19:42:22 +010013023 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13024
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013025 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
13026#if 0
13027 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
13028 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
13029#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010013030 { } /* end */
13031};
13032/*
13033 * 6ch mode
13034 * need to set the codec line out and mic 1 pin widgets to outputs
13035 */
13036static struct hda_verb alc861_threestack_ch6_init[] = {
13037 /* set pin widget 1Ah (line in) for output (Back Surround)*/
13038 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13039 /* set pin widget 18h (mic1) for output (CLFE)*/
13040 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13041
13042 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013043 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010013044
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013045 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
13046#if 0
13047 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
13048 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
13049#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010013050 { } /* end */
13051};
13052
13053static struct hda_channel_mode alc861_threestack_modes[2] = {
13054 { 2, alc861_threestack_ch2_init },
13055 { 6, alc861_threestack_ch6_init },
13056};
Takashi Iwai22309c32006-08-09 16:57:28 +020013057/* Set mic1 as input and unmute the mixer */
13058static struct hda_verb alc861_uniwill_m31_ch2_init[] = {
13059 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13060 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
13061 { } /* end */
13062};
13063/* Set mic1 as output and mute mixer */
13064static struct hda_verb alc861_uniwill_m31_ch4_init[] = {
13065 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13066 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
13067 { } /* end */
13068};
13069
13070static struct hda_channel_mode alc861_uniwill_m31_modes[2] = {
13071 { 2, alc861_uniwill_m31_ch2_init },
13072 { 4, alc861_uniwill_m31_ch4_init },
13073};
Kailang Yangdf694da2005-12-05 19:42:22 +010013074
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013075/* Set mic1 and line-in as input and unmute the mixer */
13076static struct hda_verb alc861_asus_ch2_init[] = {
13077 /* set pin widget 1Ah (line in) for input */
13078 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013079 /* set pin widget 18h (mic1/2) for input, for mic also enable
13080 * the vref
13081 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013082 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13083
13084 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
13085#if 0
13086 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
13087 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
13088#endif
13089 { } /* end */
13090};
13091/* Set mic1 nad line-in as output and mute mixer */
13092static struct hda_verb alc861_asus_ch6_init[] = {
13093 /* set pin widget 1Ah (line in) for output (Back Surround)*/
13094 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13095 /* { 0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
13096 /* set pin widget 18h (mic1) for output (CLFE)*/
13097 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13098 /* { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
13099 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
13100 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
13101
13102 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
13103#if 0
13104 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
13105 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
13106#endif
13107 { } /* end */
13108};
13109
13110static struct hda_channel_mode alc861_asus_modes[2] = {
13111 { 2, alc861_asus_ch2_init },
13112 { 6, alc861_asus_ch6_init },
13113};
13114
Kailang Yangdf694da2005-12-05 19:42:22 +010013115/* patch-ALC861 */
13116
13117static struct snd_kcontrol_new alc861_base_mixer[] = {
13118 /* output mixer control */
13119 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
13120 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
13121 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
13122 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
13123 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
13124
13125 /*Input mixer control */
13126 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
13127 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
13128 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
13129 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
13130 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
13131 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
13132 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
13133 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
13134 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
13135 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013136
Kailang Yangdf694da2005-12-05 19:42:22 +010013137 { } /* end */
13138};
13139
13140static struct snd_kcontrol_new alc861_3ST_mixer[] = {
13141 /* output mixer control */
13142 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
13143 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
13144 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
13145 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
13146 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
13147
13148 /* Input mixer control */
13149 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
13150 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
13151 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
13152 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
13153 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
13154 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
13155 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
13156 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
13157 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
13158 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013159
Kailang Yangdf694da2005-12-05 19:42:22 +010013160 {
13161 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13162 .name = "Channel Mode",
13163 .info = alc_ch_mode_info,
13164 .get = alc_ch_mode_get,
13165 .put = alc_ch_mode_put,
13166 .private_value = ARRAY_SIZE(alc861_threestack_modes),
13167 },
13168 { } /* end */
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013169};
13170
Takashi Iwaid1d985f2006-11-23 19:27:12 +010013171static struct snd_kcontrol_new alc861_toshiba_mixer[] = {
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013172 /* output mixer control */
13173 HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT),
13174 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
13175 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
Kailang Yangea1fb292008-08-26 12:58:38 +020013176
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013177 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013178};
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013179
Takashi Iwai22309c32006-08-09 16:57:28 +020013180static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = {
13181 /* output mixer control */
13182 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
13183 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
13184 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
13185 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
13186 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
13187
13188 /* Input mixer control */
13189 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
13190 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
13191 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
13192 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
13193 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
13194 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
13195 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
13196 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
13197 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
13198 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013199
Takashi Iwai22309c32006-08-09 16:57:28 +020013200 {
13201 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13202 .name = "Channel Mode",
13203 .info = alc_ch_mode_info,
13204 .get = alc_ch_mode_get,
13205 .put = alc_ch_mode_put,
13206 .private_value = ARRAY_SIZE(alc861_uniwill_m31_modes),
13207 },
13208 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013209};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013210
13211static struct snd_kcontrol_new alc861_asus_mixer[] = {
13212 /* output mixer control */
13213 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
13214 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
13215 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
13216 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
13217 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
13218
13219 /* Input mixer control */
13220 HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
13221 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT),
13222 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
13223 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
13224 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
13225 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
13226 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
13227 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
13228 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013229 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_OUTPUT),
13230
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013231 {
13232 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13233 .name = "Channel Mode",
13234 .info = alc_ch_mode_info,
13235 .get = alc_ch_mode_get,
13236 .put = alc_ch_mode_put,
13237 .private_value = ARRAY_SIZE(alc861_asus_modes),
13238 },
13239 { }
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010013240};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013241
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010013242/* additional mixer */
Takashi Iwaid1d985f2006-11-23 19:27:12 +010013243static struct snd_kcontrol_new alc861_asus_laptop_mixer[] = {
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010013244 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
13245 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010013246 { }
13247};
13248
Kailang Yangdf694da2005-12-05 19:42:22 +010013249/*
13250 * generic initialization of ADC, input mixers and output mixers
13251 */
13252static struct hda_verb alc861_base_init_verbs[] = {
13253 /*
13254 * Unmute ADC0 and set the default input to mic-in
13255 */
13256 /* port-A for surround (rear panel) */
13257 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13258 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x00 },
13259 /* port-B for mic-in (rear panel) with vref */
13260 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13261 /* port-C for line-in (rear panel) */
13262 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
13263 /* port-D for Front */
13264 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13265 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
13266 /* port-E for HP out (front panel) */
13267 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
13268 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010013269 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010013270 /* port-F for mic-in (front panel) with vref */
13271 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13272 /* port-G for CLFE (rear panel) */
13273 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13274 { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x00 },
13275 /* port-H for side (rear panel) */
13276 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13277 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x00 },
13278 /* CD-in */
13279 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
13280 /* route front mic to ADC1*/
13281 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
13282 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020013283
Kailang Yangdf694da2005-12-05 19:42:22 +010013284 /* Unmute DAC0~3 & spdif out*/
13285 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13286 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13287 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13288 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13289 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020013290
Kailang Yangdf694da2005-12-05 19:42:22 +010013291 /* Unmute Mixer 14 (mic) 1c (Line in)*/
13292 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13293 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13294 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13295 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020013296
Kailang Yangdf694da2005-12-05 19:42:22 +010013297 /* Unmute Stereo Mixer 15 */
13298 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13299 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13300 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013301 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010013302
13303 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13304 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13305 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13306 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13307 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13308 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13309 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13310 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013311 /* hp used DAC 3 (Front) */
13312 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010013313 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
13314
13315 { }
13316};
13317
13318static struct hda_verb alc861_threestack_init_verbs[] = {
13319 /*
13320 * Unmute ADC0 and set the default input to mic-in
13321 */
13322 /* port-A for surround (rear panel) */
13323 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
13324 /* port-B for mic-in (rear panel) with vref */
13325 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13326 /* port-C for line-in (rear panel) */
13327 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
13328 /* port-D for Front */
13329 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13330 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
13331 /* port-E for HP out (front panel) */
13332 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
13333 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010013334 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010013335 /* port-F for mic-in (front panel) with vref */
13336 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13337 /* port-G for CLFE (rear panel) */
13338 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
13339 /* port-H for side (rear panel) */
13340 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
13341 /* CD-in */
13342 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
13343 /* route front mic to ADC1*/
13344 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
13345 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13346 /* Unmute DAC0~3 & spdif out*/
13347 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13348 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13349 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13350 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13351 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020013352
Kailang Yangdf694da2005-12-05 19:42:22 +010013353 /* Unmute Mixer 14 (mic) 1c (Line in)*/
13354 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13355 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13356 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13357 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020013358
Kailang Yangdf694da2005-12-05 19:42:22 +010013359 /* Unmute Stereo Mixer 15 */
13360 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13361 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13362 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013363 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010013364
13365 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13366 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13367 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13368 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13369 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13370 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13371 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13372 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013373 /* hp used DAC 3 (Front) */
13374 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010013375 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
13376 { }
13377};
Takashi Iwai22309c32006-08-09 16:57:28 +020013378
13379static struct hda_verb alc861_uniwill_m31_init_verbs[] = {
13380 /*
13381 * Unmute ADC0 and set the default input to mic-in
13382 */
13383 /* port-A for surround (rear panel) */
13384 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
13385 /* port-B for mic-in (rear panel) with vref */
13386 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13387 /* port-C for line-in (rear panel) */
13388 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
13389 /* port-D for Front */
13390 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13391 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
13392 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013393 /* this has to be set to VREF80 */
13394 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Takashi Iwai22309c32006-08-09 16:57:28 +020013395 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010013396 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai22309c32006-08-09 16:57:28 +020013397 /* port-F for mic-in (front panel) with vref */
13398 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13399 /* port-G for CLFE (rear panel) */
13400 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
13401 /* port-H for side (rear panel) */
13402 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
13403 /* CD-in */
13404 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
13405 /* route front mic to ADC1*/
13406 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
13407 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13408 /* Unmute DAC0~3 & spdif out*/
13409 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13410 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13411 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13412 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13413 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020013414
Takashi Iwai22309c32006-08-09 16:57:28 +020013415 /* Unmute Mixer 14 (mic) 1c (Line in)*/
13416 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13417 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13418 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13419 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020013420
Takashi Iwai22309c32006-08-09 16:57:28 +020013421 /* Unmute Stereo Mixer 15 */
13422 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13423 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13424 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013425 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Takashi Iwai22309c32006-08-09 16:57:28 +020013426
13427 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13428 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13429 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13430 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13431 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13432 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13433 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13434 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013435 /* hp used DAC 3 (Front) */
13436 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Takashi Iwai22309c32006-08-09 16:57:28 +020013437 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
13438 { }
13439};
13440
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013441static struct hda_verb alc861_asus_init_verbs[] = {
13442 /*
13443 * Unmute ADC0 and set the default input to mic-in
13444 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013445 /* port-A for surround (rear panel)
13446 * according to codec#0 this is the HP jack
13447 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013448 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* was 0x00 */
13449 /* route front PCM to HP */
13450 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x01 },
13451 /* port-B for mic-in (rear panel) with vref */
13452 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13453 /* port-C for line-in (rear panel) */
13454 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
13455 /* port-D for Front */
13456 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13457 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
13458 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013459 /* this has to be set to VREF80 */
13460 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013461 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010013462 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013463 /* port-F for mic-in (front panel) with vref */
13464 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13465 /* port-G for CLFE (rear panel) */
13466 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13467 /* port-H for side (rear panel) */
13468 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13469 /* CD-in */
13470 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
13471 /* route front mic to ADC1*/
13472 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
13473 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13474 /* Unmute DAC0~3 & spdif out*/
13475 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13476 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13477 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13478 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13479 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13480 /* Unmute Mixer 14 (mic) 1c (Line in)*/
13481 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13482 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13483 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13484 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020013485
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013486 /* Unmute Stereo Mixer 15 */
13487 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13488 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13489 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013490 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013491
13492 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13493 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13494 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13495 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13496 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13497 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13498 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13499 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013500 /* hp used DAC 3 (Front) */
13501 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013502 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
13503 { }
13504};
13505
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010013506/* additional init verbs for ASUS laptops */
13507static struct hda_verb alc861_asus_laptop_init_verbs[] = {
13508 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x45 }, /* HP-out */
13509 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2) }, /* mute line-in */
13510 { }
13511};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013512
Kailang Yangdf694da2005-12-05 19:42:22 +010013513/*
13514 * generic initialization of ADC, input mixers and output mixers
13515 */
13516static struct hda_verb alc861_auto_init_verbs[] = {
13517 /*
13518 * Unmute ADC0 and set the default input to mic-in
13519 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013520 /* {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, */
Kailang Yangdf694da2005-12-05 19:42:22 +010013521 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020013522
Kailang Yangdf694da2005-12-05 19:42:22 +010013523 /* Unmute DAC0~3 & spdif out*/
13524 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13525 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13526 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13527 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13528 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020013529
Kailang Yangdf694da2005-12-05 19:42:22 +010013530 /* Unmute Mixer 14 (mic) 1c (Line in)*/
13531 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13532 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13533 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13534 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020013535
Kailang Yangdf694da2005-12-05 19:42:22 +010013536 /* Unmute Stereo Mixer 15 */
13537 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13538 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13539 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
13540 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c},
13541
13542 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13543 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13544 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13545 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13546 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13547 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13548 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13549 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13550
13551 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13552 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013553 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
13554 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010013555 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13556 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013557 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
13558 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010013559
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013560 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, /* set Mic 1 */
Kailang Yangdf694da2005-12-05 19:42:22 +010013561
13562 { }
13563};
13564
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013565static struct hda_verb alc861_toshiba_init_verbs[] = {
13566 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013567
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013568 { }
13569};
13570
13571/* toggle speaker-output according to the hp-jack state */
13572static void alc861_toshiba_automute(struct hda_codec *codec)
13573{
13574 unsigned int present;
13575
13576 present = snd_hda_codec_read(codec, 0x0f, 0,
13577 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020013578 snd_hda_codec_amp_stereo(codec, 0x16, HDA_INPUT, 0,
13579 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
13580 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_INPUT, 3,
13581 HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE);
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013582}
13583
13584static void alc861_toshiba_unsol_event(struct hda_codec *codec,
13585 unsigned int res)
13586{
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013587 if ((res >> 26) == ALC880_HP_EVENT)
13588 alc861_toshiba_automute(codec);
13589}
13590
Kailang Yangdf694da2005-12-05 19:42:22 +010013591/* pcm configuration: identiacal with ALC880 */
13592#define alc861_pcm_analog_playback alc880_pcm_analog_playback
13593#define alc861_pcm_analog_capture alc880_pcm_analog_capture
13594#define alc861_pcm_digital_playback alc880_pcm_digital_playback
13595#define alc861_pcm_digital_capture alc880_pcm_digital_capture
13596
13597
13598#define ALC861_DIGOUT_NID 0x07
13599
13600static struct hda_channel_mode alc861_8ch_modes[1] = {
13601 { 8, NULL }
13602};
13603
13604static hda_nid_t alc861_dac_nids[4] = {
13605 /* front, surround, clfe, side */
13606 0x03, 0x06, 0x05, 0x04
13607};
13608
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013609static hda_nid_t alc660_dac_nids[3] = {
13610 /* front, clfe, surround */
13611 0x03, 0x05, 0x06
13612};
13613
Kailang Yangdf694da2005-12-05 19:42:22 +010013614static hda_nid_t alc861_adc_nids[1] = {
13615 /* ADC0-2 */
13616 0x08,
13617};
13618
13619static struct hda_input_mux alc861_capture_source = {
13620 .num_items = 5,
13621 .items = {
13622 { "Mic", 0x0 },
13623 { "Front Mic", 0x3 },
13624 { "Line", 0x1 },
13625 { "CD", 0x4 },
13626 { "Mixer", 0x5 },
13627 },
13628};
13629
13630/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013631static int alc861_auto_fill_dac_nids(struct alc_spec *spec,
13632 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010013633{
13634 int i;
13635 hda_nid_t nid;
13636
13637 spec->multiout.dac_nids = spec->private_dac_nids;
13638 for (i = 0; i < cfg->line_outs; i++) {
13639 nid = cfg->line_out_pins[i];
13640 if (nid) {
13641 if (i >= ARRAY_SIZE(alc861_dac_nids))
13642 continue;
13643 spec->multiout.dac_nids[i] = alc861_dac_nids[i];
13644 }
13645 }
13646 spec->multiout.num_dacs = cfg->line_outs;
13647 return 0;
13648}
13649
13650/* add playback controls from the parsed DAC table */
13651static int alc861_auto_create_multi_out_ctls(struct alc_spec *spec,
13652 const struct auto_pin_cfg *cfg)
13653{
13654 char name[32];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013655 static const char *chname[4] = {
13656 "Front", "Surround", NULL /*CLFE*/, "Side"
13657 };
Kailang Yangdf694da2005-12-05 19:42:22 +010013658 hda_nid_t nid;
13659 int i, idx, err;
13660
13661 for (i = 0; i < cfg->line_outs; i++) {
13662 nid = spec->multiout.dac_nids[i];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013663 if (!nid)
Kailang Yangdf694da2005-12-05 19:42:22 +010013664 continue;
13665 if (nid == 0x05) {
13666 /* Center/LFE */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013667 err = add_control(spec, ALC_CTL_BIND_MUTE,
13668 "Center Playback Switch",
13669 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
13670 HDA_OUTPUT));
13671 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010013672 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013673 err = add_control(spec, ALC_CTL_BIND_MUTE,
13674 "LFE Playback Switch",
13675 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
13676 HDA_OUTPUT));
13677 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010013678 return err;
13679 } else {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013680 for (idx = 0; idx < ARRAY_SIZE(alc861_dac_nids) - 1;
13681 idx++)
Kailang Yangdf694da2005-12-05 19:42:22 +010013682 if (nid == alc861_dac_nids[idx])
13683 break;
13684 sprintf(name, "%s Playback Switch", chname[idx]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013685 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
13686 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
13687 HDA_OUTPUT));
13688 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010013689 return err;
13690 }
13691 }
13692 return 0;
13693}
13694
13695static int alc861_auto_create_hp_ctls(struct alc_spec *spec, hda_nid_t pin)
13696{
13697 int err;
13698 hda_nid_t nid;
13699
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013700 if (!pin)
Kailang Yangdf694da2005-12-05 19:42:22 +010013701 return 0;
13702
13703 if ((pin >= 0x0b && pin <= 0x10) || pin == 0x1f || pin == 0x20) {
13704 nid = 0x03;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013705 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
13706 "Headphone Playback Switch",
13707 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
13708 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010013709 return err;
13710 spec->multiout.hp_nid = nid;
13711 }
13712 return 0;
13713}
13714
13715/* create playback/capture controls for input pins */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013716static int alc861_auto_create_analog_input_ctls(struct alc_spec *spec,
13717 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010013718{
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020013719 struct hda_input_mux *imux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010013720 int i, err, idx, idx1;
13721
13722 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013723 switch (cfg->input_pins[i]) {
Kailang Yangdf694da2005-12-05 19:42:22 +010013724 case 0x0c:
13725 idx1 = 1;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013726 idx = 2; /* Line In */
Kailang Yangdf694da2005-12-05 19:42:22 +010013727 break;
13728 case 0x0f:
13729 idx1 = 2;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013730 idx = 2; /* Line In */
Kailang Yangdf694da2005-12-05 19:42:22 +010013731 break;
13732 case 0x0d:
13733 idx1 = 0;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013734 idx = 1; /* Mic In */
Kailang Yangdf694da2005-12-05 19:42:22 +010013735 break;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013736 case 0x10:
Kailang Yangdf694da2005-12-05 19:42:22 +010013737 idx1 = 3;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013738 idx = 1; /* Mic In */
Kailang Yangdf694da2005-12-05 19:42:22 +010013739 break;
13740 case 0x11:
13741 idx1 = 4;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013742 idx = 0; /* CD */
Kailang Yangdf694da2005-12-05 19:42:22 +010013743 break;
13744 default:
13745 continue;
13746 }
13747
Takashi Iwai4a471b72005-12-07 13:56:29 +010013748 err = new_analog_input(spec, cfg->input_pins[i],
13749 auto_pin_cfg_labels[i], idx, 0x15);
Kailang Yangdf694da2005-12-05 19:42:22 +010013750 if (err < 0)
13751 return err;
13752
Takashi Iwai4a471b72005-12-07 13:56:29 +010013753 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
Kailang Yangdf694da2005-12-05 19:42:22 +010013754 imux->items[imux->num_items].index = idx1;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013755 imux->num_items++;
Kailang Yangdf694da2005-12-05 19:42:22 +010013756 }
13757 return 0;
13758}
13759
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013760static void alc861_auto_set_output_and_unmute(struct hda_codec *codec,
13761 hda_nid_t nid,
Kailang Yangdf694da2005-12-05 19:42:22 +010013762 int pin_type, int dac_idx)
13763{
Jacek Luczak564c5be2008-05-03 18:41:23 +020013764 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
13765 pin_type);
13766 snd_hda_codec_write(codec, dac_idx, 0, AC_VERB_SET_AMP_GAIN_MUTE,
13767 AMP_OUT_UNMUTE);
Kailang Yangdf694da2005-12-05 19:42:22 +010013768}
13769
13770static void alc861_auto_init_multi_out(struct hda_codec *codec)
13771{
13772 struct alc_spec *spec = codec->spec;
13773 int i;
13774
13775 for (i = 0; i < spec->autocfg.line_outs; i++) {
13776 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020013777 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangdf694da2005-12-05 19:42:22 +010013778 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020013779 alc861_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013780 spec->multiout.dac_nids[i]);
Kailang Yangdf694da2005-12-05 19:42:22 +010013781 }
13782}
13783
13784static void alc861_auto_init_hp_out(struct hda_codec *codec)
13785{
13786 struct alc_spec *spec = codec->spec;
13787 hda_nid_t pin;
13788
Takashi Iwaieb06ed82006-09-20 17:10:27 +020013789 pin = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010013790 if (pin) /* connect to front */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013791 alc861_auto_set_output_and_unmute(codec, pin, PIN_HP,
13792 spec->multiout.dac_nids[0]);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013793 pin = spec->autocfg.speaker_pins[0];
13794 if (pin)
13795 alc861_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Kailang Yangdf694da2005-12-05 19:42:22 +010013796}
13797
13798static void alc861_auto_init_analog_input(struct hda_codec *codec)
13799{
13800 struct alc_spec *spec = codec->spec;
13801 int i;
13802
13803 for (i = 0; i < AUTO_PIN_LAST; i++) {
13804 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwai23f0c042009-02-26 13:03:58 +010013805 if (nid >= 0x0c && nid <= 0x11)
13806 alc_set_input_pin(codec, nid, i);
Kailang Yangdf694da2005-12-05 19:42:22 +010013807 }
13808}
13809
13810/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013811/* return 1 if successful, 0 if the proper config is not found,
13812 * or a negative error code
13813 */
Kailang Yangdf694da2005-12-05 19:42:22 +010013814static int alc861_parse_auto_config(struct hda_codec *codec)
13815{
13816 struct alc_spec *spec = codec->spec;
13817 int err;
13818 static hda_nid_t alc861_ignore[] = { 0x1d, 0 };
13819
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013820 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
13821 alc861_ignore);
13822 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010013823 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013824 if (!spec->autocfg.line_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +010013825 return 0; /* can't find valid BIOS pin config */
13826
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013827 err = alc861_auto_fill_dac_nids(spec, &spec->autocfg);
13828 if (err < 0)
13829 return err;
13830 err = alc861_auto_create_multi_out_ctls(spec, &spec->autocfg);
13831 if (err < 0)
13832 return err;
13833 err = alc861_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
13834 if (err < 0)
13835 return err;
13836 err = alc861_auto_create_analog_input_ctls(spec, &spec->autocfg);
13837 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010013838 return err;
13839
13840 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
13841
Takashi Iwai0852d7a2009-02-11 11:35:15 +010013842 if (spec->autocfg.dig_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +010013843 spec->multiout.dig_out_nid = ALC861_DIGOUT_NID;
13844
Takashi Iwai603c4012008-07-30 15:01:44 +020013845 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010013846 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +010013847
Takashi Iwaid88897e2008-10-31 15:01:37 +010013848 add_verb(spec, alc861_auto_init_verbs);
Kailang Yangdf694da2005-12-05 19:42:22 +010013849
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020013850 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020013851 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010013852
13853 spec->adc_nids = alc861_adc_nids;
13854 spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids);
Takashi Iwaif9e336f2008-10-31 16:37:07 +010013855 set_capture_mixer(spec);
Kailang Yangdf694da2005-12-05 19:42:22 +010013856
Takashi Iwai4a79ba32009-04-22 16:31:35 +020013857 alc_ssid_check(codec, 0x0e, 0x0f, 0x0b);
13858
Kailang Yangdf694da2005-12-05 19:42:22 +010013859 return 1;
13860}
13861
Takashi Iwaiae6b8132006-03-03 16:47:17 +010013862/* additional initialization for auto-configuration model */
13863static void alc861_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010013864{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013865 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010013866 alc861_auto_init_multi_out(codec);
13867 alc861_auto_init_hp_out(codec);
13868 alc861_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013869 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020013870 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010013871}
13872
Takashi Iwaicb53c622007-08-10 17:21:45 +020013873#ifdef CONFIG_SND_HDA_POWER_SAVE
13874static struct hda_amp_list alc861_loopbacks[] = {
13875 { 0x15, HDA_INPUT, 0 },
13876 { 0x15, HDA_INPUT, 1 },
13877 { 0x15, HDA_INPUT, 2 },
13878 { 0x15, HDA_INPUT, 3 },
13879 { } /* end */
13880};
13881#endif
13882
Kailang Yangdf694da2005-12-05 19:42:22 +010013883
13884/*
13885 * configuration and preset
13886 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010013887static const char *alc861_models[ALC861_MODEL_LAST] = {
13888 [ALC861_3ST] = "3stack",
13889 [ALC660_3ST] = "3stack-660",
13890 [ALC861_3ST_DIG] = "3stack-dig",
13891 [ALC861_6ST_DIG] = "6stack-dig",
13892 [ALC861_UNIWILL_M31] = "uniwill-m31",
13893 [ALC861_TOSHIBA] = "toshiba",
13894 [ALC861_ASUS] = "asus",
13895 [ALC861_ASUS_LAPTOP] = "asus-laptop",
13896 [ALC861_AUTO] = "auto",
13897};
13898
13899static struct snd_pci_quirk alc861_cfg_tbl[] = {
Takashi Iwai687a47b2007-01-10 11:25:58 +010013900 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010013901 SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP),
13902 SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP),
13903 SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013904 SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP),
Kailang Yang83c34212007-07-05 11:43:05 +020013905 SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS P1-AH2", ALC861_3ST_DIG),
Tobin Davisad5e7732007-01-08 10:57:32 +010013906 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA),
Takashi Iwai341d4eb2007-07-09 17:53:18 +020013907 /* FIXME: the entry below breaks Toshiba A100 (model=auto works!)
13908 * Any other models that need this preset?
13909 */
13910 /* SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), */
Claudio Matsuokaef64adb2007-07-14 00:26:16 +020013911 SND_PCI_QUIRK(0x1462, 0x7254, "HP dx2200 (MSI MS-7254)", ALC861_3ST),
13912 SND_PCI_QUIRK(0x1462, 0x7297, "HP dx2250 (MSI MS-7297)", ALC861_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013913 SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31),
13914 SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31),
13915 SND_PCI_QUIRK(0x1584, 0x9075, "Airis Praxis N1212", ALC861_ASUS_LAPTOP),
13916 /* FIXME: the below seems conflict */
13917 /* SND_PCI_QUIRK(0x1584, 0x9075, "Uniwill", ALC861_UNIWILL_M31), */
13918 SND_PCI_QUIRK(0x1849, 0x0660, "Asrock 939SLI32", ALC660_3ST),
13919 SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST),
Kailang Yangdf694da2005-12-05 19:42:22 +010013920 {}
13921};
13922
13923static struct alc_config_preset alc861_presets[] = {
13924 [ALC861_3ST] = {
13925 .mixers = { alc861_3ST_mixer },
13926 .init_verbs = { alc861_threestack_init_verbs },
13927 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
13928 .dac_nids = alc861_dac_nids,
13929 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
13930 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020013931 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010013932 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13933 .adc_nids = alc861_adc_nids,
13934 .input_mux = &alc861_capture_source,
13935 },
13936 [ALC861_3ST_DIG] = {
13937 .mixers = { alc861_base_mixer },
13938 .init_verbs = { alc861_threestack_init_verbs },
13939 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
13940 .dac_nids = alc861_dac_nids,
13941 .dig_out_nid = ALC861_DIGOUT_NID,
13942 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
13943 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020013944 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010013945 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13946 .adc_nids = alc861_adc_nids,
13947 .input_mux = &alc861_capture_source,
13948 },
13949 [ALC861_6ST_DIG] = {
13950 .mixers = { alc861_base_mixer },
13951 .init_verbs = { alc861_base_init_verbs },
13952 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
13953 .dac_nids = alc861_dac_nids,
13954 .dig_out_nid = ALC861_DIGOUT_NID,
13955 .num_channel_mode = ARRAY_SIZE(alc861_8ch_modes),
13956 .channel_mode = alc861_8ch_modes,
13957 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13958 .adc_nids = alc861_adc_nids,
13959 .input_mux = &alc861_capture_source,
13960 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013961 [ALC660_3ST] = {
13962 .mixers = { alc861_3ST_mixer },
13963 .init_verbs = { alc861_threestack_init_verbs },
13964 .num_dacs = ARRAY_SIZE(alc660_dac_nids),
13965 .dac_nids = alc660_dac_nids,
13966 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
13967 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020013968 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013969 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13970 .adc_nids = alc861_adc_nids,
13971 .input_mux = &alc861_capture_source,
13972 },
Takashi Iwai22309c32006-08-09 16:57:28 +020013973 [ALC861_UNIWILL_M31] = {
13974 .mixers = { alc861_uniwill_m31_mixer },
13975 .init_verbs = { alc861_uniwill_m31_init_verbs },
13976 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
13977 .dac_nids = alc861_dac_nids,
13978 .dig_out_nid = ALC861_DIGOUT_NID,
13979 .num_channel_mode = ARRAY_SIZE(alc861_uniwill_m31_modes),
13980 .channel_mode = alc861_uniwill_m31_modes,
13981 .need_dac_fix = 1,
13982 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13983 .adc_nids = alc861_adc_nids,
13984 .input_mux = &alc861_capture_source,
13985 },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013986 [ALC861_TOSHIBA] = {
13987 .mixers = { alc861_toshiba_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013988 .init_verbs = { alc861_base_init_verbs,
13989 alc861_toshiba_init_verbs },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013990 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
13991 .dac_nids = alc861_dac_nids,
13992 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
13993 .channel_mode = alc883_3ST_2ch_modes,
13994 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13995 .adc_nids = alc861_adc_nids,
13996 .input_mux = &alc861_capture_source,
13997 .unsol_event = alc861_toshiba_unsol_event,
13998 .init_hook = alc861_toshiba_automute,
13999 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014000 [ALC861_ASUS] = {
14001 .mixers = { alc861_asus_mixer },
14002 .init_verbs = { alc861_asus_init_verbs },
14003 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
14004 .dac_nids = alc861_dac_nids,
14005 .dig_out_nid = ALC861_DIGOUT_NID,
14006 .num_channel_mode = ARRAY_SIZE(alc861_asus_modes),
14007 .channel_mode = alc861_asus_modes,
14008 .need_dac_fix = 1,
14009 .hp_nid = 0x06,
14010 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
14011 .adc_nids = alc861_adc_nids,
14012 .input_mux = &alc861_capture_source,
14013 },
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010014014 [ALC861_ASUS_LAPTOP] = {
14015 .mixers = { alc861_toshiba_mixer, alc861_asus_laptop_mixer },
14016 .init_verbs = { alc861_asus_init_verbs,
14017 alc861_asus_laptop_init_verbs },
14018 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
14019 .dac_nids = alc861_dac_nids,
14020 .dig_out_nid = ALC861_DIGOUT_NID,
14021 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
14022 .channel_mode = alc883_3ST_2ch_modes,
14023 .need_dac_fix = 1,
14024 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
14025 .adc_nids = alc861_adc_nids,
14026 .input_mux = &alc861_capture_source,
14027 },
14028};
Kailang Yangdf694da2005-12-05 19:42:22 +010014029
14030
14031static int patch_alc861(struct hda_codec *codec)
14032{
14033 struct alc_spec *spec;
14034 int board_config;
14035 int err;
14036
Robert P. J. Daydc041e02006-12-19 14:44:15 +010014037 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010014038 if (spec == NULL)
14039 return -ENOMEM;
14040
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014041 codec->spec = spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010014042
Takashi Iwaif5fcc132006-11-24 17:07:44 +010014043 board_config = snd_hda_check_board_config(codec, ALC861_MODEL_LAST,
14044 alc861_models,
14045 alc861_cfg_tbl);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014046
Takashi Iwaif5fcc132006-11-24 17:07:44 +010014047 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014048 printk(KERN_INFO "hda_codec: Unknown model for ALC861, "
14049 "trying auto-probe from BIOS...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010014050 board_config = ALC861_AUTO;
14051 }
14052
14053 if (board_config == ALC861_AUTO) {
14054 /* automatic parse from the BIOS config */
14055 err = alc861_parse_auto_config(codec);
14056 if (err < 0) {
14057 alc_free(codec);
14058 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014059 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014060 printk(KERN_INFO
14061 "hda_codec: Cannot set up configuration "
14062 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010014063 board_config = ALC861_3ST_DIG;
14064 }
14065 }
14066
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090014067 err = snd_hda_attach_beep_device(codec, 0x23);
14068 if (err < 0) {
14069 alc_free(codec);
14070 return err;
14071 }
14072
Kailang Yangdf694da2005-12-05 19:42:22 +010014073 if (board_config != ALC861_AUTO)
14074 setup_preset(spec, &alc861_presets[board_config]);
14075
14076 spec->stream_name_analog = "ALC861 Analog";
14077 spec->stream_analog_playback = &alc861_pcm_analog_playback;
14078 spec->stream_analog_capture = &alc861_pcm_analog_capture;
14079
14080 spec->stream_name_digital = "ALC861 Digital";
14081 spec->stream_digital_playback = &alc861_pcm_digital_playback;
14082 spec->stream_digital_capture = &alc861_pcm_digital_capture;
14083
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010014084 set_beep_amp(spec, 0x23, 0, HDA_OUTPUT);
14085
Takashi Iwai2134ea42008-01-10 16:53:55 +010014086 spec->vmaster_nid = 0x03;
14087
Kailang Yangdf694da2005-12-05 19:42:22 +010014088 codec->patch_ops = alc_patch_ops;
14089 if (board_config == ALC861_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +010014090 spec->init_hook = alc861_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020014091#ifdef CONFIG_SND_HDA_POWER_SAVE
14092 if (!spec->loopback.amplist)
14093 spec->loopback.amplist = alc861_loopbacks;
14094#endif
Takashi Iwaidaead532008-11-28 12:55:36 +010014095 codec->proc_widget_hook = print_realtek_coef;
Kailang Yangea1fb292008-08-26 12:58:38 +020014096
Kailang Yangdf694da2005-12-05 19:42:22 +010014097 return 0;
14098}
14099
14100/*
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014101 * ALC861-VD support
14102 *
14103 * Based on ALC882
14104 *
14105 * In addition, an independent DAC
14106 */
14107#define ALC861VD_DIGOUT_NID 0x06
14108
14109static hda_nid_t alc861vd_dac_nids[4] = {
14110 /* front, surr, clfe, side surr */
14111 0x02, 0x03, 0x04, 0x05
14112};
14113
14114/* dac_nids for ALC660vd are in a different order - according to
14115 * Realtek's driver.
14116 * This should probably tesult in a different mixer for 6stack models
14117 * of ALC660vd codecs, but for now there is only 3stack mixer
14118 * - and it is the same as in 861vd.
14119 * adc_nids in ALC660vd are (is) the same as in 861vd
14120 */
14121static hda_nid_t alc660vd_dac_nids[3] = {
14122 /* front, rear, clfe, rear_surr */
14123 0x02, 0x04, 0x03
14124};
14125
14126static hda_nid_t alc861vd_adc_nids[1] = {
14127 /* ADC0 */
14128 0x09,
14129};
14130
Takashi Iwaie1406342008-02-11 18:32:32 +010014131static hda_nid_t alc861vd_capsrc_nids[1] = { 0x22 };
14132
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014133/* input MUX */
14134/* FIXME: should be a matrix-type input source selection */
14135static struct hda_input_mux alc861vd_capture_source = {
14136 .num_items = 4,
14137 .items = {
14138 { "Mic", 0x0 },
14139 { "Front Mic", 0x1 },
14140 { "Line", 0x2 },
14141 { "CD", 0x4 },
14142 },
14143};
14144
Kailang Yang272a5272007-05-14 11:00:38 +020014145static struct hda_input_mux alc861vd_dallas_capture_source = {
Tobin Davisb419f342008-03-07 11:57:51 +010014146 .num_items = 2,
Kailang Yang272a5272007-05-14 11:00:38 +020014147 .items = {
Tobin Davisb419f342008-03-07 11:57:51 +010014148 { "Ext Mic", 0x0 },
14149 { "Int Mic", 0x1 },
Kailang Yang272a5272007-05-14 11:00:38 +020014150 },
14151};
14152
Kailang Yangd1a991a2007-08-15 16:21:59 +020014153static struct hda_input_mux alc861vd_hp_capture_source = {
14154 .num_items = 2,
14155 .items = {
14156 { "Front Mic", 0x0 },
14157 { "ATAPI Mic", 0x1 },
14158 },
14159};
14160
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014161/*
14162 * 2ch mode
14163 */
14164static struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = {
14165 { 2, NULL }
14166};
14167
14168/*
14169 * 6ch mode
14170 */
14171static struct hda_verb alc861vd_6stack_ch6_init[] = {
14172 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
14173 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14174 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14175 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14176 { } /* end */
14177};
14178
14179/*
14180 * 8ch mode
14181 */
14182static struct hda_verb alc861vd_6stack_ch8_init[] = {
14183 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14184 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14185 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14186 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14187 { } /* end */
14188};
14189
14190static struct hda_channel_mode alc861vd_6stack_modes[2] = {
14191 { 6, alc861vd_6stack_ch6_init },
14192 { 8, alc861vd_6stack_ch8_init },
14193};
14194
14195static struct snd_kcontrol_new alc861vd_chmode_mixer[] = {
14196 {
14197 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
14198 .name = "Channel Mode",
14199 .info = alc_ch_mode_info,
14200 .get = alc_ch_mode_get,
14201 .put = alc_ch_mode_put,
14202 },
14203 { } /* end */
14204};
14205
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014206/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
14207 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
14208 */
14209static struct snd_kcontrol_new alc861vd_6st_mixer[] = {
14210 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14211 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
14212
14213 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
14214 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
14215
14216 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0,
14217 HDA_OUTPUT),
14218 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0,
14219 HDA_OUTPUT),
14220 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
14221 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
14222
14223 HDA_CODEC_VOLUME("Side Playback Volume", 0x05, 0x0, HDA_OUTPUT),
14224 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
14225
14226 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
14227
14228 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
14229 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14230 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14231
14232 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
14233 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14234 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14235
14236 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
14237 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
14238
14239 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
14240 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
14241
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014242 { } /* end */
14243};
14244
14245static struct snd_kcontrol_new alc861vd_3st_mixer[] = {
14246 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14247 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
14248
14249 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
14250
14251 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
14252 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14253 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14254
14255 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
14256 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14257 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14258
14259 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
14260 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
14261
14262 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
14263 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
14264
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014265 { } /* end */
14266};
14267
Kailang Yangbdd148a2007-05-08 15:19:08 +020014268static struct snd_kcontrol_new alc861vd_lenovo_mixer[] = {
14269 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14270 /*HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),*/
14271 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
14272
14273 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
14274
14275 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
14276 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14277 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14278
14279 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
14280 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14281 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14282
14283 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
14284 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
14285
14286 { } /* end */
14287};
14288
Tobin Davisb419f342008-03-07 11:57:51 +010014289/* Pin assignment: Speaker=0x14, HP = 0x15,
14290 * Ext Mic=0x18, Int Mic = 0x19, CD = 0x1c, PC Beep = 0x1d
Kailang Yang272a5272007-05-14 11:00:38 +020014291 */
14292static struct snd_kcontrol_new alc861vd_dallas_mixer[] = {
Tobin Davisb419f342008-03-07 11:57:51 +010014293 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14294 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020014295 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
14296 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
Tobin Davisb419f342008-03-07 11:57:51 +010014297 HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
14298 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14299 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14300 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
14301 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14302 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020014303 { } /* end */
14304};
14305
Kailang Yangd1a991a2007-08-15 16:21:59 +020014306/* Pin assignment: Speaker=0x14, Line-out = 0x15,
14307 * Front Mic=0x18, ATAPI Mic = 0x19,
14308 */
14309static struct snd_kcontrol_new alc861vd_hp_mixer[] = {
14310 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14311 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
14312 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
14313 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
14314 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14315 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14316 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14317 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangea1fb292008-08-26 12:58:38 +020014318
Kailang Yangd1a991a2007-08-15 16:21:59 +020014319 { } /* end */
14320};
14321
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014322/*
14323 * generic initialization of ADC, input mixers and output mixers
14324 */
14325static struct hda_verb alc861vd_volume_init_verbs[] = {
14326 /*
14327 * Unmute ADC0 and set the default input to mic-in
14328 */
14329 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
14330 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14331
14332 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of
14333 * the analog-loopback mixer widget
14334 */
14335 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020014336 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14337 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
14338 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
14339 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
14340 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014341
14342 /* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yangbdd148a2007-05-08 15:19:08 +020014343 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14344 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14345 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014346 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014347
14348 /*
14349 * Set up output mixers (0x02 - 0x05)
14350 */
14351 /* set vol=0 to output mixers */
14352 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14353 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14354 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14355 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14356
14357 /* set up input amps for analog loopback */
14358 /* Amp Indices: DAC = 0, mixer = 1 */
14359 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14360 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
14361 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14362 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
14363 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14364 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
14365 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14366 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
14367
14368 { }
14369};
14370
14371/*
14372 * 3-stack pin configuration:
14373 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
14374 */
14375static struct hda_verb alc861vd_3stack_init_verbs[] = {
14376 /*
14377 * Set pin mode and muting
14378 */
14379 /* set front pin widgets 0x14 for output */
14380 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14381 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14382 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
14383
14384 /* Mic (rear) pin: input vref at 80% */
14385 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14386 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14387 /* Front Mic pin: input vref at 80% */
14388 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14389 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14390 /* Line In pin: input */
14391 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14392 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14393 /* Line-2 In: Headphone output (output 0 - 0x0c) */
14394 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14395 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14396 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
14397 /* CD pin widget for input */
14398 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14399
14400 { }
14401};
14402
14403/*
14404 * 6-stack pin configuration:
14405 */
14406static struct hda_verb alc861vd_6stack_init_verbs[] = {
14407 /*
14408 * Set pin mode and muting
14409 */
14410 /* set front pin widgets 0x14 for output */
14411 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14412 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14413 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
14414
14415 /* Rear Pin: output 1 (0x0d) */
14416 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14417 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14418 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
14419 /* CLFE Pin: output 2 (0x0e) */
14420 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14421 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14422 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
14423 /* Side Pin: output 3 (0x0f) */
14424 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14425 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14426 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
14427
14428 /* Mic (rear) pin: input vref at 80% */
14429 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14430 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14431 /* Front Mic pin: input vref at 80% */
14432 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14433 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14434 /* Line In pin: input */
14435 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14436 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14437 /* Line-2 In: Headphone output (output 0 - 0x0c) */
14438 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14439 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14440 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
14441 /* CD pin widget for input */
14442 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14443
14444 { }
14445};
14446
Kailang Yangbdd148a2007-05-08 15:19:08 +020014447static struct hda_verb alc861vd_eapd_verbs[] = {
14448 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
14449 { }
14450};
14451
Kailang Yangf9423e72008-05-27 12:32:25 +020014452static struct hda_verb alc660vd_eapd_verbs[] = {
14453 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
14454 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
14455 { }
14456};
14457
Kailang Yangbdd148a2007-05-08 15:19:08 +020014458static struct hda_verb alc861vd_lenovo_unsol_verbs[] = {
14459 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14460 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14461 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
14462 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Kailang Yangea1fb292008-08-26 12:58:38 +020014463 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
Kailang Yangbdd148a2007-05-08 15:19:08 +020014464 {}
14465};
14466
Kailang Yangbdd148a2007-05-08 15:19:08 +020014467static void alc861vd_lenovo_mic_automute(struct hda_codec *codec)
14468{
14469 unsigned int present;
14470 unsigned char bits;
14471
14472 present = snd_hda_codec_read(codec, 0x18, 0,
14473 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020014474 bits = present ? HDA_AMP_MUTE : 0;
14475 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
14476 HDA_AMP_MUTE, bits);
Kailang Yangbdd148a2007-05-08 15:19:08 +020014477}
14478
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020014479static void alc861vd_lenovo_init_hook(struct hda_codec *codec)
Kailang Yangbdd148a2007-05-08 15:19:08 +020014480{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020014481 struct alc_spec *spec = codec->spec;
14482
14483 spec->autocfg.hp_pins[0] = 0x1b;
14484 spec->autocfg.speaker_pins[0] = 0x14;
14485 alc_automute_amp(codec);
Kailang Yangbdd148a2007-05-08 15:19:08 +020014486 alc861vd_lenovo_mic_automute(codec);
14487}
14488
14489static void alc861vd_lenovo_unsol_event(struct hda_codec *codec,
14490 unsigned int res)
14491{
14492 switch (res >> 26) {
Kailang Yangbdd148a2007-05-08 15:19:08 +020014493 case ALC880_MIC_EVENT:
14494 alc861vd_lenovo_mic_automute(codec);
14495 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020014496 default:
14497 alc_automute_amp_unsol_event(codec, res);
14498 break;
Kailang Yangbdd148a2007-05-08 15:19:08 +020014499 }
14500}
14501
Kailang Yang272a5272007-05-14 11:00:38 +020014502static struct hda_verb alc861vd_dallas_verbs[] = {
14503 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14504 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14505 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14506 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14507
14508 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14509 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14510 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14511 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
14512 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14513 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
14514 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14515 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020014516
Kailang Yang272a5272007-05-14 11:00:38 +020014517 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14518 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14519 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14520 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14521 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14522 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14523 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14524 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14525
14526 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
14527 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14528 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
14529 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14530 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14531 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14532 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14533 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14534
14535 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14536 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
14537 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
14538 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
14539
14540 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020014541 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yang272a5272007-05-14 11:00:38 +020014542 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14543
14544 { } /* end */
14545};
14546
14547/* toggle speaker-output according to the hp-jack state */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020014548static void alc861vd_dallas_init_hook(struct hda_codec *codec)
Kailang Yang272a5272007-05-14 11:00:38 +020014549{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020014550 struct alc_spec *spec = codec->spec;
Kailang Yang272a5272007-05-14 11:00:38 +020014551
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020014552 spec->autocfg.hp_pins[0] = 0x15;
14553 spec->autocfg.speaker_pins[0] = 0x14;
14554 alc_automute_amp(codec);
Kailang Yang272a5272007-05-14 11:00:38 +020014555}
14556
Takashi Iwaicb53c622007-08-10 17:21:45 +020014557#ifdef CONFIG_SND_HDA_POWER_SAVE
14558#define alc861vd_loopbacks alc880_loopbacks
14559#endif
14560
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014561/* pcm configuration: identiacal with ALC880 */
14562#define alc861vd_pcm_analog_playback alc880_pcm_analog_playback
14563#define alc861vd_pcm_analog_capture alc880_pcm_analog_capture
14564#define alc861vd_pcm_digital_playback alc880_pcm_digital_playback
14565#define alc861vd_pcm_digital_capture alc880_pcm_digital_capture
14566
14567/*
14568 * configuration and preset
14569 */
14570static const char *alc861vd_models[ALC861VD_MODEL_LAST] = {
14571 [ALC660VD_3ST] = "3stack-660",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020014572 [ALC660VD_3ST_DIG] = "3stack-660-digout",
Takashi Iwai13c94742008-11-05 08:06:08 +010014573 [ALC660VD_ASUS_V1S] = "asus-v1s",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014574 [ALC861VD_3ST] = "3stack",
14575 [ALC861VD_3ST_DIG] = "3stack-digout",
14576 [ALC861VD_6ST_DIG] = "6stack-digout",
Kailang Yangbdd148a2007-05-08 15:19:08 +020014577 [ALC861VD_LENOVO] = "lenovo",
Kailang Yang272a5272007-05-14 11:00:38 +020014578 [ALC861VD_DALLAS] = "dallas",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020014579 [ALC861VD_HP] = "hp",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014580 [ALC861VD_AUTO] = "auto",
14581};
14582
14583static struct snd_pci_quirk alc861vd_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +010014584 SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST),
14585 SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP),
Takashi Iwai07e038b2007-02-15 18:23:41 +010014586 SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014587 SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),
Takashi Iwai13c94742008-11-05 08:06:08 +010014588 SND_PCI_QUIRK(0x1043, 0x1633, "Asus V1Sn", ALC660VD_ASUS_V1S),
Mike Crash6963f842007-06-25 12:12:51 +020014589 SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014590 SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010014591 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO),
Takashi Iwai38baf5a2007-08-16 17:52:43 +020014592 /*SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS),*/ /*lenovo*/
Kailang Yang272a5272007-05-14 11:00:38 +020014593 SND_PCI_QUIRK(0x1179, 0xff01, "DALLAS", ALC861VD_DALLAS),
Takashi Iwai542d7c62007-08-16 18:57:30 +020014594 SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO),
Tobin Davisb419f342008-03-07 11:57:51 +010014595 SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_DALLAS),
Takashi Iwai39c5d412007-08-15 16:24:17 +020014596 SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +010014597 SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", ALC861VD_LENOVO),
Tobin Davis625dc0b2007-07-30 21:42:10 +020014598 SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014599 {}
14600};
14601
14602static struct alc_config_preset alc861vd_presets[] = {
14603 [ALC660VD_3ST] = {
14604 .mixers = { alc861vd_3st_mixer },
14605 .init_verbs = { alc861vd_volume_init_verbs,
14606 alc861vd_3stack_init_verbs },
14607 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
14608 .dac_nids = alc660vd_dac_nids,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014609 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14610 .channel_mode = alc861vd_3stack_2ch_modes,
14611 .input_mux = &alc861vd_capture_source,
14612 },
Mike Crash6963f842007-06-25 12:12:51 +020014613 [ALC660VD_3ST_DIG] = {
14614 .mixers = { alc861vd_3st_mixer },
14615 .init_verbs = { alc861vd_volume_init_verbs,
14616 alc861vd_3stack_init_verbs },
14617 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
14618 .dac_nids = alc660vd_dac_nids,
14619 .dig_out_nid = ALC861VD_DIGOUT_NID,
Mike Crash6963f842007-06-25 12:12:51 +020014620 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14621 .channel_mode = alc861vd_3stack_2ch_modes,
14622 .input_mux = &alc861vd_capture_source,
14623 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014624 [ALC861VD_3ST] = {
14625 .mixers = { alc861vd_3st_mixer },
14626 .init_verbs = { alc861vd_volume_init_verbs,
14627 alc861vd_3stack_init_verbs },
14628 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
14629 .dac_nids = alc861vd_dac_nids,
14630 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14631 .channel_mode = alc861vd_3stack_2ch_modes,
14632 .input_mux = &alc861vd_capture_source,
14633 },
14634 [ALC861VD_3ST_DIG] = {
14635 .mixers = { alc861vd_3st_mixer },
14636 .init_verbs = { alc861vd_volume_init_verbs,
14637 alc861vd_3stack_init_verbs },
14638 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
14639 .dac_nids = alc861vd_dac_nids,
14640 .dig_out_nid = ALC861VD_DIGOUT_NID,
14641 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14642 .channel_mode = alc861vd_3stack_2ch_modes,
14643 .input_mux = &alc861vd_capture_source,
14644 },
14645 [ALC861VD_6ST_DIG] = {
14646 .mixers = { alc861vd_6st_mixer, alc861vd_chmode_mixer },
14647 .init_verbs = { alc861vd_volume_init_verbs,
14648 alc861vd_6stack_init_verbs },
14649 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
14650 .dac_nids = alc861vd_dac_nids,
14651 .dig_out_nid = ALC861VD_DIGOUT_NID,
14652 .num_channel_mode = ARRAY_SIZE(alc861vd_6stack_modes),
14653 .channel_mode = alc861vd_6stack_modes,
14654 .input_mux = &alc861vd_capture_source,
14655 },
Kailang Yangbdd148a2007-05-08 15:19:08 +020014656 [ALC861VD_LENOVO] = {
14657 .mixers = { alc861vd_lenovo_mixer },
14658 .init_verbs = { alc861vd_volume_init_verbs,
14659 alc861vd_3stack_init_verbs,
14660 alc861vd_eapd_verbs,
14661 alc861vd_lenovo_unsol_verbs },
14662 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
14663 .dac_nids = alc660vd_dac_nids,
Kailang Yangbdd148a2007-05-08 15:19:08 +020014664 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14665 .channel_mode = alc861vd_3stack_2ch_modes,
14666 .input_mux = &alc861vd_capture_source,
14667 .unsol_event = alc861vd_lenovo_unsol_event,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020014668 .init_hook = alc861vd_lenovo_init_hook,
Kailang Yangbdd148a2007-05-08 15:19:08 +020014669 },
Kailang Yang272a5272007-05-14 11:00:38 +020014670 [ALC861VD_DALLAS] = {
14671 .mixers = { alc861vd_dallas_mixer },
14672 .init_verbs = { alc861vd_dallas_verbs },
14673 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
14674 .dac_nids = alc861vd_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +020014675 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14676 .channel_mode = alc861vd_3stack_2ch_modes,
14677 .input_mux = &alc861vd_dallas_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020014678 .unsol_event = alc_automute_amp_unsol_event,
14679 .init_hook = alc861vd_dallas_init_hook,
Kailang Yangd1a991a2007-08-15 16:21:59 +020014680 },
14681 [ALC861VD_HP] = {
14682 .mixers = { alc861vd_hp_mixer },
14683 .init_verbs = { alc861vd_dallas_verbs, alc861vd_eapd_verbs },
14684 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
14685 .dac_nids = alc861vd_dac_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020014686 .dig_out_nid = ALC861VD_DIGOUT_NID,
Kailang Yangd1a991a2007-08-15 16:21:59 +020014687 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14688 .channel_mode = alc861vd_3stack_2ch_modes,
14689 .input_mux = &alc861vd_hp_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020014690 .unsol_event = alc_automute_amp_unsol_event,
14691 .init_hook = alc861vd_dallas_init_hook,
Kailang Yangea1fb292008-08-26 12:58:38 +020014692 },
Takashi Iwai13c94742008-11-05 08:06:08 +010014693 [ALC660VD_ASUS_V1S] = {
14694 .mixers = { alc861vd_lenovo_mixer },
14695 .init_verbs = { alc861vd_volume_init_verbs,
14696 alc861vd_3stack_init_verbs,
14697 alc861vd_eapd_verbs,
14698 alc861vd_lenovo_unsol_verbs },
14699 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
14700 .dac_nids = alc660vd_dac_nids,
14701 .dig_out_nid = ALC861VD_DIGOUT_NID,
14702 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14703 .channel_mode = alc861vd_3stack_2ch_modes,
14704 .input_mux = &alc861vd_capture_source,
14705 .unsol_event = alc861vd_lenovo_unsol_event,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020014706 .init_hook = alc861vd_lenovo_init_hook,
Takashi Iwai13c94742008-11-05 08:06:08 +010014707 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014708};
14709
14710/*
14711 * BIOS auto configuration
14712 */
14713static void alc861vd_auto_set_output_and_unmute(struct hda_codec *codec,
14714 hda_nid_t nid, int pin_type, int dac_idx)
14715{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014716 alc_set_pin_output(codec, nid, pin_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014717}
14718
14719static void alc861vd_auto_init_multi_out(struct hda_codec *codec)
14720{
14721 struct alc_spec *spec = codec->spec;
14722 int i;
14723
14724 for (i = 0; i <= HDA_SIDE; i++) {
14725 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020014726 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014727 if (nid)
14728 alc861vd_auto_set_output_and_unmute(codec, nid,
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020014729 pin_type, i);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014730 }
14731}
14732
14733
14734static void alc861vd_auto_init_hp_out(struct hda_codec *codec)
14735{
14736 struct alc_spec *spec = codec->spec;
14737 hda_nid_t pin;
14738
14739 pin = spec->autocfg.hp_pins[0];
14740 if (pin) /* connect to front and use dac 0 */
14741 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014742 pin = spec->autocfg.speaker_pins[0];
14743 if (pin)
14744 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014745}
14746
14747#define alc861vd_is_input_pin(nid) alc880_is_input_pin(nid)
14748#define ALC861VD_PIN_CD_NID ALC880_PIN_CD_NID
14749
14750static void alc861vd_auto_init_analog_input(struct hda_codec *codec)
14751{
14752 struct alc_spec *spec = codec->spec;
14753 int i;
14754
14755 for (i = 0; i < AUTO_PIN_LAST; i++) {
14756 hda_nid_t nid = spec->autocfg.input_pins[i];
14757 if (alc861vd_is_input_pin(nid)) {
Takashi Iwai23f0c042009-02-26 13:03:58 +010014758 alc_set_input_pin(codec, nid, i);
Takashi Iwaie82c0252009-03-23 15:17:38 +010014759 if (nid != ALC861VD_PIN_CD_NID &&
14760 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014761 snd_hda_codec_write(codec, nid, 0,
14762 AC_VERB_SET_AMP_GAIN_MUTE,
14763 AMP_OUT_MUTE);
14764 }
14765 }
14766}
14767
Takashi Iwaif511b012008-08-15 16:46:42 +020014768#define alc861vd_auto_init_input_src alc882_auto_init_input_src
14769
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014770#define alc861vd_idx_to_mixer_vol(nid) ((nid) + 0x02)
14771#define alc861vd_idx_to_mixer_switch(nid) ((nid) + 0x0c)
14772
14773/* add playback controls from the parsed DAC table */
14774/* Based on ALC880 version. But ALC861VD has separate,
14775 * different NIDs for mute/unmute switch and volume control */
14776static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
14777 const struct auto_pin_cfg *cfg)
14778{
14779 char name[32];
14780 static const char *chname[4] = {"Front", "Surround", "CLFE", "Side"};
14781 hda_nid_t nid_v, nid_s;
14782 int i, err;
14783
14784 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014785 if (!spec->multiout.dac_nids[i])
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014786 continue;
14787 nid_v = alc861vd_idx_to_mixer_vol(
14788 alc880_dac_to_idx(
14789 spec->multiout.dac_nids[i]));
14790 nid_s = alc861vd_idx_to_mixer_switch(
14791 alc880_dac_to_idx(
14792 spec->multiout.dac_nids[i]));
14793
14794 if (i == 2) {
14795 /* Center/LFE */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014796 err = add_control(spec, ALC_CTL_WIDGET_VOL,
14797 "Center Playback Volume",
14798 HDA_COMPOSE_AMP_VAL(nid_v, 1, 0,
14799 HDA_OUTPUT));
14800 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014801 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014802 err = add_control(spec, ALC_CTL_WIDGET_VOL,
14803 "LFE Playback Volume",
14804 HDA_COMPOSE_AMP_VAL(nid_v, 2, 0,
14805 HDA_OUTPUT));
14806 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014807 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014808 err = add_control(spec, ALC_CTL_BIND_MUTE,
14809 "Center Playback Switch",
14810 HDA_COMPOSE_AMP_VAL(nid_s, 1, 2,
14811 HDA_INPUT));
14812 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014813 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014814 err = add_control(spec, ALC_CTL_BIND_MUTE,
14815 "LFE Playback Switch",
14816 HDA_COMPOSE_AMP_VAL(nid_s, 2, 2,
14817 HDA_INPUT));
14818 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014819 return err;
14820 } else {
14821 sprintf(name, "%s Playback Volume", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014822 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
14823 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0,
14824 HDA_OUTPUT));
14825 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014826 return err;
14827 sprintf(name, "%s Playback Switch", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014828 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
Kailang Yangbdd148a2007-05-08 15:19:08 +020014829 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014830 HDA_INPUT));
14831 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014832 return err;
14833 }
14834 }
14835 return 0;
14836}
14837
14838/* add playback controls for speaker and HP outputs */
14839/* Based on ALC880 version. But ALC861VD has separate,
14840 * different NIDs for mute/unmute switch and volume control */
14841static int alc861vd_auto_create_extra_out(struct alc_spec *spec,
14842 hda_nid_t pin, const char *pfx)
14843{
14844 hda_nid_t nid_v, nid_s;
14845 int err;
14846 char name[32];
14847
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014848 if (!pin)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014849 return 0;
14850
14851 if (alc880_is_fixed_pin(pin)) {
14852 nid_v = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
14853 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014854 if (!spec->multiout.hp_nid)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014855 spec->multiout.hp_nid = nid_v;
14856 else
14857 spec->multiout.extra_out_nid[0] = nid_v;
14858 /* control HP volume/switch on the output mixer amp */
14859 nid_v = alc861vd_idx_to_mixer_vol(
14860 alc880_fixed_pin_idx(pin));
14861 nid_s = alc861vd_idx_to_mixer_switch(
14862 alc880_fixed_pin_idx(pin));
14863
14864 sprintf(name, "%s Playback Volume", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014865 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
14866 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0, HDA_OUTPUT));
14867 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014868 return err;
14869 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014870 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
14871 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2, HDA_INPUT));
14872 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014873 return err;
14874 } else if (alc880_is_multi_pin(pin)) {
14875 /* set manual connection */
14876 /* we have only a switch on HP-out PIN */
14877 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014878 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
14879 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
14880 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014881 return err;
14882 }
14883 return 0;
14884}
14885
14886/* parse the BIOS configuration and set up the alc_spec
14887 * return 1 if successful, 0 if the proper config is not found,
14888 * or a negative error code
14889 * Based on ALC880 version - had to change it to override
14890 * alc880_auto_create_extra_out and alc880_auto_create_multi_out_ctls */
14891static int alc861vd_parse_auto_config(struct hda_codec *codec)
14892{
14893 struct alc_spec *spec = codec->spec;
14894 int err;
14895 static hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
14896
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014897 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
14898 alc861vd_ignore);
14899 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014900 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014901 if (!spec->autocfg.line_outs)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014902 return 0; /* can't find valid BIOS pin config */
14903
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014904 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
14905 if (err < 0)
14906 return err;
14907 err = alc861vd_auto_create_multi_out_ctls(spec, &spec->autocfg);
14908 if (err < 0)
14909 return err;
14910 err = alc861vd_auto_create_extra_out(spec,
14911 spec->autocfg.speaker_pins[0],
14912 "Speaker");
14913 if (err < 0)
14914 return err;
14915 err = alc861vd_auto_create_extra_out(spec,
14916 spec->autocfg.hp_pins[0],
14917 "Headphone");
14918 if (err < 0)
14919 return err;
14920 err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg);
14921 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014922 return err;
14923
14924 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
14925
Takashi Iwai0852d7a2009-02-11 11:35:15 +010014926 if (spec->autocfg.dig_outs)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014927 spec->multiout.dig_out_nid = ALC861VD_DIGOUT_NID;
14928
Takashi Iwai603c4012008-07-30 15:01:44 +020014929 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010014930 add_mixer(spec, spec->kctls.list);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014931
Takashi Iwaid88897e2008-10-31 15:01:37 +010014932 add_verb(spec, alc861vd_volume_init_verbs);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014933
14934 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020014935 spec->input_mux = &spec->private_imux[0];
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014936
Takashi Iwai776e1842007-08-29 15:07:11 +020014937 err = alc_auto_add_mic_boost(codec);
14938 if (err < 0)
14939 return err;
14940
Takashi Iwai4a79ba32009-04-22 16:31:35 +020014941 alc_ssid_check(codec, 0x15, 0x1b, 0x14);
14942
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014943 return 1;
14944}
14945
14946/* additional initialization for auto-configuration model */
14947static void alc861vd_auto_init(struct hda_codec *codec)
14948{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014949 struct alc_spec *spec = codec->spec;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014950 alc861vd_auto_init_multi_out(codec);
14951 alc861vd_auto_init_hp_out(codec);
14952 alc861vd_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020014953 alc861vd_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014954 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020014955 alc_inithook(codec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014956}
14957
14958static int patch_alc861vd(struct hda_codec *codec)
14959{
14960 struct alc_spec *spec;
14961 int err, board_config;
14962
14963 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
14964 if (spec == NULL)
14965 return -ENOMEM;
14966
14967 codec->spec = spec;
14968
14969 board_config = snd_hda_check_board_config(codec, ALC861VD_MODEL_LAST,
14970 alc861vd_models,
14971 alc861vd_cfg_tbl);
14972
14973 if (board_config < 0 || board_config >= ALC861VD_MODEL_LAST) {
14974 printk(KERN_INFO "hda_codec: Unknown model for ALC660VD/"
14975 "ALC861VD, trying auto-probe from BIOS...\n");
14976 board_config = ALC861VD_AUTO;
14977 }
14978
14979 if (board_config == ALC861VD_AUTO) {
14980 /* automatic parse from the BIOS config */
14981 err = alc861vd_parse_auto_config(codec);
14982 if (err < 0) {
14983 alc_free(codec);
14984 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014985 } else if (!err) {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014986 printk(KERN_INFO
14987 "hda_codec: Cannot set up configuration "
14988 "from BIOS. Using base mode...\n");
14989 board_config = ALC861VD_3ST;
14990 }
14991 }
14992
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090014993 err = snd_hda_attach_beep_device(codec, 0x23);
14994 if (err < 0) {
14995 alc_free(codec);
14996 return err;
14997 }
14998
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014999 if (board_config != ALC861VD_AUTO)
15000 setup_preset(spec, &alc861vd_presets[board_config]);
15001
Kailang Yang2f893282008-05-27 12:14:47 +020015002 if (codec->vendor_id == 0x10ec0660) {
15003 spec->stream_name_analog = "ALC660-VD Analog";
15004 spec->stream_name_digital = "ALC660-VD Digital";
Kailang Yangf9423e72008-05-27 12:32:25 +020015005 /* always turn on EAPD */
Takashi Iwaid88897e2008-10-31 15:01:37 +010015006 add_verb(spec, alc660vd_eapd_verbs);
Kailang Yang2f893282008-05-27 12:14:47 +020015007 } else {
15008 spec->stream_name_analog = "ALC861VD Analog";
15009 spec->stream_name_digital = "ALC861VD Digital";
15010 }
15011
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015012 spec->stream_analog_playback = &alc861vd_pcm_analog_playback;
15013 spec->stream_analog_capture = &alc861vd_pcm_analog_capture;
15014
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015015 spec->stream_digital_playback = &alc861vd_pcm_digital_playback;
15016 spec->stream_digital_capture = &alc861vd_pcm_digital_capture;
15017
15018 spec->adc_nids = alc861vd_adc_nids;
15019 spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids);
Takashi Iwaie1406342008-02-11 18:32:32 +010015020 spec->capsrc_nids = alc861vd_capsrc_nids;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020015021 spec->capture_style = CAPT_MIX;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015022
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015023 set_capture_mixer(spec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010015024 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015025
Takashi Iwai2134ea42008-01-10 16:53:55 +010015026 spec->vmaster_nid = 0x02;
15027
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015028 codec->patch_ops = alc_patch_ops;
15029
15030 if (board_config == ALC861VD_AUTO)
15031 spec->init_hook = alc861vd_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020015032#ifdef CONFIG_SND_HDA_POWER_SAVE
15033 if (!spec->loopback.amplist)
15034 spec->loopback.amplist = alc861vd_loopbacks;
15035#endif
Takashi Iwaidaead532008-11-28 12:55:36 +010015036 codec->proc_widget_hook = print_realtek_coef;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015037
15038 return 0;
15039}
15040
15041/*
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015042 * ALC662 support
15043 *
15044 * ALC662 is almost identical with ALC880 but has cleaner and more flexible
15045 * configuration. Each pin widget can choose any input DACs and a mixer.
15046 * Each ADC is connected from a mixer of all inputs. This makes possible
15047 * 6-channel independent captures.
15048 *
15049 * In addition, an independent DAC for the multi-playback (not used in this
15050 * driver yet).
15051 */
15052#define ALC662_DIGOUT_NID 0x06
15053#define ALC662_DIGIN_NID 0x0a
15054
15055static hda_nid_t alc662_dac_nids[4] = {
15056 /* front, rear, clfe, rear_surr */
15057 0x02, 0x03, 0x04
15058};
15059
Kailang Yang622e84c2009-04-21 07:39:04 +020015060static hda_nid_t alc272_dac_nids[2] = {
15061 0x02, 0x03
15062};
15063
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015064static hda_nid_t alc662_adc_nids[1] = {
15065 /* ADC1-2 */
15066 0x09,
15067};
Takashi Iwaie1406342008-02-11 18:32:32 +010015068
Kailang Yang622e84c2009-04-21 07:39:04 +020015069static hda_nid_t alc272_adc_nids[1] = {
15070 /* ADC1-2 */
15071 0x08,
15072};
15073
Kailang Yang77a261b2008-02-19 11:38:05 +010015074static hda_nid_t alc662_capsrc_nids[1] = { 0x22 };
Kailang Yang622e84c2009-04-21 07:39:04 +020015075static hda_nid_t alc272_capsrc_nids[1] = { 0x23 };
15076
Takashi Iwaie1406342008-02-11 18:32:32 +010015077
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015078/* input MUX */
15079/* FIXME: should be a matrix-type input source selection */
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015080static struct hda_input_mux alc662_capture_source = {
15081 .num_items = 4,
15082 .items = {
15083 { "Mic", 0x0 },
15084 { "Front Mic", 0x1 },
15085 { "Line", 0x2 },
15086 { "CD", 0x4 },
15087 },
15088};
15089
15090static struct hda_input_mux alc662_lenovo_101e_capture_source = {
15091 .num_items = 2,
15092 .items = {
15093 { "Mic", 0x1 },
15094 { "Line", 0x2 },
15095 },
15096};
Kailang Yang291702f2007-10-16 14:28:03 +020015097
15098static struct hda_input_mux alc662_eeepc_capture_source = {
15099 .num_items = 2,
15100 .items = {
15101 { "i-Mic", 0x1 },
15102 { "e-Mic", 0x0 },
15103 },
15104};
15105
Kailang Yang6dda9f42008-05-27 12:05:31 +020015106static struct hda_input_mux alc663_capture_source = {
15107 .num_items = 3,
15108 .items = {
15109 { "Mic", 0x0 },
15110 { "Front Mic", 0x1 },
15111 { "Line", 0x2 },
15112 },
15113};
15114
15115static struct hda_input_mux alc663_m51va_capture_source = {
15116 .num_items = 2,
15117 .items = {
15118 { "Ext-Mic", 0x0 },
15119 { "D-Mic", 0x9 },
15120 },
15121};
15122
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015123/*
15124 * 2ch mode
15125 */
15126static struct hda_channel_mode alc662_3ST_2ch_modes[1] = {
15127 { 2, NULL }
15128};
15129
15130/*
15131 * 2ch mode
15132 */
15133static struct hda_verb alc662_3ST_ch2_init[] = {
15134 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
15135 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
15136 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
15137 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
15138 { } /* end */
15139};
15140
15141/*
15142 * 6ch mode
15143 */
15144static struct hda_verb alc662_3ST_ch6_init[] = {
15145 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15146 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
15147 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
15148 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15149 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
15150 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
15151 { } /* end */
15152};
15153
15154static struct hda_channel_mode alc662_3ST_6ch_modes[2] = {
15155 { 2, alc662_3ST_ch2_init },
15156 { 6, alc662_3ST_ch6_init },
15157};
15158
15159/*
15160 * 2ch mode
15161 */
15162static struct hda_verb alc662_sixstack_ch6_init[] = {
15163 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15164 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15165 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15166 { } /* end */
15167};
15168
15169/*
15170 * 6ch mode
15171 */
15172static struct hda_verb alc662_sixstack_ch8_init[] = {
15173 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15174 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15175 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15176 { } /* end */
15177};
15178
15179static struct hda_channel_mode alc662_5stack_modes[2] = {
15180 { 2, alc662_sixstack_ch6_init },
15181 { 6, alc662_sixstack_ch8_init },
15182};
15183
15184/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
15185 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
15186 */
15187
15188static struct snd_kcontrol_new alc662_base_mixer[] = {
15189 /* output mixer control */
15190 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010015191 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015192 HDA_CODEC_VOLUME("Surround Playback Volume", 0x3, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010015193 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015194 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
15195 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010015196 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
15197 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015198 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
15199
15200 /*Input mixer control */
15201 HDA_CODEC_VOLUME("CD Playback Volume", 0xb, 0x4, HDA_INPUT),
15202 HDA_CODEC_MUTE("CD Playback Switch", 0xb, 0x4, HDA_INPUT),
15203 HDA_CODEC_VOLUME("Line Playback Volume", 0xb, 0x02, HDA_INPUT),
15204 HDA_CODEC_MUTE("Line Playback Switch", 0xb, 0x02, HDA_INPUT),
15205 HDA_CODEC_VOLUME("Mic Playback Volume", 0xb, 0x0, HDA_INPUT),
15206 HDA_CODEC_MUTE("Mic Playback Switch", 0xb, 0x0, HDA_INPUT),
15207 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0xb, 0x01, HDA_INPUT),
15208 HDA_CODEC_MUTE("Front Mic Playback Switch", 0xb, 0x01, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015209 { } /* end */
15210};
15211
15212static struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = {
15213 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010015214 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015215 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
15216 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
15217 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
15218 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
15219 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
15220 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15221 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15222 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15223 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015224 { } /* end */
15225};
15226
15227static struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = {
15228 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010015229 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015230 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010015231 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015232 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
15233 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010015234 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
15235 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015236 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
15237 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
15238 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
15239 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
15240 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
15241 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15242 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15243 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15244 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015245 { } /* end */
15246};
15247
15248static struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = {
15249 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15250 HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010015251 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x03, 0x0, HDA_OUTPUT),
15252 HDA_BIND_MUTE("Speaker Playback Switch", 0x03, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015253 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
15254 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
15255 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
15256 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15257 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015258 { } /* end */
15259};
15260
Kailang Yang291702f2007-10-16 14:28:03 +020015261static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020015262 HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15263 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yang291702f2007-10-16 14:28:03 +020015264
15265 HDA_CODEC_VOLUME("e-Mic Boost", 0x18, 0, HDA_INPUT),
15266 HDA_CODEC_VOLUME("e-Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15267 HDA_CODEC_MUTE("e-Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15268
15269 HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT),
15270 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15271 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
15272 { } /* end */
15273};
15274
Kailang Yang8c427222008-01-10 13:03:59 +010015275static struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020015276 ALC262_HIPPO_MASTER_SWITCH,
15277 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010015278 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010015279 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
15280 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010015281 HDA_BIND_MUTE("MuteCtrl Playback Switch", 0x0c, 2, HDA_INPUT),
15282 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
15283 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
15284 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15285 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15286 { } /* end */
15287};
15288
Kailang Yangf1d4e282008-08-26 14:03:29 +020015289static struct hda_bind_ctls alc663_asus_bind_master_vol = {
15290 .ops = &snd_hda_bind_vol,
15291 .values = {
15292 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
15293 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
15294 0
15295 },
15296};
15297
15298static struct hda_bind_ctls alc663_asus_one_bind_switch = {
15299 .ops = &snd_hda_bind_sw,
15300 .values = {
15301 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
15302 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
15303 0
15304 },
15305};
15306
Kailang Yang6dda9f42008-05-27 12:05:31 +020015307static struct snd_kcontrol_new alc663_m51va_mixer[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020015308 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
15309 HDA_BIND_SW("Master Playback Switch", &alc663_asus_one_bind_switch),
15310 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15311 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15312 { } /* end */
15313};
15314
15315static struct hda_bind_ctls alc663_asus_tree_bind_switch = {
15316 .ops = &snd_hda_bind_sw,
15317 .values = {
15318 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
15319 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
15320 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
15321 0
15322 },
15323};
15324
15325static struct snd_kcontrol_new alc663_two_hp_m1_mixer[] = {
15326 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
15327 HDA_BIND_SW("Master Playback Switch", &alc663_asus_tree_bind_switch),
15328 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15329 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15330 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15331 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
15332
15333 { } /* end */
15334};
15335
15336static struct hda_bind_ctls alc663_asus_four_bind_switch = {
15337 .ops = &snd_hda_bind_sw,
15338 .values = {
15339 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
15340 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
15341 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
15342 0
15343 },
15344};
15345
15346static struct snd_kcontrol_new alc663_two_hp_m2_mixer[] = {
15347 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
15348 HDA_BIND_SW("Master Playback Switch", &alc663_asus_four_bind_switch),
15349 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15350 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15351 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15352 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
15353 { } /* end */
15354};
15355
15356static struct snd_kcontrol_new alc662_1bjd_mixer[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020015357 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15358 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020015359 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
15360 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15361 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15362 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15363 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
15364 { } /* end */
15365};
15366
15367static struct hda_bind_ctls alc663_asus_two_bind_master_vol = {
15368 .ops = &snd_hda_bind_vol,
15369 .values = {
15370 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
15371 HDA_COMPOSE_AMP_VAL(0x04, 3, 0, HDA_OUTPUT),
15372 0
15373 },
15374};
15375
15376static struct hda_bind_ctls alc663_asus_two_bind_switch = {
15377 .ops = &snd_hda_bind_sw,
15378 .values = {
15379 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
15380 HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT),
15381 0
15382 },
15383};
15384
15385static struct snd_kcontrol_new alc663_asus_21jd_clfe_mixer[] = {
15386 HDA_BIND_VOL("Master Playback Volume",
15387 &alc663_asus_two_bind_master_vol),
15388 HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
15389 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020015390 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
15391 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15392 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020015393 { } /* end */
15394};
15395
15396static struct snd_kcontrol_new alc663_asus_15jd_clfe_mixer[] = {
15397 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
15398 HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
15399 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
15400 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
15401 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15402 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020015403 { } /* end */
15404};
15405
15406static struct snd_kcontrol_new alc663_g71v_mixer[] = {
15407 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15408 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
15409 HDA_CODEC_VOLUME("Front Playback Volume", 0x03, 0x0, HDA_OUTPUT),
15410 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
15411 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
15412
15413 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15414 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15415 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15416 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
15417 { } /* end */
15418};
15419
15420static struct snd_kcontrol_new alc663_g50v_mixer[] = {
15421 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15422 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
15423 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
15424
15425 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15426 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15427 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15428 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
15429 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
15430 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
15431 { } /* end */
15432};
15433
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015434static struct snd_kcontrol_new alc662_chmode_mixer[] = {
15435 {
15436 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
15437 .name = "Channel Mode",
15438 .info = alc_ch_mode_info,
15439 .get = alc_ch_mode_get,
15440 .put = alc_ch_mode_put,
15441 },
15442 { } /* end */
15443};
15444
15445static struct hda_verb alc662_init_verbs[] = {
15446 /* ADC: mute amp left and right */
15447 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15448 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
15449 /* Front mixer: unmute input/output amp left and right (volume = 0) */
15450
Takashi Iwaicb53c622007-08-10 17:21:45 +020015451 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15452 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15453 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
15454 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
15455 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015456
Kailang Yangb60dd392007-09-20 12:50:29 +020015457 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15458 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15459 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15460 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15461 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15462 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015463
15464 /* Front Pin: output 0 (0x0c) */
15465 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
15466 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15467
15468 /* Rear Pin: output 1 (0x0d) */
15469 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
15470 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15471
15472 /* CLFE Pin: output 2 (0x0e) */
15473 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
15474 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15475
15476 /* Mic (rear) pin: input vref at 80% */
15477 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
15478 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15479 /* Front Mic pin: input vref at 80% */
15480 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
15481 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15482 /* Line In pin: input */
15483 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15484 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15485 /* Line-2 In: Headphone output (output 0 - 0x0c) */
15486 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15487 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15488 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
15489 /* CD pin widget for input */
15490 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15491
15492 /* FIXME: use matrix-type input source selection */
15493 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
15494 /* Input mixer */
15495 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yang291702f2007-10-16 14:28:03 +020015496 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yang6dda9f42008-05-27 12:05:31 +020015497
15498 /* always trun on EAPD */
15499 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
15500 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
15501
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015502 { }
15503};
15504
15505static struct hda_verb alc662_sue_init_verbs[] = {
15506 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
15507 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
Kailang Yang291702f2007-10-16 14:28:03 +020015508 {}
15509};
15510
15511static struct hda_verb alc662_eeepc_sue_init_verbs[] = {
15512 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15513 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15514 {}
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015515};
15516
Kailang Yang8c427222008-01-10 13:03:59 +010015517/* Set Unsolicited Event*/
15518static struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = {
15519 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
15520 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15521 {}
15522};
15523
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015524/*
15525 * generic initialization of ADC, input mixers and output mixers
15526 */
15527static struct hda_verb alc662_auto_init_verbs[] = {
15528 /*
15529 * Unmute ADC and set the default input to mic-in
15530 */
15531 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
15532 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15533
15534 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
15535 * mixer widget
15536 * Note: PASD motherboards uses the Line In 2 as the input for front
15537 * panel mic (mic 2)
15538 */
15539 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020015540 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15541 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15542 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
15543 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
15544 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015545
15546 /*
15547 * Set up output mixers (0x0c - 0x0f)
15548 */
15549 /* set vol=0 to output mixers */
15550 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
15551 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
15552 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
15553
15554 /* set up input amps for analog loopback */
15555 /* Amp Indices: DAC = 0, mixer = 1 */
Kailang Yangb60dd392007-09-20 12:50:29 +020015556 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15557 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15558 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15559 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15560 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15561 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015562
15563
15564 /* FIXME: use matrix-type input source selection */
15565 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
15566 /* Input mixer */
15567 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangd1a991a2007-08-15 16:21:59 +020015568 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015569 { }
15570};
15571
Takashi Iwai24fb9172008-09-02 14:48:20 +020015572/* additional verbs for ALC663 */
15573static struct hda_verb alc663_auto_init_verbs[] = {
15574 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15575 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15576 { }
15577};
15578
Kailang Yang6dda9f42008-05-27 12:05:31 +020015579static struct hda_verb alc663_m51va_init_verbs[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020015580 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15581 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yang6dda9f42008-05-27 12:05:31 +020015582 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15583 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangf1d4e282008-08-26 14:03:29 +020015584 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
15585 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15586 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
Kailang Yang6dda9f42008-05-27 12:05:31 +020015587 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15588 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15589 {}
15590};
15591
Kailang Yangf1d4e282008-08-26 14:03:29 +020015592static struct hda_verb alc663_21jd_amic_init_verbs[] = {
15593 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15594 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15595 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
15596 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15597 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15598 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15599 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15600 {}
15601};
15602
15603static struct hda_verb alc662_1bjd_amic_init_verbs[] = {
15604 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15605 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15606 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15607 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
15608 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15609 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15610 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15611 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15612 {}
15613};
15614
15615static struct hda_verb alc663_15jd_amic_init_verbs[] = {
15616 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15617 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15618 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
15619 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15620 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15621 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15622 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15623 {}
15624};
15625
15626static struct hda_verb alc663_two_hp_amic_m1_init_verbs[] = {
15627 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15628 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15629 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15630 {0x21, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */
15631 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15632 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15633 {0x15, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */
15634 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15635 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15636 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15637 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15638 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15639 {}
15640};
15641
15642static struct hda_verb alc663_two_hp_amic_m2_init_verbs[] = {
15643 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15644 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15645 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15646 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
15647 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15648 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15649 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
15650 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15651 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15652 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15653 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15654 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15655 {}
15656};
15657
Kailang Yang6dda9f42008-05-27 12:05:31 +020015658static struct hda_verb alc663_g71v_init_verbs[] = {
15659 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15660 /* {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
15661 /* {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, */ /* Headphone */
15662
15663 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15664 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15665 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
15666
15667 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
15668 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_MIC_EVENT},
15669 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
15670 {}
15671};
15672
15673static struct hda_verb alc663_g50v_init_verbs[] = {
15674 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15675 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15676 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
15677
15678 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15679 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15680 {}
15681};
15682
Kailang Yangf1d4e282008-08-26 14:03:29 +020015683static struct hda_verb alc662_ecs_init_verbs[] = {
15684 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
15685 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15686 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15687 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15688 {}
15689};
15690
Kailang Yang622e84c2009-04-21 07:39:04 +020015691static struct hda_verb alc272_dell_zm1_init_verbs[] = {
15692 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15693 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15694 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15695 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15696 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15697 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15698 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
15699 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15700 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
15701 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15702 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15703 {}
15704};
15705
15706static struct hda_verb alc272_dell_init_verbs[] = {
15707 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15708 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15709 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15710 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15711 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15712 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15713 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
15714 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15715 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
15716 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15717 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15718 {}
15719};
15720
Kailang Yangf1d4e282008-08-26 14:03:29 +020015721static struct snd_kcontrol_new alc662_auto_capture_mixer[] = {
15722 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
15723 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
15724 { } /* end */
15725};
15726
Kailang Yang622e84c2009-04-21 07:39:04 +020015727static struct snd_kcontrol_new alc272_auto_capture_mixer[] = {
15728 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
15729 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
15730 { } /* end */
15731};
15732
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015733static void alc662_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
15734{
15735 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015736 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015737
15738 present = snd_hda_codec_read(codec, 0x14, 0,
15739 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020015740 bits = present ? HDA_AMP_MUTE : 0;
15741 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
15742 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015743}
15744
15745static void alc662_lenovo_101e_all_automute(struct hda_codec *codec)
15746{
15747 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015748 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015749
15750 present = snd_hda_codec_read(codec, 0x1b, 0,
15751 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020015752 bits = present ? HDA_AMP_MUTE : 0;
15753 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
15754 HDA_AMP_MUTE, bits);
15755 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
15756 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015757}
15758
15759static void alc662_lenovo_101e_unsol_event(struct hda_codec *codec,
15760 unsigned int res)
15761{
15762 if ((res >> 26) == ALC880_HP_EVENT)
15763 alc662_lenovo_101e_all_automute(codec);
15764 if ((res >> 26) == ALC880_FRONT_EVENT)
15765 alc662_lenovo_101e_ispeaker_automute(codec);
15766}
15767
Kailang Yang291702f2007-10-16 14:28:03 +020015768static void alc662_eeepc_mic_automute(struct hda_codec *codec)
15769{
15770 unsigned int present;
15771
15772 present = snd_hda_codec_read(codec, 0x18, 0,
15773 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
15774 snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
15775 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
15776 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
15777 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
15778 snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
15779 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
15780 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
15781 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
15782}
15783
15784/* unsolicited event for HP jack sensing */
15785static void alc662_eeepc_unsol_event(struct hda_codec *codec,
15786 unsigned int res)
15787{
Kailang Yang291702f2007-10-16 14:28:03 +020015788 if ((res >> 26) == ALC880_MIC_EVENT)
15789 alc662_eeepc_mic_automute(codec);
Takashi Iwai42171c12009-05-08 14:11:43 +020015790 else
15791 alc262_hippo_unsol_event(codec, res);
Kailang Yang291702f2007-10-16 14:28:03 +020015792}
15793
15794static void alc662_eeepc_inithook(struct hda_codec *codec)
15795{
Takashi Iwai42171c12009-05-08 14:11:43 +020015796 alc262_hippo1_init_hook(codec);
Kailang Yang291702f2007-10-16 14:28:03 +020015797 alc662_eeepc_mic_automute(codec);
15798}
15799
Kailang Yang8c427222008-01-10 13:03:59 +010015800static void alc662_eeepc_ep20_inithook(struct hda_codec *codec)
15801{
Takashi Iwai42171c12009-05-08 14:11:43 +020015802 struct alc_spec *spec = codec->spec;
15803
15804 spec->autocfg.hp_pins[0] = 0x14;
15805 spec->autocfg.speaker_pins[0] = 0x1b;
15806 alc262_hippo_master_update(codec);
Kailang Yang8c427222008-01-10 13:03:59 +010015807}
15808
Kailang Yang6dda9f42008-05-27 12:05:31 +020015809static void alc663_m51va_speaker_automute(struct hda_codec *codec)
15810{
15811 unsigned int present;
15812 unsigned char bits;
15813
15814 present = snd_hda_codec_read(codec, 0x21, 0,
Kailang Yangf1d4e282008-08-26 14:03:29 +020015815 AC_VERB_GET_PIN_SENSE, 0)
15816 & AC_PINSENSE_PRESENCE;
Kailang Yang6dda9f42008-05-27 12:05:31 +020015817 bits = present ? HDA_AMP_MUTE : 0;
Kailang Yangf1d4e282008-08-26 14:03:29 +020015818 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
15819 AMP_IN_MUTE(0), bits);
15820 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
15821 AMP_IN_MUTE(0), bits);
15822}
15823
15824static void alc663_21jd_two_speaker_automute(struct hda_codec *codec)
15825{
15826 unsigned int present;
15827 unsigned char bits;
15828
15829 present = snd_hda_codec_read(codec, 0x21, 0,
15830 AC_VERB_GET_PIN_SENSE, 0)
15831 & AC_PINSENSE_PRESENCE;
15832 bits = present ? HDA_AMP_MUTE : 0;
15833 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
15834 AMP_IN_MUTE(0), bits);
15835 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
15836 AMP_IN_MUTE(0), bits);
15837 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0,
15838 AMP_IN_MUTE(0), bits);
15839 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1,
15840 AMP_IN_MUTE(0), bits);
15841}
15842
15843static void alc663_15jd_two_speaker_automute(struct hda_codec *codec)
15844{
15845 unsigned int present;
15846 unsigned char bits;
15847
15848 present = snd_hda_codec_read(codec, 0x15, 0,
15849 AC_VERB_GET_PIN_SENSE, 0)
15850 & AC_PINSENSE_PRESENCE;
15851 bits = present ? HDA_AMP_MUTE : 0;
15852 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
15853 AMP_IN_MUTE(0), bits);
15854 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
15855 AMP_IN_MUTE(0), bits);
15856 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0,
15857 AMP_IN_MUTE(0), bits);
15858 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1,
15859 AMP_IN_MUTE(0), bits);
15860}
15861
15862static void alc662_f5z_speaker_automute(struct hda_codec *codec)
15863{
15864 unsigned int present;
15865 unsigned char bits;
15866
15867 present = snd_hda_codec_read(codec, 0x1b, 0,
15868 AC_VERB_GET_PIN_SENSE, 0)
15869 & AC_PINSENSE_PRESENCE;
15870 bits = present ? 0 : PIN_OUT;
15871 snd_hda_codec_write(codec, 0x14, 0,
15872 AC_VERB_SET_PIN_WIDGET_CONTROL, bits);
15873}
15874
15875static void alc663_two_hp_m1_speaker_automute(struct hda_codec *codec)
15876{
15877 unsigned int present1, present2;
15878
15879 present1 = snd_hda_codec_read(codec, 0x21, 0,
15880 AC_VERB_GET_PIN_SENSE, 0)
15881 & AC_PINSENSE_PRESENCE;
15882 present2 = snd_hda_codec_read(codec, 0x15, 0,
15883 AC_VERB_GET_PIN_SENSE, 0)
15884 & AC_PINSENSE_PRESENCE;
15885
15886 if (present1 || present2) {
15887 snd_hda_codec_write_cache(codec, 0x14, 0,
15888 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
15889 } else {
15890 snd_hda_codec_write_cache(codec, 0x14, 0,
15891 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
15892 }
15893}
15894
15895static void alc663_two_hp_m2_speaker_automute(struct hda_codec *codec)
15896{
15897 unsigned int present1, present2;
15898
15899 present1 = snd_hda_codec_read(codec, 0x1b, 0,
15900 AC_VERB_GET_PIN_SENSE, 0)
15901 & AC_PINSENSE_PRESENCE;
15902 present2 = snd_hda_codec_read(codec, 0x15, 0,
15903 AC_VERB_GET_PIN_SENSE, 0)
15904 & AC_PINSENSE_PRESENCE;
15905
15906 if (present1 || present2) {
15907 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
15908 AMP_IN_MUTE(0), AMP_IN_MUTE(0));
15909 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
15910 AMP_IN_MUTE(0), AMP_IN_MUTE(0));
15911 } else {
15912 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
15913 AMP_IN_MUTE(0), 0);
15914 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
15915 AMP_IN_MUTE(0), 0);
15916 }
Kailang Yang6dda9f42008-05-27 12:05:31 +020015917}
15918
15919static void alc663_m51va_mic_automute(struct hda_codec *codec)
15920{
15921 unsigned int present;
15922
15923 present = snd_hda_codec_read(codec, 0x18, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +020015924 AC_VERB_GET_PIN_SENSE, 0)
15925 & AC_PINSENSE_PRESENCE;
Kailang Yang6dda9f42008-05-27 12:05:31 +020015926 snd_hda_codec_write_cache(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangea1fb292008-08-26 12:58:38 +020015927 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
Kailang Yang6dda9f42008-05-27 12:05:31 +020015928 snd_hda_codec_write_cache(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangea1fb292008-08-26 12:58:38 +020015929 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
Kailang Yang6dda9f42008-05-27 12:05:31 +020015930 snd_hda_codec_write_cache(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangea1fb292008-08-26 12:58:38 +020015931 0x7000 | (0x09 << 8) | (present ? 0x80 : 0));
Kailang Yang6dda9f42008-05-27 12:05:31 +020015932 snd_hda_codec_write_cache(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangea1fb292008-08-26 12:58:38 +020015933 0x7000 | (0x09 << 8) | (present ? 0x80 : 0));
Kailang Yang6dda9f42008-05-27 12:05:31 +020015934}
15935
15936static void alc663_m51va_unsol_event(struct hda_codec *codec,
15937 unsigned int res)
15938{
15939 switch (res >> 26) {
15940 case ALC880_HP_EVENT:
15941 alc663_m51va_speaker_automute(codec);
15942 break;
15943 case ALC880_MIC_EVENT:
15944 alc663_m51va_mic_automute(codec);
15945 break;
15946 }
15947}
15948
15949static void alc663_m51va_inithook(struct hda_codec *codec)
15950{
15951 alc663_m51va_speaker_automute(codec);
15952 alc663_m51va_mic_automute(codec);
15953}
15954
Kailang Yangf1d4e282008-08-26 14:03:29 +020015955/* ***************** Mode1 ******************************/
15956static void alc663_mode1_unsol_event(struct hda_codec *codec,
15957 unsigned int res)
15958{
15959 switch (res >> 26) {
15960 case ALC880_HP_EVENT:
15961 alc663_m51va_speaker_automute(codec);
15962 break;
15963 case ALC880_MIC_EVENT:
15964 alc662_eeepc_mic_automute(codec);
15965 break;
15966 }
15967}
15968
15969static void alc663_mode1_inithook(struct hda_codec *codec)
15970{
15971 alc663_m51va_speaker_automute(codec);
15972 alc662_eeepc_mic_automute(codec);
15973}
15974/* ***************** Mode2 ******************************/
15975static void alc662_mode2_unsol_event(struct hda_codec *codec,
15976 unsigned int res)
15977{
15978 switch (res >> 26) {
15979 case ALC880_HP_EVENT:
15980 alc662_f5z_speaker_automute(codec);
15981 break;
15982 case ALC880_MIC_EVENT:
15983 alc662_eeepc_mic_automute(codec);
15984 break;
15985 }
15986}
15987
15988static void alc662_mode2_inithook(struct hda_codec *codec)
15989{
15990 alc662_f5z_speaker_automute(codec);
15991 alc662_eeepc_mic_automute(codec);
15992}
15993/* ***************** Mode3 ******************************/
15994static void alc663_mode3_unsol_event(struct hda_codec *codec,
15995 unsigned int res)
15996{
15997 switch (res >> 26) {
15998 case ALC880_HP_EVENT:
15999 alc663_two_hp_m1_speaker_automute(codec);
16000 break;
16001 case ALC880_MIC_EVENT:
16002 alc662_eeepc_mic_automute(codec);
16003 break;
16004 }
16005}
16006
16007static void alc663_mode3_inithook(struct hda_codec *codec)
16008{
16009 alc663_two_hp_m1_speaker_automute(codec);
16010 alc662_eeepc_mic_automute(codec);
16011}
16012/* ***************** Mode4 ******************************/
16013static void alc663_mode4_unsol_event(struct hda_codec *codec,
16014 unsigned int res)
16015{
16016 switch (res >> 26) {
16017 case ALC880_HP_EVENT:
16018 alc663_21jd_two_speaker_automute(codec);
16019 break;
16020 case ALC880_MIC_EVENT:
16021 alc662_eeepc_mic_automute(codec);
16022 break;
16023 }
16024}
16025
16026static void alc663_mode4_inithook(struct hda_codec *codec)
16027{
16028 alc663_21jd_two_speaker_automute(codec);
16029 alc662_eeepc_mic_automute(codec);
16030}
16031/* ***************** Mode5 ******************************/
16032static void alc663_mode5_unsol_event(struct hda_codec *codec,
16033 unsigned int res)
16034{
16035 switch (res >> 26) {
16036 case ALC880_HP_EVENT:
16037 alc663_15jd_two_speaker_automute(codec);
16038 break;
16039 case ALC880_MIC_EVENT:
16040 alc662_eeepc_mic_automute(codec);
16041 break;
16042 }
16043}
16044
16045static void alc663_mode5_inithook(struct hda_codec *codec)
16046{
16047 alc663_15jd_two_speaker_automute(codec);
16048 alc662_eeepc_mic_automute(codec);
16049}
16050/* ***************** Mode6 ******************************/
16051static void alc663_mode6_unsol_event(struct hda_codec *codec,
16052 unsigned int res)
16053{
16054 switch (res >> 26) {
16055 case ALC880_HP_EVENT:
16056 alc663_two_hp_m2_speaker_automute(codec);
16057 break;
16058 case ALC880_MIC_EVENT:
16059 alc662_eeepc_mic_automute(codec);
16060 break;
16061 }
16062}
16063
16064static void alc663_mode6_inithook(struct hda_codec *codec)
16065{
16066 alc663_two_hp_m2_speaker_automute(codec);
16067 alc662_eeepc_mic_automute(codec);
16068}
16069
Kailang Yang6dda9f42008-05-27 12:05:31 +020016070static void alc663_g71v_hp_automute(struct hda_codec *codec)
16071{
16072 unsigned int present;
16073 unsigned char bits;
16074
16075 present = snd_hda_codec_read(codec, 0x21, 0,
16076 AC_VERB_GET_PIN_SENSE, 0)
16077 & AC_PINSENSE_PRESENCE;
16078 bits = present ? HDA_AMP_MUTE : 0;
16079 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
16080 HDA_AMP_MUTE, bits);
16081 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
16082 HDA_AMP_MUTE, bits);
16083}
16084
16085static void alc663_g71v_front_automute(struct hda_codec *codec)
16086{
16087 unsigned int present;
16088 unsigned char bits;
16089
16090 present = snd_hda_codec_read(codec, 0x15, 0,
16091 AC_VERB_GET_PIN_SENSE, 0)
16092 & AC_PINSENSE_PRESENCE;
16093 bits = present ? HDA_AMP_MUTE : 0;
16094 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
16095 HDA_AMP_MUTE, bits);
16096}
16097
16098static void alc663_g71v_unsol_event(struct hda_codec *codec,
16099 unsigned int res)
16100{
16101 switch (res >> 26) {
16102 case ALC880_HP_EVENT:
16103 alc663_g71v_hp_automute(codec);
16104 break;
16105 case ALC880_FRONT_EVENT:
16106 alc663_g71v_front_automute(codec);
16107 break;
16108 case ALC880_MIC_EVENT:
16109 alc662_eeepc_mic_automute(codec);
16110 break;
16111 }
16112}
16113
16114static void alc663_g71v_inithook(struct hda_codec *codec)
16115{
16116 alc663_g71v_front_automute(codec);
16117 alc663_g71v_hp_automute(codec);
16118 alc662_eeepc_mic_automute(codec);
16119}
16120
16121static void alc663_g50v_unsol_event(struct hda_codec *codec,
16122 unsigned int res)
16123{
16124 switch (res >> 26) {
16125 case ALC880_HP_EVENT:
16126 alc663_m51va_speaker_automute(codec);
16127 break;
16128 case ALC880_MIC_EVENT:
16129 alc662_eeepc_mic_automute(codec);
16130 break;
16131 }
16132}
16133
16134static void alc663_g50v_inithook(struct hda_codec *codec)
16135{
16136 alc663_m51va_speaker_automute(codec);
16137 alc662_eeepc_mic_automute(codec);
16138}
16139
Kailang Yangf1d4e282008-08-26 14:03:29 +020016140static struct snd_kcontrol_new alc662_ecs_mixer[] = {
16141 HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020016142 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yangf1d4e282008-08-26 14:03:29 +020016143
16144 HDA_CODEC_VOLUME("e-Mic/LineIn Boost", 0x18, 0, HDA_INPUT),
16145 HDA_CODEC_VOLUME("e-Mic/LineIn Playback Volume", 0x0b, 0x0, HDA_INPUT),
16146 HDA_CODEC_MUTE("e-Mic/LineIn Playback Switch", 0x0b, 0x0, HDA_INPUT),
16147
16148 HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT),
16149 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16150 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16151 { } /* end */
16152};
16153
Takashi Iwaicb53c622007-08-10 17:21:45 +020016154#ifdef CONFIG_SND_HDA_POWER_SAVE
16155#define alc662_loopbacks alc880_loopbacks
16156#endif
16157
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016158
16159/* pcm configuration: identiacal with ALC880 */
16160#define alc662_pcm_analog_playback alc880_pcm_analog_playback
16161#define alc662_pcm_analog_capture alc880_pcm_analog_capture
16162#define alc662_pcm_digital_playback alc880_pcm_digital_playback
16163#define alc662_pcm_digital_capture alc880_pcm_digital_capture
16164
16165/*
16166 * configuration and preset
16167 */
16168static const char *alc662_models[ALC662_MODEL_LAST] = {
16169 [ALC662_3ST_2ch_DIG] = "3stack-dig",
16170 [ALC662_3ST_6ch_DIG] = "3stack-6ch-dig",
16171 [ALC662_3ST_6ch] = "3stack-6ch",
16172 [ALC662_5ST_DIG] = "6stack-dig",
16173 [ALC662_LENOVO_101E] = "lenovo-101e",
Takashi Iwaib995d762007-10-17 10:41:06 +020016174 [ALC662_ASUS_EEEPC_P701] = "eeepc-p701",
Kailang Yang8c427222008-01-10 13:03:59 +010016175 [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20",
Kailang Yangf1d4e282008-08-26 14:03:29 +020016176 [ALC662_ECS] = "ecs",
Kailang Yang6dda9f42008-05-27 12:05:31 +020016177 [ALC663_ASUS_M51VA] = "m51va",
16178 [ALC663_ASUS_G71V] = "g71v",
16179 [ALC663_ASUS_H13] = "h13",
16180 [ALC663_ASUS_G50V] = "g50v",
Kailang Yangf1d4e282008-08-26 14:03:29 +020016181 [ALC663_ASUS_MODE1] = "asus-mode1",
16182 [ALC662_ASUS_MODE2] = "asus-mode2",
16183 [ALC663_ASUS_MODE3] = "asus-mode3",
16184 [ALC663_ASUS_MODE4] = "asus-mode4",
16185 [ALC663_ASUS_MODE5] = "asus-mode5",
16186 [ALC663_ASUS_MODE6] = "asus-mode6",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016187 [ALC662_AUTO] = "auto",
16188};
16189
16190static struct snd_pci_quirk alc662_cfg_tbl[] = {
Takashi Iwaidea0a502009-02-09 17:14:52 +010016191 SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_ECS),
Kailang Yang622e84c2009-04-21 07:39:04 +020016192 SND_PCI_QUIRK(0x1028, 0x02d6, "DELL", ALC272_DELL),
16193 SND_PCI_QUIRK(0x1028, 0x02f4, "DELL ZM1", ALC272_DELL_ZM1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016194 SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC663_ASUS_MODE1),
16195 SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC663_ASUS_MODE3),
16196 SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC663_ASUS_MODE3),
16197 SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC663_ASUS_MODE1),
16198 SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_ASUS_MODE2),
16199 SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC663_ASUS_MODE1),
16200 SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_ASUS_MODE2),
16201 SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_ASUS_MODE2),
16202 SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_ASUS_MODE2),
16203 SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC663_ASUS_MODE6),
16204 SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC663_ASUS_MODE6),
16205 SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020016206 SND_PCI_QUIRK(0x1043, 0x17b3, "ASUS F70SL", ALC663_ASUS_MODE3),
16207 SND_PCI_QUIRK(0x1043, 0x17c3, "ASUS UX20", ALC663_ASUS_M51VA),
16208 SND_PCI_QUIRK(0x1043, 0x17f3, "ASUS X58LE", ALC662_ASUS_MODE2),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016209 SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_ASUS_MODE2),
16210 SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC663_ASUS_MODE5),
16211 SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC663_ASUS_MODE6),
16212 SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020016213 SND_PCI_QUIRK(0x1043, 0x1853, "ASUS F50Z", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016214 SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_ASUS_MODE2),
16215 SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yang6dda9f42008-05-27 12:05:31 +020016216 SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M51VA", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016217 /*SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M50Vr", ALC663_ASUS_MODE1),*/
16218 SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC663_ASUS_MODE3),
16219 SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC663_ASUS_MODE3),
Kailang Yang622e84c2009-04-21 07:39:04 +020016220 SND_PCI_QUIRK(0x1043, 0x18b3, "ASUS N80Vc", ALC663_ASUS_MODE1),
16221 SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS N81Te", ALC663_ASUS_MODE1),
16222 SND_PCI_QUIRK(0x1043, 0x18f3, "ASUS N505Tp", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016223 SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC663_ASUS_MODE1),
16224 SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_ASUS_MODE2),
16225 SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020016226 SND_PCI_QUIRK(0x1043, 0x1943, "ASUS Vx3V", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016227 SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC663_ASUS_MODE1),
16228 SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC663_ASUS_MODE3),
Kailang Yang622e84c2009-04-21 07:39:04 +020016229 SND_PCI_QUIRK(0x1043, 0x1983, "ASUS N5051A", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016230 SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC663_ASUS_MODE1),
Kailang Yang80ffe862008-10-15 11:23:27 +020016231 SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS G50V", ALC663_ASUS_G50V),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016232 /*SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS NB", ALC663_ASUS_MODE1),*/
16233 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC663_ASUS_MODE1),
16234 SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020016235 SND_PCI_QUIRK(0x1043, 0x19d3, "ASUS NB", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016236 SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC663_ASUS_MODE1),
16237 SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC663_ASUS_MODE4),
Herton Ronaldo Krzesinski3da23ca2008-03-14 12:52:59 +010016238 SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG),
Kailang Yang291702f2007-10-16 14:28:03 +020016239 SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701),
Kailang Yang8c427222008-01-10 13:03:59 +010016240 SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016241 SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS),
Herton Ronaldo Krzesinski95fe5f22008-09-26 23:48:45 -030016242 SND_PCI_QUIRK(0x105b, 0x0d47, "Foxconn 45CMX/45GMX/45CMX-K",
16243 ALC662_3ST_6ch_DIG),
Herton Ronaldo Krzesinskicb559742008-09-26 23:47:45 -030016244 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L",
16245 ALC662_3ST_6ch_DIG),
Vedran Miletic19c009a2008-09-29 20:29:25 +020016246 SND_PCI_QUIRK(0x1565, 0x820f, "Biostar TA780G M2+", ALC662_3ST_6ch_DIG),
Takashi Iwai5bd37292009-04-21 18:36:30 +020016247 SND_PCI_QUIRK(0x1631, 0xc10c, "PB RS65", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016248 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E),
Takashi Iwai238713d2008-10-05 10:57:39 +020016249 SND_PCI_QUIRK(0x1849, 0x3662, "ASROCK K10N78FullHD-hSLI R3.0",
Vedran Miletic19c009a2008-09-29 20:29:25 +020016250 ALC662_3ST_6ch_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016251 SND_PCI_QUIRK_MASK(0x1854, 0xf000, 0x2000, "ASUS H13-200x",
16252 ALC663_ASUS_H13),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016253 {}
16254};
16255
16256static struct alc_config_preset alc662_presets[] = {
16257 [ALC662_3ST_2ch_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016258 .mixers = { alc662_3ST_2ch_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016259 .init_verbs = { alc662_init_verbs },
16260 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16261 .dac_nids = alc662_dac_nids,
16262 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016263 .dig_in_nid = ALC662_DIGIN_NID,
16264 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16265 .channel_mode = alc662_3ST_2ch_modes,
16266 .input_mux = &alc662_capture_source,
16267 },
16268 [ALC662_3ST_6ch_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016269 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016270 .init_verbs = { alc662_init_verbs },
16271 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16272 .dac_nids = alc662_dac_nids,
16273 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016274 .dig_in_nid = ALC662_DIGIN_NID,
16275 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
16276 .channel_mode = alc662_3ST_6ch_modes,
16277 .need_dac_fix = 1,
16278 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016279 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016280 [ALC662_3ST_6ch] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016281 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016282 .init_verbs = { alc662_init_verbs },
16283 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16284 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016285 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
16286 .channel_mode = alc662_3ST_6ch_modes,
16287 .need_dac_fix = 1,
16288 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016289 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016290 [ALC662_5ST_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016291 .mixers = { alc662_base_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016292 .init_verbs = { alc662_init_verbs },
16293 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16294 .dac_nids = alc662_dac_nids,
16295 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016296 .dig_in_nid = ALC662_DIGIN_NID,
16297 .num_channel_mode = ARRAY_SIZE(alc662_5stack_modes),
16298 .channel_mode = alc662_5stack_modes,
16299 .input_mux = &alc662_capture_source,
16300 },
16301 [ALC662_LENOVO_101E] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016302 .mixers = { alc662_lenovo_101e_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016303 .init_verbs = { alc662_init_verbs, alc662_sue_init_verbs },
16304 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16305 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016306 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16307 .channel_mode = alc662_3ST_2ch_modes,
16308 .input_mux = &alc662_lenovo_101e_capture_source,
16309 .unsol_event = alc662_lenovo_101e_unsol_event,
16310 .init_hook = alc662_lenovo_101e_all_automute,
16311 },
Kailang Yang291702f2007-10-16 14:28:03 +020016312 [ALC662_ASUS_EEEPC_P701] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016313 .mixers = { alc662_eeepc_p701_mixer },
Kailang Yang291702f2007-10-16 14:28:03 +020016314 .init_verbs = { alc662_init_verbs,
16315 alc662_eeepc_sue_init_verbs },
16316 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16317 .dac_nids = alc662_dac_nids,
Kailang Yang291702f2007-10-16 14:28:03 +020016318 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16319 .channel_mode = alc662_3ST_2ch_modes,
16320 .input_mux = &alc662_eeepc_capture_source,
16321 .unsol_event = alc662_eeepc_unsol_event,
16322 .init_hook = alc662_eeepc_inithook,
16323 },
Kailang Yang8c427222008-01-10 13:03:59 +010016324 [ALC662_ASUS_EEEPC_EP20] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016325 .mixers = { alc662_eeepc_ep20_mixer,
Kailang Yang8c427222008-01-10 13:03:59 +010016326 alc662_chmode_mixer },
16327 .init_verbs = { alc662_init_verbs,
16328 alc662_eeepc_ep20_sue_init_verbs },
16329 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16330 .dac_nids = alc662_dac_nids,
Kailang Yang8c427222008-01-10 13:03:59 +010016331 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
16332 .channel_mode = alc662_3ST_6ch_modes,
16333 .input_mux = &alc662_lenovo_101e_capture_source,
Takashi Iwai42171c12009-05-08 14:11:43 +020016334 .unsol_event = alc662_eeepc_unsol_event,
Kailang Yang8c427222008-01-10 13:03:59 +010016335 .init_hook = alc662_eeepc_ep20_inithook,
16336 },
Kailang Yangf1d4e282008-08-26 14:03:29 +020016337 [ALC662_ECS] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016338 .mixers = { alc662_ecs_mixer },
Kailang Yangf1d4e282008-08-26 14:03:29 +020016339 .init_verbs = { alc662_init_verbs,
16340 alc662_ecs_init_verbs },
16341 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16342 .dac_nids = alc662_dac_nids,
16343 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16344 .channel_mode = alc662_3ST_2ch_modes,
16345 .input_mux = &alc662_eeepc_capture_source,
16346 .unsol_event = alc662_eeepc_unsol_event,
16347 .init_hook = alc662_eeepc_inithook,
16348 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020016349 [ALC663_ASUS_M51VA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016350 .mixers = { alc663_m51va_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020016351 .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
16352 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16353 .dac_nids = alc662_dac_nids,
16354 .dig_out_nid = ALC662_DIGOUT_NID,
16355 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16356 .channel_mode = alc662_3ST_2ch_modes,
16357 .input_mux = &alc663_m51va_capture_source,
16358 .unsol_event = alc663_m51va_unsol_event,
16359 .init_hook = alc663_m51va_inithook,
16360 },
16361 [ALC663_ASUS_G71V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016362 .mixers = { alc663_g71v_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020016363 .init_verbs = { alc662_init_verbs, alc663_g71v_init_verbs },
16364 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16365 .dac_nids = alc662_dac_nids,
16366 .dig_out_nid = ALC662_DIGOUT_NID,
16367 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16368 .channel_mode = alc662_3ST_2ch_modes,
16369 .input_mux = &alc662_eeepc_capture_source,
16370 .unsol_event = alc663_g71v_unsol_event,
16371 .init_hook = alc663_g71v_inithook,
16372 },
16373 [ALC663_ASUS_H13] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016374 .mixers = { alc663_m51va_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020016375 .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
16376 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16377 .dac_nids = alc662_dac_nids,
16378 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16379 .channel_mode = alc662_3ST_2ch_modes,
16380 .input_mux = &alc663_m51va_capture_source,
16381 .unsol_event = alc663_m51va_unsol_event,
16382 .init_hook = alc663_m51va_inithook,
16383 },
16384 [ALC663_ASUS_G50V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016385 .mixers = { alc663_g50v_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020016386 .init_verbs = { alc662_init_verbs, alc663_g50v_init_verbs },
16387 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16388 .dac_nids = alc662_dac_nids,
16389 .dig_out_nid = ALC662_DIGOUT_NID,
16390 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
16391 .channel_mode = alc662_3ST_6ch_modes,
16392 .input_mux = &alc663_capture_source,
16393 .unsol_event = alc663_g50v_unsol_event,
16394 .init_hook = alc663_g50v_inithook,
16395 },
Kailang Yangf1d4e282008-08-26 14:03:29 +020016396 [ALC663_ASUS_MODE1] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016397 .mixers = { alc663_m51va_mixer },
16398 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020016399 .init_verbs = { alc662_init_verbs,
16400 alc663_21jd_amic_init_verbs },
16401 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16402 .hp_nid = 0x03,
16403 .dac_nids = alc662_dac_nids,
16404 .dig_out_nid = ALC662_DIGOUT_NID,
16405 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16406 .channel_mode = alc662_3ST_2ch_modes,
16407 .input_mux = &alc662_eeepc_capture_source,
16408 .unsol_event = alc663_mode1_unsol_event,
16409 .init_hook = alc663_mode1_inithook,
16410 },
16411 [ALC662_ASUS_MODE2] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016412 .mixers = { alc662_1bjd_mixer },
16413 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020016414 .init_verbs = { alc662_init_verbs,
16415 alc662_1bjd_amic_init_verbs },
16416 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16417 .dac_nids = alc662_dac_nids,
16418 .dig_out_nid = ALC662_DIGOUT_NID,
16419 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16420 .channel_mode = alc662_3ST_2ch_modes,
16421 .input_mux = &alc662_eeepc_capture_source,
16422 .unsol_event = alc662_mode2_unsol_event,
16423 .init_hook = alc662_mode2_inithook,
16424 },
16425 [ALC663_ASUS_MODE3] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016426 .mixers = { alc663_two_hp_m1_mixer },
16427 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020016428 .init_verbs = { alc662_init_verbs,
16429 alc663_two_hp_amic_m1_init_verbs },
16430 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16431 .hp_nid = 0x03,
16432 .dac_nids = alc662_dac_nids,
16433 .dig_out_nid = ALC662_DIGOUT_NID,
16434 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16435 .channel_mode = alc662_3ST_2ch_modes,
16436 .input_mux = &alc662_eeepc_capture_source,
16437 .unsol_event = alc663_mode3_unsol_event,
16438 .init_hook = alc663_mode3_inithook,
16439 },
16440 [ALC663_ASUS_MODE4] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016441 .mixers = { alc663_asus_21jd_clfe_mixer },
16442 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020016443 .init_verbs = { alc662_init_verbs,
16444 alc663_21jd_amic_init_verbs},
16445 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16446 .hp_nid = 0x03,
16447 .dac_nids = alc662_dac_nids,
16448 .dig_out_nid = ALC662_DIGOUT_NID,
16449 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16450 .channel_mode = alc662_3ST_2ch_modes,
16451 .input_mux = &alc662_eeepc_capture_source,
16452 .unsol_event = alc663_mode4_unsol_event,
16453 .init_hook = alc663_mode4_inithook,
16454 },
16455 [ALC663_ASUS_MODE5] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016456 .mixers = { alc663_asus_15jd_clfe_mixer },
16457 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020016458 .init_verbs = { alc662_init_verbs,
16459 alc663_15jd_amic_init_verbs },
16460 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16461 .hp_nid = 0x03,
16462 .dac_nids = alc662_dac_nids,
16463 .dig_out_nid = ALC662_DIGOUT_NID,
16464 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16465 .channel_mode = alc662_3ST_2ch_modes,
16466 .input_mux = &alc662_eeepc_capture_source,
16467 .unsol_event = alc663_mode5_unsol_event,
16468 .init_hook = alc663_mode5_inithook,
16469 },
16470 [ALC663_ASUS_MODE6] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016471 .mixers = { alc663_two_hp_m2_mixer },
16472 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020016473 .init_verbs = { alc662_init_verbs,
16474 alc663_two_hp_amic_m2_init_verbs },
16475 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16476 .hp_nid = 0x03,
16477 .dac_nids = alc662_dac_nids,
16478 .dig_out_nid = ALC662_DIGOUT_NID,
16479 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16480 .channel_mode = alc662_3ST_2ch_modes,
16481 .input_mux = &alc662_eeepc_capture_source,
16482 .unsol_event = alc663_mode6_unsol_event,
16483 .init_hook = alc663_mode6_inithook,
16484 },
Kailang Yang622e84c2009-04-21 07:39:04 +020016485 [ALC272_DELL] = {
16486 .mixers = { alc663_m51va_mixer },
16487 .cap_mixer = alc272_auto_capture_mixer,
16488 .init_verbs = { alc662_init_verbs, alc272_dell_init_verbs },
16489 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
16490 .dac_nids = alc662_dac_nids,
16491 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16492 .adc_nids = alc272_adc_nids,
16493 .num_adc_nids = ARRAY_SIZE(alc272_adc_nids),
16494 .capsrc_nids = alc272_capsrc_nids,
16495 .channel_mode = alc662_3ST_2ch_modes,
16496 .input_mux = &alc663_m51va_capture_source,
16497 .unsol_event = alc663_m51va_unsol_event,
16498 .init_hook = alc663_m51va_inithook,
16499 },
16500 [ALC272_DELL_ZM1] = {
16501 .mixers = { alc663_m51va_mixer },
16502 .cap_mixer = alc662_auto_capture_mixer,
16503 .init_verbs = { alc662_init_verbs, alc272_dell_zm1_init_verbs },
16504 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
16505 .dac_nids = alc662_dac_nids,
16506 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16507 .adc_nids = alc662_adc_nids,
16508 .num_adc_nids = ARRAY_SIZE(alc662_adc_nids),
16509 .capsrc_nids = alc662_capsrc_nids,
16510 .channel_mode = alc662_3ST_2ch_modes,
16511 .input_mux = &alc663_m51va_capture_source,
16512 .unsol_event = alc663_m51va_unsol_event,
16513 .init_hook = alc663_m51va_inithook,
16514 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016515};
16516
16517
16518/*
16519 * BIOS auto configuration
16520 */
16521
16522/* add playback controls from the parsed DAC table */
16523static int alc662_auto_create_multi_out_ctls(struct alc_spec *spec,
16524 const struct auto_pin_cfg *cfg)
16525{
16526 char name[32];
16527 static const char *chname[4] = {
16528 "Front", "Surround", NULL /*CLFE*/, "Side"
16529 };
16530 hda_nid_t nid;
16531 int i, err;
16532
16533 for (i = 0; i < cfg->line_outs; i++) {
16534 if (!spec->multiout.dac_nids[i])
16535 continue;
Kailang Yangb60dd392007-09-20 12:50:29 +020016536 nid = alc880_idx_to_dac(i);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016537 if (i == 2) {
16538 /* Center/LFE */
16539 err = add_control(spec, ALC_CTL_WIDGET_VOL,
16540 "Center Playback Volume",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016541 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
16542 HDA_OUTPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016543 if (err < 0)
16544 return err;
16545 err = add_control(spec, ALC_CTL_WIDGET_VOL,
16546 "LFE Playback Volume",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016547 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
16548 HDA_OUTPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016549 if (err < 0)
16550 return err;
Herton Ronaldo Krzesinskib69ce012008-09-18 16:41:49 -030016551 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016552 "Center Playback Switch",
Herton Ronaldo Krzesinskib69ce012008-09-18 16:41:49 -030016553 HDA_COMPOSE_AMP_VAL(0x0e, 1, 0,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016554 HDA_INPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016555 if (err < 0)
16556 return err;
Herton Ronaldo Krzesinskib69ce012008-09-18 16:41:49 -030016557 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016558 "LFE Playback Switch",
Herton Ronaldo Krzesinskib69ce012008-09-18 16:41:49 -030016559 HDA_COMPOSE_AMP_VAL(0x0e, 2, 0,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016560 HDA_INPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016561 if (err < 0)
16562 return err;
16563 } else {
16564 sprintf(name, "%s Playback Volume", chname[i]);
16565 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016566 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
16567 HDA_OUTPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016568 if (err < 0)
16569 return err;
16570 sprintf(name, "%s Playback Switch", chname[i]);
Herton Ronaldo Krzesinskib69ce012008-09-18 16:41:49 -030016571 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
16572 HDA_COMPOSE_AMP_VAL(alc880_idx_to_mixer(i),
16573 3, 0, HDA_INPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016574 if (err < 0)
16575 return err;
16576 }
16577 }
16578 return 0;
16579}
16580
16581/* add playback controls for speaker and HP outputs */
16582static int alc662_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
16583 const char *pfx)
16584{
16585 hda_nid_t nid;
16586 int err;
16587 char name[32];
16588
16589 if (!pin)
16590 return 0;
16591
Takashi Iwai24fb9172008-09-02 14:48:20 +020016592 if (pin == 0x17) {
16593 /* ALC663 has a mono output pin on 0x17 */
16594 sprintf(name, "%s Playback Switch", pfx);
16595 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
16596 HDA_COMPOSE_AMP_VAL(pin, 2, 0, HDA_OUTPUT));
16597 return err;
16598 }
16599
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016600 if (alc880_is_fixed_pin(pin)) {
16601 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
Takashi Iwai939778a2009-02-05 15:57:55 +010016602 /* printk(KERN_DEBUG "DAC nid=%x\n",nid); */
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016603 /* specify the DAC as the extra output */
16604 if (!spec->multiout.hp_nid)
16605 spec->multiout.hp_nid = nid;
16606 else
16607 spec->multiout.extra_out_nid[0] = nid;
16608 /* control HP volume/switch on the output mixer amp */
16609 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
16610 sprintf(name, "%s Playback Volume", pfx);
16611 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
16612 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
16613 if (err < 0)
16614 return err;
16615 sprintf(name, "%s Playback Switch", pfx);
16616 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
16617 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
16618 if (err < 0)
16619 return err;
16620 } else if (alc880_is_multi_pin(pin)) {
16621 /* set manual connection */
16622 /* we have only a switch on HP-out PIN */
16623 sprintf(name, "%s Playback Switch", pfx);
16624 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
16625 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
16626 if (err < 0)
16627 return err;
16628 }
16629 return 0;
16630}
16631
Takashi Iwai2d864c42009-03-20 12:52:47 +010016632/* return the index of the src widget from the connection list of the nid.
16633 * return -1 if not found
16634 */
16635static int alc662_input_pin_idx(struct hda_codec *codec, hda_nid_t nid,
16636 hda_nid_t src)
16637{
16638 hda_nid_t conn_list[HDA_MAX_CONNECTIONS];
16639 int i, conns;
16640
16641 conns = snd_hda_get_connections(codec, nid, conn_list,
16642 ARRAY_SIZE(conn_list));
16643 if (conns < 0)
16644 return -1;
16645 for (i = 0; i < conns; i++)
16646 if (conn_list[i] == src)
16647 return i;
16648 return -1;
16649}
16650
16651static int alc662_is_input_pin(struct hda_codec *codec, hda_nid_t nid)
16652{
Takashi Iwai1327a322009-03-23 13:07:47 +010016653 unsigned int pincap = snd_hda_query_pin_caps(codec, nid);
Takashi Iwai2d864c42009-03-20 12:52:47 +010016654 return (pincap & AC_PINCAP_IN) != 0;
16655}
16656
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016657/* create playback/capture controls for input pins */
Takashi Iwai2d864c42009-03-20 12:52:47 +010016658static int alc662_auto_create_analog_input_ctls(struct hda_codec *codec,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016659 const struct auto_pin_cfg *cfg)
16660{
Takashi Iwai2d864c42009-03-20 12:52:47 +010016661 struct alc_spec *spec = codec->spec;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020016662 struct hda_input_mux *imux = &spec->private_imux[0];
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016663 int i, err, idx;
16664
16665 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwai2d864c42009-03-20 12:52:47 +010016666 if (alc662_is_input_pin(codec, cfg->input_pins[i])) {
16667 idx = alc662_input_pin_idx(codec, 0x0b,
16668 cfg->input_pins[i]);
16669 if (idx >= 0) {
16670 err = new_analog_input(spec, cfg->input_pins[i],
16671 auto_pin_cfg_labels[i],
16672 idx, 0x0b);
16673 if (err < 0)
16674 return err;
16675 }
16676 idx = alc662_input_pin_idx(codec, 0x22,
16677 cfg->input_pins[i]);
16678 if (idx >= 0) {
16679 imux->items[imux->num_items].label =
16680 auto_pin_cfg_labels[i];
16681 imux->items[imux->num_items].index = idx;
16682 imux->num_items++;
16683 }
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016684 }
16685 }
16686 return 0;
16687}
16688
16689static void alc662_auto_set_output_and_unmute(struct hda_codec *codec,
16690 hda_nid_t nid, int pin_type,
16691 int dac_idx)
16692{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016693 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016694 /* need the manual connection? */
16695 if (alc880_is_multi_pin(nid)) {
16696 struct alc_spec *spec = codec->spec;
16697 int idx = alc880_multi_pin_idx(nid);
16698 snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
16699 AC_VERB_SET_CONNECT_SEL,
16700 alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
16701 }
16702}
16703
16704static void alc662_auto_init_multi_out(struct hda_codec *codec)
16705{
16706 struct alc_spec *spec = codec->spec;
16707 int i;
16708
16709 for (i = 0; i <= HDA_SIDE; i++) {
16710 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020016711 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016712 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020016713 alc662_auto_set_output_and_unmute(codec, nid, pin_type,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016714 i);
16715 }
16716}
16717
16718static void alc662_auto_init_hp_out(struct hda_codec *codec)
16719{
16720 struct alc_spec *spec = codec->spec;
16721 hda_nid_t pin;
16722
16723 pin = spec->autocfg.hp_pins[0];
16724 if (pin) /* connect to front */
16725 /* use dac 0 */
16726 alc662_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016727 pin = spec->autocfg.speaker_pins[0];
16728 if (pin)
16729 alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016730}
16731
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016732#define ALC662_PIN_CD_NID ALC880_PIN_CD_NID
16733
16734static void alc662_auto_init_analog_input(struct hda_codec *codec)
16735{
16736 struct alc_spec *spec = codec->spec;
16737 int i;
16738
16739 for (i = 0; i < AUTO_PIN_LAST; i++) {
16740 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwai2d864c42009-03-20 12:52:47 +010016741 if (alc662_is_input_pin(codec, nid)) {
Takashi Iwai23f0c042009-02-26 13:03:58 +010016742 alc_set_input_pin(codec, nid, i);
Takashi Iwai52ca15b2009-03-23 12:51:55 +010016743 if (nid != ALC662_PIN_CD_NID &&
Takashi Iwaie82c0252009-03-23 15:17:38 +010016744 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016745 snd_hda_codec_write(codec, nid, 0,
16746 AC_VERB_SET_AMP_GAIN_MUTE,
16747 AMP_OUT_MUTE);
16748 }
16749 }
16750}
16751
Takashi Iwaif511b012008-08-15 16:46:42 +020016752#define alc662_auto_init_input_src alc882_auto_init_input_src
16753
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016754static int alc662_parse_auto_config(struct hda_codec *codec)
16755{
16756 struct alc_spec *spec = codec->spec;
16757 int err;
16758 static hda_nid_t alc662_ignore[] = { 0x1d, 0 };
16759
16760 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
16761 alc662_ignore);
16762 if (err < 0)
16763 return err;
16764 if (!spec->autocfg.line_outs)
16765 return 0; /* can't find valid BIOS pin config */
16766
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016767 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
16768 if (err < 0)
16769 return err;
16770 err = alc662_auto_create_multi_out_ctls(spec, &spec->autocfg);
16771 if (err < 0)
16772 return err;
16773 err = alc662_auto_create_extra_out(spec,
16774 spec->autocfg.speaker_pins[0],
16775 "Speaker");
16776 if (err < 0)
16777 return err;
16778 err = alc662_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
16779 "Headphone");
16780 if (err < 0)
16781 return err;
Takashi Iwai2d864c42009-03-20 12:52:47 +010016782 err = alc662_auto_create_analog_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016783 if (err < 0)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016784 return err;
16785
16786 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
16787
Takashi Iwai0852d7a2009-02-11 11:35:15 +010016788 if (spec->autocfg.dig_outs)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016789 spec->multiout.dig_out_nid = ALC880_DIGOUT_NID;
16790
Takashi Iwai603c4012008-07-30 15:01:44 +020016791 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010016792 add_mixer(spec, spec->kctls.list);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016793
16794 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020016795 spec->input_mux = &spec->private_imux[0];
Kailang Yangea1fb292008-08-26 12:58:38 +020016796
Takashi Iwaid88897e2008-10-31 15:01:37 +010016797 add_verb(spec, alc662_auto_init_verbs);
Takashi Iwai24fb9172008-09-02 14:48:20 +020016798 if (codec->vendor_id == 0x10ec0663)
Takashi Iwaid88897e2008-10-31 15:01:37 +010016799 add_verb(spec, alc663_auto_init_verbs);
Takashi Iwaiee979a142008-09-02 15:42:20 +020016800
16801 err = alc_auto_add_mic_boost(codec);
16802 if (err < 0)
16803 return err;
16804
Takashi Iwai4a79ba32009-04-22 16:31:35 +020016805 alc_ssid_check(codec, 0x15, 0x1b, 0x14);
16806
Takashi Iwai8c87286f2007-06-19 12:11:16 +020016807 return 1;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016808}
16809
16810/* additional initialization for auto-configuration model */
16811static void alc662_auto_init(struct hda_codec *codec)
16812{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016813 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016814 alc662_auto_init_multi_out(codec);
16815 alc662_auto_init_hp_out(codec);
16816 alc662_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020016817 alc662_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016818 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020016819 alc_inithook(codec);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016820}
16821
16822static int patch_alc662(struct hda_codec *codec)
16823{
16824 struct alc_spec *spec;
16825 int err, board_config;
16826
16827 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
16828 if (!spec)
16829 return -ENOMEM;
16830
16831 codec->spec = spec;
16832
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020016833 alc_fix_pll_init(codec, 0x20, 0x04, 15);
16834
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016835 board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST,
16836 alc662_models,
16837 alc662_cfg_tbl);
16838 if (board_config < 0) {
16839 printk(KERN_INFO "hda_codec: Unknown model for ALC662, "
16840 "trying auto-probe from BIOS...\n");
16841 board_config = ALC662_AUTO;
16842 }
16843
16844 if (board_config == ALC662_AUTO) {
16845 /* automatic parse from the BIOS config */
16846 err = alc662_parse_auto_config(codec);
16847 if (err < 0) {
16848 alc_free(codec);
16849 return err;
Takashi Iwai8c87286f2007-06-19 12:11:16 +020016850 } else if (!err) {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016851 printk(KERN_INFO
16852 "hda_codec: Cannot set up configuration "
16853 "from BIOS. Using base mode...\n");
16854 board_config = ALC662_3ST_2ch_DIG;
16855 }
16856 }
16857
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090016858 err = snd_hda_attach_beep_device(codec, 0x1);
16859 if (err < 0) {
16860 alc_free(codec);
16861 return err;
16862 }
16863
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016864 if (board_config != ALC662_AUTO)
16865 setup_preset(spec, &alc662_presets[board_config]);
16866
Kailang Yang6dda9f42008-05-27 12:05:31 +020016867 if (codec->vendor_id == 0x10ec0663) {
16868 spec->stream_name_analog = "ALC663 Analog";
16869 spec->stream_name_digital = "ALC663 Digital";
Kailang Yang01afd412008-10-15 11:22:09 +020016870 } else if (codec->vendor_id == 0x10ec0272) {
16871 spec->stream_name_analog = "ALC272 Analog";
16872 spec->stream_name_digital = "ALC272 Digital";
Kailang Yang6dda9f42008-05-27 12:05:31 +020016873 } else {
16874 spec->stream_name_analog = "ALC662 Analog";
16875 spec->stream_name_digital = "ALC662 Digital";
16876 }
16877
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016878 spec->stream_analog_playback = &alc662_pcm_analog_playback;
16879 spec->stream_analog_capture = &alc662_pcm_analog_capture;
16880
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016881 spec->stream_digital_playback = &alc662_pcm_digital_playback;
16882 spec->stream_digital_capture = &alc662_pcm_digital_capture;
16883
Takashi Iwaie1406342008-02-11 18:32:32 +010016884 spec->adc_nids = alc662_adc_nids;
16885 spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids);
16886 spec->capsrc_nids = alc662_capsrc_nids;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020016887 spec->capture_style = CAPT_MIX;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016888
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016889 if (!spec->cap_mixer)
16890 set_capture_mixer(spec);
Takashi Iwaib9591442009-03-16 15:25:00 +010016891 if (codec->vendor_id == 0x10ec0662)
16892 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
16893 else
16894 set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016895
Takashi Iwai2134ea42008-01-10 16:53:55 +010016896 spec->vmaster_nid = 0x02;
16897
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016898 codec->patch_ops = alc_patch_ops;
16899 if (board_config == ALC662_AUTO)
16900 spec->init_hook = alc662_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020016901#ifdef CONFIG_SND_HDA_POWER_SAVE
16902 if (!spec->loopback.amplist)
16903 spec->loopback.amplist = alc662_loopbacks;
16904#endif
Takashi Iwaidaead532008-11-28 12:55:36 +010016905 codec->proc_widget_hook = print_realtek_coef;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016906
16907 return 0;
16908}
16909
16910/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070016911 * patch entries
16912 */
Takashi Iwai1289e9e2008-11-27 15:47:11 +010016913static struct hda_codec_preset snd_hda_preset_realtek[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070016914 { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
Kailang Yangdf694da2005-12-05 19:42:22 +010016915 { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
Kailang Yangf6a92242007-12-13 16:52:54 +010016916 { .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 },
Kailang Yanga361d842007-06-05 12:30:55 +020016917 { .id = 0x10ec0268, .name = "ALC268", .patch = patch_alc268 },
Kailang Yangf6a92242007-12-13 16:52:54 +010016918 { .id = 0x10ec0269, .name = "ALC269", .patch = patch_alc269 },
Kailang Yang01afd412008-10-15 11:22:09 +020016919 { .id = 0x10ec0272, .name = "ALC272", .patch = patch_alc662 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016920 { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016921 .patch = patch_alc861 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016922 { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
16923 { .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 },
16924 { .id = 0x10ec0862, .name = "ALC861-VD", .patch = patch_alc861vd },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016925 { .id = 0x10ec0662, .rev = 0x100002, .name = "ALC662 rev2",
16926 .patch = patch_alc883 },
16927 { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1",
16928 .patch = patch_alc662 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020016929 { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016930 { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070016931 { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020016932 { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc883 },
Clive Messer669faba2008-09-30 15:49:13 +020016933 { .id = 0x10ec0885, .rev = 0x100101, .name = "ALC889A",
16934 .patch = patch_alc882 }, /* should be patch_alc883() in future */
Takashi Iwaicb308f92008-04-16 14:13:29 +020016935 { .id = 0x10ec0885, .rev = 0x100103, .name = "ALC889A",
Takashi Iwai7943a8a2008-04-16 17:29:09 +020016936 .patch = patch_alc882 }, /* should be patch_alc883() in future */
Kailang Yangdf694da2005-12-05 19:42:22 +010016937 { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
Kailang Yanga385a522008-10-15 11:20:21 +020016938 { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc883 },
Kailang Yang44426082008-10-15 11:18:05 +020016939 { .id = 0x10ec0888, .rev = 0x100101, .name = "ALC1200",
16940 .patch = patch_alc883 },
Wu Fengguang3fea2cb2008-12-26 12:20:43 +080016941 { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc883 },
Kailang Yangf6a92242007-12-13 16:52:54 +010016942 { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc883 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070016943 {} /* terminator */
16944};
Takashi Iwai1289e9e2008-11-27 15:47:11 +010016945
16946MODULE_ALIAS("snd-hda-codec-id:10ec*");
16947
16948MODULE_LICENSE("GPL");
16949MODULE_DESCRIPTION("Realtek HD-audio codec");
16950
16951static struct hda_codec_preset_list realtek_list = {
16952 .preset = snd_hda_preset_realtek,
16953 .owner = THIS_MODULE,
16954};
16955
16956static int __init patch_realtek_init(void)
16957{
16958 return snd_hda_add_codec_preset(&realtek_list);
16959}
16960
16961static void __exit patch_realtek_exit(void)
16962{
16963 snd_hda_delete_codec_preset(&realtek_list);
16964}
16965
16966module_init(patch_realtek_init)
16967module_exit(patch_realtek_exit)