blob: 5194a58fafaaab0ae0740412a544e2388277c9af [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Universal Interface for Intel High Definition Audio Codec
3 *
4 * HD audio interface patch for ALC 260/880/882 codecs
5 *
Kailang Yangdf694da2005-12-05 19:42:22 +01006 * Copyright (c) 2004 Kailang Yang <kailang@realtek.com.tw>
7 * PeiSen Hou <pshou@realtek.com.tw>
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 * Takashi Iwai <tiwai@suse.de>
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01009 * Jonathan Woithe <jwoithe@physics.adelaide.edu.au>
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 *
11 * This driver is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This driver is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <linux/init.h>
27#include <linux/delay.h>
28#include <linux/slab.h>
29#include <linux/pci.h>
30#include <sound/core.h>
31#include "hda_codec.h"
32#include "hda_local.h"
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090033#include "hda_beep.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070034
Kailang Yangccc656c2006-10-17 12:32:26 +020035#define ALC880_FRONT_EVENT 0x01
36#define ALC880_DCVOL_EVENT 0x02
37#define ALC880_HP_EVENT 0x04
38#define ALC880_MIC_EVENT 0x08
Linus Torvalds1da177e2005-04-16 15:20:36 -070039
40/* ALC880 board config type */
41enum {
Linus Torvalds1da177e2005-04-16 15:20:36 -070042 ALC880_3ST,
43 ALC880_3ST_DIG,
44 ALC880_5ST,
45 ALC880_5ST_DIG,
46 ALC880_W810,
Takashi Iwaidfc0ff62005-05-12 14:31:49 +020047 ALC880_Z71V,
Takashi Iwaib6482d42005-06-27 15:32:43 +020048 ALC880_6ST,
Takashi Iwai16ded522005-06-10 19:58:24 +020049 ALC880_6ST_DIG,
50 ALC880_F1734,
51 ALC880_ASUS,
52 ALC880_ASUS_DIG,
53 ALC880_ASUS_W1V,
Kailang Yangdf694da2005-12-05 19:42:22 +010054 ALC880_ASUS_DIG2,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +010055 ALC880_FUJITSU,
Takashi Iwai16ded522005-06-10 19:58:24 +020056 ALC880_UNIWILL_DIG,
Kailang Yangccc656c2006-10-17 12:32:26 +020057 ALC880_UNIWILL,
58 ALC880_UNIWILL_P53,
Kailang Yangdf694da2005-12-05 19:42:22 +010059 ALC880_CLEVO,
60 ALC880_TCL_S700,
Takashi Iwaiae6b8132006-03-03 16:47:17 +010061 ALC880_LG,
Takashi Iwaid6815182006-03-23 16:06:23 +010062 ALC880_LG_LW,
Takashi Iwaidf99cd32008-04-25 15:25:04 +020063 ALC880_MEDION_RIM,
Takashi Iwaie9edcee2005-06-13 14:16:38 +020064#ifdef CONFIG_SND_DEBUG
65 ALC880_TEST,
66#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010067 ALC880_AUTO,
Takashi Iwai16ded522005-06-10 19:58:24 +020068 ALC880_MODEL_LAST /* last tag */
69};
70
71/* ALC260 models */
72enum {
73 ALC260_BASIC,
74 ALC260_HP,
Kailang Yang3f878302008-08-26 13:02:23 +020075 ALC260_HP_DC7600,
Kailang Yangdf694da2005-12-05 19:42:22 +010076 ALC260_HP_3013,
77 ALC260_FUJITSU_S702X,
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +010078 ALC260_ACER,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020079 ALC260_WILL,
80 ALC260_REPLACER_672V,
Jonathan Woithe7cf51e42006-02-09 12:01:26 +010081#ifdef CONFIG_SND_DEBUG
82 ALC260_TEST,
83#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010084 ALC260_AUTO,
Takashi Iwai16ded522005-06-10 19:58:24 +020085 ALC260_MODEL_LAST /* last tag */
Linus Torvalds1da177e2005-04-16 15:20:36 -070086};
87
Kailang Yangdf694da2005-12-05 19:42:22 +010088/* ALC262 models */
89enum {
90 ALC262_BASIC,
Kailang Yangccc656c2006-10-17 12:32:26 +020091 ALC262_HIPPO,
92 ALC262_HIPPO_1,
Takashi Iwai834be882006-03-01 14:16:17 +010093 ALC262_FUJITSU,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020094 ALC262_HP_BPC,
Kailang Yangcd7509a2007-01-26 18:33:17 +010095 ALC262_HP_BPC_D7000_WL,
96 ALC262_HP_BPC_D7000_WF,
Kailang Yang66d2a9d2007-11-14 12:06:21 +010097 ALC262_HP_TC_T5735,
Kailang Yang8c427222008-01-10 13:03:59 +010098 ALC262_HP_RP5700,
Takashi Iwai304dcaa2006-07-25 14:51:16 +020099 ALC262_BENQ_ED8,
Kailang Yang272a5272007-05-14 11:00:38 +0200100 ALC262_SONY_ASSAMD,
Kailang Yang83c34212007-07-05 11:43:05 +0200101 ALC262_BENQ_T31,
Tobin Davisf651b502007-10-26 12:40:47 +0200102 ALC262_ULTRA,
Jiang zhe0e31daf2008-03-20 12:12:39 +0100103 ALC262_LENOVO_3000,
Pascal Terjane8f9ae22008-08-04 14:36:05 +0200104 ALC262_NEC,
Kailang Yang4e555fe2008-08-26 13:05:55 +0200105 ALC262_TOSHIBA_S06,
Hiroshi Miura9f99a632008-08-28 16:09:06 +0200106 ALC262_TOSHIBA_RX1,
Tony Vroonba340e82009-02-02 19:01:30 +0000107 ALC262_TYAN,
Kailang Yangdf694da2005-12-05 19:42:22 +0100108 ALC262_AUTO,
109 ALC262_MODEL_LAST /* last tag */
110};
111
Kailang Yanga361d842007-06-05 12:30:55 +0200112/* ALC268 models */
113enum {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +0200114 ALC267_QUANTA_IL1,
Kailang Yanga361d842007-06-05 12:30:55 +0200115 ALC268_3ST,
Kailang Yangd1a991a2007-08-15 16:21:59 +0200116 ALC268_TOSHIBA,
Takashi Iwaid2738092007-08-16 14:59:45 +0200117 ALC268_ACER,
Takashi Iwaic238b4f2008-11-05 14:57:20 +0100118 ALC268_ACER_DMIC,
Kailang Yang8ef355d2008-08-26 13:10:22 +0200119 ALC268_ACER_ASPIRE_ONE,
Takashi Iwai3866f0b2008-01-15 12:37:42 +0100120 ALC268_DELL,
Mirco Tischlerf12462c2008-02-04 12:33:59 +0100121 ALC268_ZEPTO,
Jonathan Woithe86c53bd2008-01-08 12:33:19 +0100122#ifdef CONFIG_SND_DEBUG
123 ALC268_TEST,
124#endif
Kailang Yanga361d842007-06-05 12:30:55 +0200125 ALC268_AUTO,
126 ALC268_MODEL_LAST /* last tag */
127};
128
Kailang Yangf6a92242007-12-13 16:52:54 +0100129/* ALC269 models */
130enum {
131 ALC269_BASIC,
Kailang Yang60db6b52008-08-26 13:13:00 +0200132 ALC269_QUANTA_FL1,
Kailang Yangf53281e2008-07-18 12:36:43 +0200133 ALC269_ASUS_EEEPC_P703,
134 ALC269_ASUS_EEEPC_P901,
Takashi Iwai26f5df22008-11-03 17:39:46 +0100135 ALC269_FUJITSU,
Tony Vroon64154832008-11-06 15:08:49 +0000136 ALC269_LIFEBOOK,
Kailang Yangf6a92242007-12-13 16:52:54 +0100137 ALC269_AUTO,
138 ALC269_MODEL_LAST /* last tag */
139};
140
Kailang Yangdf694da2005-12-05 19:42:22 +0100141/* ALC861 models */
142enum {
143 ALC861_3ST,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200144 ALC660_3ST,
Kailang Yangdf694da2005-12-05 19:42:22 +0100145 ALC861_3ST_DIG,
146 ALC861_6ST_DIG,
Takashi Iwai22309c32006-08-09 16:57:28 +0200147 ALC861_UNIWILL_M31,
Tobin Davisa53d1ae2006-10-17 12:00:28 +0200148 ALC861_TOSHIBA,
Mariusz Domanski7cdbff92006-10-23 13:42:56 +0200149 ALC861_ASUS,
Takashi Iwai56bb0ca2006-11-22 11:52:52 +0100150 ALC861_ASUS_LAPTOP,
Kailang Yangdf694da2005-12-05 19:42:22 +0100151 ALC861_AUTO,
152 ALC861_MODEL_LAST,
153};
154
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100155/* ALC861-VD models */
156enum {
157 ALC660VD_3ST,
Mike Crash6963f842007-06-25 12:12:51 +0200158 ALC660VD_3ST_DIG,
Takashi Iwai13c94742008-11-05 08:06:08 +0100159 ALC660VD_ASUS_V1S,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100160 ALC861VD_3ST,
161 ALC861VD_3ST_DIG,
162 ALC861VD_6ST_DIG,
Kailang Yangbdd148a2007-05-08 15:19:08 +0200163 ALC861VD_LENOVO,
Kailang Yang272a5272007-05-14 11:00:38 +0200164 ALC861VD_DALLAS,
Kailang Yangd1a991a2007-08-15 16:21:59 +0200165 ALC861VD_HP,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100166 ALC861VD_AUTO,
167 ALC861VD_MODEL_LAST,
168};
169
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200170/* ALC662 models */
171enum {
172 ALC662_3ST_2ch_DIG,
173 ALC662_3ST_6ch_DIG,
174 ALC662_3ST_6ch,
175 ALC662_5ST_DIG,
176 ALC662_LENOVO_101E,
Kailang Yang291702f2007-10-16 14:28:03 +0200177 ALC662_ASUS_EEEPC_P701,
Kailang Yang8c427222008-01-10 13:03:59 +0100178 ALC662_ASUS_EEEPC_EP20,
Kailang Yang6dda9f42008-05-27 12:05:31 +0200179 ALC663_ASUS_M51VA,
180 ALC663_ASUS_G71V,
181 ALC663_ASUS_H13,
182 ALC663_ASUS_G50V,
Kailang Yangf1d4e282008-08-26 14:03:29 +0200183 ALC662_ECS,
184 ALC663_ASUS_MODE1,
185 ALC662_ASUS_MODE2,
186 ALC663_ASUS_MODE3,
187 ALC663_ASUS_MODE4,
188 ALC663_ASUS_MODE5,
189 ALC663_ASUS_MODE6,
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200190 ALC662_AUTO,
191 ALC662_MODEL_LAST,
192};
193
Kailang Yangdf694da2005-12-05 19:42:22 +0100194/* ALC882 models */
195enum {
196 ALC882_3ST_DIG,
197 ALC882_6ST_DIG,
Takashi Iwai4b146cb2006-07-28 14:42:36 +0200198 ALC882_ARIMA,
Kailang Yangbdd148a2007-05-08 15:19:08 +0200199 ALC882_W2JC,
Kailang Yang272a5272007-05-14 11:00:38 +0200200 ALC882_TARGA,
201 ALC882_ASUS_A7J,
Takashi Iwai914759b2007-09-06 14:52:04 +0200202 ALC882_ASUS_A7M,
Tobin Davis9102cd12006-12-15 10:02:12 +0100203 ALC885_MACPRO,
Takashi Iwai87350ad2007-08-16 18:19:38 +0200204 ALC885_MBP3,
Nicola Fagnanic54728d2007-07-19 23:28:52 +0200205 ALC885_IMAC24,
Kailang Yang272a5272007-05-14 11:00:38 +0200206 ALC882_AUTO,
Kailang Yangdf694da2005-12-05 19:42:22 +0100207 ALC882_MODEL_LAST,
208};
209
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200210/* ALC883 models */
211enum {
212 ALC883_3ST_2ch_DIG,
213 ALC883_3ST_6ch_DIG,
214 ALC883_3ST_6ch,
215 ALC883_6ST_DIG,
Kailang Yangccc656c2006-10-17 12:32:26 +0200216 ALC883_TARGA_DIG,
217 ALC883_TARGA_2ch_DIG,
Vladimir Avdoninbab282b2006-08-22 13:31:58 +0200218 ALC883_ACER,
Tobin Davis2880a862007-08-07 11:50:26 +0200219 ALC883_ACER_ASPIRE,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +0800220 ALC888_ACER_ASPIRE_4930G,
Tobin Davisc07584c2006-10-13 12:32:16 +0200221 ALC883_MEDION,
Kailang Yangea1fb292008-08-26 12:58:38 +0200222 ALC883_MEDION_MD2,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +0100223 ALC883_LAPTOP_EAPD,
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200224 ALC883_LENOVO_101E_2ch,
Kailang Yang272a5272007-05-14 11:00:38 +0200225 ALC883_LENOVO_NB0763,
Kailang Yang189609a2007-08-20 11:31:23 +0200226 ALC888_LENOVO_MS7195_DIG,
Kailang Yange2757d52008-08-26 13:17:46 +0200227 ALC888_LENOVO_SKY,
Kailang Yangea1fb292008-08-26 12:58:38 +0200228 ALC883_HAIER_W66,
Claudio Matsuoka4723c022007-07-13 14:36:19 +0200229 ALC888_3ST_HP,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +0100230 ALC888_6ST_DELL,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +0100231 ALC883_MITAC,
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +0100232 ALC883_CLEVO_M720,
Jiang zhefb97dc62008-03-06 11:07:11 +0100233 ALC883_FUJITSU_PI2515,
Vincent Petryef8ef5f2008-11-23 11:31:41 +0800234 ALC888_FUJITSU_XA3530,
Jiang zhe17bba1b2008-06-04 12:11:07 +0200235 ALC883_3ST_6ch_INTEL,
Kailang Yange2757d52008-08-26 13:17:46 +0200236 ALC888_ASUS_M90V,
237 ALC888_ASUS_EEE1601,
Wu Fengguang3ab90932008-11-17 09:51:09 +0100238 ALC1200_ASUS_P5Q,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200239 ALC883_AUTO,
240 ALC883_MODEL_LAST,
241};
242
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -0200243/* styles of capture selection */
244enum {
245 CAPT_MUX = 0, /* only mux based */
246 CAPT_MIX, /* only mixer based */
247 CAPT_1MUX_MIX, /* first mux and other mixers */
248};
249
Kailang Yangdf694da2005-12-05 19:42:22 +0100250/* for GPIO Poll */
251#define GPIO_MASK 0x03
252
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253struct alc_spec {
254 /* codec parameterization */
Kailang Yangdf694da2005-12-05 19:42:22 +0100255 struct snd_kcontrol_new *mixers[5]; /* mixer arrays */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 unsigned int num_mixers;
Takashi Iwaif9e336f2008-10-31 16:37:07 +0100257 struct snd_kcontrol_new *cap_mixer; /* capture mixer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258
Kailang Yangdf694da2005-12-05 19:42:22 +0100259 const struct hda_verb *init_verbs[5]; /* initialization verbs
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200260 * don't forget NULL
261 * termination!
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200262 */
263 unsigned int num_init_verbs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264
Takashi Iwai16ded522005-06-10 19:58:24 +0200265 char *stream_name_analog; /* analog PCM stream */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266 struct hda_pcm_stream *stream_analog_playback;
267 struct hda_pcm_stream *stream_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +0100268 struct hda_pcm_stream *stream_analog_alt_playback;
269 struct hda_pcm_stream *stream_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200271 char *stream_name_digital; /* digital PCM stream */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 struct hda_pcm_stream *stream_digital_playback;
273 struct hda_pcm_stream *stream_digital_capture;
274
275 /* playback */
Takashi Iwai16ded522005-06-10 19:58:24 +0200276 struct hda_multi_out multiout; /* playback set-up
277 * max_channels, dacs must be set
278 * dig_out_nid and hp_nid are optional
279 */
Takashi Iwai63300792008-01-24 15:31:36 +0100280 hda_nid_t alt_dac_nid;
Takashi Iwai8c441982009-01-20 18:30:20 +0100281 int dig_out_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282
283 /* capture */
284 unsigned int num_adc_nids;
285 hda_nid_t *adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100286 hda_nid_t *capsrc_nids;
Takashi Iwai16ded522005-06-10 19:58:24 +0200287 hda_nid_t dig_in_nid; /* digital-in NID; optional */
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -0200288 int capture_style; /* capture style (CAPT_*) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289
290 /* capture source */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200291 unsigned int num_mux_defs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 const struct hda_input_mux *input_mux;
293 unsigned int cur_mux[3];
294
295 /* channel model */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100296 const struct hda_channel_mode *channel_mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 int num_channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200298 int need_dac_fix;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299
300 /* PCM information */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100301 struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */
Takashi Iwai41e41f12005-06-08 14:48:49 +0200302
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200303 /* dynamic controls, init_verbs and input_mux */
304 struct auto_pin_cfg autocfg;
Takashi Iwai603c4012008-07-30 15:01:44 +0200305 struct snd_array kctls;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -0200306 struct hda_input_mux private_imux[3];
Takashi Iwai41923e42007-10-22 17:20:10 +0200307 hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
Takashi Iwai834be882006-03-01 14:16:17 +0100308
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100309 /* hooks */
310 void (*init_hook)(struct hda_codec *codec);
311 void (*unsol_event)(struct hda_codec *codec, unsigned int res);
312
Takashi Iwai834be882006-03-01 14:16:17 +0100313 /* for pin sensing */
314 unsigned int sense_updated: 1;
315 unsigned int jack_present: 1;
Takashi Iwaibec15c32008-01-28 18:16:30 +0100316 unsigned int master_sw: 1;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200317
Takashi Iwaie64f14f2009-01-20 18:32:55 +0100318 /* other flags */
319 unsigned int no_analog :1; /* digital I/O only */
320
Takashi Iwai2134ea42008-01-10 16:53:55 +0100321 /* for virtual master */
322 hda_nid_t vmaster_nid;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200323#ifdef CONFIG_SND_HDA_POWER_SAVE
324 struct hda_loopback_check loopback;
325#endif
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +0200326
327 /* for PLL fix */
328 hda_nid_t pll_nid;
329 unsigned int pll_coef_idx, pll_coef_bit;
Takashi Iwaie044c392008-10-27 16:56:24 +0100330
331#ifdef SND_HDA_NEEDS_RESUME
332#define ALC_MAX_PINS 16
333 unsigned int num_pins;
334 hda_nid_t pin_nids[ALC_MAX_PINS];
335 unsigned int pin_cfgs[ALC_MAX_PINS];
336#endif
Kailang Yangdf694da2005-12-05 19:42:22 +0100337};
338
339/*
340 * configuration template - to be copied to the spec instance
341 */
342struct alc_config_preset {
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200343 struct snd_kcontrol_new *mixers[5]; /* should be identical size
344 * with spec
345 */
Takashi Iwaif9e336f2008-10-31 16:37:07 +0100346 struct snd_kcontrol_new *cap_mixer; /* capture mixer */
Kailang Yangdf694da2005-12-05 19:42:22 +0100347 const struct hda_verb *init_verbs[5];
348 unsigned int num_dacs;
349 hda_nid_t *dac_nids;
350 hda_nid_t dig_out_nid; /* optional */
351 hda_nid_t hp_nid; /* optional */
Wu Fengguangb25c9da2009-02-06 15:02:27 +0800352 hda_nid_t *slave_dig_outs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100353 unsigned int num_adc_nids;
354 hda_nid_t *adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100355 hda_nid_t *capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +0100356 hda_nid_t dig_in_nid;
357 unsigned int num_channel_mode;
358 const struct hda_channel_mode *channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200359 int need_dac_fix;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200360 unsigned int num_mux_defs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100361 const struct hda_input_mux *input_mux;
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100362 void (*unsol_event)(struct hda_codec *, unsigned int);
363 void (*init_hook)(struct hda_codec *);
Takashi Iwaicb53c622007-08-10 17:21:45 +0200364#ifdef CONFIG_SND_HDA_POWER_SAVE
365 struct hda_amp_list *loopbacks;
366#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367};
368
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369
370/*
371 * input MUX handling
372 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200373static int alc_mux_enum_info(struct snd_kcontrol *kcontrol,
374 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375{
376 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
377 struct alc_spec *spec = codec->spec;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200378 unsigned int mux_idx = snd_ctl_get_ioffidx(kcontrol, &uinfo->id);
379 if (mux_idx >= spec->num_mux_defs)
380 mux_idx = 0;
381 return snd_hda_input_mux_info(&spec->input_mux[mux_idx], uinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382}
383
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200384static int alc_mux_enum_get(struct snd_kcontrol *kcontrol,
385 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386{
387 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
388 struct alc_spec *spec = codec->spec;
389 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
390
391 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
392 return 0;
393}
394
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200395static int alc_mux_enum_put(struct snd_kcontrol *kcontrol,
396 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397{
398 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
399 struct alc_spec *spec = codec->spec;
Takashi Iwaicd896c32008-11-18 12:36:33 +0100400 const struct hda_input_mux *imux;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Takashi Iwaicd896c32008-11-18 12:36:33 +0100402 unsigned int mux_idx;
Takashi Iwaie1406342008-02-11 18:32:32 +0100403 hda_nid_t nid = spec->capsrc_nids ?
404 spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405
Takashi Iwaicd896c32008-11-18 12:36:33 +0100406 mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx;
407 imux = &spec->input_mux[mux_idx];
408
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -0200409 if (spec->capture_style &&
410 !(spec->capture_style == CAPT_1MUX_MIX && !adc_idx)) {
Takashi Iwai54cbc9a2008-10-31 15:24:04 +0100411 /* Matrix-mixer style (e.g. ALC882) */
412 unsigned int *cur_val = &spec->cur_mux[adc_idx];
413 unsigned int i, idx;
414
415 idx = ucontrol->value.enumerated.item[0];
416 if (idx >= imux->num_items)
417 idx = imux->num_items - 1;
418 if (*cur_val == idx)
419 return 0;
420 for (i = 0; i < imux->num_items; i++) {
421 unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE;
422 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT,
423 imux->items[i].index,
424 HDA_AMP_MUTE, v);
425 }
426 *cur_val = idx;
427 return 1;
428 } else {
429 /* MUX style (e.g. ALC880) */
Takashi Iwaicd896c32008-11-18 12:36:33 +0100430 return snd_hda_input_mux_put(codec, imux, ucontrol, nid,
Takashi Iwai54cbc9a2008-10-31 15:24:04 +0100431 &spec->cur_mux[adc_idx]);
432 }
433}
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200434
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435/*
436 * channel mode setting
437 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200438static int alc_ch_mode_info(struct snd_kcontrol *kcontrol,
439 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440{
441 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
442 struct alc_spec *spec = codec->spec;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100443 return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode,
444 spec->num_channel_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445}
446
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200447static int alc_ch_mode_get(struct snd_kcontrol *kcontrol,
448 struct snd_ctl_elem_value *ucontrol)
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_get(codec, ucontrol, spec->channel_mode,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200453 spec->num_channel_mode,
454 spec->multiout.max_channels);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455}
456
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200457static int alc_ch_mode_put(struct snd_kcontrol *kcontrol,
458 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459{
460 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
461 struct alc_spec *spec = codec->spec;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200462 int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
463 spec->num_channel_mode,
464 &spec->multiout.max_channels);
Takashi Iwaibd2033f2006-10-10 19:49:31 +0200465 if (err >= 0 && spec->need_dac_fix)
Takashi Iwai4e195a72006-07-28 14:47:34 +0200466 spec->multiout.num_dacs = spec->multiout.max_channels / 2;
467 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468}
469
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470/*
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100471 * Control the mode of pin widget settings via the mixer. "pc" is used
Kailang Yangea1fb292008-08-26 12:58:38 +0200472 * instead of "%" to avoid consequences of accidently treating the % as
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100473 * being part of a format specifier. Maximum allowed length of a value is
474 * 63 characters plus NULL terminator.
Jonathan Woithe7cf51e42006-02-09 12:01:26 +0100475 *
476 * Note: some retasking pin complexes seem to ignore requests for input
477 * states other than HiZ (eg: PIN_VREFxx) and revert to HiZ if any of these
478 * are requested. Therefore order this list so that this behaviour will not
479 * cause problems when mixer clients move through the enum sequentially.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200480 * NIDs 0x0f and 0x10 have been observed to have this behaviour as of
481 * March 2006.
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200482 */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100483static char *alc_pin_mode_names[] = {
Jonathan Woithe7cf51e42006-02-09 12:01:26 +0100484 "Mic 50pc bias", "Mic 80pc bias",
485 "Line in", "Line out", "Headphone out",
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100486};
487static unsigned char alc_pin_mode_values[] = {
Jonathan Woithe7cf51e42006-02-09 12:01:26 +0100488 PIN_VREF50, PIN_VREF80, PIN_IN, PIN_OUT, PIN_HP,
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100489};
490/* The control can present all 5 options, or it can limit the options based
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200491 * in the pin being assumed to be exclusively an input or an output pin. In
492 * addition, "input" pins may or may not process the mic bias option
493 * depending on actual widget capability (NIDs 0x0f and 0x10 don't seem to
494 * accept requests for bias as of chip versions up to March 2006) and/or
495 * wiring in the computer.
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100496 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200497#define ALC_PIN_DIR_IN 0x00
498#define ALC_PIN_DIR_OUT 0x01
499#define ALC_PIN_DIR_INOUT 0x02
500#define ALC_PIN_DIR_IN_NOMICBIAS 0x03
501#define ALC_PIN_DIR_INOUT_NOMICBIAS 0x04
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100502
Kailang Yangea1fb292008-08-26 12:58:38 +0200503/* Info about the pin modes supported by the different pin direction modes.
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100504 * For each direction the minimum and maximum values are given.
505 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200506static signed char alc_pin_mode_dir_info[5][2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100507 { 0, 2 }, /* ALC_PIN_DIR_IN */
508 { 3, 4 }, /* ALC_PIN_DIR_OUT */
509 { 0, 4 }, /* ALC_PIN_DIR_INOUT */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200510 { 2, 2 }, /* ALC_PIN_DIR_IN_NOMICBIAS */
511 { 2, 4 }, /* ALC_PIN_DIR_INOUT_NOMICBIAS */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100512};
513#define alc_pin_mode_min(_dir) (alc_pin_mode_dir_info[_dir][0])
514#define alc_pin_mode_max(_dir) (alc_pin_mode_dir_info[_dir][1])
515#define alc_pin_mode_n_items(_dir) \
516 (alc_pin_mode_max(_dir)-alc_pin_mode_min(_dir)+1)
517
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200518static int alc_pin_mode_info(struct snd_kcontrol *kcontrol,
519 struct snd_ctl_elem_info *uinfo)
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200520{
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100521 unsigned int item_num = uinfo->value.enumerated.item;
522 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
523
524 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200525 uinfo->count = 1;
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100526 uinfo->value.enumerated.items = alc_pin_mode_n_items(dir);
527
528 if (item_num<alc_pin_mode_min(dir) || item_num>alc_pin_mode_max(dir))
529 item_num = alc_pin_mode_min(dir);
530 strcpy(uinfo->value.enumerated.name, alc_pin_mode_names[item_num]);
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200531 return 0;
532}
533
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200534static int alc_pin_mode_get(struct snd_kcontrol *kcontrol,
535 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200536{
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100537 unsigned int i;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200538 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
539 hda_nid_t nid = kcontrol->private_value & 0xffff;
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100540 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200541 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200542 unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
543 AC_VERB_GET_PIN_WIDGET_CONTROL,
544 0x00);
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200545
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100546 /* Find enumerated value for current pinctl setting */
547 i = alc_pin_mode_min(dir);
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200548 while (alc_pin_mode_values[i] != pinctl && i <= alc_pin_mode_max(dir))
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100549 i++;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200550 *valp = i <= alc_pin_mode_max(dir) ? i: alc_pin_mode_min(dir);
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100551 return 0;
552}
553
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200554static int alc_pin_mode_put(struct snd_kcontrol *kcontrol,
555 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100556{
557 signed int change;
558 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
559 hda_nid_t nid = kcontrol->private_value & 0xffff;
560 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
561 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200562 unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
563 AC_VERB_GET_PIN_WIDGET_CONTROL,
564 0x00);
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100565
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200566 if (val < alc_pin_mode_min(dir) || val > alc_pin_mode_max(dir))
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100567 val = alc_pin_mode_min(dir);
568
569 change = pinctl != alc_pin_mode_values[val];
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100570 if (change) {
571 /* Set pin mode to that requested */
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200572 snd_hda_codec_write_cache(codec, nid, 0,
573 AC_VERB_SET_PIN_WIDGET_CONTROL,
574 alc_pin_mode_values[val]);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100575
Kailang Yangea1fb292008-08-26 12:58:38 +0200576 /* Also enable the retasking pin's input/output as required
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100577 * for the requested pin mode. Enum values of 2 or less are
578 * input modes.
579 *
580 * Dynamically switching the input/output buffers probably
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200581 * reduces noise slightly (particularly on input) so we'll
582 * do it. However, having both input and output buffers
583 * enabled simultaneously doesn't seem to be problematic if
584 * this turns out to be necessary in the future.
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100585 */
586 if (val <= 2) {
Takashi Iwai47fd8302007-08-10 17:11:07 +0200587 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
588 HDA_AMP_MUTE, HDA_AMP_MUTE);
589 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
590 HDA_AMP_MUTE, 0);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100591 } else {
Takashi Iwai47fd8302007-08-10 17:11:07 +0200592 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
593 HDA_AMP_MUTE, HDA_AMP_MUTE);
594 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
595 HDA_AMP_MUTE, 0);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100596 }
597 }
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200598 return change;
599}
600
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100601#define ALC_PIN_MODE(xname, nid, dir) \
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200602 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100603 .info = alc_pin_mode_info, \
604 .get = alc_pin_mode_get, \
605 .put = alc_pin_mode_put, \
606 .private_value = nid | (dir<<16) }
Kailang Yangdf694da2005-12-05 19:42:22 +0100607
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100608/* A switch control for ALC260 GPIO pins. Multiple GPIOs can be ganged
609 * together using a mask with more than one bit set. This control is
610 * currently used only by the ALC260 test model. At this stage they are not
611 * needed for any "production" models.
612 */
613#ifdef CONFIG_SND_DEBUG
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200614#define alc_gpio_data_info snd_ctl_boolean_mono_info
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200615
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200616static int alc_gpio_data_get(struct snd_kcontrol *kcontrol,
617 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100618{
619 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
620 hda_nid_t nid = kcontrol->private_value & 0xffff;
621 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
622 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200623 unsigned int val = snd_hda_codec_read(codec, nid, 0,
624 AC_VERB_GET_GPIO_DATA, 0x00);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100625
626 *valp = (val & mask) != 0;
627 return 0;
628}
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200629static int alc_gpio_data_put(struct snd_kcontrol *kcontrol,
630 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100631{
632 signed int change;
633 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
634 hda_nid_t nid = kcontrol->private_value & 0xffff;
635 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
636 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200637 unsigned int gpio_data = snd_hda_codec_read(codec, nid, 0,
638 AC_VERB_GET_GPIO_DATA,
639 0x00);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100640
641 /* Set/unset the masked GPIO bit(s) as needed */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200642 change = (val == 0 ? 0 : mask) != (gpio_data & mask);
643 if (val == 0)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100644 gpio_data &= ~mask;
645 else
646 gpio_data |= mask;
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200647 snd_hda_codec_write_cache(codec, nid, 0,
648 AC_VERB_SET_GPIO_DATA, gpio_data);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100649
650 return change;
651}
652#define ALC_GPIO_DATA_SWITCH(xname, nid, mask) \
653 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
654 .info = alc_gpio_data_info, \
655 .get = alc_gpio_data_get, \
656 .put = alc_gpio_data_put, \
657 .private_value = nid | (mask<<16) }
658#endif /* CONFIG_SND_DEBUG */
659
Jonathan Woithe92621f12006-02-28 11:47:47 +0100660/* A switch control to allow the enabling of the digital IO pins on the
661 * ALC260. This is incredibly simplistic; the intention of this control is
662 * to provide something in the test model allowing digital outputs to be
663 * identified if present. If models are found which can utilise these
664 * outputs a more complete mixer control can be devised for those models if
665 * necessary.
666 */
667#ifdef CONFIG_SND_DEBUG
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200668#define alc_spdif_ctrl_info snd_ctl_boolean_mono_info
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200669
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200670static int alc_spdif_ctrl_get(struct snd_kcontrol *kcontrol,
671 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe92621f12006-02-28 11:47:47 +0100672{
673 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
674 hda_nid_t nid = kcontrol->private_value & 0xffff;
675 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
676 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200677 unsigned int val = snd_hda_codec_read(codec, nid, 0,
Andrew Paprocki3982d172007-12-19 12:13:44 +0100678 AC_VERB_GET_DIGI_CONVERT_1, 0x00);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100679
680 *valp = (val & mask) != 0;
681 return 0;
682}
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200683static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol,
684 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe92621f12006-02-28 11:47:47 +0100685{
686 signed int change;
687 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
688 hda_nid_t nid = kcontrol->private_value & 0xffff;
689 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
690 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200691 unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
Andrew Paprocki3982d172007-12-19 12:13:44 +0100692 AC_VERB_GET_DIGI_CONVERT_1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200693 0x00);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100694
695 /* Set/unset the masked control bit(s) as needed */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200696 change = (val == 0 ? 0 : mask) != (ctrl_data & mask);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100697 if (val==0)
698 ctrl_data &= ~mask;
699 else
700 ctrl_data |= mask;
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200701 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
702 ctrl_data);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100703
704 return change;
705}
706#define ALC_SPDIF_CTRL_SWITCH(xname, nid, mask) \
707 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
708 .info = alc_spdif_ctrl_info, \
709 .get = alc_spdif_ctrl_get, \
710 .put = alc_spdif_ctrl_put, \
711 .private_value = nid | (mask<<16) }
712#endif /* CONFIG_SND_DEBUG */
713
Jonathan Woithef8225f62008-01-08 12:16:54 +0100714/* A switch control to allow the enabling EAPD digital outputs on the ALC26x.
715 * Again, this is only used in the ALC26x test models to help identify when
716 * the EAPD line must be asserted for features to work.
717 */
718#ifdef CONFIG_SND_DEBUG
719#define alc_eapd_ctrl_info snd_ctl_boolean_mono_info
720
721static int alc_eapd_ctrl_get(struct snd_kcontrol *kcontrol,
722 struct snd_ctl_elem_value *ucontrol)
723{
724 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
725 hda_nid_t nid = kcontrol->private_value & 0xffff;
726 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
727 long *valp = ucontrol->value.integer.value;
728 unsigned int val = snd_hda_codec_read(codec, nid, 0,
729 AC_VERB_GET_EAPD_BTLENABLE, 0x00);
730
731 *valp = (val & mask) != 0;
732 return 0;
733}
734
735static int alc_eapd_ctrl_put(struct snd_kcontrol *kcontrol,
736 struct snd_ctl_elem_value *ucontrol)
737{
738 int change;
739 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
740 hda_nid_t nid = kcontrol->private_value & 0xffff;
741 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
742 long val = *ucontrol->value.integer.value;
743 unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
744 AC_VERB_GET_EAPD_BTLENABLE,
745 0x00);
746
747 /* Set/unset the masked control bit(s) as needed */
748 change = (!val ? 0 : mask) != (ctrl_data & mask);
749 if (!val)
750 ctrl_data &= ~mask;
751 else
752 ctrl_data |= mask;
753 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
754 ctrl_data);
755
756 return change;
757}
758
759#define ALC_EAPD_CTRL_SWITCH(xname, nid, mask) \
760 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
761 .info = alc_eapd_ctrl_info, \
762 .get = alc_eapd_ctrl_get, \
763 .put = alc_eapd_ctrl_put, \
764 .private_value = nid | (mask<<16) }
765#endif /* CONFIG_SND_DEBUG */
766
Kailang Yangdf694da2005-12-05 19:42:22 +0100767/*
Takashi Iwaid88897e2008-10-31 15:01:37 +0100768 */
769static void add_mixer(struct alc_spec *spec, struct snd_kcontrol_new *mix)
770{
771 if (snd_BUG_ON(spec->num_mixers >= ARRAY_SIZE(spec->mixers)))
772 return;
773 spec->mixers[spec->num_mixers++] = mix;
774}
775
776static void add_verb(struct alc_spec *spec, const struct hda_verb *verb)
777{
778 if (snd_BUG_ON(spec->num_init_verbs >= ARRAY_SIZE(spec->init_verbs)))
779 return;
780 spec->init_verbs[spec->num_init_verbs++] = verb;
781}
782
Takashi Iwaidaead532008-11-28 12:55:36 +0100783#ifdef CONFIG_PROC_FS
784/*
785 * hook for proc
786 */
787static void print_realtek_coef(struct snd_info_buffer *buffer,
788 struct hda_codec *codec, hda_nid_t nid)
789{
790 int coeff;
791
792 if (nid != 0x20)
793 return;
794 coeff = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PROC_COEF, 0);
795 snd_iprintf(buffer, " Processing Coefficient: 0x%02x\n", coeff);
796 coeff = snd_hda_codec_read(codec, nid, 0,
797 AC_VERB_GET_COEF_INDEX, 0);
798 snd_iprintf(buffer, " Coefficient Index: 0x%02x\n", coeff);
799}
800#else
801#define print_realtek_coef NULL
802#endif
803
Takashi Iwaid88897e2008-10-31 15:01:37 +0100804/*
Kailang Yangdf694da2005-12-05 19:42:22 +0100805 * set up from the preset table
806 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200807static void setup_preset(struct alc_spec *spec,
808 const struct alc_config_preset *preset)
Kailang Yangdf694da2005-12-05 19:42:22 +0100809{
810 int i;
811
812 for (i = 0; i < ARRAY_SIZE(preset->mixers) && preset->mixers[i]; i++)
Takashi Iwaid88897e2008-10-31 15:01:37 +0100813 add_mixer(spec, preset->mixers[i]);
Takashi Iwaif9e336f2008-10-31 16:37:07 +0100814 spec->cap_mixer = preset->cap_mixer;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200815 for (i = 0; i < ARRAY_SIZE(preset->init_verbs) && preset->init_verbs[i];
816 i++)
Takashi Iwaid88897e2008-10-31 15:01:37 +0100817 add_verb(spec, preset->init_verbs[i]);
Kailang Yangea1fb292008-08-26 12:58:38 +0200818
Kailang Yangdf694da2005-12-05 19:42:22 +0100819 spec->channel_mode = preset->channel_mode;
820 spec->num_channel_mode = preset->num_channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200821 spec->need_dac_fix = preset->need_dac_fix;
Kailang Yangdf694da2005-12-05 19:42:22 +0100822
823 spec->multiout.max_channels = spec->channel_mode[0].channels;
824
825 spec->multiout.num_dacs = preset->num_dacs;
826 spec->multiout.dac_nids = preset->dac_nids;
827 spec->multiout.dig_out_nid = preset->dig_out_nid;
Wu Fengguangb25c9da2009-02-06 15:02:27 +0800828 spec->multiout.slave_dig_outs = preset->slave_dig_outs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100829 spec->multiout.hp_nid = preset->hp_nid;
Kailang Yangea1fb292008-08-26 12:58:38 +0200830
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200831 spec->num_mux_defs = preset->num_mux_defs;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200832 if (!spec->num_mux_defs)
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200833 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +0100834 spec->input_mux = preset->input_mux;
835
836 spec->num_adc_nids = preset->num_adc_nids;
837 spec->adc_nids = preset->adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100838 spec->capsrc_nids = preset->capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +0100839 spec->dig_in_nid = preset->dig_in_nid;
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100840
841 spec->unsol_event = preset->unsol_event;
842 spec->init_hook = preset->init_hook;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200843#ifdef CONFIG_SND_HDA_POWER_SAVE
844 spec->loopback.amplist = preset->loopbacks;
845#endif
Kailang Yangdf694da2005-12-05 19:42:22 +0100846}
847
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200848/* Enable GPIO mask and set output */
849static struct hda_verb alc_gpio1_init_verbs[] = {
850 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
851 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
852 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
853 { }
854};
855
856static struct hda_verb alc_gpio2_init_verbs[] = {
857 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
858 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
859 {0x01, AC_VERB_SET_GPIO_DATA, 0x02},
860 { }
861};
862
Kailang Yangbdd148a2007-05-08 15:19:08 +0200863static struct hda_verb alc_gpio3_init_verbs[] = {
864 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
865 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
866 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
867 { }
868};
869
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +0200870/*
871 * Fix hardware PLL issue
872 * On some codecs, the analog PLL gating control must be off while
873 * the default value is 1.
874 */
875static void alc_fix_pll(struct hda_codec *codec)
876{
877 struct alc_spec *spec = codec->spec;
878 unsigned int val;
879
880 if (!spec->pll_nid)
881 return;
882 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
883 spec->pll_coef_idx);
884 val = snd_hda_codec_read(codec, spec->pll_nid, 0,
885 AC_VERB_GET_PROC_COEF, 0);
886 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
887 spec->pll_coef_idx);
888 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_PROC_COEF,
889 val & ~(1 << spec->pll_coef_bit));
890}
891
892static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
893 unsigned int coef_idx, unsigned int coef_bit)
894{
895 struct alc_spec *spec = codec->spec;
896 spec->pll_nid = nid;
897 spec->pll_coef_idx = coef_idx;
898 spec->pll_coef_bit = coef_bit;
899 alc_fix_pll(codec);
900}
901
Kailang Yangc9b58002007-10-16 14:30:01 +0200902static void alc_sku_automute(struct hda_codec *codec)
903{
904 struct alc_spec *spec = codec->spec;
Kailang Yangc9b58002007-10-16 14:30:01 +0200905 unsigned int present;
906 unsigned int hp_nid = spec->autocfg.hp_pins[0];
907 unsigned int sp_nid = spec->autocfg.speaker_pins[0];
908
909 /* need to execute and sync at first */
910 snd_hda_codec_read(codec, hp_nid, 0, AC_VERB_SET_PIN_SENSE, 0);
911 present = snd_hda_codec_read(codec, hp_nid, 0,
912 AC_VERB_GET_PIN_SENSE, 0);
913 spec->jack_present = (present & 0x80000000) != 0;
Takashi Iwaif6c7e542008-02-12 18:32:23 +0100914 snd_hda_codec_write(codec, sp_nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
915 spec->jack_present ? 0 : PIN_OUT);
Kailang Yangc9b58002007-10-16 14:30:01 +0200916}
917
Takashi Iwai4605b712008-10-31 14:18:24 +0100918#if 0 /* it's broken in some acses -- temporarily disabled */
Kailang Yang7fb0d782008-10-15 11:12:35 +0200919static void alc_mic_automute(struct hda_codec *codec)
920{
921 struct alc_spec *spec = codec->spec;
922 unsigned int present;
923 unsigned int mic_nid = spec->autocfg.input_pins[AUTO_PIN_MIC];
924 unsigned int fmic_nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC];
925 unsigned int mix_nid = spec->capsrc_nids[0];
926 unsigned int capsrc_idx_mic, capsrc_idx_fmic;
927
928 capsrc_idx_mic = mic_nid - 0x18;
929 capsrc_idx_fmic = fmic_nid - 0x18;
930 present = snd_hda_codec_read(codec, mic_nid, 0,
931 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
932 snd_hda_codec_write(codec, mix_nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
933 0x7000 | (capsrc_idx_mic << 8) | (present ? 0 : 0x80));
934 snd_hda_codec_write(codec, mix_nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
935 0x7000 | (capsrc_idx_fmic << 8) | (present ? 0x80 : 0));
936 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, capsrc_idx_fmic,
937 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
938}
Takashi Iwai4605b712008-10-31 14:18:24 +0100939#else
940#define alc_mic_automute(codec) /* NOP */
941#endif /* disabled */
Kailang Yang7fb0d782008-10-15 11:12:35 +0200942
Kailang Yangc9b58002007-10-16 14:30:01 +0200943/* unsolicited event for HP jack sensing */
944static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res)
945{
946 if (codec->vendor_id == 0x10ec0880)
947 res >>= 28;
948 else
949 res >>= 26;
Kailang Yang7fb0d782008-10-15 11:12:35 +0200950 if (res == ALC880_HP_EVENT)
951 alc_sku_automute(codec);
Kailang Yangc9b58002007-10-16 14:30:01 +0200952
Kailang Yang7fb0d782008-10-15 11:12:35 +0200953 if (res == ALC880_MIC_EVENT)
954 alc_mic_automute(codec);
955}
956
957static void alc_inithook(struct hda_codec *codec)
958{
Kailang Yangc9b58002007-10-16 14:30:01 +0200959 alc_sku_automute(codec);
Kailang Yang7fb0d782008-10-15 11:12:35 +0200960 alc_mic_automute(codec);
Kailang Yangc9b58002007-10-16 14:30:01 +0200961}
962
Kailang Yangf9423e72008-05-27 12:32:25 +0200963/* additional initialization for ALC888 variants */
964static void alc888_coef_init(struct hda_codec *codec)
965{
966 unsigned int tmp;
967
968 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0);
969 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
970 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
971 if ((tmp & 0xf0) == 2)
972 /* alc888S-VC */
973 snd_hda_codec_read(codec, 0x20, 0,
974 AC_VERB_SET_PROC_COEF, 0x830);
975 else
976 /* alc888-VB */
977 snd_hda_codec_read(codec, 0x20, 0,
978 AC_VERB_SET_PROC_COEF, 0x3030);
979}
980
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200981/* 32-bit subsystem ID for BIOS loading in HD Audio codec.
982 * 31 ~ 16 : Manufacture ID
983 * 15 ~ 8 : SKU ID
984 * 7 ~ 0 : Assembly ID
985 * port-A --> pin 39/41, port-E --> pin 14/15, port-D --> pin 35/36
986 */
987static void alc_subsystem_id(struct hda_codec *codec,
988 unsigned int porta, unsigned int porte,
989 unsigned int portd)
990{
Kailang Yangc9b58002007-10-16 14:30:01 +0200991 unsigned int ass, tmp, i;
992 unsigned nid;
993 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200994
Kailang Yangc9b58002007-10-16 14:30:01 +0200995 ass = codec->subsystem_id & 0xffff;
996 if ((ass != codec->bus->pci->subsystem_device) && (ass & 1))
997 goto do_sku;
998
Kailang Yangea1fb292008-08-26 12:58:38 +0200999 /*
Kailang Yangc9b58002007-10-16 14:30:01 +02001000 * 31~30 : port conetcivity
1001 * 29~21 : reserve
1002 * 20 : PCBEEP input
1003 * 19~16 : Check sum (15:1)
1004 * 15~1 : Custom
1005 * 0 : override
1006 */
1007 nid = 0x1d;
1008 if (codec->vendor_id == 0x10ec0260)
1009 nid = 0x17;
1010 ass = snd_hda_codec_read(codec, nid, 0,
1011 AC_VERB_GET_CONFIG_DEFAULT, 0);
1012 if (!(ass & 1) && !(ass & 0x100000))
1013 return;
1014 if ((ass >> 30) != 1) /* no physical connection */
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001015 return;
1016
Kailang Yangc9b58002007-10-16 14:30:01 +02001017 /* check sum */
1018 tmp = 0;
1019 for (i = 1; i < 16; i++) {
Kailang Yang8c427222008-01-10 13:03:59 +01001020 if ((ass >> i) & 1)
Kailang Yangc9b58002007-10-16 14:30:01 +02001021 tmp++;
1022 }
1023 if (((ass >> 16) & 0xf) != tmp)
1024 return;
1025do_sku:
1026 /*
1027 * 0 : override
1028 * 1 : Swap Jack
1029 * 2 : 0 --> Desktop, 1 --> Laptop
1030 * 3~5 : External Amplifier control
1031 * 7~6 : Reserved
1032 */
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001033 tmp = (ass & 0x38) >> 3; /* external Amp control */
1034 switch (tmp) {
1035 case 1:
1036 snd_hda_sequence_write(codec, alc_gpio1_init_verbs);
1037 break;
1038 case 3:
1039 snd_hda_sequence_write(codec, alc_gpio2_init_verbs);
1040 break;
Kailang Yangbdd148a2007-05-08 15:19:08 +02001041 case 7:
1042 snd_hda_sequence_write(codec, alc_gpio3_init_verbs);
1043 break;
Kailang Yangc9b58002007-10-16 14:30:01 +02001044 case 5: /* set EAPD output high */
Kailang Yangbdd148a2007-05-08 15:19:08 +02001045 switch (codec->vendor_id) {
Kailang Yangc9b58002007-10-16 14:30:01 +02001046 case 0x10ec0260:
1047 snd_hda_codec_write(codec, 0x0f, 0,
1048 AC_VERB_SET_EAPD_BTLENABLE, 2);
1049 snd_hda_codec_write(codec, 0x10, 0,
1050 AC_VERB_SET_EAPD_BTLENABLE, 2);
1051 break;
1052 case 0x10ec0262:
Kailang Yangbdd148a2007-05-08 15:19:08 +02001053 case 0x10ec0267:
1054 case 0x10ec0268:
Kailang Yangc9b58002007-10-16 14:30:01 +02001055 case 0x10ec0269:
Kailang Yangf9423e72008-05-27 12:32:25 +02001056 case 0x10ec0660:
1057 case 0x10ec0662:
1058 case 0x10ec0663:
Kailang Yangc9b58002007-10-16 14:30:01 +02001059 case 0x10ec0862:
Takashi Iwai20a3a052008-05-23 17:52:53 +02001060 case 0x10ec0889:
Kailang Yangbdd148a2007-05-08 15:19:08 +02001061 snd_hda_codec_write(codec, 0x14, 0,
1062 AC_VERB_SET_EAPD_BTLENABLE, 2);
1063 snd_hda_codec_write(codec, 0x15, 0,
1064 AC_VERB_SET_EAPD_BTLENABLE, 2);
Kailang Yangc9b58002007-10-16 14:30:01 +02001065 break;
Kailang Yangbdd148a2007-05-08 15:19:08 +02001066 }
Kailang Yangc9b58002007-10-16 14:30:01 +02001067 switch (codec->vendor_id) {
1068 case 0x10ec0260:
1069 snd_hda_codec_write(codec, 0x1a, 0,
1070 AC_VERB_SET_COEF_INDEX, 7);
1071 tmp = snd_hda_codec_read(codec, 0x1a, 0,
1072 AC_VERB_GET_PROC_COEF, 0);
1073 snd_hda_codec_write(codec, 0x1a, 0,
1074 AC_VERB_SET_COEF_INDEX, 7);
1075 snd_hda_codec_write(codec, 0x1a, 0,
1076 AC_VERB_SET_PROC_COEF,
1077 tmp | 0x2010);
1078 break;
1079 case 0x10ec0262:
1080 case 0x10ec0880:
1081 case 0x10ec0882:
1082 case 0x10ec0883:
1083 case 0x10ec0885:
Takashi Iwai20a3a052008-05-23 17:52:53 +02001084 case 0x10ec0889:
Kailang Yangc9b58002007-10-16 14:30:01 +02001085 snd_hda_codec_write(codec, 0x20, 0,
1086 AC_VERB_SET_COEF_INDEX, 7);
1087 tmp = snd_hda_codec_read(codec, 0x20, 0,
1088 AC_VERB_GET_PROC_COEF, 0);
1089 snd_hda_codec_write(codec, 0x20, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +02001090 AC_VERB_SET_COEF_INDEX, 7);
Kailang Yangc9b58002007-10-16 14:30:01 +02001091 snd_hda_codec_write(codec, 0x20, 0,
1092 AC_VERB_SET_PROC_COEF,
1093 tmp | 0x2010);
1094 break;
Kailang Yangf9423e72008-05-27 12:32:25 +02001095 case 0x10ec0888:
Takashi Iwai1082c742008-08-22 15:24:22 +02001096 /*alc888_coef_init(codec);*/ /* called in alc_init() */
Kailang Yangf9423e72008-05-27 12:32:25 +02001097 break;
Kailang Yangc9b58002007-10-16 14:30:01 +02001098 case 0x10ec0267:
1099 case 0x10ec0268:
1100 snd_hda_codec_write(codec, 0x20, 0,
1101 AC_VERB_SET_COEF_INDEX, 7);
1102 tmp = snd_hda_codec_read(codec, 0x20, 0,
1103 AC_VERB_GET_PROC_COEF, 0);
1104 snd_hda_codec_write(codec, 0x20, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +02001105 AC_VERB_SET_COEF_INDEX, 7);
Kailang Yangc9b58002007-10-16 14:30:01 +02001106 snd_hda_codec_write(codec, 0x20, 0,
1107 AC_VERB_SET_PROC_COEF,
1108 tmp | 0x3000);
1109 break;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001110 }
Kailang Yangc9b58002007-10-16 14:30:01 +02001111 default:
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001112 break;
1113 }
Kailang Yangea1fb292008-08-26 12:58:38 +02001114
Kailang Yang8c427222008-01-10 13:03:59 +01001115 /* is laptop or Desktop and enable the function "Mute internal speaker
Kailang Yangc9b58002007-10-16 14:30:01 +02001116 * when the external headphone out jack is plugged"
1117 */
Kailang Yang8c427222008-01-10 13:03:59 +01001118 if (!(ass & 0x8000))
Kailang Yangc9b58002007-10-16 14:30:01 +02001119 return;
1120 /*
1121 * 10~8 : Jack location
1122 * 12~11: Headphone out -> 00: PortA, 01: PortE, 02: PortD, 03: Resvered
1123 * 14~13: Resvered
1124 * 15 : 1 --> enable the function "Mute internal speaker
1125 * when the external headphone out jack is plugged"
1126 */
1127 if (!spec->autocfg.speaker_pins[0]) {
Kailang Yang8c427222008-01-10 13:03:59 +01001128 if (spec->autocfg.line_out_pins[0])
Kailang Yangc9b58002007-10-16 14:30:01 +02001129 spec->autocfg.speaker_pins[0] =
Kailang Yang8c427222008-01-10 13:03:59 +01001130 spec->autocfg.line_out_pins[0];
Kailang Yangc9b58002007-10-16 14:30:01 +02001131 else
1132 return;
1133 }
1134
1135 if (!spec->autocfg.hp_pins[0]) {
1136 tmp = (ass >> 11) & 0x3; /* HP to chassis */
1137 if (tmp == 0)
1138 spec->autocfg.hp_pins[0] = porta;
1139 else if (tmp == 1)
1140 spec->autocfg.hp_pins[0] = porte;
1141 else if (tmp == 2)
1142 spec->autocfg.hp_pins[0] = portd;
1143 else
1144 return;
1145 }
Kailang Yang7fb0d782008-10-15 11:12:35 +02001146 if (spec->autocfg.hp_pins[0])
1147 snd_hda_codec_write(codec, spec->autocfg.hp_pins[0], 0,
1148 AC_VERB_SET_UNSOLICITED_ENABLE,
1149 AC_USRSP_EN | ALC880_HP_EVENT);
Kailang Yangc9b58002007-10-16 14:30:01 +02001150
Takashi Iwai4605b712008-10-31 14:18:24 +01001151#if 0 /* it's broken in some acses -- temporarily disabled */
Kailang Yang7fb0d782008-10-15 11:12:35 +02001152 if (spec->autocfg.input_pins[AUTO_PIN_MIC] &&
1153 spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC])
1154 snd_hda_codec_write(codec,
1155 spec->autocfg.input_pins[AUTO_PIN_MIC], 0,
1156 AC_VERB_SET_UNSOLICITED_ENABLE,
1157 AC_USRSP_EN | ALC880_MIC_EVENT);
Takashi Iwai4605b712008-10-31 14:18:24 +01001158#endif /* disabled */
Kailang Yangea1fb292008-08-26 12:58:38 +02001159
Kailang Yangc9b58002007-10-16 14:30:01 +02001160 spec->unsol_event = alc_sku_unsol_event;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001161}
1162
Takashi Iwai41e41f12005-06-08 14:48:49 +02001163/*
Takashi Iwaif95474e2007-07-10 00:47:43 +02001164 * Fix-up pin default configurations
1165 */
1166
1167struct alc_pincfg {
1168 hda_nid_t nid;
1169 u32 val;
1170};
1171
1172static void alc_fix_pincfg(struct hda_codec *codec,
1173 const struct snd_pci_quirk *quirk,
1174 const struct alc_pincfg **pinfix)
1175{
1176 const struct alc_pincfg *cfg;
1177
1178 quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk);
1179 if (!quirk)
1180 return;
1181
1182 cfg = pinfix[quirk->value];
1183 for (; cfg->nid; cfg++) {
1184 int i;
1185 u32 val = cfg->val;
1186 for (i = 0; i < 4; i++) {
1187 snd_hda_codec_write(codec, cfg->nid, 0,
1188 AC_VERB_SET_CONFIG_DEFAULT_BYTES_0 + i,
1189 val & 0xff);
1190 val >>= 8;
1191 }
1192 }
1193}
1194
1195/*
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001196 * ALC888
1197 */
1198
1199/*
1200 * 2ch mode
1201 */
1202static struct hda_verb alc888_4ST_ch2_intel_init[] = {
1203/* Mic-in jack as mic in */
1204 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1205 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1206/* Line-in jack as Line in */
1207 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
1208 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1209/* Line-Out as Front */
1210 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00},
1211 { } /* end */
1212};
1213
1214/*
1215 * 4ch mode
1216 */
1217static struct hda_verb alc888_4ST_ch4_intel_init[] = {
1218/* Mic-in jack as mic in */
1219 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1220 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1221/* Line-in jack as Surround */
1222 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1223 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1224/* Line-Out as Front */
1225 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00},
1226 { } /* end */
1227};
1228
1229/*
1230 * 6ch mode
1231 */
1232static struct hda_verb alc888_4ST_ch6_intel_init[] = {
1233/* Mic-in jack as CLFE */
1234 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1235 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1236/* Line-in jack as Surround */
1237 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1238 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1239/* Line-Out as CLFE (workaround because Mic-in is not loud enough) */
1240 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
1241 { } /* end */
1242};
1243
1244/*
1245 * 8ch mode
1246 */
1247static struct hda_verb alc888_4ST_ch8_intel_init[] = {
1248/* Mic-in jack as CLFE */
1249 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1250 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1251/* Line-in jack as Surround */
1252 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1253 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1254/* Line-Out as Side */
1255 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
1256 { } /* end */
1257};
1258
1259static struct hda_channel_mode alc888_4ST_8ch_intel_modes[4] = {
1260 { 2, alc888_4ST_ch2_intel_init },
1261 { 4, alc888_4ST_ch4_intel_init },
1262 { 6, alc888_4ST_ch6_intel_init },
1263 { 8, alc888_4ST_ch8_intel_init },
1264};
1265
1266/*
1267 * ALC888 Fujitsu Siemens Amillo xa3530
1268 */
1269
1270static struct hda_verb alc888_fujitsu_xa3530_verbs[] = {
1271/* Front Mic: set to PIN_IN (empty by default) */
1272 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1273/* Connect Internal HP to Front */
1274 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1275 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1276 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
1277/* Connect Bass HP to Front */
1278 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1279 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1280 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
1281/* Connect Line-Out side jack (SPDIF) to Side */
1282 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1283 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1284 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
1285/* Connect Mic jack to CLFE */
1286 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1287 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1288 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02},
1289/* Connect Line-in jack to Surround */
1290 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1291 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1292 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
1293/* Connect HP out jack to Front */
1294 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1295 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1296 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
1297/* Enable unsolicited event for HP jack and Line-out jack */
1298 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
1299 {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
1300 {}
1301};
1302
1303static void alc888_fujitsu_xa3530_automute(struct hda_codec *codec)
1304{
1305 unsigned int present;
1306 unsigned int bits;
1307 /* Line out presence */
1308 present = snd_hda_codec_read(codec, 0x17, 0,
1309 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
1310 /* HP out presence */
1311 present = present || snd_hda_codec_read(codec, 0x1b, 0,
1312 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
1313 bits = present ? HDA_AMP_MUTE : 0;
1314 /* Toggle internal speakers muting */
1315 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
1316 HDA_AMP_MUTE, bits);
1317 /* Toggle internal bass muting */
1318 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
1319 HDA_AMP_MUTE, bits);
1320}
1321
1322static void alc888_fujitsu_xa3530_unsol_event(struct hda_codec *codec,
1323 unsigned int res)
1324{
1325 if (res >> 26 == ALC880_HP_EVENT)
1326 alc888_fujitsu_xa3530_automute(codec);
1327}
1328
1329
1330/*
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001331 * ALC888 Acer Aspire 4930G model
1332 */
1333
1334static struct hda_verb alc888_acer_aspire_4930g_verbs[] = {
1335/* Front Mic: set to PIN_IN (empty by default) */
1336 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1337/* Unselect Front Mic by default in input mixer 3 */
1338 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001339/* Enable unsolicited event for HP jack */
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001340 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
1341/* Connect Internal HP to front */
1342 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1343 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1344 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
1345/* Connect HP out to front */
1346 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1347 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1348 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
1349 { }
1350};
1351
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001352static struct hda_input_mux alc888_2_capture_sources[2] = {
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001353 /* Front mic only available on one ADC */
1354 {
1355 .num_items = 4,
1356 .items = {
1357 { "Mic", 0x0 },
1358 { "Line", 0x2 },
1359 { "CD", 0x4 },
1360 { "Front Mic", 0xb },
1361 },
1362 },
1363 {
1364 .num_items = 3,
1365 .items = {
1366 { "Mic", 0x0 },
1367 { "Line", 0x2 },
1368 { "CD", 0x4 },
1369 },
1370 }
1371};
1372
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001373static struct snd_kcontrol_new alc888_base_mixer[] = {
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001374 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1375 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
1376 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1377 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
1378 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
1379 HDA_OUTPUT),
1380 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
1381 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1382 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
1383 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
1384 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
1385 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1386 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1387 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1388 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1389 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1390 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
1391 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1392 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
1393 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
1394 { } /* end */
1395};
1396
1397static void alc888_acer_aspire_4930g_automute(struct hda_codec *codec)
1398{
1399 unsigned int present;
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001400 unsigned int bits;
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001401 present = snd_hda_codec_read(codec, 0x15, 0,
1402 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001403 bits = present ? HDA_AMP_MUTE : 0;
1404 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
1405 HDA_AMP_MUTE, bits);
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001406}
1407
1408static void alc888_acer_aspire_4930g_unsol_event(struct hda_codec *codec,
1409 unsigned int res)
1410{
1411 if (res >> 26 == ALC880_HP_EVENT)
1412 alc888_acer_aspire_4930g_automute(codec);
1413}
1414
1415/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001416 * ALC880 3-stack model
1417 *
1418 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0e)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001419 * Pin assignment: Front = 0x14, Line-In/Surr = 0x1a, Mic/CLFE = 0x18,
1420 * F-Mic = 0x1b, HP = 0x19
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421 */
1422
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001423static hda_nid_t alc880_dac_nids[4] = {
1424 /* front, rear, clfe, rear_surr */
1425 0x02, 0x05, 0x04, 0x03
1426};
1427
1428static hda_nid_t alc880_adc_nids[3] = {
1429 /* ADC0-2 */
1430 0x07, 0x08, 0x09,
1431};
1432
1433/* The datasheet says the node 0x07 is connected from inputs,
1434 * but it shows zero connection in the real implementation on some devices.
Kailang Yangdf694da2005-12-05 19:42:22 +01001435 * Note: this is a 915GAV bug, fixed on 915GLV
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001437static hda_nid_t alc880_adc_nids_alt[2] = {
1438 /* ADC1-2 */
1439 0x08, 0x09,
1440};
1441
1442#define ALC880_DIGOUT_NID 0x06
1443#define ALC880_DIGIN_NID 0x0a
1444
1445static struct hda_input_mux alc880_capture_source = {
1446 .num_items = 4,
1447 .items = {
1448 { "Mic", 0x0 },
1449 { "Front Mic", 0x3 },
1450 { "Line", 0x2 },
1451 { "CD", 0x4 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452 },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001453};
1454
1455/* channel source setting (2/6 channel selection for 3-stack) */
1456/* 2ch mode */
1457static struct hda_verb alc880_threestack_ch2_init[] = {
1458 /* set line-in to input, mute it */
1459 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
1460 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1461 /* set mic-in to input vref 80%, mute it */
1462 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1463 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464 { } /* end */
1465};
1466
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001467/* 6ch mode */
1468static struct hda_verb alc880_threestack_ch6_init[] = {
1469 /* set line-in to output, unmute it */
1470 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1471 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1472 /* set mic-in to output, unmute it */
1473 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1474 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1475 { } /* end */
1476};
1477
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001478static struct hda_channel_mode alc880_threestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001479 { 2, alc880_threestack_ch2_init },
1480 { 6, alc880_threestack_ch6_init },
1481};
1482
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01001483static struct snd_kcontrol_new alc880_three_stack_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02001484 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001485 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02001486 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001487 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02001488 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1489 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001490 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1491 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1493 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1494 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1495 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1496 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1497 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1498 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
1499 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
1500 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
1501 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502 HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001503 {
1504 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1505 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01001506 .info = alc_ch_mode_info,
1507 .get = alc_ch_mode_get,
1508 .put = alc_ch_mode_put,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001509 },
1510 { } /* end */
1511};
1512
1513/* capture mixer elements */
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001514static int alc_cap_vol_info(struct snd_kcontrol *kcontrol,
1515 struct snd_ctl_elem_info *uinfo)
1516{
1517 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1518 struct alc_spec *spec = codec->spec;
1519 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001520
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001521 mutex_lock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001522 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0,
1523 HDA_INPUT);
1524 err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001525 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001526 return err;
1527}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001529static int alc_cap_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
1530 unsigned int size, unsigned int __user *tlv)
1531{
1532 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1533 struct alc_spec *spec = codec->spec;
1534 int err;
1535
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001536 mutex_lock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001537 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0,
1538 HDA_INPUT);
1539 err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001540 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001541 return err;
1542}
1543
1544typedef int (*getput_call_t)(struct snd_kcontrol *kcontrol,
1545 struct snd_ctl_elem_value *ucontrol);
1546
1547static int alc_cap_getput_caller(struct snd_kcontrol *kcontrol,
1548 struct snd_ctl_elem_value *ucontrol,
1549 getput_call_t func)
1550{
1551 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1552 struct alc_spec *spec = codec->spec;
1553 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1554 int err;
1555
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001556 mutex_lock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001557 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[adc_idx],
1558 3, 0, HDA_INPUT);
1559 err = func(kcontrol, ucontrol);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001560 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001561 return err;
1562}
1563
1564static int alc_cap_vol_get(struct snd_kcontrol *kcontrol,
1565 struct snd_ctl_elem_value *ucontrol)
1566{
1567 return alc_cap_getput_caller(kcontrol, ucontrol,
1568 snd_hda_mixer_amp_volume_get);
1569}
1570
1571static int alc_cap_vol_put(struct snd_kcontrol *kcontrol,
1572 struct snd_ctl_elem_value *ucontrol)
1573{
1574 return alc_cap_getput_caller(kcontrol, ucontrol,
1575 snd_hda_mixer_amp_volume_put);
1576}
1577
1578/* capture mixer elements */
1579#define alc_cap_sw_info snd_ctl_boolean_stereo_info
1580
1581static int alc_cap_sw_get(struct snd_kcontrol *kcontrol,
1582 struct snd_ctl_elem_value *ucontrol)
1583{
1584 return alc_cap_getput_caller(kcontrol, ucontrol,
1585 snd_hda_mixer_amp_switch_get);
1586}
1587
1588static int alc_cap_sw_put(struct snd_kcontrol *kcontrol,
1589 struct snd_ctl_elem_value *ucontrol)
1590{
1591 return alc_cap_getput_caller(kcontrol, ucontrol,
1592 snd_hda_mixer_amp_switch_put);
1593}
1594
1595#define DEFINE_CAPMIX(num) \
1596static struct snd_kcontrol_new alc_capture_mixer ## num[] = { \
1597 { \
1598 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
1599 .name = "Capture Switch", \
1600 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
1601 .count = num, \
1602 .info = alc_cap_sw_info, \
1603 .get = alc_cap_sw_get, \
1604 .put = alc_cap_sw_put, \
1605 }, \
1606 { \
1607 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
1608 .name = "Capture Volume", \
1609 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | \
1610 SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
1611 SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK), \
1612 .count = num, \
1613 .info = alc_cap_vol_info, \
1614 .get = alc_cap_vol_get, \
1615 .put = alc_cap_vol_put, \
1616 .tlv = { .c = alc_cap_vol_tlv }, \
1617 }, \
Takashi Iwai3c3e9892008-10-31 17:48:56 +01001618 { \
1619 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
1620 /* .name = "Capture Source", */ \
1621 .name = "Input Source", \
1622 .count = num, \
1623 .info = alc_mux_enum_info, \
1624 .get = alc_mux_enum_get, \
1625 .put = alc_mux_enum_put, \
1626 }, \
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001627 { } /* end */ \
1628}
1629
1630/* up to three ADCs */
1631DEFINE_CAPMIX(1);
1632DEFINE_CAPMIX(2);
1633DEFINE_CAPMIX(3);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001634
1635
1636/*
1637 * ALC880 5-stack model
1638 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001639 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0d),
1640 * Side = 0x02 (0xd)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001641 * Pin assignment: Front = 0x14, Surr = 0x17, CLFE = 0x16
1642 * Line-In/Side = 0x1a, Mic = 0x18, F-Mic = 0x1b, HP = 0x19
1643 */
1644
1645/* additional mixers to alc880_three_stack_mixer */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01001646static struct snd_kcontrol_new alc880_five_stack_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001647 HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001648 HDA_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649 { } /* end */
1650};
1651
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001652/* channel source setting (6/8 channel selection for 5-stack) */
1653/* 6ch mode */
1654static struct hda_verb alc880_fivestack_ch6_init[] = {
1655 /* set line-in to input, mute it */
1656 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
1657 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02001658 { } /* end */
1659};
1660
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001661/* 8ch mode */
1662static struct hda_verb alc880_fivestack_ch8_init[] = {
1663 /* set line-in to output, unmute it */
1664 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1665 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1666 { } /* end */
1667};
1668
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001669static struct hda_channel_mode alc880_fivestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001670 { 6, alc880_fivestack_ch6_init },
1671 { 8, alc880_fivestack_ch8_init },
1672};
1673
1674
1675/*
1676 * ALC880 6-stack model
1677 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001678 * DAC: Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e),
1679 * Side = 0x05 (0x0f)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001680 * Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, Side = 0x17,
1681 * Mic = 0x18, F-Mic = 0x19, Line = 0x1a, HP = 0x1b
1682 */
1683
1684static hda_nid_t alc880_6st_dac_nids[4] = {
1685 /* front, rear, clfe, rear_surr */
1686 0x02, 0x03, 0x04, 0x05
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02001687};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001688
1689static struct hda_input_mux alc880_6stack_capture_source = {
1690 .num_items = 4,
1691 .items = {
1692 { "Mic", 0x0 },
1693 { "Front Mic", 0x1 },
1694 { "Line", 0x2 },
1695 { "CD", 0x4 },
1696 },
1697};
1698
1699/* fixed 8-channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001700static struct hda_channel_mode alc880_sixstack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001701 { 8, NULL },
1702};
1703
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01001704static struct snd_kcontrol_new alc880_six_stack_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001705 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001706 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001707 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001708 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001709 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1710 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001711 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1712 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001713 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001714 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001715 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1716 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1717 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1718 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1719 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1720 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1721 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1722 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
1723 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
1724 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001725 {
1726 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1727 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01001728 .info = alc_ch_mode_info,
1729 .get = alc_ch_mode_get,
1730 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02001731 },
1732 { } /* end */
1733};
1734
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001735
1736/*
1737 * ALC880 W810 model
1738 *
1739 * W810 has rear IO for:
1740 * Front (DAC 02)
1741 * Surround (DAC 03)
1742 * Center/LFE (DAC 04)
1743 * Digital out (06)
1744 *
1745 * The system also has a pair of internal speakers, and a headphone jack.
1746 * These are both connected to Line2 on the codec, hence to DAC 02.
Kailang Yangea1fb292008-08-26 12:58:38 +02001747 *
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001748 * There is a variable resistor to control the speaker or headphone
1749 * volume. This is a hardware-only device without a software API.
1750 *
1751 * Plugging headphones in will disable the internal speakers. This is
1752 * implemented in hardware, not via the driver using jack sense. In
1753 * a similar fashion, plugging into the rear socket marked "front" will
1754 * disable both the speakers and headphones.
1755 *
1756 * For input, there's a microphone jack, and an "audio in" jack.
1757 * These may not do anything useful with this driver yet, because I
1758 * haven't setup any initialization verbs for these yet...
1759 */
1760
1761static hda_nid_t alc880_w810_dac_nids[3] = {
1762 /* front, rear/surround, clfe */
1763 0x02, 0x03, 0x04
1764};
1765
1766/* fixed 6 channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001767static struct hda_channel_mode alc880_w810_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001768 { 6, NULL }
1769};
1770
1771/* Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, HP = 0x1b */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01001772static struct snd_kcontrol_new alc880_w810_base_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001773 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001774 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001775 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001776 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001777 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1778 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001779 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1780 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001781 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
1782 { } /* end */
1783};
1784
1785
1786/*
1787 * Z710V model
1788 *
1789 * DAC: Front = 0x02 (0x0c), HP = 0x03 (0x0d)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001790 * Pin assignment: Front = 0x14, HP = 0x15, Mic = 0x18, Mic2 = 0x19(?),
1791 * Line = 0x1a
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001792 */
1793
1794static hda_nid_t alc880_z71v_dac_nids[1] = {
1795 0x02
1796};
1797#define ALC880_Z71V_HP_DAC 0x03
1798
1799/* fixed 2 channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001800static struct hda_channel_mode alc880_2_jack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001801 { 2, NULL }
1802};
1803
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01001804static struct snd_kcontrol_new alc880_z71v_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +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 Iwaie9edcee2005-06-13 14:16:38 +02001807 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001808 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001809 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1810 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1811 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1812 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1813 { } /* end */
1814};
1815
1816
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001817/*
1818 * ALC880 F1734 model
1819 *
1820 * DAC: HP = 0x02 (0x0c), Front = 0x03 (0x0d)
1821 * Pin assignment: HP = 0x14, Front = 0x15, Mic = 0x18
1822 */
1823
1824static hda_nid_t alc880_f1734_dac_nids[1] = {
1825 0x03
1826};
1827#define ALC880_F1734_HP_DAC 0x02
1828
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01001829static struct snd_kcontrol_new alc880_f1734_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001830 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001831 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01001832 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1833 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001834 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1835 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Takashi Iwai937b4162008-02-11 14:52:36 +01001836 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1837 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001838 { } /* end */
1839};
1840
Takashi Iwai937b4162008-02-11 14:52:36 +01001841static struct hda_input_mux alc880_f1734_capture_source = {
1842 .num_items = 2,
1843 .items = {
1844 { "Mic", 0x1 },
1845 { "CD", 0x4 },
1846 },
1847};
1848
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001849
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001850/*
1851 * ALC880 ASUS model
1852 *
1853 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
1854 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
1855 * Mic = 0x18, Line = 0x1a
1856 */
1857
1858#define alc880_asus_dac_nids alc880_w810_dac_nids /* identical with w810 */
1859#define alc880_asus_modes alc880_threestack_modes /* 2/6 channel mode */
1860
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01001861static struct snd_kcontrol_new alc880_asus_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001862 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001863 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001864 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001865 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001866 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1867 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001868 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1869 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001870 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1871 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1872 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1873 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1874 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1875 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001876 {
1877 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1878 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01001879 .info = alc_ch_mode_info,
1880 .get = alc_ch_mode_get,
1881 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02001882 },
1883 { } /* end */
1884};
1885
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001886/*
1887 * ALC880 ASUS W1V model
1888 *
1889 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
1890 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
1891 * Mic = 0x18, Line = 0x1a, Line2 = 0x1b
1892 */
1893
1894/* additional mixers to alc880_asus_mixer */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01001895static struct snd_kcontrol_new alc880_asus_w1v_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001896 HDA_CODEC_VOLUME("Line2 Playback Volume", 0x0b, 0x03, HDA_INPUT),
1897 HDA_CODEC_MUTE("Line2 Playback Switch", 0x0b, 0x03, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001898 { } /* end */
1899};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001900
Takashi Iwai3c10a9d2005-08-23 20:02:27 +02001901/* additional mixers to alc880_asus_mixer */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01001902static struct snd_kcontrol_new alc880_pcbeep_mixer[] = {
Takashi Iwai3c10a9d2005-08-23 20:02:27 +02001903 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
1904 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
1905 { } /* end */
1906};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001907
Kailang Yangdf694da2005-12-05 19:42:22 +01001908/* TCL S700 */
1909static struct snd_kcontrol_new alc880_tcl_s700_mixer[] = {
1910 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1911 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
1912 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
1913 HDA_CODEC_VOLUME("CD Playback Volume", 0x0B, 0x04, HDA_INPUT),
1914 HDA_CODEC_MUTE("CD Playback Switch", 0x0B, 0x04, HDA_INPUT),
1915 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0B, 0x0, HDA_INPUT),
1916 HDA_CODEC_MUTE("Mic Playback Switch", 0x0B, 0x0, HDA_INPUT),
1917 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
1918 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01001919 { } /* end */
1920};
1921
Kailang Yangccc656c2006-10-17 12:32:26 +02001922/* Uniwill */
1923static struct snd_kcontrol_new alc880_uniwill_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01001924 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1925 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
1926 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1927 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02001928 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1929 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
1930 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1931 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
1932 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1933 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1934 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1935 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1936 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1937 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1938 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1939 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
1940 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
1941 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
1942 {
1943 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1944 .name = "Channel Mode",
1945 .info = alc_ch_mode_info,
1946 .get = alc_ch_mode_get,
1947 .put = alc_ch_mode_put,
1948 },
1949 { } /* end */
1950};
1951
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01001952static struct snd_kcontrol_new alc880_fujitsu_mixer[] = {
1953 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1954 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
1955 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1956 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
1957 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1958 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1959 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1960 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1961 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1962 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
1963 { } /* end */
1964};
1965
Kailang Yangccc656c2006-10-17 12:32:26 +02001966static struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01001967 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1968 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
1969 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1970 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02001971 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1972 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1973 { } /* end */
1974};
1975
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976/*
Takashi Iwai2134ea42008-01-10 16:53:55 +01001977 * virtual master controls
1978 */
1979
1980/*
1981 * slave controls for virtual master
1982 */
1983static const char *alc_slave_vols[] = {
1984 "Front Playback Volume",
1985 "Surround Playback Volume",
1986 "Center Playback Volume",
1987 "LFE Playback Volume",
1988 "Side Playback Volume",
1989 "Headphone Playback Volume",
1990 "Speaker Playback Volume",
1991 "Mono Playback Volume",
Takashi Iwai2134ea42008-01-10 16:53:55 +01001992 "Line-Out Playback Volume",
Takashi Iwai26f5df22008-11-03 17:39:46 +01001993 "PCM Playback Volume",
Takashi Iwai2134ea42008-01-10 16:53:55 +01001994 NULL,
1995};
1996
1997static const char *alc_slave_sws[] = {
1998 "Front Playback Switch",
1999 "Surround Playback Switch",
2000 "Center Playback Switch",
2001 "LFE Playback Switch",
2002 "Side Playback Switch",
2003 "Headphone Playback Switch",
2004 "Speaker Playback Switch",
2005 "Mono Playback Switch",
Takashi Iwaiedb54a52008-01-29 12:47:02 +01002006 "IEC958 Playback Switch",
Takashi Iwai2134ea42008-01-10 16:53:55 +01002007 NULL,
2008};
2009
2010/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002011 * build control elements
Linus Torvalds1da177e2005-04-16 15:20:36 -07002012 */
Takashi Iwai603c4012008-07-30 15:01:44 +02002013
2014static void alc_free_kctls(struct hda_codec *codec);
2015
Linus Torvalds1da177e2005-04-16 15:20:36 -07002016static int alc_build_controls(struct hda_codec *codec)
2017{
2018 struct alc_spec *spec = codec->spec;
2019 int err;
2020 int i;
2021
2022 for (i = 0; i < spec->num_mixers; i++) {
2023 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
2024 if (err < 0)
2025 return err;
2026 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002027 if (spec->cap_mixer) {
2028 err = snd_hda_add_new_ctls(codec, spec->cap_mixer);
2029 if (err < 0)
2030 return err;
2031 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002032 if (spec->multiout.dig_out_nid) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002033 err = snd_hda_create_spdif_out_ctls(codec,
2034 spec->multiout.dig_out_nid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002035 if (err < 0)
2036 return err;
Takashi Iwaie64f14f2009-01-20 18:32:55 +01002037 if (!spec->no_analog) {
2038 err = snd_hda_create_spdif_share_sw(codec,
2039 &spec->multiout);
2040 if (err < 0)
2041 return err;
2042 spec->multiout.share_spdif = 1;
2043 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002044 }
2045 if (spec->dig_in_nid) {
2046 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
2047 if (err < 0)
2048 return err;
2049 }
Takashi Iwai2134ea42008-01-10 16:53:55 +01002050
2051 /* if we have no master control, let's create it */
Takashi Iwaie64f14f2009-01-20 18:32:55 +01002052 if (!spec->no_analog &&
2053 !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
Takashi Iwai1c82ed12008-02-18 13:05:50 +01002054 unsigned int vmaster_tlv[4];
Takashi Iwai2134ea42008-01-10 16:53:55 +01002055 snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
Takashi Iwai1c82ed12008-02-18 13:05:50 +01002056 HDA_OUTPUT, vmaster_tlv);
Takashi Iwai2134ea42008-01-10 16:53:55 +01002057 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
Takashi Iwai1c82ed12008-02-18 13:05:50 +01002058 vmaster_tlv, alc_slave_vols);
Takashi Iwai2134ea42008-01-10 16:53:55 +01002059 if (err < 0)
2060 return err;
2061 }
Takashi Iwaie64f14f2009-01-20 18:32:55 +01002062 if (!spec->no_analog &&
2063 !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
Takashi Iwai2134ea42008-01-10 16:53:55 +01002064 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
2065 NULL, alc_slave_sws);
2066 if (err < 0)
2067 return err;
2068 }
2069
Takashi Iwai603c4012008-07-30 15:01:44 +02002070 alc_free_kctls(codec); /* no longer needed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002071 return 0;
2072}
2073
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002074
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075/*
2076 * initialize the codec volumes, etc
2077 */
2078
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002079/*
2080 * generic initialization of ADC, input mixers and output mixers
2081 */
2082static struct hda_verb alc880_volume_init_verbs[] = {
2083 /*
2084 * Unmute ADC0-2 and set the default input to mic-in
2085 */
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002086 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002087 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002088 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002089 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002090 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002091 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002092
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002093 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
2094 * mixer widget
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002095 * Note: PASD motherboards uses the Line In 2 as the input for front
2096 * panel mic (mic 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002097 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002098 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02002099 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2100 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2101 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
2102 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2103 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
2104 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
2105 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002106
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002107 /*
2108 * Set up output mixers (0x0c - 0x0f)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002109 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002110 /* set vol=0 to output mixers */
2111 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2112 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2113 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2114 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2115 /* set up input amps for analog loopback */
2116 /* Amp Indices: DAC = 0, mixer = 1 */
Takashi Iwai05acb862005-06-10 19:50:25 +02002117 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2118 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02002119 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2120 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02002121 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2122 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02002123 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2124 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002125
2126 { }
2127};
2128
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002129/*
2130 * 3-stack pin configuration:
2131 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
2132 */
2133static struct hda_verb alc880_pin_3stack_init_verbs[] = {
2134 /*
2135 * preset connection lists of input pins
2136 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
2137 */
2138 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
2139 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2140 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
2141
2142 /*
2143 * Set pin mode and muting
2144 */
2145 /* set front pin widgets 0x14 for output */
2146 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2147 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2148 /* Mic1 (rear panel) pin widget for input and vref at 80% */
2149 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2150 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2151 /* Mic2 (as headphone out) for HP output */
2152 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2153 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2154 /* Line In pin widget for input */
2155 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2156 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2157 /* Line2 (as front mic) pin widget for input and vref at 80% */
2158 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2159 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2160 /* CD pin widget for input */
2161 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2162
2163 { }
2164};
2165
2166/*
2167 * 5-stack pin configuration:
2168 * front = 0x14, surround = 0x17, clfe = 0x16, mic = 0x18, HP = 0x19,
2169 * line-in/side = 0x1a, f-mic = 0x1b
2170 */
2171static struct hda_verb alc880_pin_5stack_init_verbs[] = {
2172 /*
2173 * preset connection lists of input pins
2174 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
2175 */
2176 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2177 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/side */
2178
2179 /*
2180 * Set pin mode and muting
2181 */
2182 /* set pin widgets 0x14-0x17 for output */
Takashi Iwai05acb862005-06-10 19:50:25 +02002183 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2184 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2185 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2186 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002187 /* unmute pins for output (no gain on this amp) */
2188 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2189 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2190 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2191 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2192
Linus Torvalds1da177e2005-04-16 15:20:36 -07002193 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02002194 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002195 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2196 /* Mic2 (as headphone out) for HP output */
2197 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02002198 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002199 /* Line In pin widget for input */
2200 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2201 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2202 /* Line2 (as front mic) pin widget for input and vref at 80% */
2203 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2204 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2205 /* CD pin widget for input */
2206 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002207
2208 { }
2209};
2210
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002211/*
2212 * W810 pin configuration:
2213 * front = 0x14, surround = 0x15, clfe = 0x16, HP = 0x1b
2214 */
2215static struct hda_verb alc880_pin_w810_init_verbs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002216 /* hphone/speaker input selector: front DAC */
2217 {0x13, AC_VERB_SET_CONNECT_SEL, 0x0},
2218
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002219 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2220 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2221 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2222 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2223 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2224 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2225
2226 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02002227 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228
Linus Torvalds1da177e2005-04-16 15:20:36 -07002229 { }
2230};
2231
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002232/*
2233 * Z71V pin configuration:
2234 * Speaker-out = 0x14, HP = 0x15, Mic = 0x18, Line-in = 0x1a, Mic2 = 0x1b (?)
2235 */
2236static struct hda_verb alc880_pin_z71v_init_verbs[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02002237 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002238 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai05acb862005-06-10 19:50:25 +02002239 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002240 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02002241
Takashi Iwai16ded522005-06-10 19:58:24 +02002242 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002243 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02002244 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002245 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02002246
2247 { }
2248};
2249
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002250/*
2251 * 6-stack pin configuration:
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002252 * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18,
2253 * f-mic = 0x19, line = 0x1a, HP = 0x1b
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002254 */
2255static struct hda_verb alc880_pin_6stack_init_verbs[] = {
2256 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2257
Takashi Iwai16ded522005-06-10 19:58:24 +02002258 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002259 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002260 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002261 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002262 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002263 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002264 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002265 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2266
Takashi Iwai16ded522005-06-10 19:58:24 +02002267 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002268 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002269 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002270 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002271 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002272 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002273 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai16ded522005-06-10 19:58:24 +02002274 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002275 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangea1fb292008-08-26 12:58:38 +02002276
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002277 { }
2278};
Takashi Iwai16ded522005-06-10 19:58:24 +02002279
Kailang Yangccc656c2006-10-17 12:32:26 +02002280/*
2281 * Uniwill pin configuration:
2282 * HP = 0x14, InternalSpeaker = 0x15, mic = 0x18, internal mic = 0x19,
2283 * line = 0x1a
2284 */
2285static struct hda_verb alc880_uniwill_init_verbs[] = {
2286 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2287
2288 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2289 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2290 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2291 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2292 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2293 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2294 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2295 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2296 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2297 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2298 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2299 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2300 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2301 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2302
2303 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2304 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2305 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2306 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2307 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2308 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2309 /* {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, */
2310 /* {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
2311 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2312
2313 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
2314 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
2315
2316 { }
2317};
2318
2319/*
2320* Uniwill P53
Kailang Yangea1fb292008-08-26 12:58:38 +02002321* HP = 0x14, InternalSpeaker = 0x15, mic = 0x19,
Kailang Yangccc656c2006-10-17 12:32:26 +02002322 */
2323static struct hda_verb alc880_uniwill_p53_init_verbs[] = {
2324 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2325
2326 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2327 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2328 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2329 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2330 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2331 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2332 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2333 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2334 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2335 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2336 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2337 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2338
2339 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2340 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2341 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2342 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2343 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2344 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2345
2346 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
2347 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_DCVOL_EVENT},
2348
2349 { }
2350};
2351
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01002352static struct hda_verb alc880_beep_init_verbs[] = {
2353 { 0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) },
2354 { }
2355};
2356
Kailang Yangccc656c2006-10-17 12:32:26 +02002357/* toggle speaker-output according to the hp-jack state */
Takashi Iwai458a4fa2007-05-05 12:18:40 +02002358static void alc880_uniwill_hp_automute(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02002359{
2360 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002361 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02002362
2363 present = snd_hda_codec_read(codec, 0x14, 0,
2364 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02002365 bits = present ? HDA_AMP_MUTE : 0;
2366 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
2367 HDA_AMP_MUTE, bits);
2368 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
2369 HDA_AMP_MUTE, bits);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02002370}
2371
2372/* auto-toggle front mic */
2373static void alc880_uniwill_mic_automute(struct hda_codec *codec)
2374{
2375 unsigned int present;
2376 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02002377
2378 present = snd_hda_codec_read(codec, 0x18, 0,
2379 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02002380 bits = present ? HDA_AMP_MUTE : 0;
2381 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02002382}
2383
2384static void alc880_uniwill_automute(struct hda_codec *codec)
2385{
2386 alc880_uniwill_hp_automute(codec);
2387 alc880_uniwill_mic_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02002388}
2389
2390static void alc880_uniwill_unsol_event(struct hda_codec *codec,
2391 unsigned int res)
2392{
2393 /* Looks like the unsol event is incompatible with the standard
2394 * definition. 4bit tag is placed at 28 bit!
2395 */
Takashi Iwai458a4fa2007-05-05 12:18:40 +02002396 switch (res >> 28) {
2397 case ALC880_HP_EVENT:
2398 alc880_uniwill_hp_automute(codec);
2399 break;
2400 case ALC880_MIC_EVENT:
2401 alc880_uniwill_mic_automute(codec);
2402 break;
2403 }
Kailang Yangccc656c2006-10-17 12:32:26 +02002404}
2405
2406static void alc880_uniwill_p53_hp_automute(struct hda_codec *codec)
2407{
2408 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002409 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02002410
2411 present = snd_hda_codec_read(codec, 0x14, 0,
2412 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02002413 bits = present ? HDA_AMP_MUTE : 0;
Jiang zhe64654c22008-04-14 13:26:21 +02002414 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, HDA_AMP_MUTE, bits);
Kailang Yangccc656c2006-10-17 12:32:26 +02002415}
2416
2417static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec)
2418{
2419 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02002420
Kailang Yangccc656c2006-10-17 12:32:26 +02002421 present = snd_hda_codec_read(codec, 0x21, 0,
Takashi Iwai47fd8302007-08-10 17:11:07 +02002422 AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
2423 present &= HDA_AMP_VOLMASK;
2424 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0,
2425 HDA_AMP_VOLMASK, present);
2426 snd_hda_codec_amp_stereo(codec, 0x0d, HDA_OUTPUT, 0,
2427 HDA_AMP_VOLMASK, present);
Kailang Yangccc656c2006-10-17 12:32:26 +02002428}
Takashi Iwai47fd8302007-08-10 17:11:07 +02002429
Kailang Yangccc656c2006-10-17 12:32:26 +02002430static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec,
2431 unsigned int res)
2432{
2433 /* Looks like the unsol event is incompatible with the standard
2434 * definition. 4bit tag is placed at 28 bit!
2435 */
2436 if ((res >> 28) == ALC880_HP_EVENT)
2437 alc880_uniwill_p53_hp_automute(codec);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002438 if ((res >> 28) == ALC880_DCVOL_EVENT)
Kailang Yangccc656c2006-10-17 12:32:26 +02002439 alc880_uniwill_p53_dcvol_automute(codec);
2440}
2441
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002442/*
2443 * F1734 pin configuration:
2444 * HP = 0x14, speaker-out = 0x15, mic = 0x18
2445 */
2446static struct hda_verb alc880_pin_f1734_init_verbs[] = {
Michael Gruberee7a9c72008-03-10 11:30:59 +01002447 {0x07, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002448 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
2449 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
2450 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
2451 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
2452
2453 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2454 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2455 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2456 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2457
2458 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2459 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Michael Gruberee7a9c72008-03-10 11:30:59 +01002460 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002461 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2462 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2463 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2464 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2465 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2466 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02002467
Takashi Iwai937b4162008-02-11 14:52:36 +01002468 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
2469 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_DCVOL_EVENT},
2470
Takashi Iwai16ded522005-06-10 19:58:24 +02002471 { }
2472};
2473
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002474/*
2475 * ASUS pin configuration:
2476 * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a
2477 */
2478static struct hda_verb alc880_pin_asus_init_verbs[] = {
2479 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
2480 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
2481 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
2482 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
2483
2484 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2485 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2486 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2487 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2488 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2489 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2490 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2491 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2492
2493 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2494 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2495 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2496 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2497 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2498 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2499 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2500 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2501 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangea1fb292008-08-26 12:58:38 +02002502
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002503 { }
2504};
2505
2506/* Enable GPIO mask and set output */
Kailang Yangbc9f98a2007-04-12 13:06:07 +02002507#define alc880_gpio1_init_verbs alc_gpio1_init_verbs
2508#define alc880_gpio2_init_verbs alc_gpio2_init_verbs
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002509
Kailang Yangdf694da2005-12-05 19:42:22 +01002510/* Clevo m520g init */
2511static struct hda_verb alc880_pin_clevo_init_verbs[] = {
2512 /* headphone output */
2513 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
2514 /* line-out */
2515 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2516 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2517 /* Line-in */
2518 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2519 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2520 /* CD */
2521 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2522 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2523 /* Mic1 (rear panel) */
2524 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2525 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2526 /* Mic2 (front panel) */
2527 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2528 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2529 /* headphone */
2530 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2531 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2532 /* change to EAPD mode */
2533 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
2534 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
2535
2536 { }
2537};
2538
2539static struct hda_verb alc880_pin_tcl_S700_init_verbs[] = {
Takashi Iwai4b146cb2006-07-28 14:42:36 +02002540 /* change to EAPD mode */
2541 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
2542 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
2543
Kailang Yangdf694da2005-12-05 19:42:22 +01002544 /* Headphone output */
2545 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2546 /* Front output*/
2547 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2548 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
2549
2550 /* Line In pin widget for input */
2551 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2552 /* CD pin widget for input */
2553 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2554 /* Mic1 (rear panel) pin widget for input and vref at 80% */
2555 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2556
2557 /* change to EAPD mode */
2558 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
2559 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
2560
2561 { }
2562};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002563
2564/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002565 * LG m1 express dual
2566 *
2567 * Pin assignment:
2568 * Rear Line-In/Out (blue): 0x14
2569 * Build-in Mic-In: 0x15
2570 * Speaker-out: 0x17
2571 * HP-Out (green): 0x1b
2572 * Mic-In/Out (red): 0x19
2573 * SPDIF-Out: 0x1e
2574 */
2575
2576/* To make 5.1 output working (green=Front, blue=Surr, red=CLFE) */
2577static hda_nid_t alc880_lg_dac_nids[3] = {
2578 0x05, 0x02, 0x03
2579};
2580
2581/* seems analog CD is not working */
2582static struct hda_input_mux alc880_lg_capture_source = {
2583 .num_items = 3,
2584 .items = {
2585 { "Mic", 0x1 },
2586 { "Line", 0x5 },
2587 { "Internal Mic", 0x6 },
2588 },
2589};
2590
2591/* 2,4,6 channel modes */
2592static struct hda_verb alc880_lg_ch2_init[] = {
2593 /* set line-in and mic-in to input */
2594 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2595 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2596 { }
2597};
2598
2599static struct hda_verb alc880_lg_ch4_init[] = {
2600 /* set line-in to out and mic-in to input */
2601 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
2602 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2603 { }
2604};
2605
2606static struct hda_verb alc880_lg_ch6_init[] = {
2607 /* set line-in and mic-in to output */
2608 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
2609 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
2610 { }
2611};
2612
2613static struct hda_channel_mode alc880_lg_ch_modes[3] = {
2614 { 2, alc880_lg_ch2_init },
2615 { 4, alc880_lg_ch4_init },
2616 { 6, alc880_lg_ch6_init },
2617};
2618
2619static struct snd_kcontrol_new alc880_lg_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01002620 HDA_CODEC_VOLUME("Front Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
2621 HDA_BIND_MUTE("Front Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002622 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2623 HDA_BIND_MUTE("Surround Playback Switch", 0x0c, 2, HDA_INPUT),
2624 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
2625 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
2626 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
2627 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
2628 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2629 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
2630 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x06, HDA_INPUT),
2631 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x06, HDA_INPUT),
2632 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x07, HDA_INPUT),
2633 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x07, HDA_INPUT),
2634 {
2635 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2636 .name = "Channel Mode",
2637 .info = alc_ch_mode_info,
2638 .get = alc_ch_mode_get,
2639 .put = alc_ch_mode_put,
2640 },
2641 { } /* end */
2642};
2643
2644static struct hda_verb alc880_lg_init_verbs[] = {
2645 /* set capture source to mic-in */
2646 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2647 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2648 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2649 /* mute all amp mixer inputs */
2650 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02002651 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
2652 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002653 /* line-in to input */
2654 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2655 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2656 /* built-in mic */
2657 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2658 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2659 /* speaker-out */
2660 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2661 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2662 /* mic-in to input */
2663 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
2664 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2665 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2666 /* HP-out */
2667 {0x13, AC_VERB_SET_CONNECT_SEL, 0x03},
2668 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2669 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2670 /* jack sense */
2671 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | 0x1},
2672 { }
2673};
2674
2675/* toggle speaker-output according to the hp-jack state */
2676static void alc880_lg_automute(struct hda_codec *codec)
2677{
2678 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002679 unsigned char bits;
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002680
2681 present = snd_hda_codec_read(codec, 0x1b, 0,
2682 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02002683 bits = present ? HDA_AMP_MUTE : 0;
2684 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
2685 HDA_AMP_MUTE, bits);
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002686}
2687
2688static void alc880_lg_unsol_event(struct hda_codec *codec, unsigned int res)
2689{
2690 /* Looks like the unsol event is incompatible with the standard
2691 * definition. 4bit tag is placed at 28 bit!
2692 */
2693 if ((res >> 28) == 0x01)
2694 alc880_lg_automute(codec);
2695}
2696
2697/*
Takashi Iwaid6815182006-03-23 16:06:23 +01002698 * LG LW20
2699 *
2700 * Pin assignment:
2701 * Speaker-out: 0x14
2702 * Mic-In: 0x18
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02002703 * Built-in Mic-In: 0x19
2704 * Line-In: 0x1b
2705 * HP-Out: 0x1a
Takashi Iwaid6815182006-03-23 16:06:23 +01002706 * SPDIF-Out: 0x1e
2707 */
2708
Takashi Iwaid6815182006-03-23 16:06:23 +01002709static struct hda_input_mux alc880_lg_lw_capture_source = {
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02002710 .num_items = 3,
Takashi Iwaid6815182006-03-23 16:06:23 +01002711 .items = {
2712 { "Mic", 0x0 },
2713 { "Internal Mic", 0x1 },
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02002714 { "Line In", 0x2 },
Takashi Iwaid6815182006-03-23 16:06:23 +01002715 },
2716};
2717
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002718#define alc880_lg_lw_modes alc880_threestack_modes
2719
Takashi Iwaid6815182006-03-23 16:06:23 +01002720static struct snd_kcontrol_new alc880_lg_lw_mixer[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002721 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2722 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
2723 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
2724 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
2725 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2726 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
2727 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2728 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
2729 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2730 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaid6815182006-03-23 16:06:23 +01002731 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2732 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2733 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
2734 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002735 {
2736 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2737 .name = "Channel Mode",
2738 .info = alc_ch_mode_info,
2739 .get = alc_ch_mode_get,
2740 .put = alc_ch_mode_put,
2741 },
Takashi Iwaid6815182006-03-23 16:06:23 +01002742 { } /* end */
2743};
2744
2745static struct hda_verb alc880_lg_lw_init_verbs[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002746 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2747 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
2748 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
2749
Takashi Iwaid6815182006-03-23 16:06:23 +01002750 /* set capture source to mic-in */
2751 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2752 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2753 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02002754 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaid6815182006-03-23 16:06:23 +01002755 /* speaker-out */
2756 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2757 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2758 /* HP-out */
Takashi Iwaid6815182006-03-23 16:06:23 +01002759 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2760 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2761 /* mic-in to input */
2762 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2763 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2764 /* built-in mic */
2765 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2766 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2767 /* jack sense */
2768 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | 0x1},
2769 { }
2770};
2771
2772/* toggle speaker-output according to the hp-jack state */
2773static void alc880_lg_lw_automute(struct hda_codec *codec)
2774{
2775 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002776 unsigned char bits;
Takashi Iwaid6815182006-03-23 16:06:23 +01002777
2778 present = snd_hda_codec_read(codec, 0x1b, 0,
2779 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02002780 bits = present ? HDA_AMP_MUTE : 0;
2781 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
2782 HDA_AMP_MUTE, bits);
Takashi Iwaid6815182006-03-23 16:06:23 +01002783}
2784
2785static void alc880_lg_lw_unsol_event(struct hda_codec *codec, unsigned int res)
2786{
2787 /* Looks like the unsol event is incompatible with the standard
2788 * definition. 4bit tag is placed at 28 bit!
2789 */
2790 if ((res >> 28) == 0x01)
2791 alc880_lg_lw_automute(codec);
2792}
2793
Takashi Iwaidf99cd32008-04-25 15:25:04 +02002794static struct snd_kcontrol_new alc880_medion_rim_mixer[] = {
2795 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2796 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
2797 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2798 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2799 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2800 HDA_CODEC_MUTE("Internal Playback Switch", 0x0b, 0x1, HDA_INPUT),
2801 { } /* end */
2802};
2803
2804static struct hda_input_mux alc880_medion_rim_capture_source = {
2805 .num_items = 2,
2806 .items = {
2807 { "Mic", 0x0 },
2808 { "Internal Mic", 0x1 },
2809 },
2810};
2811
2812static struct hda_verb alc880_medion_rim_init_verbs[] = {
2813 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2814
2815 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2816 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2817
2818 /* Mic1 (rear panel) pin widget for input and vref at 80% */
2819 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2820 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2821 /* Mic2 (as headphone out) for HP output */
2822 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2823 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2824 /* Internal Speaker */
2825 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2826 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2827
2828 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
2829 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
2830
2831 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
2832 { }
2833};
2834
2835/* toggle speaker-output according to the hp-jack state */
2836static void alc880_medion_rim_automute(struct hda_codec *codec)
2837{
2838 unsigned int present;
2839 unsigned char bits;
2840
2841 present = snd_hda_codec_read(codec, 0x14, 0,
2842 AC_VERB_GET_PIN_SENSE, 0)
2843 & AC_PINSENSE_PRESENCE;
2844 bits = present ? HDA_AMP_MUTE : 0;
2845 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
2846 HDA_AMP_MUTE, bits);
2847 if (present)
2848 snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0);
2849 else
2850 snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 2);
2851}
2852
2853static void alc880_medion_rim_unsol_event(struct hda_codec *codec,
2854 unsigned int res)
2855{
2856 /* Looks like the unsol event is incompatible with the standard
2857 * definition. 4bit tag is placed at 28 bit!
2858 */
2859 if ((res >> 28) == ALC880_HP_EVENT)
2860 alc880_medion_rim_automute(codec);
2861}
2862
Takashi Iwaicb53c622007-08-10 17:21:45 +02002863#ifdef CONFIG_SND_HDA_POWER_SAVE
2864static struct hda_amp_list alc880_loopbacks[] = {
2865 { 0x0b, HDA_INPUT, 0 },
2866 { 0x0b, HDA_INPUT, 1 },
2867 { 0x0b, HDA_INPUT, 2 },
2868 { 0x0b, HDA_INPUT, 3 },
2869 { 0x0b, HDA_INPUT, 4 },
2870 { } /* end */
2871};
2872
2873static struct hda_amp_list alc880_lg_loopbacks[] = {
2874 { 0x0b, HDA_INPUT, 1 },
2875 { 0x0b, HDA_INPUT, 6 },
2876 { 0x0b, HDA_INPUT, 7 },
2877 { } /* end */
2878};
2879#endif
2880
Takashi Iwaid6815182006-03-23 16:06:23 +01002881/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002882 * Common callbacks
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002883 */
Takashi Iwai16ded522005-06-10 19:58:24 +02002884
Linus Torvalds1da177e2005-04-16 15:20:36 -07002885static int alc_init(struct hda_codec *codec)
2886{
2887 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002888 unsigned int i;
2889
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02002890 alc_fix_pll(codec);
Takashi Iwai1082c742008-08-22 15:24:22 +02002891 if (codec->vendor_id == 0x10ec0888)
2892 alc888_coef_init(codec);
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02002893
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002894 for (i = 0; i < spec->num_init_verbs; i++)
2895 snd_hda_sequence_write(codec, spec->init_verbs[i]);
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002896
2897 if (spec->init_hook)
2898 spec->init_hook(codec);
2899
Linus Torvalds1da177e2005-04-16 15:20:36 -07002900 return 0;
2901}
2902
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002903static void alc_unsol_event(struct hda_codec *codec, unsigned int res)
2904{
2905 struct alc_spec *spec = codec->spec;
2906
2907 if (spec->unsol_event)
2908 spec->unsol_event(codec, res);
2909}
2910
Takashi Iwaicb53c622007-08-10 17:21:45 +02002911#ifdef CONFIG_SND_HDA_POWER_SAVE
2912static int alc_check_power_status(struct hda_codec *codec, hda_nid_t nid)
2913{
2914 struct alc_spec *spec = codec->spec;
2915 return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
2916}
2917#endif
2918
Linus Torvalds1da177e2005-04-16 15:20:36 -07002919/*
2920 * Analog playback callbacks
2921 */
2922static int alc880_playback_pcm_open(struct hda_pcm_stream *hinfo,
2923 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002924 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002925{
2926 struct alc_spec *spec = codec->spec;
Takashi Iwai9a081602008-02-12 18:37:26 +01002927 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
2928 hinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002929}
2930
2931static int alc880_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
2932 struct hda_codec *codec,
2933 unsigned int stream_tag,
2934 unsigned int format,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002935 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002936{
2937 struct alc_spec *spec = codec->spec;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002938 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
2939 stream_tag, format, substream);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002940}
2941
2942static int alc880_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
2943 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002944 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002945{
2946 struct alc_spec *spec = codec->spec;
2947 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
2948}
2949
2950/*
2951 * Digital out
2952 */
2953static int alc880_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
2954 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002955 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002956{
2957 struct alc_spec *spec = codec->spec;
2958 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
2959}
2960
Takashi Iwai6b97eb42007-04-05 14:51:48 +02002961static int alc880_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
2962 struct hda_codec *codec,
2963 unsigned int stream_tag,
2964 unsigned int format,
2965 struct snd_pcm_substream *substream)
2966{
2967 struct alc_spec *spec = codec->spec;
2968 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
2969 stream_tag, format, substream);
2970}
2971
Linus Torvalds1da177e2005-04-16 15:20:36 -07002972static int alc880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
2973 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002974 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002975{
2976 struct alc_spec *spec = codec->spec;
2977 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
2978}
2979
2980/*
2981 * Analog capture
2982 */
Takashi Iwai63300792008-01-24 15:31:36 +01002983static int alc880_alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002984 struct hda_codec *codec,
2985 unsigned int stream_tag,
2986 unsigned int format,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002987 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002988{
2989 struct alc_spec *spec = codec->spec;
2990
Takashi Iwai63300792008-01-24 15:31:36 +01002991 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1],
Linus Torvalds1da177e2005-04-16 15:20:36 -07002992 stream_tag, 0, format);
2993 return 0;
2994}
2995
Takashi Iwai63300792008-01-24 15:31:36 +01002996static int alc880_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002997 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002998 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002999{
3000 struct alc_spec *spec = codec->spec;
3001
Takashi Iwai888afa12008-03-18 09:57:50 +01003002 snd_hda_codec_cleanup_stream(codec,
3003 spec->adc_nids[substream->number + 1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003004 return 0;
3005}
3006
3007
3008/*
3009 */
3010static struct hda_pcm_stream alc880_pcm_analog_playback = {
3011 .substreams = 1,
3012 .channels_min = 2,
3013 .channels_max = 8,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003014 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003015 .ops = {
3016 .open = alc880_playback_pcm_open,
3017 .prepare = alc880_playback_pcm_prepare,
3018 .cleanup = alc880_playback_pcm_cleanup
3019 },
3020};
3021
3022static struct hda_pcm_stream alc880_pcm_analog_capture = {
Takashi Iwai63300792008-01-24 15:31:36 +01003023 .substreams = 1,
3024 .channels_min = 2,
3025 .channels_max = 2,
3026 /* NID is set in alc_build_pcms */
3027};
3028
3029static struct hda_pcm_stream alc880_pcm_analog_alt_playback = {
3030 .substreams = 1,
3031 .channels_min = 2,
3032 .channels_max = 2,
3033 /* NID is set in alc_build_pcms */
3034};
3035
3036static struct hda_pcm_stream alc880_pcm_analog_alt_capture = {
3037 .substreams = 2, /* can be overridden */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003038 .channels_min = 2,
3039 .channels_max = 2,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003040 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003041 .ops = {
Takashi Iwai63300792008-01-24 15:31:36 +01003042 .prepare = alc880_alt_capture_pcm_prepare,
3043 .cleanup = alc880_alt_capture_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07003044 },
3045};
3046
3047static struct hda_pcm_stream alc880_pcm_digital_playback = {
3048 .substreams = 1,
3049 .channels_min = 2,
3050 .channels_max = 2,
3051 /* NID is set in alc_build_pcms */
3052 .ops = {
3053 .open = alc880_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02003054 .close = alc880_dig_playback_pcm_close,
3055 .prepare = alc880_dig_playback_pcm_prepare
Linus Torvalds1da177e2005-04-16 15:20:36 -07003056 },
3057};
3058
3059static struct hda_pcm_stream alc880_pcm_digital_capture = {
3060 .substreams = 1,
3061 .channels_min = 2,
3062 .channels_max = 2,
3063 /* NID is set in alc_build_pcms */
3064};
3065
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01003066/* Used by alc_build_pcms to flag that a PCM has no playback stream */
Takashi Iwai63300792008-01-24 15:31:36 +01003067static struct hda_pcm_stream alc_pcm_null_stream = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01003068 .substreams = 0,
3069 .channels_min = 0,
3070 .channels_max = 0,
3071};
3072
Linus Torvalds1da177e2005-04-16 15:20:36 -07003073static int alc_build_pcms(struct hda_codec *codec)
3074{
3075 struct alc_spec *spec = codec->spec;
3076 struct hda_pcm *info = spec->pcm_rec;
3077 int i;
3078
3079 codec->num_pcms = 1;
3080 codec->pcm_info = info;
3081
Takashi Iwaie64f14f2009-01-20 18:32:55 +01003082 if (spec->no_analog)
3083 goto skip_analog;
3084
Linus Torvalds1da177e2005-04-16 15:20:36 -07003085 info->name = spec->stream_name_analog;
Takashi Iwai4a471b72005-12-07 13:56:29 +01003086 if (spec->stream_analog_playback) {
Takashi Iwaida3cec32008-08-08 17:12:14 +02003087 if (snd_BUG_ON(!spec->multiout.dac_nids))
3088 return -EINVAL;
Takashi Iwai4a471b72005-12-07 13:56:29 +01003089 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
3090 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
3091 }
3092 if (spec->stream_analog_capture) {
Takashi Iwaida3cec32008-08-08 17:12:14 +02003093 if (snd_BUG_ON(!spec->adc_nids))
3094 return -EINVAL;
Takashi Iwai4a471b72005-12-07 13:56:29 +01003095 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
3096 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
3097 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003098
Takashi Iwai4a471b72005-12-07 13:56:29 +01003099 if (spec->channel_mode) {
3100 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0;
3101 for (i = 0; i < spec->num_channel_mode; i++) {
3102 if (spec->channel_mode[i].channels > info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max) {
3103 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->channel_mode[i].channels;
3104 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003105 }
3106 }
3107
Takashi Iwaie64f14f2009-01-20 18:32:55 +01003108 skip_analog:
Takashi Iwaie08a0072006-09-07 17:52:14 +02003109 /* SPDIF for stream index #1 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003110 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
Takashi Iwaie08a0072006-09-07 17:52:14 +02003111 codec->num_pcms = 2;
Wu Fengguangb25c9da2009-02-06 15:02:27 +08003112 codec->slave_dig_outs = spec->multiout.slave_dig_outs;
Takashi Iwaic06134d2006-10-11 18:49:13 +02003113 info = spec->pcm_rec + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003114 info->name = spec->stream_name_digital;
Takashi Iwai8c441982009-01-20 18:30:20 +01003115 if (spec->dig_out_type)
3116 info->pcm_type = spec->dig_out_type;
3117 else
3118 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Takashi Iwai4a471b72005-12-07 13:56:29 +01003119 if (spec->multiout.dig_out_nid &&
3120 spec->stream_digital_playback) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003121 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_digital_playback);
3122 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
3123 }
Takashi Iwai4a471b72005-12-07 13:56:29 +01003124 if (spec->dig_in_nid &&
3125 spec->stream_digital_capture) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003126 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_digital_capture);
3127 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
3128 }
Takashi Iwai963f8032008-08-11 10:04:40 +02003129 /* FIXME: do we need this for all Realtek codec models? */
3130 codec->spdif_status_reset = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003131 }
3132
Takashi Iwaie64f14f2009-01-20 18:32:55 +01003133 if (spec->no_analog)
3134 return 0;
3135
Takashi Iwaie08a0072006-09-07 17:52:14 +02003136 /* If the use of more than one ADC is requested for the current
3137 * model, configure a second analog capture-only PCM.
3138 */
3139 /* Additional Analaog capture for index #2 */
Takashi Iwai63300792008-01-24 15:31:36 +01003140 if ((spec->alt_dac_nid && spec->stream_analog_alt_playback) ||
3141 (spec->num_adc_nids > 1 && spec->stream_analog_alt_capture)) {
Takashi Iwaie08a0072006-09-07 17:52:14 +02003142 codec->num_pcms = 3;
Takashi Iwaic06134d2006-10-11 18:49:13 +02003143 info = spec->pcm_rec + 2;
Takashi Iwaie08a0072006-09-07 17:52:14 +02003144 info->name = spec->stream_name_analog;
Takashi Iwai63300792008-01-24 15:31:36 +01003145 if (spec->alt_dac_nid) {
3146 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
3147 *spec->stream_analog_alt_playback;
3148 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
3149 spec->alt_dac_nid;
3150 } else {
3151 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
3152 alc_pcm_null_stream;
3153 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
3154 }
3155 if (spec->num_adc_nids > 1) {
3156 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
3157 *spec->stream_analog_alt_capture;
3158 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
3159 spec->adc_nids[1];
3160 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams =
3161 spec->num_adc_nids - 1;
3162 } else {
3163 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
3164 alc_pcm_null_stream;
3165 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0;
Takashi Iwaie08a0072006-09-07 17:52:14 +02003166 }
3167 }
3168
Linus Torvalds1da177e2005-04-16 15:20:36 -07003169 return 0;
3170}
3171
Takashi Iwai603c4012008-07-30 15:01:44 +02003172static void alc_free_kctls(struct hda_codec *codec)
3173{
3174 struct alc_spec *spec = codec->spec;
3175
3176 if (spec->kctls.list) {
3177 struct snd_kcontrol_new *kctl = spec->kctls.list;
3178 int i;
3179 for (i = 0; i < spec->kctls.used; i++)
3180 kfree(kctl[i].name);
3181 }
3182 snd_array_free(&spec->kctls);
3183}
3184
Linus Torvalds1da177e2005-04-16 15:20:36 -07003185static void alc_free(struct hda_codec *codec)
3186{
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003187 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003188
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003189 if (!spec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003190 return;
3191
Takashi Iwai603c4012008-07-30 15:01:44 +02003192 alc_free_kctls(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003193 kfree(spec);
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09003194 snd_hda_detach_beep_device(codec);
Takashi Iwai7943a8a2008-04-16 17:29:09 +02003195 codec->spec = NULL; /* to be sure */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003196}
3197
Takashi Iwaie044c392008-10-27 16:56:24 +01003198#ifdef SND_HDA_NEEDS_RESUME
3199static void store_pin_configs(struct hda_codec *codec)
3200{
3201 struct alc_spec *spec = codec->spec;
3202 hda_nid_t nid, end_nid;
3203
3204 end_nid = codec->start_nid + codec->num_nodes;
3205 for (nid = codec->start_nid; nid < end_nid; nid++) {
3206 unsigned int wid_caps = get_wcaps(codec, nid);
3207 unsigned int wid_type =
3208 (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
3209 if (wid_type != AC_WID_PIN)
3210 continue;
3211 if (spec->num_pins >= ARRAY_SIZE(spec->pin_nids))
3212 break;
3213 spec->pin_nids[spec->num_pins] = nid;
3214 spec->pin_cfgs[spec->num_pins] =
3215 snd_hda_codec_read(codec, nid, 0,
3216 AC_VERB_GET_CONFIG_DEFAULT, 0);
3217 spec->num_pins++;
3218 }
3219}
3220
3221static void resume_pin_configs(struct hda_codec *codec)
3222{
3223 struct alc_spec *spec = codec->spec;
3224 int i;
3225
3226 for (i = 0; i < spec->num_pins; i++) {
3227 hda_nid_t pin_nid = spec->pin_nids[i];
3228 unsigned int pin_config = spec->pin_cfgs[i];
3229 snd_hda_codec_write(codec, pin_nid, 0,
3230 AC_VERB_SET_CONFIG_DEFAULT_BYTES_0,
3231 pin_config & 0x000000ff);
3232 snd_hda_codec_write(codec, pin_nid, 0,
3233 AC_VERB_SET_CONFIG_DEFAULT_BYTES_1,
3234 (pin_config & 0x0000ff00) >> 8);
3235 snd_hda_codec_write(codec, pin_nid, 0,
3236 AC_VERB_SET_CONFIG_DEFAULT_BYTES_2,
3237 (pin_config & 0x00ff0000) >> 16);
3238 snd_hda_codec_write(codec, pin_nid, 0,
3239 AC_VERB_SET_CONFIG_DEFAULT_BYTES_3,
3240 pin_config >> 24);
3241 }
3242}
3243
3244static int alc_resume(struct hda_codec *codec)
3245{
3246 resume_pin_configs(codec);
3247 codec->patch_ops.init(codec);
3248 snd_hda_codec_resume_amp(codec);
3249 snd_hda_codec_resume_cache(codec);
3250 return 0;
3251}
3252#else
3253#define store_pin_configs(codec)
3254#endif
3255
Linus Torvalds1da177e2005-04-16 15:20:36 -07003256/*
3257 */
3258static struct hda_codec_ops alc_patch_ops = {
3259 .build_controls = alc_build_controls,
3260 .build_pcms = alc_build_pcms,
3261 .init = alc_init,
3262 .free = alc_free,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003263 .unsol_event = alc_unsol_event,
Takashi Iwaie044c392008-10-27 16:56:24 +01003264#ifdef SND_HDA_NEEDS_RESUME
3265 .resume = alc_resume,
3266#endif
Takashi Iwaicb53c622007-08-10 17:21:45 +02003267#ifdef CONFIG_SND_HDA_POWER_SAVE
3268 .check_power_status = alc_check_power_status,
3269#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07003270};
3271
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003272
3273/*
3274 * Test configuration for debugging
3275 *
3276 * Almost all inputs/outputs are enabled. I/O pins can be configured via
3277 * enum controls.
3278 */
3279#ifdef CONFIG_SND_DEBUG
3280static hda_nid_t alc880_test_dac_nids[4] = {
3281 0x02, 0x03, 0x04, 0x05
3282};
3283
3284static struct hda_input_mux alc880_test_capture_source = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003285 .num_items = 7,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003286 .items = {
3287 { "In-1", 0x0 },
3288 { "In-2", 0x1 },
3289 { "In-3", 0x2 },
3290 { "In-4", 0x3 },
3291 { "CD", 0x4 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003292 { "Front", 0x5 },
3293 { "Surround", 0x6 },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003294 },
3295};
3296
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01003297static struct hda_channel_mode alc880_test_modes[4] = {
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003298 { 2, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02003299 { 4, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003300 { 6, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02003301 { 8, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003302};
3303
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003304static int alc_test_pin_ctl_info(struct snd_kcontrol *kcontrol,
3305 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003306{
3307 static char *texts[] = {
3308 "N/A", "Line Out", "HP Out",
3309 "In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%"
3310 };
3311 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
3312 uinfo->count = 1;
3313 uinfo->value.enumerated.items = 8;
3314 if (uinfo->value.enumerated.item >= 8)
3315 uinfo->value.enumerated.item = 7;
3316 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
3317 return 0;
3318}
3319
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003320static int alc_test_pin_ctl_get(struct snd_kcontrol *kcontrol,
3321 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003322{
3323 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3324 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
3325 unsigned int pin_ctl, item = 0;
3326
3327 pin_ctl = snd_hda_codec_read(codec, nid, 0,
3328 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
3329 if (pin_ctl & AC_PINCTL_OUT_EN) {
3330 if (pin_ctl & AC_PINCTL_HP_EN)
3331 item = 2;
3332 else
3333 item = 1;
3334 } else if (pin_ctl & AC_PINCTL_IN_EN) {
3335 switch (pin_ctl & AC_PINCTL_VREFEN) {
3336 case AC_PINCTL_VREF_HIZ: item = 3; break;
3337 case AC_PINCTL_VREF_50: item = 4; break;
3338 case AC_PINCTL_VREF_GRD: item = 5; break;
3339 case AC_PINCTL_VREF_80: item = 6; break;
3340 case AC_PINCTL_VREF_100: item = 7; break;
3341 }
3342 }
3343 ucontrol->value.enumerated.item[0] = item;
3344 return 0;
3345}
3346
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003347static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol,
3348 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003349{
3350 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3351 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
3352 static unsigned int ctls[] = {
3353 0, AC_PINCTL_OUT_EN, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN,
3354 AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ,
3355 AC_PINCTL_IN_EN | AC_PINCTL_VREF_50,
3356 AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD,
3357 AC_PINCTL_IN_EN | AC_PINCTL_VREF_80,
3358 AC_PINCTL_IN_EN | AC_PINCTL_VREF_100,
3359 };
3360 unsigned int old_ctl, new_ctl;
3361
3362 old_ctl = snd_hda_codec_read(codec, nid, 0,
3363 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
3364 new_ctl = ctls[ucontrol->value.enumerated.item[0]];
3365 if (old_ctl != new_ctl) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003366 int val;
3367 snd_hda_codec_write_cache(codec, nid, 0,
3368 AC_VERB_SET_PIN_WIDGET_CONTROL,
3369 new_ctl);
Takashi Iwai47fd8302007-08-10 17:11:07 +02003370 val = ucontrol->value.enumerated.item[0] >= 3 ?
3371 HDA_AMP_MUTE : 0;
3372 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
3373 HDA_AMP_MUTE, val);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003374 return 1;
3375 }
3376 return 0;
3377}
3378
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003379static int alc_test_pin_src_info(struct snd_kcontrol *kcontrol,
3380 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003381{
3382 static char *texts[] = {
3383 "Front", "Surround", "CLFE", "Side"
3384 };
3385 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
3386 uinfo->count = 1;
3387 uinfo->value.enumerated.items = 4;
3388 if (uinfo->value.enumerated.item >= 4)
3389 uinfo->value.enumerated.item = 3;
3390 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
3391 return 0;
3392}
3393
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003394static int alc_test_pin_src_get(struct snd_kcontrol *kcontrol,
3395 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003396{
3397 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3398 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
3399 unsigned int sel;
3400
3401 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0);
3402 ucontrol->value.enumerated.item[0] = sel & 3;
3403 return 0;
3404}
3405
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003406static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol,
3407 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003408{
3409 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3410 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
3411 unsigned int sel;
3412
3413 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3;
3414 if (ucontrol->value.enumerated.item[0] != sel) {
3415 sel = ucontrol->value.enumerated.item[0] & 3;
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003416 snd_hda_codec_write_cache(codec, nid, 0,
3417 AC_VERB_SET_CONNECT_SEL, sel);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003418 return 1;
3419 }
3420 return 0;
3421}
3422
3423#define PIN_CTL_TEST(xname,nid) { \
3424 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
3425 .name = xname, \
3426 .info = alc_test_pin_ctl_info, \
3427 .get = alc_test_pin_ctl_get, \
3428 .put = alc_test_pin_ctl_put, \
3429 .private_value = nid \
3430 }
3431
3432#define PIN_SRC_TEST(xname,nid) { \
3433 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
3434 .name = xname, \
3435 .info = alc_test_pin_src_info, \
3436 .get = alc_test_pin_src_get, \
3437 .put = alc_test_pin_src_put, \
3438 .private_value = nid \
3439 }
3440
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01003441static struct snd_kcontrol_new alc880_test_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02003442 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3443 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
3444 HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
3445 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003446 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
3447 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
3448 HDA_BIND_MUTE("CLFE Playback Switch", 0x0e, 2, HDA_INPUT),
3449 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003450 PIN_CTL_TEST("Front Pin Mode", 0x14),
3451 PIN_CTL_TEST("Surround Pin Mode", 0x15),
3452 PIN_CTL_TEST("CLFE Pin Mode", 0x16),
3453 PIN_CTL_TEST("Side Pin Mode", 0x17),
3454 PIN_CTL_TEST("In-1 Pin Mode", 0x18),
3455 PIN_CTL_TEST("In-2 Pin Mode", 0x19),
3456 PIN_CTL_TEST("In-3 Pin Mode", 0x1a),
3457 PIN_CTL_TEST("In-4 Pin Mode", 0x1b),
3458 PIN_SRC_TEST("In-1 Pin Source", 0x18),
3459 PIN_SRC_TEST("In-2 Pin Source", 0x19),
3460 PIN_SRC_TEST("In-3 Pin Source", 0x1a),
3461 PIN_SRC_TEST("In-4 Pin Source", 0x1b),
3462 HDA_CODEC_VOLUME("In-1 Playback Volume", 0x0b, 0x0, HDA_INPUT),
3463 HDA_CODEC_MUTE("In-1 Playback Switch", 0x0b, 0x0, HDA_INPUT),
3464 HDA_CODEC_VOLUME("In-2 Playback Volume", 0x0b, 0x1, HDA_INPUT),
3465 HDA_CODEC_MUTE("In-2 Playback Switch", 0x0b, 0x1, HDA_INPUT),
3466 HDA_CODEC_VOLUME("In-3 Playback Volume", 0x0b, 0x2, HDA_INPUT),
3467 HDA_CODEC_MUTE("In-3 Playback Switch", 0x0b, 0x2, HDA_INPUT),
3468 HDA_CODEC_VOLUME("In-4 Playback Volume", 0x0b, 0x3, HDA_INPUT),
3469 HDA_CODEC_MUTE("In-4 Playback Switch", 0x0b, 0x3, HDA_INPUT),
3470 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x4, HDA_INPUT),
3471 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x4, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003472 {
3473 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3474 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01003475 .info = alc_ch_mode_info,
3476 .get = alc_ch_mode_get,
3477 .put = alc_ch_mode_put,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003478 },
3479 { } /* end */
3480};
3481
3482static struct hda_verb alc880_test_init_verbs[] = {
3483 /* Unmute inputs of 0x0c - 0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02003484 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3485 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3486 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3487 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3488 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3489 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3490 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3491 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003492 /* Vol output for 0x0c-0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02003493 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3494 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3495 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3496 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003497 /* Set output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02003498 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3499 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3500 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3501 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003502 /* Unmute output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02003503 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3504 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3505 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3506 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003507 /* Set input pins 0x18-0x1c */
Takashi Iwai16ded522005-06-10 19:58:24 +02003508 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3509 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwai05acb862005-06-10 19:50:25 +02003510 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3511 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3512 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003513 /* Mute input pins 0x18-0x1b */
Takashi Iwai05acb862005-06-10 19:50:25 +02003514 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3515 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3516 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3517 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003518 /* ADC set up */
Takashi Iwai05acb862005-06-10 19:50:25 +02003519 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003520 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02003521 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003522 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02003523 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003524 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02003525 /* Analog input/passthru */
3526 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3527 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
3528 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
3529 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
3530 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003531 { }
3532};
3533#endif
3534
Linus Torvalds1da177e2005-04-16 15:20:36 -07003535/*
3536 */
3537
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003538static const char *alc880_models[ALC880_MODEL_LAST] = {
3539 [ALC880_3ST] = "3stack",
3540 [ALC880_TCL_S700] = "tcl",
3541 [ALC880_3ST_DIG] = "3stack-digout",
3542 [ALC880_CLEVO] = "clevo",
3543 [ALC880_5ST] = "5stack",
3544 [ALC880_5ST_DIG] = "5stack-digout",
3545 [ALC880_W810] = "w810",
3546 [ALC880_Z71V] = "z71v",
3547 [ALC880_6ST] = "6stack",
3548 [ALC880_6ST_DIG] = "6stack-digout",
3549 [ALC880_ASUS] = "asus",
3550 [ALC880_ASUS_W1V] = "asus-w1v",
3551 [ALC880_ASUS_DIG] = "asus-dig",
3552 [ALC880_ASUS_DIG2] = "asus-dig2",
3553 [ALC880_UNIWILL_DIG] = "uniwill",
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003554 [ALC880_UNIWILL_P53] = "uniwill-p53",
3555 [ALC880_FUJITSU] = "fujitsu",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003556 [ALC880_F1734] = "F1734",
3557 [ALC880_LG] = "lg",
3558 [ALC880_LG_LW] = "lg-lw",
Takashi Iwaidf99cd32008-04-25 15:25:04 +02003559 [ALC880_MEDION_RIM] = "medion",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003560#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003561 [ALC880_TEST] = "test",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003562#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003563 [ALC880_AUTO] = "auto",
3564};
3565
3566static struct snd_pci_quirk alc880_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003567 SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003568 SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG),
3569 SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST),
3570 SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_3ST_DIG),
3571 SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_6ST_DIG),
3572 SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_6ST_DIG),
3573 SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_6ST_DIG),
3574 SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_3ST_DIG),
3575 SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003576 SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_6ST_DIG),
3577 SND_PCI_QUIRK(0x103c, 0x2a09, "HP", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003578 SND_PCI_QUIRK(0x1043, 0x10b3, "ASUS W1V", ALC880_ASUS_W1V),
3579 SND_PCI_QUIRK(0x1043, 0x10c2, "ASUS W6A", ALC880_ASUS_DIG),
3580 SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS Wxx", ALC880_ASUS_DIG),
3581 SND_PCI_QUIRK(0x1043, 0x1113, "ASUS", ALC880_ASUS_DIG),
3582 SND_PCI_QUIRK(0x1043, 0x1123, "ASUS", ALC880_ASUS_DIG),
3583 SND_PCI_QUIRK(0x1043, 0x1173, "ASUS", ALC880_ASUS_DIG),
3584 SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_Z71V),
3585 /* SND_PCI_QUIRK(0x1043, 0x1964, "ASUS", ALC880_ASUS_DIG), */
3586 SND_PCI_QUIRK(0x1043, 0x1973, "ASUS", ALC880_ASUS_DIG),
3587 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS", ALC880_ASUS_DIG),
Travis Place186c3112008-05-20 11:54:41 +02003588 SND_PCI_QUIRK(0x1043, 0x814e, "ASUS P5GD1 w/SPDIF", ALC880_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003589 SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG),
3590 SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST),
3591 SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003592 SND_PCI_QUIRK(0x1043, 0, "ASUS", ALC880_ASUS), /* default ASUS */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003593 SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003594 SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST),
3595 SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003596 SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_5ST),
3597 SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003598 SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_6ST_DIG),
3599 SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_6ST_DIG),
3600 SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_6ST_DIG),
3601 SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003602 SND_PCI_QUIRK(0x1558, 0x0520, "Clevo m520G", ALC880_CLEVO),
3603 SND_PCI_QUIRK(0x1558, 0x0660, "Clevo m655n", ALC880_CLEVO),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003604 SND_PCI_QUIRK(0x1558, 0x5401, "ASUS", ALC880_ASUS_DIG2),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003605 SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003606 SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_UNIWILL_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003607 SND_PCI_QUIRK(0x1584, 0x9054, "Uniwlll", ALC880_F1734),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003608 SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL),
3609 SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003610 SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810),
Takashi Iwaidf99cd32008-04-25 15:25:04 +02003611 SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_MEDION_RIM),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003612 SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003613 SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003614 SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734),
Travis Place1d116042008-06-23 11:42:30 +02003615 SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FUJITSU),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003616 SND_PCI_QUIRK(0x1734, 0x10ac, "FSC", ALC880_UNIWILL),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003617 SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003618 SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003619 SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG),
3620 SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003621 SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003622 SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700),
3623 SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG), /* broken BIOS */
3624 SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG),
3625 SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003626 SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_5ST_DIG),
3627 SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003628 SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003629 SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003630 SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_3ST_DIG),
3631 SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003632 SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_5ST_DIG),
3633 SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_5ST_DIG),
3634 SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003635 SND_PCI_QUIRK(0x8086, 0, "Intel mobo", ALC880_3ST), /* default Intel */
3636 SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG),
3637 SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003638 {}
3639};
3640
Takashi Iwai16ded522005-06-10 19:58:24 +02003641/*
Kailang Yangdf694da2005-12-05 19:42:22 +01003642 * ALC880 codec presets
Takashi Iwai16ded522005-06-10 19:58:24 +02003643 */
Takashi Iwai16ded522005-06-10 19:58:24 +02003644static struct alc_config_preset alc880_presets[] = {
3645 [ALC880_3ST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003646 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003647 .init_verbs = { alc880_volume_init_verbs,
3648 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003649 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02003650 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003651 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
3652 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003653 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003654 .input_mux = &alc880_capture_source,
3655 },
3656 [ALC880_3ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003657 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003658 .init_verbs = { alc880_volume_init_verbs,
3659 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003660 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02003661 .dac_nids = alc880_dac_nids,
3662 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003663 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
3664 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003665 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003666 .input_mux = &alc880_capture_source,
3667 },
Kailang Yangdf694da2005-12-05 19:42:22 +01003668 [ALC880_TCL_S700] = {
3669 .mixers = { alc880_tcl_s700_mixer },
3670 .init_verbs = { alc880_volume_init_verbs,
3671 alc880_pin_tcl_S700_init_verbs,
3672 alc880_gpio2_init_verbs },
3673 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3674 .dac_nids = alc880_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01003675 .adc_nids = alc880_adc_nids_alt, /* FIXME: correct? */
3676 .num_adc_nids = 1, /* single ADC */
Kailang Yangdf694da2005-12-05 19:42:22 +01003677 .hp_nid = 0x03,
3678 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3679 .channel_mode = alc880_2_jack_modes,
3680 .input_mux = &alc880_capture_source,
3681 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003682 [ALC880_5ST] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003683 .mixers = { alc880_three_stack_mixer,
3684 alc880_five_stack_mixer},
3685 .init_verbs = { alc880_volume_init_verbs,
3686 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003687 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3688 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003689 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
3690 .channel_mode = alc880_fivestack_modes,
3691 .input_mux = &alc880_capture_source,
3692 },
3693 [ALC880_5ST_DIG] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003694 .mixers = { alc880_three_stack_mixer,
3695 alc880_five_stack_mixer },
3696 .init_verbs = { alc880_volume_init_verbs,
3697 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003698 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3699 .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_fivestack_modes),
3702 .channel_mode = alc880_fivestack_modes,
3703 .input_mux = &alc880_capture_source,
3704 },
Takashi Iwaib6482d42005-06-27 15:32:43 +02003705 [ALC880_6ST] = {
3706 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003707 .init_verbs = { alc880_volume_init_verbs,
3708 alc880_pin_6stack_init_verbs },
Takashi Iwaib6482d42005-06-27 15:32:43 +02003709 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
3710 .dac_nids = alc880_6st_dac_nids,
3711 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
3712 .channel_mode = alc880_sixstack_modes,
3713 .input_mux = &alc880_6stack_capture_source,
3714 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003715 [ALC880_6ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003716 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003717 .init_verbs = { alc880_volume_init_verbs,
3718 alc880_pin_6stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003719 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
3720 .dac_nids = alc880_6st_dac_nids,
3721 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003722 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
3723 .channel_mode = alc880_sixstack_modes,
3724 .input_mux = &alc880_6stack_capture_source,
3725 },
3726 [ALC880_W810] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003727 .mixers = { alc880_w810_base_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003728 .init_verbs = { alc880_volume_init_verbs,
3729 alc880_pin_w810_init_verbs,
Takashi Iwaib0af0de2005-06-21 14:49:19 +02003730 alc880_gpio2_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003731 .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids),
3732 .dac_nids = alc880_w810_dac_nids,
3733 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003734 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
3735 .channel_mode = alc880_w810_modes,
3736 .input_mux = &alc880_capture_source,
3737 },
3738 [ALC880_Z71V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003739 .mixers = { alc880_z71v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003740 .init_verbs = { alc880_volume_init_verbs,
3741 alc880_pin_z71v_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003742 .num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids),
3743 .dac_nids = alc880_z71v_dac_nids,
3744 .dig_out_nid = ALC880_DIGOUT_NID,
3745 .hp_nid = 0x03,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003746 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3747 .channel_mode = alc880_2_jack_modes,
Takashi Iwai16ded522005-06-10 19:58:24 +02003748 .input_mux = &alc880_capture_source,
3749 },
3750 [ALC880_F1734] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003751 .mixers = { alc880_f1734_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003752 .init_verbs = { alc880_volume_init_verbs,
3753 alc880_pin_f1734_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003754 .num_dacs = ARRAY_SIZE(alc880_f1734_dac_nids),
3755 .dac_nids = alc880_f1734_dac_nids,
3756 .hp_nid = 0x02,
3757 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3758 .channel_mode = alc880_2_jack_modes,
Takashi Iwai937b4162008-02-11 14:52:36 +01003759 .input_mux = &alc880_f1734_capture_source,
3760 .unsol_event = alc880_uniwill_p53_unsol_event,
3761 .init_hook = alc880_uniwill_p53_hp_automute,
Takashi Iwai16ded522005-06-10 19:58:24 +02003762 },
3763 [ALC880_ASUS] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003764 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003765 .init_verbs = { alc880_volume_init_verbs,
3766 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003767 alc880_gpio1_init_verbs },
3768 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3769 .dac_nids = alc880_asus_dac_nids,
3770 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3771 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003772 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003773 .input_mux = &alc880_capture_source,
3774 },
3775 [ALC880_ASUS_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003776 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003777 .init_verbs = { alc880_volume_init_verbs,
3778 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003779 alc880_gpio1_init_verbs },
3780 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3781 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003782 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003783 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3784 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003785 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003786 .input_mux = &alc880_capture_source,
3787 },
Kailang Yangdf694da2005-12-05 19:42:22 +01003788 [ALC880_ASUS_DIG2] = {
3789 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003790 .init_verbs = { alc880_volume_init_verbs,
3791 alc880_pin_asus_init_verbs,
Kailang Yangdf694da2005-12-05 19:42:22 +01003792 alc880_gpio2_init_verbs }, /* use GPIO2 */
3793 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3794 .dac_nids = alc880_asus_dac_nids,
3795 .dig_out_nid = ALC880_DIGOUT_NID,
3796 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3797 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003798 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01003799 .input_mux = &alc880_capture_source,
3800 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003801 [ALC880_ASUS_W1V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003802 .mixers = { alc880_asus_mixer, alc880_asus_w1v_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,
Takashi Iwai16ded522005-06-10 19:58:24 +02003808 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003809 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3810 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003811 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003812 .input_mux = &alc880_capture_source,
3813 },
3814 [ALC880_UNIWILL_DIG] = {
Takashi Iwai3c10a9d2005-08-23 20:02:27 +02003815 .mixers = { alc880_asus_mixer, alc880_pcbeep_mixer },
Kailang Yangccc656c2006-10-17 12:32:26 +02003816 .init_verbs = { alc880_volume_init_verbs,
3817 alc880_pin_asus_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003818 .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 Yangccc656c2006-10-17 12:32:26 +02003826 [ALC880_UNIWILL] = {
3827 .mixers = { alc880_uniwill_mixer },
3828 .init_verbs = { alc880_volume_init_verbs,
3829 alc880_uniwill_init_verbs },
3830 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3831 .dac_nids = alc880_asus_dac_nids,
3832 .dig_out_nid = ALC880_DIGOUT_NID,
3833 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
3834 .channel_mode = alc880_threestack_modes,
3835 .need_dac_fix = 1,
3836 .input_mux = &alc880_capture_source,
3837 .unsol_event = alc880_uniwill_unsol_event,
3838 .init_hook = alc880_uniwill_automute,
3839 },
3840 [ALC880_UNIWILL_P53] = {
3841 .mixers = { alc880_uniwill_p53_mixer },
3842 .init_verbs = { alc880_volume_init_verbs,
3843 alc880_uniwill_p53_init_verbs },
3844 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3845 .dac_nids = alc880_asus_dac_nids,
3846 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003847 .channel_mode = alc880_threestack_modes,
3848 .input_mux = &alc880_capture_source,
3849 .unsol_event = alc880_uniwill_p53_unsol_event,
3850 .init_hook = alc880_uniwill_p53_hp_automute,
3851 },
3852 [ALC880_FUJITSU] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003853 .mixers = { alc880_fujitsu_mixer,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003854 alc880_pcbeep_mixer, },
3855 .init_verbs = { alc880_volume_init_verbs,
3856 alc880_uniwill_p53_init_verbs,
3857 alc880_beep_init_verbs },
3858 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3859 .dac_nids = alc880_dac_nids,
Takashi Iwaid53d7d92007-08-20 15:20:02 +02003860 .dig_out_nid = ALC880_DIGOUT_NID,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003861 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3862 .channel_mode = alc880_2_jack_modes,
Kailang Yangccc656c2006-10-17 12:32:26 +02003863 .input_mux = &alc880_capture_source,
3864 .unsol_event = alc880_uniwill_p53_unsol_event,
3865 .init_hook = alc880_uniwill_p53_hp_automute,
3866 },
Kailang Yangdf694da2005-12-05 19:42:22 +01003867 [ALC880_CLEVO] = {
3868 .mixers = { alc880_three_stack_mixer },
3869 .init_verbs = { alc880_volume_init_verbs,
3870 alc880_pin_clevo_init_verbs },
3871 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3872 .dac_nids = alc880_dac_nids,
3873 .hp_nid = 0x03,
3874 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
3875 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003876 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01003877 .input_mux = &alc880_capture_source,
3878 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003879 [ALC880_LG] = {
3880 .mixers = { alc880_lg_mixer },
3881 .init_verbs = { alc880_volume_init_verbs,
3882 alc880_lg_init_verbs },
3883 .num_dacs = ARRAY_SIZE(alc880_lg_dac_nids),
3884 .dac_nids = alc880_lg_dac_nids,
3885 .dig_out_nid = ALC880_DIGOUT_NID,
3886 .num_channel_mode = ARRAY_SIZE(alc880_lg_ch_modes),
3887 .channel_mode = alc880_lg_ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003888 .need_dac_fix = 1,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003889 .input_mux = &alc880_lg_capture_source,
3890 .unsol_event = alc880_lg_unsol_event,
3891 .init_hook = alc880_lg_automute,
Takashi Iwaicb53c622007-08-10 17:21:45 +02003892#ifdef CONFIG_SND_HDA_POWER_SAVE
3893 .loopbacks = alc880_lg_loopbacks,
3894#endif
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003895 },
Takashi Iwaid6815182006-03-23 16:06:23 +01003896 [ALC880_LG_LW] = {
3897 .mixers = { alc880_lg_lw_mixer },
3898 .init_verbs = { alc880_volume_init_verbs,
3899 alc880_lg_lw_init_verbs },
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003900 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwaid6815182006-03-23 16:06:23 +01003901 .dac_nids = alc880_dac_nids,
3902 .dig_out_nid = ALC880_DIGOUT_NID,
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003903 .num_channel_mode = ARRAY_SIZE(alc880_lg_lw_modes),
3904 .channel_mode = alc880_lg_lw_modes,
Takashi Iwaid6815182006-03-23 16:06:23 +01003905 .input_mux = &alc880_lg_lw_capture_source,
3906 .unsol_event = alc880_lg_lw_unsol_event,
3907 .init_hook = alc880_lg_lw_automute,
3908 },
Takashi Iwaidf99cd32008-04-25 15:25:04 +02003909 [ALC880_MEDION_RIM] = {
3910 .mixers = { alc880_medion_rim_mixer },
3911 .init_verbs = { alc880_volume_init_verbs,
3912 alc880_medion_rim_init_verbs,
3913 alc_gpio2_init_verbs },
3914 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3915 .dac_nids = alc880_dac_nids,
3916 .dig_out_nid = ALC880_DIGOUT_NID,
3917 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3918 .channel_mode = alc880_2_jack_modes,
3919 .input_mux = &alc880_medion_rim_capture_source,
3920 .unsol_event = alc880_medion_rim_unsol_event,
3921 .init_hook = alc880_medion_rim_automute,
3922 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003923#ifdef CONFIG_SND_DEBUG
3924 [ALC880_TEST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003925 .mixers = { alc880_test_mixer },
3926 .init_verbs = { alc880_test_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003927 .num_dacs = ARRAY_SIZE(alc880_test_dac_nids),
3928 .dac_nids = alc880_test_dac_nids,
3929 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003930 .num_channel_mode = ARRAY_SIZE(alc880_test_modes),
3931 .channel_mode = alc880_test_modes,
3932 .input_mux = &alc880_test_capture_source,
3933 },
3934#endif
3935};
3936
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003937/*
3938 * Automatic parse of I/O pins from the BIOS configuration
3939 */
3940
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003941enum {
3942 ALC_CTL_WIDGET_VOL,
3943 ALC_CTL_WIDGET_MUTE,
3944 ALC_CTL_BIND_MUTE,
3945};
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01003946static struct snd_kcontrol_new alc880_control_templates[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003947 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
3948 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Takashi Iwai985be542005-11-02 18:26:49 +01003949 HDA_BIND_MUTE(NULL, 0, 0, 0),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003950};
3951
3952/* add dynamic controls */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003953static int add_control(struct alc_spec *spec, int type, const char *name,
3954 unsigned long val)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003955{
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01003956 struct snd_kcontrol_new *knew;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003957
Takashi Iwai603c4012008-07-30 15:01:44 +02003958 snd_array_init(&spec->kctls, sizeof(*knew), 32);
3959 knew = snd_array_new(&spec->kctls);
3960 if (!knew)
3961 return -ENOMEM;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003962 *knew = alc880_control_templates[type];
Paulo Marques543537b2005-06-23 00:09:02 -07003963 knew->name = kstrdup(name, GFP_KERNEL);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003964 if (!knew->name)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003965 return -ENOMEM;
3966 knew->private_value = val;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003967 return 0;
3968}
3969
3970#define alc880_is_fixed_pin(nid) ((nid) >= 0x14 && (nid) <= 0x17)
3971#define alc880_fixed_pin_idx(nid) ((nid) - 0x14)
3972#define alc880_is_multi_pin(nid) ((nid) >= 0x18)
3973#define alc880_multi_pin_idx(nid) ((nid) - 0x18)
3974#define alc880_is_input_pin(nid) ((nid) >= 0x18)
3975#define alc880_input_pin_idx(nid) ((nid) - 0x18)
3976#define alc880_idx_to_dac(nid) ((nid) + 0x02)
3977#define alc880_dac_to_idx(nid) ((nid) - 0x02)
3978#define alc880_idx_to_mixer(nid) ((nid) + 0x0c)
3979#define alc880_idx_to_selector(nid) ((nid) + 0x10)
3980#define ALC880_PIN_CD_NID 0x1c
3981
3982/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003983static int alc880_auto_fill_dac_nids(struct alc_spec *spec,
3984 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003985{
3986 hda_nid_t nid;
3987 int assigned[4];
3988 int i, j;
3989
3990 memset(assigned, 0, sizeof(assigned));
Takashi Iwaib0af0de2005-06-21 14:49:19 +02003991 spec->multiout.dac_nids = spec->private_dac_nids;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003992
3993 /* check the pins hardwired to audio widget */
3994 for (i = 0; i < cfg->line_outs; i++) {
3995 nid = cfg->line_out_pins[i];
3996 if (alc880_is_fixed_pin(nid)) {
3997 int idx = alc880_fixed_pin_idx(nid);
Libin Yang5014f192005-11-23 15:48:36 +01003998 spec->multiout.dac_nids[i] = alc880_idx_to_dac(idx);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003999 assigned[idx] = 1;
4000 }
4001 }
4002 /* left pins can be connect to any audio widget */
4003 for (i = 0; i < cfg->line_outs; i++) {
4004 nid = cfg->line_out_pins[i];
4005 if (alc880_is_fixed_pin(nid))
4006 continue;
4007 /* search for an empty channel */
4008 for (j = 0; j < cfg->line_outs; j++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004009 if (!assigned[j]) {
4010 spec->multiout.dac_nids[i] =
4011 alc880_idx_to_dac(j);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004012 assigned[j] = 1;
4013 break;
4014 }
4015 }
4016 }
4017 spec->multiout.num_dacs = cfg->line_outs;
4018 return 0;
4019}
4020
4021/* add playback controls from the parsed DAC table */
Kailang Yangdf694da2005-12-05 19:42:22 +01004022static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
4023 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004024{
4025 char name[32];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004026 static const char *chname[4] = {
4027 "Front", "Surround", NULL /*CLFE*/, "Side"
4028 };
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004029 hda_nid_t nid;
4030 int i, err;
4031
4032 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004033 if (!spec->multiout.dac_nids[i])
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004034 continue;
4035 nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i]));
4036 if (i == 2) {
4037 /* Center/LFE */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004038 err = add_control(spec, ALC_CTL_WIDGET_VOL,
4039 "Center Playback Volume",
4040 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
4041 HDA_OUTPUT));
4042 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004043 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004044 err = add_control(spec, ALC_CTL_WIDGET_VOL,
4045 "LFE Playback Volume",
4046 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
4047 HDA_OUTPUT));
4048 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004049 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004050 err = add_control(spec, ALC_CTL_BIND_MUTE,
4051 "Center Playback Switch",
4052 HDA_COMPOSE_AMP_VAL(nid, 1, 2,
4053 HDA_INPUT));
4054 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004055 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004056 err = add_control(spec, ALC_CTL_BIND_MUTE,
4057 "LFE Playback Switch",
4058 HDA_COMPOSE_AMP_VAL(nid, 2, 2,
4059 HDA_INPUT));
4060 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004061 return err;
4062 } else {
4063 sprintf(name, "%s Playback Volume", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004064 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
4065 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
4066 HDA_OUTPUT));
4067 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004068 return err;
4069 sprintf(name, "%s Playback Switch", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004070 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
4071 HDA_COMPOSE_AMP_VAL(nid, 3, 2,
4072 HDA_INPUT));
4073 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004074 return err;
4075 }
4076 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004077 return 0;
4078}
4079
Takashi Iwai8d88bc32005-11-17 11:09:23 +01004080/* add playback controls for speaker and HP outputs */
4081static int alc880_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
4082 const char *pfx)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004083{
4084 hda_nid_t nid;
4085 int err;
Takashi Iwai8d88bc32005-11-17 11:09:23 +01004086 char name[32];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004087
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004088 if (!pin)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004089 return 0;
4090
4091 if (alc880_is_fixed_pin(pin)) {
4092 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
Takashi Iwai82bc9552006-03-21 11:24:42 +01004093 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004094 if (!spec->multiout.hp_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004095 spec->multiout.hp_nid = nid;
Takashi Iwai82bc9552006-03-21 11:24:42 +01004096 else
4097 spec->multiout.extra_out_nid[0] = nid;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004098 /* control HP volume/switch on the output mixer amp */
4099 nid = alc880_idx_to_mixer(alc880_fixed_pin_idx(pin));
Takashi Iwai8d88bc32005-11-17 11:09:23 +01004100 sprintf(name, "%s Playback Volume", pfx);
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, HDA_OUTPUT));
4103 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004104 return err;
Takashi Iwai8d88bc32005-11-17 11:09:23 +01004105 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004106 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
4107 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
4108 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004109 return err;
4110 } else if (alc880_is_multi_pin(pin)) {
4111 /* set manual connection */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004112 /* we have only a switch on HP-out PIN */
Takashi Iwai8d88bc32005-11-17 11:09:23 +01004113 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004114 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
4115 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
4116 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004117 return err;
4118 }
4119 return 0;
4120}
4121
4122/* create input playback/capture controls for the given pin */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004123static int new_analog_input(struct alc_spec *spec, hda_nid_t pin,
4124 const char *ctlname,
Kailang Yangdf694da2005-12-05 19:42:22 +01004125 int idx, hda_nid_t mix_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004126{
4127 char name[32];
Kailang Yangdf694da2005-12-05 19:42:22 +01004128 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004129
4130 sprintf(name, "%s Playback Volume", ctlname);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004131 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
4132 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
4133 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004134 return err;
4135 sprintf(name, "%s Playback Switch", ctlname);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004136 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
4137 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
4138 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004139 return err;
4140 return 0;
4141}
4142
4143/* create playback/capture controls for input pins */
Kailang Yangdf694da2005-12-05 19:42:22 +01004144static int alc880_auto_create_analog_input_ctls(struct alc_spec *spec,
4145 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004146{
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02004147 struct hda_input_mux *imux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01004148 int i, err, idx;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004149
4150 for (i = 0; i < AUTO_PIN_LAST; i++) {
4151 if (alc880_is_input_pin(cfg->input_pins[i])) {
Kailang Yangdf694da2005-12-05 19:42:22 +01004152 idx = alc880_input_pin_idx(cfg->input_pins[i]);
Takashi Iwai4a471b72005-12-07 13:56:29 +01004153 err = new_analog_input(spec, cfg->input_pins[i],
4154 auto_pin_cfg_labels[i],
Kailang Yangdf694da2005-12-05 19:42:22 +01004155 idx, 0x0b);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004156 if (err < 0)
4157 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004158 imux->items[imux->num_items].label =
4159 auto_pin_cfg_labels[i];
4160 imux->items[imux->num_items].index =
4161 alc880_input_pin_idx(cfg->input_pins[i]);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004162 imux->num_items++;
4163 }
4164 }
4165 return 0;
4166}
4167
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004168static void alc_set_pin_output(struct hda_codec *codec, hda_nid_t nid,
4169 unsigned int pin_type)
4170{
4171 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
4172 pin_type);
4173 /* unmute pin */
Takashi Iwaid260cdf2008-02-13 17:19:35 +01004174 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
4175 AMP_OUT_UNMUTE);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004176}
4177
Kailang Yangdf694da2005-12-05 19:42:22 +01004178static void alc880_auto_set_output_and_unmute(struct hda_codec *codec,
4179 hda_nid_t nid, int pin_type,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004180 int dac_idx)
4181{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004182 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004183 /* need the manual connection? */
4184 if (alc880_is_multi_pin(nid)) {
4185 struct alc_spec *spec = codec->spec;
4186 int idx = alc880_multi_pin_idx(nid);
4187 snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
4188 AC_VERB_SET_CONNECT_SEL,
4189 alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
4190 }
4191}
4192
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02004193static int get_pin_type(int line_out_type)
4194{
4195 if (line_out_type == AUTO_PIN_HP_OUT)
4196 return PIN_HP;
4197 else
4198 return PIN_OUT;
4199}
4200
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004201static void alc880_auto_init_multi_out(struct hda_codec *codec)
4202{
4203 struct alc_spec *spec = codec->spec;
4204 int i;
Kailang Yangea1fb292008-08-26 12:58:38 +02004205
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004206 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004207 for (i = 0; i < spec->autocfg.line_outs; i++) {
4208 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02004209 int pin_type = get_pin_type(spec->autocfg.line_out_type);
4210 alc880_auto_set_output_and_unmute(codec, nid, pin_type, i);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004211 }
4212}
4213
Takashi Iwai8d88bc32005-11-17 11:09:23 +01004214static void alc880_auto_init_extra_out(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004215{
4216 struct alc_spec *spec = codec->spec;
4217 hda_nid_t pin;
4218
Takashi Iwai82bc9552006-03-21 11:24:42 +01004219 pin = spec->autocfg.speaker_pins[0];
Takashi Iwai8d88bc32005-11-17 11:09:23 +01004220 if (pin) /* connect to front */
4221 alc880_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02004222 pin = spec->autocfg.hp_pins[0];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004223 if (pin) /* connect to front */
4224 alc880_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
4225}
4226
4227static void alc880_auto_init_analog_input(struct hda_codec *codec)
4228{
4229 struct alc_spec *spec = codec->spec;
4230 int i;
4231
4232 for (i = 0; i < AUTO_PIN_LAST; i++) {
4233 hda_nid_t nid = spec->autocfg.input_pins[i];
4234 if (alc880_is_input_pin(nid)) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004235 snd_hda_codec_write(codec, nid, 0,
4236 AC_VERB_SET_PIN_WIDGET_CONTROL,
4237 i <= AUTO_PIN_FRONT_MIC ?
4238 PIN_VREF80 : PIN_IN);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004239 if (nid != ALC880_PIN_CD_NID)
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004240 snd_hda_codec_write(codec, nid, 0,
4241 AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004242 AMP_OUT_MUTE);
4243 }
4244 }
4245}
4246
4247/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004248/* return 1 if successful, 0 if the proper config is not found,
4249 * or a negative error code
4250 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004251static int alc880_parse_auto_config(struct hda_codec *codec)
4252{
4253 struct alc_spec *spec = codec->spec;
4254 int err;
Kailang Yangdf694da2005-12-05 19:42:22 +01004255 static hda_nid_t alc880_ignore[] = { 0x1d, 0 };
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004256
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004257 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
4258 alc880_ignore);
4259 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004260 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004261 if (!spec->autocfg.line_outs)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004262 return 0; /* can't find valid BIOS pin config */
Kailang Yangdf694da2005-12-05 19:42:22 +01004263
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004264 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
4265 if (err < 0)
4266 return err;
4267 err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
4268 if (err < 0)
4269 return err;
4270 err = alc880_auto_create_extra_out(spec,
4271 spec->autocfg.speaker_pins[0],
4272 "Speaker");
4273 if (err < 0)
4274 return err;
4275 err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
4276 "Headphone");
4277 if (err < 0)
4278 return err;
4279 err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg);
4280 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004281 return err;
4282
4283 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
4284
4285 if (spec->autocfg.dig_out_pin)
4286 spec->multiout.dig_out_nid = ALC880_DIGOUT_NID;
4287 if (spec->autocfg.dig_in_pin)
4288 spec->dig_in_nid = ALC880_DIGIN_NID;
4289
Takashi Iwai603c4012008-07-30 15:01:44 +02004290 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +01004291 add_mixer(spec, spec->kctls.list);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004292
Takashi Iwaid88897e2008-10-31 15:01:37 +01004293 add_verb(spec, alc880_volume_init_verbs);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004294
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004295 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02004296 spec->input_mux = &spec->private_imux[0];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004297
Takashi Iwaie044c392008-10-27 16:56:24 +01004298 store_pin_configs(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004299 return 1;
4300}
4301
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004302/* additional initialization for auto-configuration model */
4303static void alc880_auto_init(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004304{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004305 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004306 alc880_auto_init_multi_out(codec);
Takashi Iwai8d88bc32005-11-17 11:09:23 +01004307 alc880_auto_init_extra_out(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004308 alc880_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004309 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02004310 alc_inithook(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004311}
4312
4313/*
4314 * OK, here we have finally the patch for ALC880
4315 */
4316
Takashi Iwaif9e336f2008-10-31 16:37:07 +01004317static void set_capture_mixer(struct alc_spec *spec)
4318{
4319 static struct snd_kcontrol_new *caps[3] = {
4320 alc_capture_mixer1,
4321 alc_capture_mixer2,
4322 alc_capture_mixer3,
4323 };
Takashi Iwai30d72e92008-11-27 15:25:34 +01004324 if (spec->num_adc_nids > 0 && spec->num_adc_nids <= 3)
Takashi Iwaif9e336f2008-10-31 16:37:07 +01004325 spec->cap_mixer = caps[spec->num_adc_nids - 1];
4326}
4327
Linus Torvalds1da177e2005-04-16 15:20:36 -07004328static int patch_alc880(struct hda_codec *codec)
4329{
4330 struct alc_spec *spec;
4331 int board_config;
Kailang Yangdf694da2005-12-05 19:42:22 +01004332 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004333
Takashi Iwaie560d8d2005-09-09 14:21:46 +02004334 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004335 if (spec == NULL)
4336 return -ENOMEM;
4337
4338 codec->spec = spec;
4339
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004340 board_config = snd_hda_check_board_config(codec, ALC880_MODEL_LAST,
4341 alc880_models,
4342 alc880_cfg_tbl);
4343 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004344 printk(KERN_INFO "hda_codec: Unknown model for ALC880, "
4345 "trying auto-probe from BIOS...\n");
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004346 board_config = ALC880_AUTO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004347 }
4348
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004349 if (board_config == ALC880_AUTO) {
4350 /* automatic parse from the BIOS config */
4351 err = alc880_parse_auto_config(codec);
4352 if (err < 0) {
4353 alc_free(codec);
4354 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004355 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004356 printk(KERN_INFO
4357 "hda_codec: Cannot set up configuration "
4358 "from BIOS. Using 3-stack mode...\n");
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004359 board_config = ALC880_3ST;
4360 }
4361 }
4362
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09004363 err = snd_hda_attach_beep_device(codec, 0x1);
4364 if (err < 0) {
4365 alc_free(codec);
4366 return err;
4367 }
4368
Kailang Yangdf694da2005-12-05 19:42:22 +01004369 if (board_config != ALC880_AUTO)
4370 setup_preset(spec, &alc880_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004371
4372 spec->stream_name_analog = "ALC880 Analog";
4373 spec->stream_analog_playback = &alc880_pcm_analog_playback;
4374 spec->stream_analog_capture = &alc880_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01004375 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004376
4377 spec->stream_name_digital = "ALC880 Digital";
4378 spec->stream_digital_playback = &alc880_pcm_digital_playback;
4379 spec->stream_digital_capture = &alc880_pcm_digital_capture;
4380
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004381 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004382 /* check whether NID 0x07 is valid */
Takashi Iwai54d17402005-11-21 16:33:22 +01004383 unsigned int wcap = get_wcaps(codec, alc880_adc_nids[0]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004384 /* get type */
4385 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004386 if (wcap != AC_WID_AUD_IN) {
4387 spec->adc_nids = alc880_adc_nids_alt;
4388 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids_alt);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004389 } else {
4390 spec->adc_nids = alc880_adc_nids;
4391 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004392 }
4393 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01004394 set_capture_mixer(spec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004395
Takashi Iwai2134ea42008-01-10 16:53:55 +01004396 spec->vmaster_nid = 0x0c;
4397
Linus Torvalds1da177e2005-04-16 15:20:36 -07004398 codec->patch_ops = alc_patch_ops;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004399 if (board_config == ALC880_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004400 spec->init_hook = alc880_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02004401#ifdef CONFIG_SND_HDA_POWER_SAVE
4402 if (!spec->loopback.amplist)
4403 spec->loopback.amplist = alc880_loopbacks;
4404#endif
Takashi Iwaidaead532008-11-28 12:55:36 +01004405 codec->proc_widget_hook = print_realtek_coef;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004406
4407 return 0;
4408}
4409
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004410
Linus Torvalds1da177e2005-04-16 15:20:36 -07004411/*
4412 * ALC260 support
4413 */
4414
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004415static hda_nid_t alc260_dac_nids[1] = {
4416 /* front */
4417 0x02,
4418};
4419
4420static hda_nid_t alc260_adc_nids[1] = {
4421 /* ADC0 */
4422 0x04,
4423};
4424
Kailang Yangdf694da2005-12-05 19:42:22 +01004425static hda_nid_t alc260_adc_nids_alt[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004426 /* ADC1 */
4427 0x05,
4428};
4429
Jonathan Woithed57fdac2006-02-28 11:38:35 +01004430/* NIDs used when simultaneous access to both ADCs makes sense. Note that
4431 * alc260_capture_mixer assumes ADC0 (nid 0x04) is the first ADC.
4432 */
4433static hda_nid_t alc260_dual_adc_nids[2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004434 /* ADC0, ADC1 */
4435 0x04, 0x05
4436};
4437
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004438#define ALC260_DIGOUT_NID 0x03
4439#define ALC260_DIGIN_NID 0x06
4440
4441static struct hda_input_mux alc260_capture_source = {
4442 .num_items = 4,
4443 .items = {
4444 { "Mic", 0x0 },
4445 { "Front Mic", 0x1 },
4446 { "Line", 0x2 },
4447 { "CD", 0x4 },
4448 },
4449};
4450
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01004451/* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004452 * headphone jack and the internal CD lines since these are the only pins at
4453 * which audio can appear. For flexibility, also allow the option of
4454 * recording the mixer output on the second ADC (ADC0 doesn't have a
4455 * connection to the mixer output).
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004456 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004457static struct hda_input_mux alc260_fujitsu_capture_sources[2] = {
4458 {
4459 .num_items = 3,
4460 .items = {
4461 { "Mic/Line", 0x0 },
4462 { "CD", 0x4 },
4463 { "Headphone", 0x2 },
4464 },
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004465 },
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004466 {
4467 .num_items = 4,
4468 .items = {
4469 { "Mic/Line", 0x0 },
4470 { "CD", 0x4 },
4471 { "Headphone", 0x2 },
4472 { "Mixer", 0x5 },
4473 },
4474 },
4475
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004476};
4477
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004478/* Acer TravelMate(/Extensa/Aspire) notebooks have similar configuration to
4479 * the Fujitsu S702x, but jacks are marked differently.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004480 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004481static struct hda_input_mux alc260_acer_capture_sources[2] = {
4482 {
4483 .num_items = 4,
4484 .items = {
4485 { "Mic", 0x0 },
4486 { "Line", 0x2 },
4487 { "CD", 0x4 },
4488 { "Headphone", 0x5 },
4489 },
4490 },
4491 {
4492 .num_items = 5,
4493 .items = {
4494 { "Mic", 0x0 },
4495 { "Line", 0x2 },
4496 { "CD", 0x4 },
4497 { "Headphone", 0x6 },
4498 { "Mixer", 0x5 },
4499 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004500 },
4501};
Linus Torvalds1da177e2005-04-16 15:20:36 -07004502/*
4503 * This is just place-holder, so there's something for alc_build_pcms to look
4504 * at when it calculates the maximum number of channels. ALC260 has no mixer
4505 * element which allows changing the channel mode, so the verb list is
4506 * never used.
4507 */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01004508static struct hda_channel_mode alc260_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004509 { 2, NULL },
4510};
4511
Kailang Yangdf694da2005-12-05 19:42:22 +01004512
4513/* Mixer combinations
4514 *
4515 * basic: base_output + input + pc_beep + capture
4516 * HP: base_output + input + capture_alt
4517 * HP_3013: hp_3013 + input + capture
4518 * fujitsu: fujitsu + capture
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004519 * acer: acer + capture
Kailang Yangdf694da2005-12-05 19:42:22 +01004520 */
4521
4522static struct snd_kcontrol_new alc260_base_output_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02004523 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01004524 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01004525 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
4526 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
4527 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
4528 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
4529 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004530};
Kailang Yangdf694da2005-12-05 19:42:22 +01004531
4532static struct snd_kcontrol_new alc260_input_mixer[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004533 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4534 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
4535 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
4536 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
4537 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
4538 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
4539 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT),
4540 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004541 { } /* end */
4542};
4543
Kailang Yangdf694da2005-12-05 19:42:22 +01004544static struct snd_kcontrol_new alc260_pc_beep_mixer[] = {
4545 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x07, 0x05, HDA_INPUT),
4546 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x07, 0x05, HDA_INPUT),
4547 { } /* end */
4548};
4549
Takashi Iwaibec15c32008-01-28 18:16:30 +01004550/* update HP, line and mono out pins according to the master switch */
4551static void alc260_hp_master_update(struct hda_codec *codec,
4552 hda_nid_t hp, hda_nid_t line,
4553 hda_nid_t mono)
4554{
4555 struct alc_spec *spec = codec->spec;
4556 unsigned int val = spec->master_sw ? PIN_HP : 0;
4557 /* change HP and line-out pins */
Takashi Iwai30cde0a2008-11-07 14:49:28 +01004558 snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwaibec15c32008-01-28 18:16:30 +01004559 val);
Takashi Iwai30cde0a2008-11-07 14:49:28 +01004560 snd_hda_codec_write(codec, line, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwaibec15c32008-01-28 18:16:30 +01004561 val);
4562 /* mono (speaker) depending on the HP jack sense */
4563 val = (val && !spec->jack_present) ? PIN_OUT : 0;
Takashi Iwai30cde0a2008-11-07 14:49:28 +01004564 snd_hda_codec_write(codec, mono, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwaibec15c32008-01-28 18:16:30 +01004565 val);
4566}
4567
4568static int alc260_hp_master_sw_get(struct snd_kcontrol *kcontrol,
4569 struct snd_ctl_elem_value *ucontrol)
4570{
4571 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4572 struct alc_spec *spec = codec->spec;
4573 *ucontrol->value.integer.value = spec->master_sw;
4574 return 0;
4575}
4576
4577static int alc260_hp_master_sw_put(struct snd_kcontrol *kcontrol,
4578 struct snd_ctl_elem_value *ucontrol)
4579{
4580 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4581 struct alc_spec *spec = codec->spec;
4582 int val = !!*ucontrol->value.integer.value;
4583 hda_nid_t hp, line, mono;
4584
4585 if (val == spec->master_sw)
4586 return 0;
4587 spec->master_sw = val;
4588 hp = (kcontrol->private_value >> 16) & 0xff;
4589 line = (kcontrol->private_value >> 8) & 0xff;
4590 mono = kcontrol->private_value & 0xff;
4591 alc260_hp_master_update(codec, hp, line, mono);
4592 return 1;
4593}
4594
4595static struct snd_kcontrol_new alc260_hp_output_mixer[] = {
4596 {
4597 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4598 .name = "Master Playback Switch",
4599 .info = snd_ctl_boolean_mono_info,
4600 .get = alc260_hp_master_sw_get,
4601 .put = alc260_hp_master_sw_put,
4602 .private_value = (0x0f << 16) | (0x10 << 8) | 0x11
4603 },
4604 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4605 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
4606 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
4607 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
4608 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
4609 HDA_OUTPUT),
4610 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2, HDA_INPUT),
4611 { } /* end */
4612};
4613
4614static struct hda_verb alc260_hp_unsol_verbs[] = {
4615 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
4616 {},
4617};
4618
4619static void alc260_hp_automute(struct hda_codec *codec)
4620{
4621 struct alc_spec *spec = codec->spec;
4622 unsigned int present;
4623
4624 present = snd_hda_codec_read(codec, 0x10, 0,
4625 AC_VERB_GET_PIN_SENSE, 0);
4626 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
4627 alc260_hp_master_update(codec, 0x0f, 0x10, 0x11);
4628}
4629
4630static void alc260_hp_unsol_event(struct hda_codec *codec, unsigned int res)
4631{
4632 if ((res >> 26) == ALC880_HP_EVENT)
4633 alc260_hp_automute(codec);
4634}
4635
Kailang Yangdf694da2005-12-05 19:42:22 +01004636static struct snd_kcontrol_new alc260_hp_3013_mixer[] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01004637 {
4638 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4639 .name = "Master Playback Switch",
4640 .info = snd_ctl_boolean_mono_info,
4641 .get = alc260_hp_master_sw_get,
4642 .put = alc260_hp_master_sw_put,
Takashi Iwai30cde0a2008-11-07 14:49:28 +01004643 .private_value = (0x15 << 16) | (0x10 << 8) | 0x11
Takashi Iwaibec15c32008-01-28 18:16:30 +01004644 },
Kailang Yangdf694da2005-12-05 19:42:22 +01004645 HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT),
4646 HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT),
4647 HDA_CODEC_VOLUME("Aux-In Playback Volume", 0x07, 0x06, HDA_INPUT),
4648 HDA_CODEC_MUTE("Aux-In Playback Switch", 0x07, 0x06, HDA_INPUT),
4649 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4650 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01004651 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
4652 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02004653 { } /* end */
4654};
4655
Kailang Yang3f878302008-08-26 13:02:23 +02004656static struct hda_bind_ctls alc260_dc7600_bind_master_vol = {
4657 .ops = &snd_hda_bind_vol,
4658 .values = {
4659 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_OUTPUT),
4660 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_OUTPUT),
4661 HDA_COMPOSE_AMP_VAL(0x0a, 3, 0, HDA_OUTPUT),
4662 0
4663 },
4664};
4665
4666static struct hda_bind_ctls alc260_dc7600_bind_switch = {
4667 .ops = &snd_hda_bind_sw,
4668 .values = {
4669 HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT),
4670 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
4671 0
4672 },
4673};
4674
4675static struct snd_kcontrol_new alc260_hp_dc7600_mixer[] = {
4676 HDA_BIND_VOL("Master Playback Volume", &alc260_dc7600_bind_master_vol),
4677 HDA_BIND_SW("LineOut Playback Switch", &alc260_dc7600_bind_switch),
4678 HDA_CODEC_MUTE("Speaker Playback Switch", 0x0f, 0x0, HDA_OUTPUT),
4679 HDA_CODEC_MUTE("Headphone Playback Switch", 0x10, 0x0, HDA_OUTPUT),
4680 { } /* end */
4681};
4682
Takashi Iwaibec15c32008-01-28 18:16:30 +01004683static struct hda_verb alc260_hp_3013_unsol_verbs[] = {
4684 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
4685 {},
4686};
4687
4688static void alc260_hp_3013_automute(struct hda_codec *codec)
4689{
4690 struct alc_spec *spec = codec->spec;
4691 unsigned int present;
4692
4693 present = snd_hda_codec_read(codec, 0x15, 0,
4694 AC_VERB_GET_PIN_SENSE, 0);
4695 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
Takashi Iwai30cde0a2008-11-07 14:49:28 +01004696 alc260_hp_master_update(codec, 0x15, 0x10, 0x11);
Takashi Iwaibec15c32008-01-28 18:16:30 +01004697}
4698
4699static void alc260_hp_3013_unsol_event(struct hda_codec *codec,
4700 unsigned int res)
4701{
4702 if ((res >> 26) == ALC880_HP_EVENT)
4703 alc260_hp_3013_automute(codec);
4704}
4705
Kailang Yang3f878302008-08-26 13:02:23 +02004706static void alc260_hp_3012_automute(struct hda_codec *codec)
4707{
4708 unsigned int present, bits;
4709
4710 present = snd_hda_codec_read(codec, 0x10, 0,
4711 AC_VERB_GET_PIN_SENSE, 0) & AC_PINSENSE_PRESENCE;
4712
4713 bits = present ? 0 : PIN_OUT;
4714 snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
4715 bits);
4716 snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
4717 bits);
4718 snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
4719 bits);
4720}
4721
4722static void alc260_hp_3012_unsol_event(struct hda_codec *codec,
4723 unsigned int res)
4724{
4725 if ((res >> 26) == ALC880_HP_EVENT)
4726 alc260_hp_3012_automute(codec);
4727}
4728
4729/* Fujitsu S702x series laptops. ALC260 pin usage: Mic/Line jack = 0x12,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004730 * HP jack = 0x14, CD audio = 0x16, internal speaker = 0x10.
4731 */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01004732static struct snd_kcontrol_new alc260_fujitsu_mixer[] = {
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004733 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01004734 HDA_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004735 ALC_PIN_MODE("Headphone Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004736 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4737 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
4738 HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT),
4739 HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004740 ALC_PIN_MODE("Mic/Line Jack Mode", 0x12, ALC_PIN_DIR_IN),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004741 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
4742 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01004743 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT),
4744 HDA_BIND_MUTE("Speaker Playback Switch", 0x09, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01004745 { } /* end */
4746};
4747
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004748/* Mixer for Acer TravelMate(/Extensa/Aspire) notebooks. Note that current
4749 * versions of the ALC260 don't act on requests to enable mic bias from NID
4750 * 0x0f (used to drive the headphone jack in these laptops). The ALC260
4751 * datasheet doesn't mention this restriction. At this stage it's not clear
4752 * whether this behaviour is intentional or is a hardware bug in chip
4753 * revisions available in early 2006. Therefore for now allow the
4754 * "Headphone Jack Mode" control to span all choices, but if it turns out
4755 * that the lack of mic bias for this NID is intentional we could change the
4756 * mode from ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
4757 *
4758 * In addition, Acer TravelMate(/Extensa/Aspire) notebooks in early 2006
4759 * don't appear to make the mic bias available from the "line" jack, even
4760 * though the NID used for this jack (0x14) can supply it. The theory is
4761 * that perhaps Acer have included blocking capacitors between the ALC260
4762 * and the output jack. If this turns out to be the case for all such
4763 * models the "Line Jack Mode" mode could be changed from ALC_PIN_DIR_INOUT
4764 * to ALC_PIN_DIR_INOUT_NOMICBIAS.
Jonathan Woithebd869482006-11-28 11:35:52 +01004765 *
4766 * The C20x Tablet series have a mono internal speaker which is controlled
4767 * via the chip's Mono sum widget and pin complex, so include the necessary
4768 * controls for such models. On models without a "mono speaker" the control
4769 * won't do anything.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004770 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004771static struct snd_kcontrol_new alc260_acer_mixer[] = {
4772 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4773 HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004774 ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01004775 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
Jonathan Woithebd869482006-11-28 11:35:52 +01004776 HDA_OUTPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01004777 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2,
Jonathan Woithebd869482006-11-28 11:35:52 +01004778 HDA_INPUT),
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004779 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4780 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
4781 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
4782 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
4783 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
4784 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
4785 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
4786 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
4787 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
4788 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
4789 { } /* end */
4790};
4791
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004792/* Packard bell V7900 ALC260 pin usage: HP = 0x0f, Mic jack = 0x12,
4793 * Line In jack = 0x14, CD audio = 0x16, pc beep = 0x17.
4794 */
4795static struct snd_kcontrol_new alc260_will_mixer[] = {
4796 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4797 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
4798 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
4799 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
4800 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
4801 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
4802 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
4803 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
4804 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4805 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
4806 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
4807 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
4808 { } /* end */
4809};
4810
4811/* Replacer 672V ALC260 pin usage: Mic jack = 0x12,
4812 * Line In jack = 0x14, ATAPI Mic = 0x13, speaker = 0x0f.
4813 */
4814static struct snd_kcontrol_new alc260_replacer_672v_mixer[] = {
4815 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4816 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
4817 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
4818 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
4819 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
4820 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x07, 0x1, HDA_INPUT),
4821 HDA_CODEC_MUTE("ATATI Mic Playback Switch", 0x07, 0x1, HDA_INPUT),
4822 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
4823 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
4824 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
4825 { } /* end */
4826};
4827
Kailang Yangdf694da2005-12-05 19:42:22 +01004828/*
4829 * initialization verbs
4830 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004831static struct hda_verb alc260_init_verbs[] = {
4832 /* Line In pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02004833 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004834 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02004835 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004836 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02004837 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004838 /* Mic2 (front panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02004839 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004840 /* LINE-2 is used for line-out in rear */
Takashi Iwai05acb862005-06-10 19:50:25 +02004841 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004842 /* select line-out */
Jonathan Woithefd56f2d2006-01-24 10:35:46 +01004843 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004844 /* LINE-OUT pin */
Takashi Iwai05acb862005-06-10 19:50:25 +02004845 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004846 /* enable HP */
Takashi Iwai05acb862005-06-10 19:50:25 +02004847 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004848 /* enable Mono */
Takashi Iwai05acb862005-06-10 19:50:25 +02004849 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4850 /* mute capture amp left and right */
Takashi Iwai16ded522005-06-10 19:58:24 +02004851 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004852 /* set connection select to line in (default select for this ADC) */
4853 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai16ded522005-06-10 19:58:24 +02004854 /* mute capture amp left and right */
4855 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4856 /* set connection select to line in (default select for this ADC) */
4857 {0x05, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai05acb862005-06-10 19:50:25 +02004858 /* set vol=0 Line-Out mixer amp left and right */
4859 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4860 /* unmute pin widget amp left and right (no gain on this amp) */
4861 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4862 /* set vol=0 HP mixer amp left and right */
4863 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4864 /* unmute pin widget amp left and right (no gain on this amp) */
4865 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4866 /* set vol=0 Mono mixer amp left and right */
4867 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4868 /* unmute pin widget amp left and right (no gain on this amp) */
4869 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4870 /* unmute LINE-2 out pin */
4871 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004872 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
4873 * Line In 2 = 0x03
4874 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02004875 /* mute analog inputs */
4876 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4877 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4878 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4879 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4880 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004881 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
Takashi Iwai05acb862005-06-10 19:50:25 +02004882 /* mute Front out path */
4883 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4884 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4885 /* mute Headphone out path */
4886 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4887 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4888 /* mute Mono out path */
4889 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4890 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004891 { }
4892};
4893
Takashi Iwai474167d2006-05-17 17:17:43 +02004894#if 0 /* should be identical with alc260_init_verbs? */
Kailang Yangdf694da2005-12-05 19:42:22 +01004895static struct hda_verb alc260_hp_init_verbs[] = {
4896 /* Headphone and output */
4897 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
4898 /* mono output */
4899 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4900 /* Mic1 (rear panel) pin widget for input and vref at 80% */
4901 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4902 /* Mic2 (front panel) pin widget for input and vref at 80% */
4903 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4904 /* Line In pin widget for input */
4905 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4906 /* Line-2 pin widget for output */
4907 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4908 /* CD pin widget for input */
4909 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4910 /* unmute amp left and right */
4911 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
4912 /* set connection select to line in (default select for this ADC) */
4913 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
4914 /* unmute Line-Out mixer amp left and right (volume = 0) */
4915 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
4916 /* mute pin widget amp left and right (no gain on this amp) */
4917 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
4918 /* unmute HP mixer amp left and right (volume = 0) */
4919 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
4920 /* mute pin widget amp left and right (no gain on this amp) */
4921 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004922 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
4923 * Line In 2 = 0x03
4924 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02004925 /* mute analog inputs */
4926 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4927 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4928 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4929 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4930 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01004931 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
4932 /* Unmute Front out path */
4933 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4934 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4935 /* Unmute Headphone out path */
4936 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4937 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4938 /* Unmute Mono out path */
4939 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4940 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4941 { }
4942};
Takashi Iwai474167d2006-05-17 17:17:43 +02004943#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01004944
4945static struct hda_verb alc260_hp_3013_init_verbs[] = {
4946 /* Line out and output */
4947 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4948 /* mono output */
4949 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4950 /* Mic1 (rear panel) pin widget for input and vref at 80% */
4951 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4952 /* Mic2 (front panel) pin widget for input and vref at 80% */
4953 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4954 /* Line In pin widget for input */
4955 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4956 /* Headphone pin widget for output */
4957 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
4958 /* CD pin widget for input */
4959 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4960 /* unmute amp left and right */
4961 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
4962 /* set connection select to line in (default select for this ADC) */
4963 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
4964 /* unmute Line-Out mixer amp left and right (volume = 0) */
4965 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
4966 /* mute pin widget amp left and right (no gain on this amp) */
4967 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
4968 /* unmute HP mixer amp left and right (volume = 0) */
4969 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
4970 /* mute pin widget amp left and right (no gain on this amp) */
4971 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004972 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
4973 * Line In 2 = 0x03
4974 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02004975 /* mute analog inputs */
4976 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4977 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4978 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4979 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4980 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01004981 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
4982 /* Unmute Front out path */
4983 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4984 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4985 /* Unmute Headphone out path */
4986 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4987 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4988 /* Unmute Mono out path */
4989 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4990 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4991 { }
4992};
4993
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004994/* Initialisation sequence for ALC260 as configured in Fujitsu S702x
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004995 * laptops. ALC260 pin usage: Mic/Line jack = 0x12, HP jack = 0x14, CD
4996 * audio = 0x16, internal speaker = 0x10.
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004997 */
4998static struct hda_verb alc260_fujitsu_init_verbs[] = {
4999 /* Disable all GPIOs */
5000 {0x01, AC_VERB_SET_GPIO_MASK, 0},
5001 /* Internal speaker is connected to headphone pin */
5002 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5003 /* Headphone/Line-out jack connects to Line1 pin; make it an output */
5004 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Jonathan Woithef7ace402006-02-28 11:46:14 +01005005 /* Mic/Line-in jack is connected to mic1 pin, so make it an input */
5006 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
5007 /* Ensure all other unused pins are disabled and muted. */
5008 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5009 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005010 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01005011 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005012 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01005013 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5014 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5015 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005016
Jonathan Woithef7ace402006-02-28 11:46:14 +01005017 /* Disable digital (SPDIF) pins */
5018 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
5019 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01005020
Kailang Yangea1fb292008-08-26 12:58:38 +02005021 /* Ensure Line1 pin widget takes its input from the OUT1 sum bus
Jonathan Woithef7ace402006-02-28 11:46:14 +01005022 * when acting as an output.
5023 */
5024 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
5025
5026 /* Start with output sum widgets muted and their output gains at min */
Takashi Iwai8b33a5a2006-02-09 11:57:01 +01005027 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5028 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5029 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5030 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5031 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5032 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5033 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5034 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5035 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005036
Jonathan Woithef7ace402006-02-28 11:46:14 +01005037 /* Unmute HP pin widget amp left and right (no equiv mixer ctrl) */
5038 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5039 /* Unmute Line1 pin widget output buffer since it starts as an output.
5040 * If the pin mode is changed by the user the pin mode control will
5041 * take care of enabling the pin's input/output buffers as needed.
5042 * Therefore there's no need to enable the input buffer at this
5043 * stage.
Jonathan Woithecdcd9262006-02-28 11:36:42 +01005044 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01005045 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +02005046 /* Unmute input buffer of pin widget used for Line-in (no equiv
Jonathan Woithecdcd9262006-02-28 11:36:42 +01005047 * mixer ctrl)
5048 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01005049 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005050
Jonathan Woithef7ace402006-02-28 11:46:14 +01005051 /* Mute capture amp left and right */
5052 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +02005053 /* Set ADC connection select to match default mixer setting - line
Jonathan Woithef7ace402006-02-28 11:46:14 +01005054 * in (on mic1 pin)
5055 */
5056 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005057
Jonathan Woithef7ace402006-02-28 11:46:14 +01005058 /* Do the same for the second ADC: mute capture input amp and
5059 * set ADC connection to line in (on mic1 pin)
5060 */
5061 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5062 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01005063
Jonathan Woithef7ace402006-02-28 11:46:14 +01005064 /* Mute all inputs to mixer widget (even unconnected ones) */
5065 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
5066 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
5067 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
5068 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
5069 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
5070 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
5071 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
5072 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
Takashi Iwai4a471b72005-12-07 13:56:29 +01005073
5074 { }
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005075};
5076
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005077/* Initialisation sequence for ALC260 as configured in Acer TravelMate and
5078 * similar laptops (adapted from Fujitsu init verbs).
5079 */
5080static struct hda_verb alc260_acer_init_verbs[] = {
5081 /* On TravelMate laptops, GPIO 0 enables the internal speaker and
5082 * the headphone jack. Turn this on and rely on the standard mute
5083 * methods whenever the user wants to turn these outputs off.
5084 */
5085 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
5086 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
5087 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
5088 /* Internal speaker/Headphone jack is connected to Line-out pin */
5089 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5090 /* Internal microphone/Mic jack is connected to Mic1 pin */
5091 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
5092 /* Line In jack is connected to Line1 pin */
5093 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Jonathan Woithebd869482006-11-28 11:35:52 +01005094 /* Some Acers (eg: C20x Tablets) use Mono pin for internal speaker */
5095 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005096 /* Ensure all other unused pins are disabled and muted. */
5097 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5098 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005099 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5100 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5101 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5102 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5103 /* Disable digital (SPDIF) pins */
5104 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
5105 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
5106
Kailang Yangea1fb292008-08-26 12:58:38 +02005107 /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005108 * bus when acting as outputs.
5109 */
5110 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
5111 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
5112
5113 /* Start with output sum widgets muted and their output gains at min */
5114 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5115 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5116 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5117 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5118 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5119 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5120 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5121 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5122 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5123
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005124 /* Unmute Line-out pin widget amp left and right
5125 * (no equiv mixer ctrl)
5126 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005127 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithebd869482006-11-28 11:35:52 +01005128 /* Unmute mono pin widget amp output (no equiv mixer ctrl) */
5129 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005130 /* Unmute Mic1 and Line1 pin widget input buffers since they start as
5131 * inputs. If the pin mode is changed by the user the pin mode control
5132 * will take care of enabling the pin's input/output buffers as needed.
5133 * Therefore there's no need to enable the input buffer at this
5134 * stage.
5135 */
5136 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5137 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5138
5139 /* Mute capture amp left and right */
5140 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5141 /* Set ADC connection select to match default mixer setting - mic
5142 * (on mic1 pin)
5143 */
5144 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
5145
5146 /* Do similar with the second ADC: mute capture input amp and
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005147 * set ADC connection to mic to match ALSA's default state.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005148 */
5149 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005150 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005151
5152 /* Mute all inputs to mixer widget (even unconnected ones) */
5153 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
5154 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
5155 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
5156 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
5157 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
5158 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
5159 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
5160 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
5161
5162 { }
5163};
5164
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005165static struct hda_verb alc260_will_verbs[] = {
5166 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5167 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x00},
5168 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
5169 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
5170 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
5171 {0x1a, AC_VERB_SET_PROC_COEF, 0x3040},
5172 {}
5173};
5174
5175static struct hda_verb alc260_replacer_672v_verbs[] = {
5176 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
5177 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
5178 {0x1a, AC_VERB_SET_PROC_COEF, 0x3050},
5179
5180 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
5181 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
5182 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
5183
5184 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
5185 {}
5186};
5187
5188/* toggle speaker-output according to the hp-jack state */
5189static void alc260_replacer_672v_automute(struct hda_codec *codec)
5190{
5191 unsigned int present;
5192
5193 /* speaker --> GPIO Data 0, hp or spdif --> GPIO data 1 */
5194 present = snd_hda_codec_read(codec, 0x0f, 0,
5195 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
5196 if (present) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02005197 snd_hda_codec_write_cache(codec, 0x01, 0,
5198 AC_VERB_SET_GPIO_DATA, 1);
5199 snd_hda_codec_write_cache(codec, 0x0f, 0,
5200 AC_VERB_SET_PIN_WIDGET_CONTROL,
5201 PIN_HP);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005202 } else {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02005203 snd_hda_codec_write_cache(codec, 0x01, 0,
5204 AC_VERB_SET_GPIO_DATA, 0);
5205 snd_hda_codec_write_cache(codec, 0x0f, 0,
5206 AC_VERB_SET_PIN_WIDGET_CONTROL,
5207 PIN_OUT);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005208 }
5209}
5210
5211static void alc260_replacer_672v_unsol_event(struct hda_codec *codec,
5212 unsigned int res)
5213{
5214 if ((res >> 26) == ALC880_HP_EVENT)
5215 alc260_replacer_672v_automute(codec);
5216}
5217
Kailang Yang3f878302008-08-26 13:02:23 +02005218static struct hda_verb alc260_hp_dc7600_verbs[] = {
5219 {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
5220 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
5221 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5222 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5223 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5224 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5225 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
5226 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
5227 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
5228 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
5229 {}
5230};
5231
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005232/* Test configuration for debugging, modelled after the ALC880 test
5233 * configuration.
5234 */
5235#ifdef CONFIG_SND_DEBUG
5236static hda_nid_t alc260_test_dac_nids[1] = {
5237 0x02,
5238};
5239static hda_nid_t alc260_test_adc_nids[2] = {
5240 0x04, 0x05,
5241};
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005242/* For testing the ALC260, each input MUX needs its own definition since
Kailang Yangea1fb292008-08-26 12:58:38 +02005243 * the signal assignments are different. This assumes that the first ADC
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005244 * is NID 0x04.
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01005245 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005246static struct hda_input_mux alc260_test_capture_sources[2] = {
5247 {
5248 .num_items = 7,
5249 .items = {
5250 { "MIC1 pin", 0x0 },
5251 { "MIC2 pin", 0x1 },
5252 { "LINE1 pin", 0x2 },
5253 { "LINE2 pin", 0x3 },
5254 { "CD pin", 0x4 },
5255 { "LINE-OUT pin", 0x5 },
5256 { "HP-OUT pin", 0x6 },
5257 },
5258 },
5259 {
5260 .num_items = 8,
5261 .items = {
5262 { "MIC1 pin", 0x0 },
5263 { "MIC2 pin", 0x1 },
5264 { "LINE1 pin", 0x2 },
5265 { "LINE2 pin", 0x3 },
5266 { "CD pin", 0x4 },
5267 { "Mixer", 0x5 },
5268 { "LINE-OUT pin", 0x6 },
5269 { "HP-OUT pin", 0x7 },
5270 },
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005271 },
5272};
5273static struct snd_kcontrol_new alc260_test_mixer[] = {
5274 /* Output driver widgets */
5275 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
5276 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
5277 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x09, 0x0, HDA_OUTPUT),
5278 HDA_BIND_MUTE("LOUT2 Playback Switch", 0x09, 2, HDA_INPUT),
5279 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5280 HDA_BIND_MUTE("LOUT1 Playback Switch", 0x08, 2, HDA_INPUT),
5281
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005282 /* Modes for retasking pin widgets
5283 * Note: the ALC260 doesn't seem to act on requests to enable mic
5284 * bias from NIDs 0x0f and 0x10. The ALC260 datasheet doesn't
5285 * mention this restriction. At this stage it's not clear whether
5286 * this behaviour is intentional or is a hardware bug in chip
5287 * revisions available at least up until early 2006. Therefore for
5288 * now allow the "HP-OUT" and "LINE-OUT" Mode controls to span all
5289 * choices, but if it turns out that the lack of mic bias for these
5290 * NIDs is intentional we could change their modes from
5291 * ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
5292 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005293 ALC_PIN_MODE("HP-OUT pin mode", 0x10, ALC_PIN_DIR_INOUT),
5294 ALC_PIN_MODE("LINE-OUT pin mode", 0x0f, ALC_PIN_DIR_INOUT),
5295 ALC_PIN_MODE("LINE2 pin mode", 0x15, ALC_PIN_DIR_INOUT),
5296 ALC_PIN_MODE("LINE1 pin mode", 0x14, ALC_PIN_DIR_INOUT),
5297 ALC_PIN_MODE("MIC2 pin mode", 0x13, ALC_PIN_DIR_INOUT),
5298 ALC_PIN_MODE("MIC1 pin mode", 0x12, ALC_PIN_DIR_INOUT),
5299
5300 /* Loopback mixer controls */
5301 HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x07, 0x00, HDA_INPUT),
5302 HDA_CODEC_MUTE("MIC1 Playback Switch", 0x07, 0x00, HDA_INPUT),
5303 HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x07, 0x01, HDA_INPUT),
5304 HDA_CODEC_MUTE("MIC2 Playback Switch", 0x07, 0x01, HDA_INPUT),
5305 HDA_CODEC_VOLUME("LINE1 Playback Volume", 0x07, 0x02, HDA_INPUT),
5306 HDA_CODEC_MUTE("LINE1 Playback Switch", 0x07, 0x02, HDA_INPUT),
5307 HDA_CODEC_VOLUME("LINE2 Playback Volume", 0x07, 0x03, HDA_INPUT),
5308 HDA_CODEC_MUTE("LINE2 Playback Switch", 0x07, 0x03, HDA_INPUT),
5309 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
5310 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
5311 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
5312 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
5313 HDA_CODEC_VOLUME("LINE-OUT loopback Playback Volume", 0x07, 0x06, HDA_INPUT),
5314 HDA_CODEC_MUTE("LINE-OUT loopback Playback Switch", 0x07, 0x06, HDA_INPUT),
5315 HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x07, 0x7, HDA_INPUT),
5316 HDA_CODEC_MUTE("HP-OUT loopback Playback Switch", 0x07, 0x7, HDA_INPUT),
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01005317
5318 /* Controls for GPIO pins, assuming they are configured as outputs */
5319 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
5320 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
5321 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
5322 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
5323
Jonathan Woithe92621f12006-02-28 11:47:47 +01005324 /* Switches to allow the digital IO pins to be enabled. The datasheet
5325 * is ambigious as to which NID is which; testing on laptops which
Kailang Yangea1fb292008-08-26 12:58:38 +02005326 * make this output available should provide clarification.
Jonathan Woithe92621f12006-02-28 11:47:47 +01005327 */
5328 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x03, 0x01),
5329 ALC_SPDIF_CTRL_SWITCH("SPDIF Capture Switch", 0x06, 0x01),
5330
Jonathan Woithef8225f62008-01-08 12:16:54 +01005331 /* A switch allowing EAPD to be enabled. Some laptops seem to use
5332 * this output to turn on an external amplifier.
5333 */
5334 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
5335 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
5336
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005337 { } /* end */
5338};
5339static struct hda_verb alc260_test_init_verbs[] = {
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01005340 /* Enable all GPIOs as outputs with an initial value of 0 */
5341 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f},
5342 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
5343 {0x01, AC_VERB_SET_GPIO_MASK, 0x0f},
5344
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005345 /* Enable retasking pins as output, initially without power amp */
5346 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5347 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5348 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5349 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5350 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5351 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5352
Jonathan Woithe92621f12006-02-28 11:47:47 +01005353 /* Disable digital (SPDIF) pins initially, but users can enable
5354 * them via a mixer switch. In the case of SPDIF-out, this initverb
5355 * payload also sets the generation to 0, output to be in "consumer"
5356 * PCM format, copyright asserted, no pre-emphasis and no validity
5357 * control.
5358 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005359 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
5360 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
5361
Kailang Yangea1fb292008-08-26 12:58:38 +02005362 /* Ensure mic1, mic2, line1 and line2 pin widgets take input from the
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005363 * OUT1 sum bus when acting as an output.
5364 */
5365 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
5366 {0x0c, AC_VERB_SET_CONNECT_SEL, 0},
5367 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
5368 {0x0e, AC_VERB_SET_CONNECT_SEL, 0},
5369
5370 /* Start with output sum widgets muted and their output gains at min */
5371 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5372 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5373 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5374 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5375 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5376 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5377 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5378 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5379 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5380
Jonathan Woithecdcd9262006-02-28 11:36:42 +01005381 /* Unmute retasking pin widget output buffers since the default
5382 * state appears to be output. As the pin mode is changed by the
5383 * user the pin mode control will take care of enabling the pin's
5384 * input/output buffers as needed.
5385 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005386 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5387 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5388 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5389 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5390 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5391 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5392 /* Also unmute the mono-out pin widget */
5393 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5394
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005395 /* Mute capture amp left and right */
5396 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithef7ace402006-02-28 11:46:14 +01005397 /* Set ADC connection select to match default mixer setting (mic1
5398 * pin)
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005399 */
5400 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
5401
5402 /* Do the same for the second ADC: mute capture input amp and
Jonathan Woithef7ace402006-02-28 11:46:14 +01005403 * set ADC connection to mic1 pin
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005404 */
5405 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5406 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
5407
5408 /* Mute all inputs to mixer widget (even unconnected ones) */
5409 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
5410 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
5411 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
5412 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
5413 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
5414 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
5415 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
5416 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
5417
5418 { }
5419};
5420#endif
5421
Takashi Iwai63300792008-01-24 15:31:36 +01005422#define alc260_pcm_analog_playback alc880_pcm_analog_alt_playback
5423#define alc260_pcm_analog_capture alc880_pcm_analog_capture
Linus Torvalds1da177e2005-04-16 15:20:36 -07005424
Takashi Iwaia3bcba32005-12-06 19:05:29 +01005425#define alc260_pcm_digital_playback alc880_pcm_digital_playback
5426#define alc260_pcm_digital_capture alc880_pcm_digital_capture
5427
Kailang Yangdf694da2005-12-05 19:42:22 +01005428/*
5429 * for BIOS auto-configuration
5430 */
5431
5432static int alc260_add_playback_controls(struct alc_spec *spec, hda_nid_t nid,
Takashi Iwai863b4512008-10-21 17:01:47 +02005433 const char *pfx, int *vol_bits)
Kailang Yangdf694da2005-12-05 19:42:22 +01005434{
5435 hda_nid_t nid_vol;
5436 unsigned long vol_val, sw_val;
5437 char name[32];
5438 int err;
5439
5440 if (nid >= 0x0f && nid < 0x11) {
5441 nid_vol = nid - 0x7;
5442 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
5443 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
5444 } else if (nid == 0x11) {
5445 nid_vol = nid - 0x7;
5446 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT);
5447 sw_val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
5448 } else if (nid >= 0x12 && nid <= 0x15) {
5449 nid_vol = 0x08;
5450 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
5451 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
5452 } else
5453 return 0; /* N/A */
Kailang Yangea1fb292008-08-26 12:58:38 +02005454
Takashi Iwai863b4512008-10-21 17:01:47 +02005455 if (!(*vol_bits & (1 << nid_vol))) {
5456 /* first control for the volume widget */
5457 snprintf(name, sizeof(name), "%s Playback Volume", pfx);
5458 err = add_control(spec, ALC_CTL_WIDGET_VOL, name, vol_val);
5459 if (err < 0)
5460 return err;
5461 *vol_bits |= (1 << nid_vol);
5462 }
Kailang Yangdf694da2005-12-05 19:42:22 +01005463 snprintf(name, sizeof(name), "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005464 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, sw_val);
5465 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01005466 return err;
5467 return 1;
5468}
5469
5470/* add playback controls from the parsed DAC table */
5471static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec,
5472 const struct auto_pin_cfg *cfg)
5473{
5474 hda_nid_t nid;
5475 int err;
Takashi Iwai863b4512008-10-21 17:01:47 +02005476 int vols = 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01005477
5478 spec->multiout.num_dacs = 1;
5479 spec->multiout.dac_nids = spec->private_dac_nids;
5480 spec->multiout.dac_nids[0] = 0x02;
5481
5482 nid = cfg->line_out_pins[0];
5483 if (nid) {
Takashi Iwai863b4512008-10-21 17:01:47 +02005484 err = alc260_add_playback_controls(spec, nid, "Front", &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01005485 if (err < 0)
5486 return err;
5487 }
5488
Takashi Iwai82bc9552006-03-21 11:24:42 +01005489 nid = cfg->speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01005490 if (nid) {
Takashi Iwai863b4512008-10-21 17:01:47 +02005491 err = alc260_add_playback_controls(spec, nid, "Speaker", &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01005492 if (err < 0)
5493 return err;
5494 }
5495
Takashi Iwaieb06ed82006-09-20 17:10:27 +02005496 nid = cfg->hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01005497 if (nid) {
Takashi Iwai863b4512008-10-21 17:01:47 +02005498 err = alc260_add_playback_controls(spec, nid, "Headphone",
5499 &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01005500 if (err < 0)
5501 return err;
5502 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005503 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01005504}
5505
5506/* create playback/capture controls for input pins */
5507static int alc260_auto_create_analog_input_ctls(struct alc_spec *spec,
5508 const struct auto_pin_cfg *cfg)
5509{
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02005510 struct hda_input_mux *imux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01005511 int i, err, idx;
5512
5513 for (i = 0; i < AUTO_PIN_LAST; i++) {
5514 if (cfg->input_pins[i] >= 0x12) {
5515 idx = cfg->input_pins[i] - 0x12;
Takashi Iwai4a471b72005-12-07 13:56:29 +01005516 err = new_analog_input(spec, cfg->input_pins[i],
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005517 auto_pin_cfg_labels[i], idx,
5518 0x07);
Kailang Yangdf694da2005-12-05 19:42:22 +01005519 if (err < 0)
5520 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005521 imux->items[imux->num_items].label =
5522 auto_pin_cfg_labels[i];
Kailang Yangdf694da2005-12-05 19:42:22 +01005523 imux->items[imux->num_items].index = idx;
5524 imux->num_items++;
5525 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005526 if (cfg->input_pins[i] >= 0x0f && cfg->input_pins[i] <= 0x10){
Kailang Yangdf694da2005-12-05 19:42:22 +01005527 idx = cfg->input_pins[i] - 0x09;
Takashi Iwai4a471b72005-12-07 13:56:29 +01005528 err = new_analog_input(spec, cfg->input_pins[i],
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005529 auto_pin_cfg_labels[i], idx,
5530 0x07);
Kailang Yangdf694da2005-12-05 19:42:22 +01005531 if (err < 0)
5532 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005533 imux->items[imux->num_items].label =
5534 auto_pin_cfg_labels[i];
Kailang Yangdf694da2005-12-05 19:42:22 +01005535 imux->items[imux->num_items].index = idx;
5536 imux->num_items++;
5537 }
5538 }
5539 return 0;
5540}
5541
5542static void alc260_auto_set_output_and_unmute(struct hda_codec *codec,
5543 hda_nid_t nid, int pin_type,
5544 int sel_idx)
5545{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005546 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01005547 /* need the manual connection? */
5548 if (nid >= 0x12) {
5549 int idx = nid - 0x12;
5550 snd_hda_codec_write(codec, idx + 0x0b, 0,
5551 AC_VERB_SET_CONNECT_SEL, sel_idx);
Kailang Yangdf694da2005-12-05 19:42:22 +01005552 }
5553}
5554
5555static void alc260_auto_init_multi_out(struct hda_codec *codec)
5556{
5557 struct alc_spec *spec = codec->spec;
5558 hda_nid_t nid;
5559
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005560 alc_subsystem_id(codec, 0x10, 0x15, 0x0f);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005561 nid = spec->autocfg.line_out_pins[0];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02005562 if (nid) {
5563 int pin_type = get_pin_type(spec->autocfg.line_out_type);
5564 alc260_auto_set_output_and_unmute(codec, nid, pin_type, 0);
5565 }
Kailang Yangea1fb292008-08-26 12:58:38 +02005566
Takashi Iwai82bc9552006-03-21 11:24:42 +01005567 nid = spec->autocfg.speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01005568 if (nid)
5569 alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
5570
Takashi Iwaieb06ed82006-09-20 17:10:27 +02005571 nid = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01005572 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02005573 alc260_auto_set_output_and_unmute(codec, nid, PIN_HP, 0);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005574}
Kailang Yangdf694da2005-12-05 19:42:22 +01005575
5576#define ALC260_PIN_CD_NID 0x16
5577static void alc260_auto_init_analog_input(struct hda_codec *codec)
5578{
5579 struct alc_spec *spec = codec->spec;
5580 int i;
5581
5582 for (i = 0; i < AUTO_PIN_LAST; i++) {
5583 hda_nid_t nid = spec->autocfg.input_pins[i];
5584 if (nid >= 0x12) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005585 snd_hda_codec_write(codec, nid, 0,
5586 AC_VERB_SET_PIN_WIDGET_CONTROL,
5587 i <= AUTO_PIN_FRONT_MIC ?
5588 PIN_VREF80 : PIN_IN);
Kailang Yangdf694da2005-12-05 19:42:22 +01005589 if (nid != ALC260_PIN_CD_NID)
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005590 snd_hda_codec_write(codec, nid, 0,
5591 AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangdf694da2005-12-05 19:42:22 +01005592 AMP_OUT_MUTE);
5593 }
5594 }
5595}
5596
5597/*
5598 * generic initialization of ADC, input mixers and output mixers
5599 */
5600static struct hda_verb alc260_volume_init_verbs[] = {
5601 /*
5602 * Unmute ADC0-1 and set the default input to mic-in
5603 */
5604 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
5605 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5606 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
5607 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +02005608
Kailang Yangdf694da2005-12-05 19:42:22 +01005609 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
5610 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005611 * Note: PASD motherboards uses the Line In 2 as the input for
5612 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01005613 */
5614 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02005615 /* mute analog inputs */
5616 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5617 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5618 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5619 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5620 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01005621
5622 /*
5623 * Set up output mixers (0x08 - 0x0a)
5624 */
5625 /* set vol=0 to output mixers */
5626 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5627 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5628 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5629 /* set up input amps for analog loopback */
5630 /* Amp Indices: DAC = 0, mixer = 1 */
5631 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5632 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5633 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5634 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5635 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5636 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +02005637
Kailang Yangdf694da2005-12-05 19:42:22 +01005638 { }
5639};
5640
5641static int alc260_parse_auto_config(struct hda_codec *codec)
5642{
5643 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01005644 int err;
5645 static hda_nid_t alc260_ignore[] = { 0x17, 0 };
5646
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005647 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
5648 alc260_ignore);
5649 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01005650 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005651 err = alc260_auto_create_multi_out_ctls(spec, &spec->autocfg);
5652 if (err < 0)
Takashi Iwai4a471b72005-12-07 13:56:29 +01005653 return err;
Takashi Iwai603c4012008-07-30 15:01:44 +02005654 if (!spec->kctls.list)
Kailang Yangdf694da2005-12-05 19:42:22 +01005655 return 0; /* can't find valid BIOS pin config */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005656 err = alc260_auto_create_analog_input_ctls(spec, &spec->autocfg);
5657 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01005658 return err;
5659
5660 spec->multiout.max_channels = 2;
5661
5662 if (spec->autocfg.dig_out_pin)
5663 spec->multiout.dig_out_nid = ALC260_DIGOUT_NID;
Takashi Iwai603c4012008-07-30 15:01:44 +02005664 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +01005665 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +01005666
Takashi Iwaid88897e2008-10-31 15:01:37 +01005667 add_verb(spec, alc260_volume_init_verbs);
Kailang Yangdf694da2005-12-05 19:42:22 +01005668
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005669 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02005670 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01005671
Takashi Iwaie044c392008-10-27 16:56:24 +01005672 store_pin_configs(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01005673 return 1;
5674}
5675
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005676/* additional initialization for auto-configuration model */
5677static void alc260_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01005678{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005679 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01005680 alc260_auto_init_multi_out(codec);
5681 alc260_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005682 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02005683 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01005684}
5685
Takashi Iwaicb53c622007-08-10 17:21:45 +02005686#ifdef CONFIG_SND_HDA_POWER_SAVE
5687static struct hda_amp_list alc260_loopbacks[] = {
5688 { 0x07, HDA_INPUT, 0 },
5689 { 0x07, HDA_INPUT, 1 },
5690 { 0x07, HDA_INPUT, 2 },
5691 { 0x07, HDA_INPUT, 3 },
5692 { 0x07, HDA_INPUT, 4 },
5693 { } /* end */
5694};
5695#endif
5696
Kailang Yangdf694da2005-12-05 19:42:22 +01005697/*
5698 * ALC260 configurations
5699 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005700static const char *alc260_models[ALC260_MODEL_LAST] = {
5701 [ALC260_BASIC] = "basic",
5702 [ALC260_HP] = "hp",
5703 [ALC260_HP_3013] = "hp-3013",
Takashi Iwai2922c9a2008-08-27 18:12:42 +02005704 [ALC260_HP_DC7600] = "hp-dc7600",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005705 [ALC260_FUJITSU_S702X] = "fujitsu",
5706 [ALC260_ACER] = "acer",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005707 [ALC260_WILL] = "will",
5708 [ALC260_REPLACER_672V] = "replacer",
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005709#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005710 [ALC260_TEST] = "test",
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005711#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005712 [ALC260_AUTO] = "auto",
5713};
5714
5715static struct snd_pci_quirk alc260_cfg_tbl[] = {
Jonathan Woithebd869482006-11-28 11:35:52 +01005716 SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005717 SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER),
Takashi Iwai9720b712007-03-13 21:46:23 +01005718 SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013),
Takashi Iwaia8a5d062007-03-15 15:10:28 +01005719 SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_HP_3013),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005720 SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013),
Jaroslav Kysela34ec8a02008-07-10 14:49:19 +02005721 SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP_3013),
Kailang Yang3f878302008-08-26 13:02:23 +02005722 SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_DC7600),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005723 SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013),
5724 SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP),
5725 SND_PCI_QUIRK(0x103c, 0x3015, "HP", ALC260_HP),
5726 SND_PCI_QUIRK(0x103c, 0x3016, "HP", ALC260_HP),
5727 SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_BASIC),
5728 SND_PCI_QUIRK(0x104d, 0x81cc, "Sony VAIO", ALC260_BASIC),
5729 SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC),
5730 SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X),
5731 SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005732 SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_REPLACER_672V),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01005733 SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_WILL),
Takashi Iwai16ded522005-06-10 19:58:24 +02005734 {}
5735};
5736
Kailang Yangdf694da2005-12-05 19:42:22 +01005737static struct alc_config_preset alc260_presets[] = {
5738 [ALC260_BASIC] = {
5739 .mixers = { alc260_base_output_mixer,
5740 alc260_input_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005741 alc260_pc_beep_mixer },
Kailang Yangdf694da2005-12-05 19:42:22 +01005742 .init_verbs = { alc260_init_verbs },
5743 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5744 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005745 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
Kailang Yangdf694da2005-12-05 19:42:22 +01005746 .adc_nids = alc260_adc_nids,
5747 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5748 .channel_mode = alc260_modes,
5749 .input_mux = &alc260_capture_source,
5750 },
5751 [ALC260_HP] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01005752 .mixers = { alc260_hp_output_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005753 alc260_input_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01005754 .init_verbs = { alc260_init_verbs,
5755 alc260_hp_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01005756 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5757 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005758 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
5759 .adc_nids = alc260_adc_nids_alt,
Kailang Yangdf694da2005-12-05 19:42:22 +01005760 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5761 .channel_mode = alc260_modes,
5762 .input_mux = &alc260_capture_source,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005763 .unsol_event = alc260_hp_unsol_event,
5764 .init_hook = alc260_hp_automute,
Kailang Yangdf694da2005-12-05 19:42:22 +01005765 },
Kailang Yang3f878302008-08-26 13:02:23 +02005766 [ALC260_HP_DC7600] = {
5767 .mixers = { alc260_hp_dc7600_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005768 alc260_input_mixer },
Kailang Yang3f878302008-08-26 13:02:23 +02005769 .init_verbs = { alc260_init_verbs,
5770 alc260_hp_dc7600_verbs },
5771 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5772 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005773 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
5774 .adc_nids = alc260_adc_nids_alt,
Kailang Yang3f878302008-08-26 13:02:23 +02005775 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5776 .channel_mode = alc260_modes,
5777 .input_mux = &alc260_capture_source,
5778 .unsol_event = alc260_hp_3012_unsol_event,
5779 .init_hook = alc260_hp_3012_automute,
5780 },
Kailang Yangdf694da2005-12-05 19:42:22 +01005781 [ALC260_HP_3013] = {
5782 .mixers = { alc260_hp_3013_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005783 alc260_input_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01005784 .init_verbs = { alc260_hp_3013_init_verbs,
5785 alc260_hp_3013_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01005786 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5787 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005788 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
5789 .adc_nids = alc260_adc_nids_alt,
Kailang Yangdf694da2005-12-05 19:42:22 +01005790 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5791 .channel_mode = alc260_modes,
5792 .input_mux = &alc260_capture_source,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005793 .unsol_event = alc260_hp_3013_unsol_event,
5794 .init_hook = alc260_hp_3013_automute,
Kailang Yangdf694da2005-12-05 19:42:22 +01005795 },
5796 [ALC260_FUJITSU_S702X] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005797 .mixers = { alc260_fujitsu_mixer },
Kailang Yangdf694da2005-12-05 19:42:22 +01005798 .init_verbs = { alc260_fujitsu_init_verbs },
5799 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5800 .dac_nids = alc260_dac_nids,
Jonathan Woithed57fdac2006-02-28 11:38:35 +01005801 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
5802 .adc_nids = alc260_dual_adc_nids,
Kailang Yangdf694da2005-12-05 19:42:22 +01005803 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5804 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005805 .num_mux_defs = ARRAY_SIZE(alc260_fujitsu_capture_sources),
5806 .input_mux = alc260_fujitsu_capture_sources,
Kailang Yangdf694da2005-12-05 19:42:22 +01005807 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005808 [ALC260_ACER] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005809 .mixers = { alc260_acer_mixer },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005810 .init_verbs = { alc260_acer_init_verbs },
5811 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5812 .dac_nids = alc260_dac_nids,
5813 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
5814 .adc_nids = alc260_dual_adc_nids,
5815 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5816 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005817 .num_mux_defs = ARRAY_SIZE(alc260_acer_capture_sources),
5818 .input_mux = alc260_acer_capture_sources,
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005819 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005820 [ALC260_WILL] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005821 .mixers = { alc260_will_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005822 .init_verbs = { alc260_init_verbs, alc260_will_verbs },
5823 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5824 .dac_nids = alc260_dac_nids,
5825 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
5826 .adc_nids = alc260_adc_nids,
5827 .dig_out_nid = ALC260_DIGOUT_NID,
5828 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5829 .channel_mode = alc260_modes,
5830 .input_mux = &alc260_capture_source,
5831 },
5832 [ALC260_REPLACER_672V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005833 .mixers = { alc260_replacer_672v_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005834 .init_verbs = { alc260_init_verbs, alc260_replacer_672v_verbs },
5835 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5836 .dac_nids = alc260_dac_nids,
5837 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
5838 .adc_nids = alc260_adc_nids,
5839 .dig_out_nid = ALC260_DIGOUT_NID,
5840 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5841 .channel_mode = alc260_modes,
5842 .input_mux = &alc260_capture_source,
5843 .unsol_event = alc260_replacer_672v_unsol_event,
5844 .init_hook = alc260_replacer_672v_automute,
5845 },
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005846#ifdef CONFIG_SND_DEBUG
5847 [ALC260_TEST] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005848 .mixers = { alc260_test_mixer },
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005849 .init_verbs = { alc260_test_init_verbs },
5850 .num_dacs = ARRAY_SIZE(alc260_test_dac_nids),
5851 .dac_nids = alc260_test_dac_nids,
5852 .num_adc_nids = ARRAY_SIZE(alc260_test_adc_nids),
5853 .adc_nids = alc260_test_adc_nids,
5854 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5855 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005856 .num_mux_defs = ARRAY_SIZE(alc260_test_capture_sources),
5857 .input_mux = alc260_test_capture_sources,
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005858 },
5859#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01005860};
5861
Linus Torvalds1da177e2005-04-16 15:20:36 -07005862static int patch_alc260(struct hda_codec *codec)
5863{
5864 struct alc_spec *spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01005865 int err, board_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005866
Takashi Iwaie560d8d2005-09-09 14:21:46 +02005867 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005868 if (spec == NULL)
5869 return -ENOMEM;
5870
5871 codec->spec = spec;
5872
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005873 board_config = snd_hda_check_board_config(codec, ALC260_MODEL_LAST,
5874 alc260_models,
5875 alc260_cfg_tbl);
5876 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02005877 snd_printd(KERN_INFO "hda_codec: Unknown model for ALC260, "
5878 "trying auto-probe from BIOS...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01005879 board_config = ALC260_AUTO;
Takashi Iwai16ded522005-06-10 19:58:24 +02005880 }
5881
Kailang Yangdf694da2005-12-05 19:42:22 +01005882 if (board_config == ALC260_AUTO) {
5883 /* automatic parse from the BIOS config */
5884 err = alc260_parse_auto_config(codec);
5885 if (err < 0) {
5886 alc_free(codec);
5887 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005888 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02005889 printk(KERN_INFO
5890 "hda_codec: Cannot set up configuration "
5891 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01005892 board_config = ALC260_BASIC;
5893 }
Takashi Iwai16ded522005-06-10 19:58:24 +02005894 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005895
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09005896 err = snd_hda_attach_beep_device(codec, 0x1);
5897 if (err < 0) {
5898 alc_free(codec);
5899 return err;
5900 }
5901
Kailang Yangdf694da2005-12-05 19:42:22 +01005902 if (board_config != ALC260_AUTO)
5903 setup_preset(spec, &alc260_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005904
5905 spec->stream_name_analog = "ALC260 Analog";
5906 spec->stream_analog_playback = &alc260_pcm_analog_playback;
5907 spec->stream_analog_capture = &alc260_pcm_analog_capture;
5908
Takashi Iwaia3bcba32005-12-06 19:05:29 +01005909 spec->stream_name_digital = "ALC260 Digital";
5910 spec->stream_digital_playback = &alc260_pcm_digital_playback;
5911 spec->stream_digital_capture = &alc260_pcm_digital_capture;
5912
Takashi Iwai4ef0ef12008-11-03 17:47:49 +01005913 if (!spec->adc_nids && spec->input_mux) {
5914 /* check whether NID 0x04 is valid */
5915 unsigned int wcap = get_wcaps(codec, 0x04);
5916 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
5917 /* get type */
5918 if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
5919 spec->adc_nids = alc260_adc_nids_alt;
5920 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt);
5921 } else {
5922 spec->adc_nids = alc260_adc_nids;
5923 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids);
5924 }
5925 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005926 set_capture_mixer(spec);
5927
Takashi Iwai2134ea42008-01-10 16:53:55 +01005928 spec->vmaster_nid = 0x08;
5929
Linus Torvalds1da177e2005-04-16 15:20:36 -07005930 codec->patch_ops = alc_patch_ops;
Kailang Yangdf694da2005-12-05 19:42:22 +01005931 if (board_config == ALC260_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005932 spec->init_hook = alc260_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02005933#ifdef CONFIG_SND_HDA_POWER_SAVE
5934 if (!spec->loopback.amplist)
5935 spec->loopback.amplist = alc260_loopbacks;
5936#endif
Takashi Iwaidaead532008-11-28 12:55:36 +01005937 codec->proc_widget_hook = print_realtek_coef;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005938
5939 return 0;
5940}
5941
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005942
Linus Torvalds1da177e2005-04-16 15:20:36 -07005943/*
5944 * ALC882 support
5945 *
5946 * ALC882 is almost identical with ALC880 but has cleaner and more flexible
5947 * configuration. Each pin widget can choose any input DACs and a mixer.
5948 * Each ADC is connected from a mixer of all inputs. This makes possible
5949 * 6-channel independent captures.
5950 *
5951 * In addition, an independent DAC for the multi-playback (not used in this
5952 * driver yet).
5953 */
Kailang Yangdf694da2005-12-05 19:42:22 +01005954#define ALC882_DIGOUT_NID 0x06
5955#define ALC882_DIGIN_NID 0x0a
Linus Torvalds1da177e2005-04-16 15:20:36 -07005956
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01005957static struct hda_channel_mode alc882_ch_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005958 { 8, NULL }
5959};
5960
5961static hda_nid_t alc882_dac_nids[4] = {
5962 /* front, rear, clfe, rear_surr */
5963 0x02, 0x03, 0x04, 0x05
5964};
5965
Kailang Yangdf694da2005-12-05 19:42:22 +01005966/* identical with ALC880 */
5967#define alc882_adc_nids alc880_adc_nids
5968#define alc882_adc_nids_alt alc880_adc_nids_alt
Linus Torvalds1da177e2005-04-16 15:20:36 -07005969
Takashi Iwaie1406342008-02-11 18:32:32 +01005970static hda_nid_t alc882_capsrc_nids[3] = { 0x24, 0x23, 0x22 };
5971static hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 };
5972
Linus Torvalds1da177e2005-04-16 15:20:36 -07005973/* input MUX */
5974/* FIXME: should be a matrix-type input source selection */
5975
5976static struct hda_input_mux alc882_capture_source = {
5977 .num_items = 4,
5978 .items = {
5979 { "Mic", 0x0 },
5980 { "Front Mic", 0x1 },
5981 { "Line", 0x2 },
5982 { "CD", 0x4 },
5983 },
5984};
Kailang Yangdf694da2005-12-05 19:42:22 +01005985/*
Kailang Yang272a5272007-05-14 11:00:38 +02005986 * 2ch mode
5987 */
5988static struct hda_verb alc882_3ST_ch2_init[] = {
5989 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
5990 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
5991 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
5992 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
5993 { } /* end */
5994};
5995
5996/*
5997 * 6ch mode
5998 */
5999static struct hda_verb alc882_3ST_ch6_init[] = {
6000 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6001 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6002 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
6003 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6004 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6005 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6006 { } /* end */
6007};
6008
6009static struct hda_channel_mode alc882_3ST_6ch_modes[2] = {
6010 { 2, alc882_3ST_ch2_init },
6011 { 6, alc882_3ST_ch6_init },
6012};
6013
6014/*
Kailang Yangdf694da2005-12-05 19:42:22 +01006015 * 6ch mode
6016 */
6017static struct hda_verb alc882_sixstack_ch6_init[] = {
6018 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
6019 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6020 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6021 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6022 { } /* end */
6023};
6024
6025/*
6026 * 8ch mode
6027 */
6028static struct hda_verb alc882_sixstack_ch8_init[] = {
6029 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6030 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6031 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6032 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6033 { } /* end */
6034};
6035
6036static struct hda_channel_mode alc882_sixstack_modes[2] = {
6037 { 6, alc882_sixstack_ch6_init },
6038 { 8, alc882_sixstack_ch8_init },
6039};
6040
Takashi Iwai87350ad2007-08-16 18:19:38 +02006041/*
6042 * macbook pro ALC885 can switch LineIn to LineOut without loosing Mic
6043 */
6044
6045/*
6046 * 2ch mode
6047 */
6048static struct hda_verb alc885_mbp_ch2_init[] = {
6049 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
6050 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6051 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6052 { } /* end */
6053};
6054
6055/*
6056 * 6ch mode
6057 */
6058static struct hda_verb alc885_mbp_ch6_init[] = {
6059 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6060 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6061 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6062 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6063 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6064 { } /* end */
6065};
6066
6067static struct hda_channel_mode alc885_mbp_6ch_modes[2] = {
6068 { 2, alc885_mbp_ch2_init },
6069 { 6, alc885_mbp_ch6_init },
6070};
6071
6072
Linus Torvalds1da177e2005-04-16 15:20:36 -07006073/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
6074 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
6075 */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01006076static struct snd_kcontrol_new alc882_base_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02006077 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01006078 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02006079 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01006080 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02006081 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
6082 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01006083 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
6084 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02006085 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01006086 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07006087 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6088 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6089 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6090 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6091 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6092 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006093 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07006094 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6095 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006096 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07006097 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6098 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
6099 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07006100 { } /* end */
6101};
6102
Takashi Iwai87350ad2007-08-16 18:19:38 +02006103static struct snd_kcontrol_new alc885_mbp3_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01006104 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
6105 HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
6106 HDA_CODEC_MUTE ("Speaker Playback Switch", 0x14, 0x00, HDA_OUTPUT),
6107 HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
6108 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6109 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02006110 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
6111 HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01006112 HDA_CODEC_VOLUME("Line Boost", 0x1a, 0x00, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02006113 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT),
6114 { } /* end */
6115};
Kailang Yangbdd148a2007-05-08 15:19:08 +02006116static struct snd_kcontrol_new alc882_w2jc_mixer[] = {
6117 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6118 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6119 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6120 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6121 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6122 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6123 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6124 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
6125 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6126 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
6127 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
6128 { } /* end */
6129};
6130
Kailang Yang272a5272007-05-14 11:00:38 +02006131static struct snd_kcontrol_new alc882_targa_mixer[] = {
6132 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6133 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6134 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6135 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6136 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6137 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6138 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6139 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6140 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai96fe7cc2007-09-07 10:57:44 +02006141 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02006142 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
6143 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai96fe7cc2007-09-07 10:57:44 +02006144 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02006145 { } /* end */
6146};
6147
6148/* Pin assignment: Front=0x14, HP = 0x15, Front = 0x16, ???
6149 * Front Mic=0x18, Line In = 0x1a, Line In = 0x1b, CD = 0x1c
6150 */
6151static struct snd_kcontrol_new alc882_asus_a7j_mixer[] = {
6152 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6153 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
6154 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
6155 HDA_CODEC_MUTE("Mobile Front Playback Switch", 0x16, 0x0, HDA_OUTPUT),
6156 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6157 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6158 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6159 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6160 HDA_CODEC_VOLUME("Mobile Line Playback Volume", 0x0b, 0x03, HDA_INPUT),
6161 HDA_CODEC_MUTE("Mobile Line Playback Switch", 0x0b, 0x03, HDA_INPUT),
6162 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6163 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai96fe7cc2007-09-07 10:57:44 +02006164 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02006165 { } /* end */
6166};
6167
Takashi Iwai914759b2007-09-06 14:52:04 +02006168static struct snd_kcontrol_new alc882_asus_a7m_mixer[] = {
6169 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6170 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6171 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
6172 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6173 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6174 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6175 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6176 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6177 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
6178 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6179 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
6180 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
6181 { } /* end */
6182};
6183
Kailang Yangdf694da2005-12-05 19:42:22 +01006184static struct snd_kcontrol_new alc882_chmode_mixer[] = {
6185 {
6186 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6187 .name = "Channel Mode",
6188 .info = alc_ch_mode_info,
6189 .get = alc_ch_mode_get,
6190 .put = alc_ch_mode_put,
6191 },
6192 { } /* end */
6193};
6194
Linus Torvalds1da177e2005-04-16 15:20:36 -07006195static struct hda_verb alc882_init_verbs[] = {
6196 /* Front mixer: unmute input/output amp left and right (volume = 0) */
Takashi Iwai05acb862005-06-10 19:50:25 +02006197 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6198 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6199 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006200 /* Rear mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02006201 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6202 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6203 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006204 /* CLFE mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02006205 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6206 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6207 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006208 /* Side mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02006209 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6210 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6211 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006212
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006213 /* Front Pin: output 0 (0x0c) */
Takashi Iwai05acb862005-06-10 19:50:25 +02006214 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02006215 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006216 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006217 /* Rear Pin: output 1 (0x0d) */
Takashi Iwai05acb862005-06-10 19:50:25 +02006218 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02006219 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006220 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006221 /* CLFE Pin: output 2 (0x0e) */
Takashi Iwai05acb862005-06-10 19:50:25 +02006222 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02006223 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006224 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006225 /* Side Pin: output 3 (0x0f) */
Takashi Iwai05acb862005-06-10 19:50:25 +02006226 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02006227 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006228 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006229 /* Mic (rear) pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02006230 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006231 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6232 /* Front Mic pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02006233 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006234 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6235 /* Line In pin: input */
Takashi Iwai05acb862005-06-10 19:50:25 +02006236 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006237 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6238 /* Line-2 In: Headphone output (output 0 - 0x0c) */
6239 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6240 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6241 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006242 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02006243 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006244
6245 /* FIXME: use matrix-type input source selection */
6246 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
6247 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
Takashi Iwai05acb862005-06-10 19:50:25 +02006248 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6249 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6250 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6251 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006252 /* Input mixer2 */
Takashi Iwai05acb862005-06-10 19:50:25 +02006253 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6254 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6255 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6256 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006257 /* Input mixer3 */
Takashi Iwai05acb862005-06-10 19:50:25 +02006258 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6259 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6260 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6261 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6262 /* ADC1: mute amp left and right */
6263 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02006264 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02006265 /* ADC2: mute amp left and right */
6266 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02006267 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02006268 /* ADC3: mute amp left and right */
6269 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02006270 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006271
6272 { }
6273};
6274
Takashi Iwai4b146cb2006-07-28 14:42:36 +02006275static struct hda_verb alc882_eapd_verbs[] = {
6276 /* change to EAPD mode */
6277 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01006278 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006279 { }
Takashi Iwai4b146cb2006-07-28 14:42:36 +02006280};
6281
Tobin Davis9102cd12006-12-15 10:02:12 +01006282/* Mac Pro test */
6283static struct snd_kcontrol_new alc882_macpro_mixer[] = {
6284 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6285 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6286 HDA_CODEC_MUTE("Headphone Playback Switch", 0x18, 0x0, HDA_OUTPUT),
6287 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
6288 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
6289 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x02, HDA_INPUT),
6290 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x02, HDA_INPUT),
6291 { } /* end */
6292};
6293
6294static struct hda_verb alc882_macpro_init_verbs[] = {
6295 /* Front mixer: unmute input/output amp left and right (volume = 0) */
6296 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6297 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6298 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6299 /* Front Pin: output 0 (0x0c) */
6300 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6301 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6302 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
6303 /* Front Mic pin: input vref at 80% */
6304 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
6305 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6306 /* Speaker: output */
6307 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6308 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6309 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x04},
6310 /* Headphone output (output 0 - 0x0c) */
6311 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6312 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6313 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
6314
6315 /* FIXME: use matrix-type input source selection */
6316 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
6317 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
6318 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6319 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6320 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6321 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6322 /* Input mixer2 */
6323 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6324 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6325 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6326 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6327 /* Input mixer3 */
6328 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6329 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6330 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6331 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6332 /* ADC1: mute amp left and right */
6333 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6334 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
6335 /* ADC2: mute amp left and right */
6336 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6337 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
6338 /* ADC3: mute amp left and right */
6339 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6340 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
6341
6342 { }
6343};
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006344
Takashi Iwai87350ad2007-08-16 18:19:38 +02006345/* Macbook Pro rev3 */
6346static struct hda_verb alc885_mbp3_init_verbs[] = {
6347 /* Front mixer: unmute input/output amp left and right (volume = 0) */
6348 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6349 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6350 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6351 /* Rear mixer */
6352 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6353 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6354 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6355 /* Front Pin: output 0 (0x0c) */
6356 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6357 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6358 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
6359 /* HP Pin: output 0 (0x0d) */
6360 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
6361 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6362 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
6363 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
6364 /* Mic (rear) pin: input vref at 80% */
6365 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
6366 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6367 /* Front Mic pin: input vref at 80% */
6368 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
6369 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6370 /* Line In pin: use output 1 when in LineOut mode */
6371 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
6372 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6373 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
6374
6375 /* FIXME: use matrix-type input source selection */
6376 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
6377 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
6378 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6379 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6380 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6381 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6382 /* Input mixer2 */
6383 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6384 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6385 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6386 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6387 /* Input mixer3 */
6388 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6389 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6390 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6391 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6392 /* ADC1: mute amp left and right */
6393 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6394 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
6395 /* ADC2: mute amp left and right */
6396 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6397 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
6398 /* ADC3: mute amp left and right */
6399 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6400 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
6401
6402 { }
6403};
6404
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006405/* iMac 24 mixer. */
6406static struct snd_kcontrol_new alc885_imac24_mixer[] = {
6407 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
6408 HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x00, HDA_INPUT),
6409 { } /* end */
6410};
6411
6412/* iMac 24 init verbs. */
6413static struct hda_verb alc885_imac24_init_verbs[] = {
6414 /* Internal speakers: output 0 (0x0c) */
6415 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6416 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6417 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
6418 /* Internal speakers: output 0 (0x0c) */
6419 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6420 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6421 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
6422 /* Headphone: output 0 (0x0c) */
6423 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6424 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6425 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
6426 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
6427 /* Front Mic: input vref at 80% */
6428 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
6429 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6430 { }
6431};
6432
6433/* Toggle speaker-output according to the hp-jack state */
6434static void alc885_imac24_automute(struct hda_codec *codec)
6435{
6436 unsigned int present;
6437
6438 present = snd_hda_codec_read(codec, 0x14, 0,
6439 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02006440 snd_hda_codec_amp_stereo(codec, 0x18, HDA_OUTPUT, 0,
6441 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
6442 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0,
6443 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006444}
6445
6446/* Processes unsolicited events. */
6447static void alc885_imac24_unsol_event(struct hda_codec *codec,
6448 unsigned int res)
6449{
6450 /* Headphone insertion or removal. */
6451 if ((res >> 26) == ALC880_HP_EVENT)
6452 alc885_imac24_automute(codec);
6453}
6454
Takashi Iwai87350ad2007-08-16 18:19:38 +02006455static void alc885_mbp3_automute(struct hda_codec *codec)
6456{
6457 unsigned int present;
6458
6459 present = snd_hda_codec_read(codec, 0x15, 0,
6460 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
6461 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
6462 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
6463 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
6464 HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE);
6465
6466}
6467static void alc885_mbp3_unsol_event(struct hda_codec *codec,
6468 unsigned int res)
6469{
6470 /* Headphone insertion or removal. */
6471 if ((res >> 26) == ALC880_HP_EVENT)
6472 alc885_mbp3_automute(codec);
6473}
6474
6475
Kailang Yang272a5272007-05-14 11:00:38 +02006476static struct hda_verb alc882_targa_verbs[] = {
6477 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6478 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6479
6480 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6481 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02006482
Kailang Yang272a5272007-05-14 11:00:38 +02006483 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
6484 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
6485 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
6486
6487 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
6488 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
6489 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
6490 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
6491 { } /* end */
6492};
6493
6494/* toggle speaker-output according to the hp-jack state */
6495static void alc882_targa_automute(struct hda_codec *codec)
6496{
6497 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02006498
Kailang Yang272a5272007-05-14 11:00:38 +02006499 present = snd_hda_codec_read(codec, 0x14, 0,
6500 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02006501 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
6502 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02006503 snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
6504 present ? 1 : 3);
Kailang Yang272a5272007-05-14 11:00:38 +02006505}
6506
6507static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res)
6508{
6509 /* Looks like the unsol event is incompatible with the standard
6510 * definition. 4bit tag is placed at 26 bit!
6511 */
6512 if (((res >> 26) == ALC880_HP_EVENT)) {
6513 alc882_targa_automute(codec);
6514 }
6515}
6516
6517static struct hda_verb alc882_asus_a7j_verbs[] = {
6518 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6519 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6520
6521 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6522 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6523 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02006524
Kailang Yang272a5272007-05-14 11:00:38 +02006525 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
6526 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
6527 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
6528
6529 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
6530 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
6531 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
6532 { } /* end */
6533};
6534
Takashi Iwai914759b2007-09-06 14:52:04 +02006535static struct hda_verb alc882_asus_a7m_verbs[] = {
6536 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6537 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6538
6539 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6540 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6541 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02006542
Takashi Iwai914759b2007-09-06 14:52:04 +02006543 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
6544 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
6545 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
6546
6547 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
6548 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
6549 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
6550 { } /* end */
6551};
6552
Tobin Davis9102cd12006-12-15 10:02:12 +01006553static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted)
6554{
6555 unsigned int gpiostate, gpiomask, gpiodir;
6556
6557 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
6558 AC_VERB_GET_GPIO_DATA, 0);
6559
6560 if (!muted)
6561 gpiostate |= (1 << pin);
6562 else
6563 gpiostate &= ~(1 << pin);
6564
6565 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
6566 AC_VERB_GET_GPIO_MASK, 0);
6567 gpiomask |= (1 << pin);
6568
6569 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
6570 AC_VERB_GET_GPIO_DIRECTION, 0);
6571 gpiodir |= (1 << pin);
6572
6573
6574 snd_hda_codec_write(codec, codec->afg, 0,
6575 AC_VERB_SET_GPIO_MASK, gpiomask);
6576 snd_hda_codec_write(codec, codec->afg, 0,
6577 AC_VERB_SET_GPIO_DIRECTION, gpiodir);
6578
6579 msleep(1);
6580
6581 snd_hda_codec_write(codec, codec->afg, 0,
6582 AC_VERB_SET_GPIO_DATA, gpiostate);
6583}
6584
Takashi Iwai7debbe52007-08-16 15:01:03 +02006585/* set up GPIO at initialization */
6586static void alc885_macpro_init_hook(struct hda_codec *codec)
6587{
6588 alc882_gpio_mute(codec, 0, 0);
6589 alc882_gpio_mute(codec, 1, 0);
6590}
6591
6592/* set up GPIO and update auto-muting at initialization */
6593static void alc885_imac24_init_hook(struct hda_codec *codec)
6594{
6595 alc885_macpro_init_hook(codec);
6596 alc885_imac24_automute(codec);
6597}
6598
Kailang Yangdf694da2005-12-05 19:42:22 +01006599/*
6600 * generic initialization of ADC, input mixers and output mixers
6601 */
6602static struct hda_verb alc882_auto_init_verbs[] = {
6603 /*
6604 * Unmute ADC0-2 and set the default input to mic-in
6605 */
6606 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
6607 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6608 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
6609 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6610 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
6611 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6612
Takashi Iwaicb53c622007-08-10 17:21:45 +02006613 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +01006614 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006615 * Note: PASD motherboards uses the Line In 2 as the input for
6616 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01006617 */
6618 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02006619 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6620 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6621 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6622 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6623 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01006624
6625 /*
6626 * Set up output mixers (0x0c - 0x0f)
6627 */
6628 /* set vol=0 to output mixers */
6629 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6630 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6631 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6632 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6633 /* set up input amps for analog loopback */
6634 /* Amp Indices: DAC = 0, mixer = 1 */
6635 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6636 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6637 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6638 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6639 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6640 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6641 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6642 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6643 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6644 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6645
6646 /* FIXME: use matrix-type input source selection */
6647 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
6648 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
6649 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6650 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
6651 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
6652 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
6653 /* Input mixer2 */
6654 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6655 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
6656 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
6657 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
6658 /* Input mixer3 */
6659 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6660 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
6661 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
6662 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
6663
6664 { }
6665};
6666
Takashi Iwaicb53c622007-08-10 17:21:45 +02006667#ifdef CONFIG_SND_HDA_POWER_SAVE
6668#define alc882_loopbacks alc880_loopbacks
6669#endif
6670
Kailang Yangdf694da2005-12-05 19:42:22 +01006671/* pcm configuration: identiacal with ALC880 */
6672#define alc882_pcm_analog_playback alc880_pcm_analog_playback
6673#define alc882_pcm_analog_capture alc880_pcm_analog_capture
6674#define alc882_pcm_digital_playback alc880_pcm_digital_playback
6675#define alc882_pcm_digital_capture alc880_pcm_digital_capture
6676
6677/*
6678 * configuration and preset
6679 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006680static const char *alc882_models[ALC882_MODEL_LAST] = {
6681 [ALC882_3ST_DIG] = "3stack-dig",
6682 [ALC882_6ST_DIG] = "6stack-dig",
6683 [ALC882_ARIMA] = "arima",
Kailang Yangbdd148a2007-05-08 15:19:08 +02006684 [ALC882_W2JC] = "w2jc",
Takashi Iwai0438a002007-09-06 14:54:11 +02006685 [ALC882_TARGA] = "targa",
6686 [ALC882_ASUS_A7J] = "asus-a7j",
6687 [ALC882_ASUS_A7M] = "asus-a7m",
Tobin Davis9102cd12006-12-15 10:02:12 +01006688 [ALC885_MACPRO] = "macpro",
Takashi Iwai87350ad2007-08-16 18:19:38 +02006689 [ALC885_MBP3] = "mbp3",
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006690 [ALC885_IMAC24] = "imac24",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006691 [ALC882_AUTO] = "auto",
6692};
6693
6694static struct snd_pci_quirk alc882_cfg_tbl[] = {
6695 SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG),
Kailang Yang272a5272007-05-14 11:00:38 +02006696 SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J),
Kailang Yangac8842a2007-09-20 12:51:39 +02006697 SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J),
Takashi Iwai914759b2007-09-06 14:52:04 +02006698 SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01006699 SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC),
Claudio Matsuokac5d9f1c2007-07-19 23:18:32 +02006700 SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG),
Tobin Davis7b9470d2006-12-28 13:56:48 +01006701 SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01006702 SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG),
Jiang zhe44447042008-01-28 12:28:24 +01006703 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01006704 SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */
6705 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG),
6706 SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA),
Kailang Yangdf694da2005-12-05 19:42:22 +01006707 {}
6708};
6709
6710static struct alc_config_preset alc882_presets[] = {
6711 [ALC882_3ST_DIG] = {
6712 .mixers = { alc882_base_mixer },
6713 .init_verbs = { alc882_init_verbs },
6714 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6715 .dac_nids = alc882_dac_nids,
6716 .dig_out_nid = ALC882_DIGOUT_NID,
Kailang Yangdf694da2005-12-05 19:42:22 +01006717 .dig_in_nid = ALC882_DIGIN_NID,
6718 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
6719 .channel_mode = alc882_ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02006720 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01006721 .input_mux = &alc882_capture_source,
6722 },
6723 [ALC882_6ST_DIG] = {
6724 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
6725 .init_verbs = { alc882_init_verbs },
6726 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6727 .dac_nids = alc882_dac_nids,
6728 .dig_out_nid = ALC882_DIGOUT_NID,
Kailang Yangdf694da2005-12-05 19:42:22 +01006729 .dig_in_nid = ALC882_DIGIN_NID,
6730 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
6731 .channel_mode = alc882_sixstack_modes,
6732 .input_mux = &alc882_capture_source,
6733 },
Takashi Iwai4b146cb2006-07-28 14:42:36 +02006734 [ALC882_ARIMA] = {
6735 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
6736 .init_verbs = { alc882_init_verbs, alc882_eapd_verbs },
6737 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6738 .dac_nids = alc882_dac_nids,
6739 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
6740 .channel_mode = alc882_sixstack_modes,
6741 .input_mux = &alc882_capture_source,
6742 },
Kailang Yangbdd148a2007-05-08 15:19:08 +02006743 [ALC882_W2JC] = {
6744 .mixers = { alc882_w2jc_mixer, alc882_chmode_mixer },
6745 .init_verbs = { alc882_init_verbs, alc882_eapd_verbs,
6746 alc880_gpio1_init_verbs },
6747 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6748 .dac_nids = alc882_dac_nids,
6749 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
6750 .channel_mode = alc880_threestack_modes,
6751 .need_dac_fix = 1,
6752 .input_mux = &alc882_capture_source,
6753 .dig_out_nid = ALC882_DIGOUT_NID,
6754 },
Takashi Iwai87350ad2007-08-16 18:19:38 +02006755 [ALC885_MBP3] = {
6756 .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer },
6757 .init_verbs = { alc885_mbp3_init_verbs,
6758 alc880_gpio1_init_verbs },
6759 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6760 .dac_nids = alc882_dac_nids,
6761 .channel_mode = alc885_mbp_6ch_modes,
6762 .num_channel_mode = ARRAY_SIZE(alc885_mbp_6ch_modes),
6763 .input_mux = &alc882_capture_source,
6764 .dig_out_nid = ALC882_DIGOUT_NID,
6765 .dig_in_nid = ALC882_DIGIN_NID,
6766 .unsol_event = alc885_mbp3_unsol_event,
6767 .init_hook = alc885_mbp3_automute,
6768 },
Tobin Davis9102cd12006-12-15 10:02:12 +01006769 [ALC885_MACPRO] = {
6770 .mixers = { alc882_macpro_mixer },
6771 .init_verbs = { alc882_macpro_init_verbs },
6772 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6773 .dac_nids = alc882_dac_nids,
6774 .dig_out_nid = ALC882_DIGOUT_NID,
6775 .dig_in_nid = ALC882_DIGIN_NID,
6776 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
6777 .channel_mode = alc882_ch_modes,
6778 .input_mux = &alc882_capture_source,
Takashi Iwai7debbe52007-08-16 15:01:03 +02006779 .init_hook = alc885_macpro_init_hook,
Tobin Davis9102cd12006-12-15 10:02:12 +01006780 },
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006781 [ALC885_IMAC24] = {
6782 .mixers = { alc885_imac24_mixer },
6783 .init_verbs = { alc885_imac24_init_verbs },
6784 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6785 .dac_nids = alc882_dac_nids,
6786 .dig_out_nid = ALC882_DIGOUT_NID,
6787 .dig_in_nid = ALC882_DIGIN_NID,
6788 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
6789 .channel_mode = alc882_ch_modes,
6790 .input_mux = &alc882_capture_source,
6791 .unsol_event = alc885_imac24_unsol_event,
Takashi Iwai7debbe52007-08-16 15:01:03 +02006792 .init_hook = alc885_imac24_init_hook,
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006793 },
Kailang Yang272a5272007-05-14 11:00:38 +02006794 [ALC882_TARGA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006795 .mixers = { alc882_targa_mixer, alc882_chmode_mixer },
Kailang Yang272a5272007-05-14 11:00:38 +02006796 .init_verbs = { alc882_init_verbs, alc882_targa_verbs},
6797 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6798 .dac_nids = alc882_dac_nids,
6799 .dig_out_nid = ALC882_DIGOUT_NID,
6800 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
6801 .adc_nids = alc882_adc_nids,
Takashi Iwaie1406342008-02-11 18:32:32 +01006802 .capsrc_nids = alc882_capsrc_nids,
Kailang Yang272a5272007-05-14 11:00:38 +02006803 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
6804 .channel_mode = alc882_3ST_6ch_modes,
6805 .need_dac_fix = 1,
6806 .input_mux = &alc882_capture_source,
6807 .unsol_event = alc882_targa_unsol_event,
6808 .init_hook = alc882_targa_automute,
6809 },
6810 [ALC882_ASUS_A7J] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006811 .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer },
Kailang Yang272a5272007-05-14 11:00:38 +02006812 .init_verbs = { alc882_init_verbs, alc882_asus_a7j_verbs},
6813 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6814 .dac_nids = alc882_dac_nids,
6815 .dig_out_nid = ALC882_DIGOUT_NID,
6816 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
6817 .adc_nids = alc882_adc_nids,
Takashi Iwaie1406342008-02-11 18:32:32 +01006818 .capsrc_nids = alc882_capsrc_nids,
Kailang Yang272a5272007-05-14 11:00:38 +02006819 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
6820 .channel_mode = alc882_3ST_6ch_modes,
6821 .need_dac_fix = 1,
6822 .input_mux = &alc882_capture_source,
Kailang Yangea1fb292008-08-26 12:58:38 +02006823 },
Takashi Iwai914759b2007-09-06 14:52:04 +02006824 [ALC882_ASUS_A7M] = {
6825 .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer },
6826 .init_verbs = { alc882_init_verbs, alc882_eapd_verbs,
6827 alc880_gpio1_init_verbs,
6828 alc882_asus_a7m_verbs },
6829 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6830 .dac_nids = alc882_dac_nids,
6831 .dig_out_nid = ALC882_DIGOUT_NID,
6832 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
6833 .channel_mode = alc880_threestack_modes,
6834 .need_dac_fix = 1,
6835 .input_mux = &alc882_capture_source,
Kailang Yangea1fb292008-08-26 12:58:38 +02006836 },
Kailang Yangdf694da2005-12-05 19:42:22 +01006837};
6838
6839
6840/*
Takashi Iwaif95474e2007-07-10 00:47:43 +02006841 * Pin config fixes
6842 */
Kailang Yangea1fb292008-08-26 12:58:38 +02006843enum {
Takashi Iwaif95474e2007-07-10 00:47:43 +02006844 PINFIX_ABIT_AW9D_MAX
6845};
6846
6847static struct alc_pincfg alc882_abit_aw9d_pinfix[] = {
6848 { 0x15, 0x01080104 }, /* side */
6849 { 0x16, 0x01011012 }, /* rear */
6850 { 0x17, 0x01016011 }, /* clfe */
6851 { }
6852};
6853
6854static const struct alc_pincfg *alc882_pin_fixes[] = {
6855 [PINFIX_ABIT_AW9D_MAX] = alc882_abit_aw9d_pinfix,
6856};
6857
6858static struct snd_pci_quirk alc882_pinfix_tbl[] = {
6859 SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
6860 {}
6861};
6862
6863/*
Kailang Yangdf694da2005-12-05 19:42:22 +01006864 * BIOS auto configuration
6865 */
6866static void alc882_auto_set_output_and_unmute(struct hda_codec *codec,
6867 hda_nid_t nid, int pin_type,
6868 int dac_idx)
6869{
6870 /* set as output */
6871 struct alc_spec *spec = codec->spec;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006872 int idx;
6873
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006874 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01006875 if (spec->multiout.dac_nids[dac_idx] == 0x25)
6876 idx = 4;
6877 else
6878 idx = spec->multiout.dac_nids[dac_idx] - 2;
Kailang Yangdf694da2005-12-05 19:42:22 +01006879 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
6880
6881}
6882
6883static void alc882_auto_init_multi_out(struct hda_codec *codec)
6884{
6885 struct alc_spec *spec = codec->spec;
6886 int i;
6887
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006888 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Kailang Yangdf694da2005-12-05 19:42:22 +01006889 for (i = 0; i <= HDA_SIDE; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006890 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02006891 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01006892 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02006893 alc882_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006894 i);
Kailang Yangdf694da2005-12-05 19:42:22 +01006895 }
6896}
6897
6898static void alc882_auto_init_hp_out(struct hda_codec *codec)
6899{
6900 struct alc_spec *spec = codec->spec;
6901 hda_nid_t pin;
6902
Takashi Iwaieb06ed82006-09-20 17:10:27 +02006903 pin = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006904 if (pin) /* connect to front */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006905 /* use dac 0 */
6906 alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006907 pin = spec->autocfg.speaker_pins[0];
6908 if (pin)
6909 alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Kailang Yangdf694da2005-12-05 19:42:22 +01006910}
6911
6912#define alc882_is_input_pin(nid) alc880_is_input_pin(nid)
6913#define ALC882_PIN_CD_NID ALC880_PIN_CD_NID
6914
6915static void alc882_auto_init_analog_input(struct hda_codec *codec)
6916{
6917 struct alc_spec *spec = codec->spec;
6918 int i;
6919
6920 for (i = 0; i < AUTO_PIN_LAST; i++) {
6921 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwai7194cae2008-03-06 16:58:17 +01006922 unsigned int vref;
6923 if (!nid)
6924 continue;
6925 vref = PIN_IN;
6926 if (1 /*i <= AUTO_PIN_FRONT_MIC*/) {
Kailang Yang531240f2008-05-27 12:10:25 +02006927 unsigned int pincap;
6928 pincap = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
6929 if ((pincap >> AC_PINCAP_VREF_SHIFT) &
Takashi Iwai7194cae2008-03-06 16:58:17 +01006930 AC_PINCAP_VREF_80)
6931 vref = PIN_VREF80;
Kailang Yangdf694da2005-12-05 19:42:22 +01006932 }
Takashi Iwai7194cae2008-03-06 16:58:17 +01006933 snd_hda_codec_write(codec, nid, 0,
6934 AC_VERB_SET_PIN_WIDGET_CONTROL, vref);
6935 if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
6936 snd_hda_codec_write(codec, nid, 0,
6937 AC_VERB_SET_AMP_GAIN_MUTE,
6938 AMP_OUT_MUTE);
Kailang Yangdf694da2005-12-05 19:42:22 +01006939 }
6940}
6941
Takashi Iwaif511b012008-08-15 16:46:42 +02006942static void alc882_auto_init_input_src(struct hda_codec *codec)
6943{
6944 struct alc_spec *spec = codec->spec;
Takashi Iwaif511b012008-08-15 16:46:42 +02006945 int c;
6946
6947 for (c = 0; c < spec->num_adc_nids; c++) {
6948 hda_nid_t conn_list[HDA_MAX_NUM_INPUTS];
6949 hda_nid_t nid = spec->capsrc_nids[c];
Herton Ronaldo Krzesinskib98b7b32009-01-29 13:18:31 -02006950 unsigned int mux_idx;
6951 const struct hda_input_mux *imux;
Takashi Iwaif511b012008-08-15 16:46:42 +02006952 int conns, mute, idx, item;
6953
6954 conns = snd_hda_get_connections(codec, nid, conn_list,
6955 ARRAY_SIZE(conn_list));
6956 if (conns < 0)
6957 continue;
Herton Ronaldo Krzesinskib98b7b32009-01-29 13:18:31 -02006958 mux_idx = c >= spec->num_mux_defs ? 0 : c;
6959 imux = &spec->input_mux[mux_idx];
Takashi Iwaif511b012008-08-15 16:46:42 +02006960 for (idx = 0; idx < conns; idx++) {
6961 /* if the current connection is the selected one,
6962 * unmute it as default - otherwise mute it
6963 */
6964 mute = AMP_IN_MUTE(idx);
6965 for (item = 0; item < imux->num_items; item++) {
6966 if (imux->items[item].index == idx) {
6967 if (spec->cur_mux[c] == item)
6968 mute = AMP_IN_UNMUTE(idx);
6969 break;
6970 }
6971 }
Herton Ronaldo Krzesinskib98b7b32009-01-29 13:18:31 -02006972 /* check if we have a selector or mixer
6973 * we could check for the widget type instead, but
6974 * just check for Amp-In presence (in case of mixer
6975 * without amp-in there is something wrong, this
6976 * function shouldn't be used or capsrc nid is wrong)
6977 */
6978 if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)
6979 snd_hda_codec_write(codec, nid, 0,
6980 AC_VERB_SET_AMP_GAIN_MUTE,
6981 mute);
6982 else if (mute != AMP_IN_MUTE(idx))
6983 snd_hda_codec_write(codec, nid, 0,
6984 AC_VERB_SET_CONNECT_SEL,
6985 idx);
Takashi Iwaif511b012008-08-15 16:46:42 +02006986 }
6987 }
6988}
6989
Takashi Iwai776e1842007-08-29 15:07:11 +02006990/* add mic boosts if needed */
6991static int alc_auto_add_mic_boost(struct hda_codec *codec)
6992{
6993 struct alc_spec *spec = codec->spec;
6994 int err;
6995 hda_nid_t nid;
6996
6997 nid = spec->autocfg.input_pins[AUTO_PIN_MIC];
Takashi Iwaice22e032008-01-11 17:38:35 +01006998 if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
Takashi Iwai776e1842007-08-29 15:07:11 +02006999 err = add_control(spec, ALC_CTL_WIDGET_VOL,
7000 "Mic Boost",
7001 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
7002 if (err < 0)
7003 return err;
7004 }
7005 nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC];
Takashi Iwaice22e032008-01-11 17:38:35 +01007006 if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
Takashi Iwai776e1842007-08-29 15:07:11 +02007007 err = add_control(spec, ALC_CTL_WIDGET_VOL,
7008 "Front Mic Boost",
7009 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
7010 if (err < 0)
7011 return err;
7012 }
7013 return 0;
7014}
7015
Kailang Yangdf694da2005-12-05 19:42:22 +01007016/* almost identical with ALC880 parser... */
7017static int alc882_parse_auto_config(struct hda_codec *codec)
7018{
7019 struct alc_spec *spec = codec->spec;
7020 int err = alc880_parse_auto_config(codec);
7021
7022 if (err < 0)
7023 return err;
Takashi Iwai776e1842007-08-29 15:07:11 +02007024 else if (!err)
7025 return 0; /* no config found */
7026
7027 err = alc_auto_add_mic_boost(codec);
7028 if (err < 0)
7029 return err;
7030
7031 /* hack - override the init verbs */
7032 spec->init_verbs[0] = alc882_auto_init_verbs;
7033
7034 return 1; /* config found */
Kailang Yangdf694da2005-12-05 19:42:22 +01007035}
7036
Takashi Iwaiae6b8132006-03-03 16:47:17 +01007037/* additional initialization for auto-configuration model */
7038static void alc882_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01007039{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01007040 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01007041 alc882_auto_init_multi_out(codec);
7042 alc882_auto_init_hp_out(codec);
7043 alc882_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +02007044 alc882_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01007045 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02007046 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01007047}
7048
Takashi Iwai7943a8a2008-04-16 17:29:09 +02007049static int patch_alc883(struct hda_codec *codec); /* called in patch_alc882() */
7050
Linus Torvalds1da177e2005-04-16 15:20:36 -07007051static int patch_alc882(struct hda_codec *codec)
7052{
7053 struct alc_spec *spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01007054 int err, board_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007055
Takashi Iwaie560d8d2005-09-09 14:21:46 +02007056 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007057 if (spec == NULL)
7058 return -ENOMEM;
7059
Linus Torvalds1da177e2005-04-16 15:20:36 -07007060 codec->spec = spec;
7061
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007062 board_config = snd_hda_check_board_config(codec, ALC882_MODEL_LAST,
7063 alc882_models,
7064 alc882_cfg_tbl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007065
Kailang Yangdf694da2005-12-05 19:42:22 +01007066 if (board_config < 0 || board_config >= ALC882_MODEL_LAST) {
Tobin Davis081d17c2007-02-15 17:46:18 +01007067 /* Pick up systems that don't supply PCI SSID */
7068 switch (codec->subsystem_id) {
7069 case 0x106b0c00: /* Mac Pro */
7070 board_config = ALC885_MACPRO;
7071 break;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02007072 case 0x106b1000: /* iMac 24 */
Peter Korsgaardf3911c52008-09-27 09:13:45 +02007073 case 0x106b2800: /* AppleTV */
Mark Eggleston3077e442009-01-31 17:57:54 +01007074 case 0x106b3e00: /* iMac 24 Aluminium */
Nicola Fagnanic54728d2007-07-19 23:28:52 +02007075 board_config = ALC885_IMAC24;
7076 break;
Takashi Iwaic7e07572008-06-26 14:42:51 +02007077 case 0x106b00a1: /* Macbook (might be wrong - PCI SSID?) */
David Woodhouse9c95c432008-09-18 13:37:13 -07007078 case 0x106b00a4: /* MacbookPro4,1 */
Takashi Iwai87350ad2007-08-16 18:19:38 +02007079 case 0x106b2c00: /* Macbook Pro rev3 */
Takashi Iwaic7e07572008-06-26 14:42:51 +02007080 case 0x106b3600: /* Macbook 3.1 */
Luke Yelavich2a884642009-01-28 15:58:38 +11007081 case 0x106b3800: /* MacbookPro4,1 - latter revision */
Takashi Iwai87350ad2007-08-16 18:19:38 +02007082 board_config = ALC885_MBP3;
7083 break;
Tobin Davis081d17c2007-02-15 17:46:18 +01007084 default:
Takashi Iwai7943a8a2008-04-16 17:29:09 +02007085 /* ALC889A is handled better as ALC888-compatible */
Clive Messer669faba2008-09-30 15:49:13 +02007086 if (codec->revision_id == 0x100101 ||
7087 codec->revision_id == 0x100103) {
Takashi Iwai7943a8a2008-04-16 17:29:09 +02007088 alc_free(codec);
7089 return patch_alc883(codec);
7090 }
Tobin Davis081d17c2007-02-15 17:46:18 +01007091 printk(KERN_INFO "hda_codec: Unknown model for ALC882, "
7092 "trying auto-probe from BIOS...\n");
7093 board_config = ALC882_AUTO;
7094 }
Kailang Yangdf694da2005-12-05 19:42:22 +01007095 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007096
Takashi Iwaif95474e2007-07-10 00:47:43 +02007097 alc_fix_pincfg(codec, alc882_pinfix_tbl, alc882_pin_fixes);
7098
Kailang Yangdf694da2005-12-05 19:42:22 +01007099 if (board_config == ALC882_AUTO) {
7100 /* automatic parse from the BIOS config */
7101 err = alc882_parse_auto_config(codec);
7102 if (err < 0) {
7103 alc_free(codec);
7104 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007105 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007106 printk(KERN_INFO
7107 "hda_codec: Cannot set up configuration "
7108 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01007109 board_config = ALC882_3ST_DIG;
7110 }
7111 }
7112
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09007113 err = snd_hda_attach_beep_device(codec, 0x1);
7114 if (err < 0) {
7115 alc_free(codec);
7116 return err;
7117 }
7118
Kailang Yangdf694da2005-12-05 19:42:22 +01007119 if (board_config != ALC882_AUTO)
7120 setup_preset(spec, &alc882_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007121
Kailang Yang2f893282008-05-27 12:14:47 +02007122 if (codec->vendor_id == 0x10ec0885) {
7123 spec->stream_name_analog = "ALC885 Analog";
7124 spec->stream_name_digital = "ALC885 Digital";
7125 } else {
7126 spec->stream_name_analog = "ALC882 Analog";
7127 spec->stream_name_digital = "ALC882 Digital";
7128 }
7129
Kailang Yangdf694da2005-12-05 19:42:22 +01007130 spec->stream_analog_playback = &alc882_pcm_analog_playback;
7131 spec->stream_analog_capture = &alc882_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01007132 /* FIXME: setup DAC5 */
7133 /*spec->stream_analog_alt_playback = &alc880_pcm_analog_alt_playback;*/
7134 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007135
Kailang Yangdf694da2005-12-05 19:42:22 +01007136 spec->stream_digital_playback = &alc882_pcm_digital_playback;
7137 spec->stream_digital_capture = &alc882_pcm_digital_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007138
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02007139 spec->capture_style = CAPT_MIX; /* matrix-style capture */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007140 if (!spec->adc_nids && spec->input_mux) {
Kailang Yangdf694da2005-12-05 19:42:22 +01007141 /* check whether NID 0x07 is valid */
Takashi Iwai4a471b72005-12-07 13:56:29 +01007142 unsigned int wcap = get_wcaps(codec, 0x07);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007143 /* get type */
7144 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Kailang Yangdf694da2005-12-05 19:42:22 +01007145 if (wcap != AC_WID_AUD_IN) {
7146 spec->adc_nids = alc882_adc_nids_alt;
7147 spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids_alt);
Takashi Iwaie1406342008-02-11 18:32:32 +01007148 spec->capsrc_nids = alc882_capsrc_nids_alt;
Kailang Yangdf694da2005-12-05 19:42:22 +01007149 } else {
7150 spec->adc_nids = alc882_adc_nids;
7151 spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids);
Takashi Iwaie1406342008-02-11 18:32:32 +01007152 spec->capsrc_nids = alc882_capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +01007153 }
7154 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007155 set_capture_mixer(spec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007156
Takashi Iwai2134ea42008-01-10 16:53:55 +01007157 spec->vmaster_nid = 0x0c;
7158
Linus Torvalds1da177e2005-04-16 15:20:36 -07007159 codec->patch_ops = alc_patch_ops;
Kailang Yangdf694da2005-12-05 19:42:22 +01007160 if (board_config == ALC882_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01007161 spec->init_hook = alc882_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02007162#ifdef CONFIG_SND_HDA_POWER_SAVE
7163 if (!spec->loopback.amplist)
7164 spec->loopback.amplist = alc882_loopbacks;
7165#endif
Takashi Iwaidaead532008-11-28 12:55:36 +01007166 codec->proc_widget_hook = print_realtek_coef;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007167
7168 return 0;
7169}
7170
7171/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007172 * ALC883 support
7173 *
7174 * ALC883 is almost identical with ALC880 but has cleaner and more flexible
7175 * configuration. Each pin widget can choose any input DACs and a mixer.
7176 * Each ADC is connected from a mixer of all inputs. This makes possible
7177 * 6-channel independent captures.
7178 *
7179 * In addition, an independent DAC for the multi-playback (not used in this
7180 * driver yet).
7181 */
7182#define ALC883_DIGOUT_NID 0x06
7183#define ALC883_DIGIN_NID 0x0a
7184
Wu Fengguang3ab90932008-11-17 09:51:09 +01007185#define ALC1200_DIGOUT_NID 0x10
7186
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007187static hda_nid_t alc883_dac_nids[4] = {
7188 /* front, rear, clfe, rear_surr */
Herton Ronaldo Krzesinskif32a19e2008-03-18 09:27:08 +01007189 0x02, 0x03, 0x04, 0x05
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007190};
7191
7192static hda_nid_t alc883_adc_nids[2] = {
7193 /* ADC1-2 */
7194 0x08, 0x09,
7195};
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007196
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007197static hda_nid_t alc883_adc_nids_alt[1] = {
7198 /* ADC1 */
7199 0x08,
7200};
7201
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08007202static hda_nid_t alc883_adc_nids_rev[2] = {
7203 /* ADC2-1 */
7204 0x09, 0x08
7205};
7206
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02007207#define alc889_adc_nids alc880_adc_nids
7208
Takashi Iwaie1406342008-02-11 18:32:32 +01007209static hda_nid_t alc883_capsrc_nids[2] = { 0x23, 0x22 };
7210
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08007211static hda_nid_t alc883_capsrc_nids_rev[2] = { 0x22, 0x23 };
7212
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02007213#define alc889_capsrc_nids alc882_capsrc_nids
7214
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007215/* input MUX */
7216/* FIXME: should be a matrix-type input source selection */
7217
7218static struct hda_input_mux alc883_capture_source = {
7219 .num_items = 4,
7220 .items = {
7221 { "Mic", 0x0 },
7222 { "Front Mic", 0x1 },
7223 { "Line", 0x2 },
7224 { "CD", 0x4 },
7225 },
7226};
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007227
Jiang zhe17bba1b2008-06-04 12:11:07 +02007228static struct hda_input_mux alc883_3stack_6ch_intel = {
7229 .num_items = 4,
7230 .items = {
7231 { "Mic", 0x1 },
7232 { "Front Mic", 0x0 },
7233 { "Line", 0x2 },
7234 { "CD", 0x4 },
7235 },
7236};
7237
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007238static struct hda_input_mux alc883_lenovo_101e_capture_source = {
7239 .num_items = 2,
7240 .items = {
7241 { "Mic", 0x1 },
7242 { "Line", 0x2 },
7243 },
7244};
7245
Kailang Yang272a5272007-05-14 11:00:38 +02007246static struct hda_input_mux alc883_lenovo_nb0763_capture_source = {
7247 .num_items = 4,
7248 .items = {
7249 { "Mic", 0x0 },
7250 { "iMic", 0x1 },
7251 { "Line", 0x2 },
7252 { "CD", 0x4 },
7253 },
7254};
7255
Jiang zhefb97dc62008-03-06 11:07:11 +01007256static struct hda_input_mux alc883_fujitsu_pi2515_capture_source = {
7257 .num_items = 2,
7258 .items = {
7259 { "Mic", 0x0 },
7260 { "Int Mic", 0x1 },
7261 },
7262};
7263
Kailang Yange2757d52008-08-26 13:17:46 +02007264static struct hda_input_mux alc883_lenovo_sky_capture_source = {
7265 .num_items = 3,
7266 .items = {
7267 { "Mic", 0x0 },
7268 { "Front Mic", 0x1 },
7269 { "Line", 0x4 },
7270 },
7271};
7272
7273static struct hda_input_mux alc883_asus_eee1601_capture_source = {
7274 .num_items = 2,
7275 .items = {
7276 { "Mic", 0x0 },
7277 { "Line", 0x2 },
7278 },
7279};
7280
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007281/*
7282 * 2ch mode
7283 */
7284static struct hda_channel_mode alc883_3ST_2ch_modes[1] = {
7285 { 2, NULL }
7286};
7287
7288/*
7289 * 2ch mode
7290 */
7291static struct hda_verb alc883_3ST_ch2_init[] = {
7292 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7293 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7294 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7295 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7296 { } /* end */
7297};
7298
7299/*
Tobin Davisb2011312007-09-17 12:45:11 +02007300 * 4ch mode
7301 */
7302static struct hda_verb alc883_3ST_ch4_init[] = {
7303 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7304 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7305 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7306 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7307 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7308 { } /* end */
7309};
7310
7311/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007312 * 6ch mode
7313 */
7314static struct hda_verb alc883_3ST_ch6_init[] = {
7315 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7316 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7317 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7318 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7319 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7320 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7321 { } /* end */
7322};
7323
Tobin Davisb2011312007-09-17 12:45:11 +02007324static struct hda_channel_mode alc883_3ST_6ch_modes[3] = {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007325 { 2, alc883_3ST_ch2_init },
Tobin Davisb2011312007-09-17 12:45:11 +02007326 { 4, alc883_3ST_ch4_init },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007327 { 6, alc883_3ST_ch6_init },
7328};
7329
7330/*
Jiang zhe17bba1b2008-06-04 12:11:07 +02007331 * 2ch mode
7332 */
7333static struct hda_verb alc883_3ST_ch2_intel_init[] = {
7334 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7335 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7336 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7337 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7338 { } /* end */
7339};
7340
7341/*
7342 * 4ch mode
7343 */
7344static struct hda_verb alc883_3ST_ch4_intel_init[] = {
7345 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7346 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7347 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7348 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7349 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7350 { } /* end */
7351};
7352
7353/*
7354 * 6ch mode
7355 */
7356static struct hda_verb alc883_3ST_ch6_intel_init[] = {
7357 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7358 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7359 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x02 },
7360 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7361 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7362 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7363 { } /* end */
7364};
7365
7366static struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = {
7367 { 2, alc883_3ST_ch2_intel_init },
7368 { 4, alc883_3ST_ch4_intel_init },
7369 { 6, alc883_3ST_ch6_intel_init },
7370};
7371
7372/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007373 * 6ch mode
7374 */
7375static struct hda_verb alc883_sixstack_ch6_init[] = {
7376 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
7377 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7378 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7379 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7380 { } /* end */
7381};
7382
7383/*
7384 * 8ch mode
7385 */
7386static struct hda_verb alc883_sixstack_ch8_init[] = {
7387 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7388 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7389 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7390 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7391 { } /* end */
7392};
7393
7394static struct hda_channel_mode alc883_sixstack_modes[2] = {
7395 { 6, alc883_sixstack_ch6_init },
7396 { 8, alc883_sixstack_ch8_init },
7397};
7398
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01007399static struct hda_verb alc883_medion_eapd_verbs[] = {
7400 /* eanable EAPD on medion laptop */
7401 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
7402 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
7403 { }
7404};
7405
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007406/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
7407 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
7408 */
7409
7410static struct snd_kcontrol_new alc883_base_mixer[] = {
7411 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7412 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7413 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7414 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
7415 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7416 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
7417 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7418 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
7419 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
7420 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
7421 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7422 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7423 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7424 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7425 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7426 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007427 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007428 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7429 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007430 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007431 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
7432 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
7433 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007434 { } /* end */
7435};
7436
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01007437static struct snd_kcontrol_new alc883_mitac_mixer[] = {
7438 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7439 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7440 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7441 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
7442 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7443 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
7444 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
7445 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7446 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7447 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7448 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7449 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
7450 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01007451 { } /* end */
7452};
7453
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007454static struct snd_kcontrol_new alc883_clevo_m720_mixer[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01007455 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7456 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
7457 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7458 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
7459 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7460 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7461 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7462 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7463 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
7464 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Jiang zhe368c7a92008-03-04 11:20:33 +01007465 { } /* end */
7466};
7467
Jiang zhefb97dc62008-03-06 11:07:11 +01007468static struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = {
7469 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7470 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
7471 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7472 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
7473 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7474 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7475 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7476 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7477 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
7478 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Jiang zhefb97dc62008-03-06 11:07:11 +01007479 { } /* end */
7480};
7481
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007482static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = {
7483 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7484 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7485 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7486 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7487 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7488 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7489 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7490 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007491 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007492 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7493 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007494 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007495 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
7496 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
7497 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007498 { } /* end */
7499};
7500
7501static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
7502 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7503 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7504 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7505 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
7506 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7507 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
7508 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7509 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
7510 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7511 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7512 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7513 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7514 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7515 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007516 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007517 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7518 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007519 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007520 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
7521 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
7522 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007523 { } /* end */
7524};
7525
Jiang zhe17bba1b2008-06-04 12:11:07 +02007526static struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = {
7527 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7528 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7529 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7530 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
7531 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
7532 HDA_OUTPUT),
7533 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
7534 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7535 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
7536 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
7537 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7538 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7539 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7540 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7541 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7542 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
7543 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
7544 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7545 HDA_CODEC_VOLUME("Front Mic Boost", 0x18, 0, HDA_INPUT),
7546 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7547 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
7548 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Jiang zhe17bba1b2008-06-04 12:11:07 +02007549 { } /* end */
7550};
7551
Takashi Iwaid1d985f2006-11-23 19:27:12 +01007552static struct snd_kcontrol_new alc883_fivestack_mixer[] = {
Tobin Davisc07584c2006-10-13 12:32:16 +02007553 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02007554 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007555 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02007556 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007557 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7558 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02007559 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7560 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007561 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7562 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7563 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7564 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7565 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7566 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007567 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007568 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7569 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007570 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007571 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
7572 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
7573 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007574 { } /* end */
7575};
7576
Kailang Yangccc656c2006-10-17 12:32:26 +02007577static struct snd_kcontrol_new alc883_tagra_mixer[] = {
7578 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7579 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7580 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7581 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7582 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
7583 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7584 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
7585 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7586 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
7587 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7588 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7589 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7590 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7591 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007592 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02007593 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02007594 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007595};
Kailang Yangccc656c2006-10-17 12:32:26 +02007596
7597static struct snd_kcontrol_new alc883_tagra_2ch_mixer[] = {
7598 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7599 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7600 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7601 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7602 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7603 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007604 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02007605 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Jiang zhe4383fae2008-04-14 12:58:57 +02007606 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7607 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
7608 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02007609 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007610};
Kailang Yangccc656c2006-10-17 12:32:26 +02007611
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007612static struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = {
7613 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7614 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01007615 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7616 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007617 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7618 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7619 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7620 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007621 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007622};
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007623
Kailang Yang272a5272007-05-14 11:00:38 +02007624static struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = {
7625 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7626 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
7627 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7628 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7629 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7630 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7631 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7632 HDA_CODEC_VOLUME("iMic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7633 HDA_CODEC_MUTE("iMic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02007634 { } /* end */
7635};
7636
7637static struct snd_kcontrol_new alc883_medion_md2_mixer[] = {
7638 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7639 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7640 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
7641 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7642 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7643 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7644 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7645 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7646 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02007647 { } /* end */
Kailang Yangea1fb292008-08-26 12:58:38 +02007648};
Kailang Yang272a5272007-05-14 11:00:38 +02007649
Tobin Davis2880a862007-08-07 11:50:26 +02007650static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = {
Kailang Yangd1a991a2007-08-15 16:21:59 +02007651 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7652 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02007653 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02007654 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7655 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Kailang Yangd1a991a2007-08-15 16:21:59 +02007656 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7657 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7658 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02007659 { } /* end */
Kailang Yangd1a991a2007-08-15 16:21:59 +02007660};
Tobin Davis2880a862007-08-07 11:50:26 +02007661
Kailang Yange2757d52008-08-26 13:17:46 +02007662static struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = {
7663 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7664 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7665 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
7666 HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
7667 HDA_CODEC_VOLUME_MONO("Center Playback Volume",
7668 0x0d, 1, 0x0, HDA_OUTPUT),
7669 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
7670 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
7671 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
7672 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
7673 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
7674 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7675 HDA_CODEC_MUTE("iSpeaker Playback Switch", 0x1a, 0x0, HDA_OUTPUT),
7676 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7677 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7678 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7679 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7680 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7681 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7682 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7683 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7684 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
7685 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02007686 { } /* end */
7687};
7688
7689static struct hda_bind_ctls alc883_bind_cap_vol = {
7690 .ops = &snd_hda_bind_vol,
7691 .values = {
7692 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
7693 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
7694 0
7695 },
7696};
7697
7698static struct hda_bind_ctls alc883_bind_cap_switch = {
7699 .ops = &snd_hda_bind_sw,
7700 .values = {
7701 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
7702 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
7703 0
7704 },
7705};
7706
7707static struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = {
7708 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7709 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7710 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7711 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7712 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7713 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7714 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7715 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007716 { } /* end */
7717};
7718
7719static struct snd_kcontrol_new alc883_asus_eee1601_cap_mixer[] = {
Kailang Yange2757d52008-08-26 13:17:46 +02007720 HDA_BIND_VOL("Capture Volume", &alc883_bind_cap_vol),
7721 HDA_BIND_SW("Capture Switch", &alc883_bind_cap_switch),
7722 {
7723 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7724 /* .name = "Capture Source", */
7725 .name = "Input Source",
7726 .count = 1,
Takashi Iwai54cbc9a2008-10-31 15:24:04 +01007727 .info = alc_mux_enum_info,
7728 .get = alc_mux_enum_get,
7729 .put = alc_mux_enum_put,
Kailang Yange2757d52008-08-26 13:17:46 +02007730 },
7731 { } /* end */
7732};
7733
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007734static struct snd_kcontrol_new alc883_chmode_mixer[] = {
7735 {
7736 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7737 .name = "Channel Mode",
7738 .info = alc_ch_mode_info,
7739 .get = alc_ch_mode_get,
7740 .put = alc_ch_mode_put,
7741 },
7742 { } /* end */
7743};
7744
7745static struct hda_verb alc883_init_verbs[] = {
7746 /* ADC1: mute amp left and right */
Kailang Yange2757d52008-08-26 13:17:46 +02007747 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007748 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
7749 /* ADC2: mute amp left and right */
7750 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7751 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
7752 /* Front mixer: unmute input/output amp left and right (volume = 0) */
7753 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7754 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7755 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7756 /* Rear mixer */
7757 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7758 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7759 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7760 /* CLFE mixer */
7761 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7762 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7763 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7764 /* Side mixer */
7765 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7766 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7767 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7768
Takashi Iwaicb53c622007-08-10 17:21:45 +02007769 /* mute analog input loopbacks */
7770 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7771 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7772 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7773 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7774 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007775
7776 /* Front Pin: output 0 (0x0c) */
7777 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7778 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7779 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
7780 /* Rear Pin: output 1 (0x0d) */
7781 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7782 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7783 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
7784 /* CLFE Pin: output 2 (0x0e) */
7785 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7786 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7787 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
7788 /* Side Pin: output 3 (0x0f) */
7789 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7790 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7791 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
7792 /* Mic (rear) pin: input vref at 80% */
7793 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7794 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7795 /* Front Mic pin: input vref at 80% */
7796 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7797 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7798 /* Line In pin: input */
7799 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
7800 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7801 /* Line-2 In: Headphone output (output 0 - 0x0c) */
7802 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7803 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7804 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
7805 /* CD pin widget for input */
7806 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
7807
7808 /* FIXME: use matrix-type input source selection */
7809 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
7810 /* Input mixer2 */
7811 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yange2757d52008-08-26 13:17:46 +02007812 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7813 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7814 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007815 /* Input mixer3 */
7816 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yange2757d52008-08-26 13:17:46 +02007817 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7818 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7819 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007820 { }
7821};
7822
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01007823/* toggle speaker-output according to the hp-jack state */
7824static void alc883_mitac_hp_automute(struct hda_codec *codec)
7825{
7826 unsigned int present;
7827
7828 present = snd_hda_codec_read(codec, 0x15, 0,
7829 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7830 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7831 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7832 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
7833 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7834}
7835
7836/* auto-toggle front mic */
7837/*
7838static void alc883_mitac_mic_automute(struct hda_codec *codec)
7839{
7840 unsigned int present;
7841 unsigned char bits;
7842
7843 present = snd_hda_codec_read(codec, 0x18, 0,
7844 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7845 bits = present ? HDA_AMP_MUTE : 0;
7846 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
7847}
7848*/
7849
7850static void alc883_mitac_automute(struct hda_codec *codec)
7851{
7852 alc883_mitac_hp_automute(codec);
7853 /* alc883_mitac_mic_automute(codec); */
7854}
7855
7856static void alc883_mitac_unsol_event(struct hda_codec *codec,
7857 unsigned int res)
7858{
7859 switch (res >> 26) {
7860 case ALC880_HP_EVENT:
7861 alc883_mitac_hp_automute(codec);
7862 break;
7863 case ALC880_MIC_EVENT:
7864 /* alc883_mitac_mic_automute(codec); */
7865 break;
7866 }
7867}
7868
7869static struct hda_verb alc883_mitac_verbs[] = {
7870 /* HP */
7871 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7872 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7873 /* Subwoofer */
7874 {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
7875 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7876
7877 /* enable unsolicited event */
7878 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7879 /* {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, */
7880
7881 { } /* end */
7882};
7883
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007884static struct hda_verb alc883_clevo_m720_verbs[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01007885 /* HP */
7886 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7887 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7888 /* Int speaker */
7889 {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
7890 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7891
7892 /* enable unsolicited event */
7893 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007894 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Jiang zhe368c7a92008-03-04 11:20:33 +01007895
7896 { } /* end */
7897};
7898
Jiang zhefb97dc62008-03-06 11:07:11 +01007899static struct hda_verb alc883_2ch_fujitsu_pi2515_verbs[] = {
7900 /* HP */
7901 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
7902 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7903 /* Subwoofer */
7904 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
7905 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7906
7907 /* enable unsolicited event */
7908 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7909
7910 { } /* end */
7911};
7912
Kailang Yangccc656c2006-10-17 12:32:26 +02007913static struct hda_verb alc883_tagra_verbs[] = {
7914 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7915 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7916
7917 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7918 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02007919
Kailang Yangccc656c2006-10-17 12:32:26 +02007920 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
7921 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
7922 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
7923
7924 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007925 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
7926 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
7927 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
Kailang Yangccc656c2006-10-17 12:32:26 +02007928
7929 { } /* end */
7930};
7931
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007932static struct hda_verb alc883_lenovo_101e_verbs[] = {
7933 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7934 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT|AC_USRSP_EN},
7935 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT|AC_USRSP_EN},
7936 { } /* end */
7937};
7938
Kailang Yang272a5272007-05-14 11:00:38 +02007939static struct hda_verb alc883_lenovo_nb0763_verbs[] = {
7940 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7941 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7942 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7943 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7944 { } /* end */
7945};
7946
7947static struct hda_verb alc888_lenovo_ms7195_verbs[] = {
7948 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7949 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7950 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7951 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT | AC_USRSP_EN},
7952 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7953 { } /* end */
7954};
7955
Kailang Yang189609a2007-08-20 11:31:23 +02007956static struct hda_verb alc883_haier_w66_verbs[] = {
7957 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7958 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7959
7960 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7961
7962 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
7963 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7964 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7965 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7966 { } /* end */
7967};
7968
Kailang Yange2757d52008-08-26 13:17:46 +02007969static struct hda_verb alc888_lenovo_sky_verbs[] = {
7970 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7971 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7972 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7973 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7974 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7975 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7976 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
7977 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7978 { } /* end */
7979};
7980
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007981static struct hda_verb alc888_3st_hp_verbs[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007982 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */
Herton Ronaldo Krzesinskif32a19e2008-03-18 09:27:08 +01007983 {0x16, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Rear : output 1 (0x0d) */
7984 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* CLFE : output 2 (0x0e) */
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007985 { }
7986};
7987
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007988static struct hda_verb alc888_6st_dell_verbs[] = {
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007989 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7990 { }
7991};
7992
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007993static struct hda_verb alc888_3st_hp_2ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007994 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7995 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7996 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7997 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7998 { }
7999};
8000
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008001static struct hda_verb alc888_3st_hp_6ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008002 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8003 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
8004 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8005 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
8006 { }
8007};
8008
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008009static struct hda_channel_mode alc888_3st_hp_modes[2] = {
8010 { 2, alc888_3st_hp_2ch_init },
8011 { 6, alc888_3st_hp_6ch_init },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008012};
8013
Kailang Yang272a5272007-05-14 11:00:38 +02008014/* toggle front-jack and RCA according to the hp-jack state */
8015static void alc888_lenovo_ms7195_front_automute(struct hda_codec *codec)
8016{
8017 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02008018
Kailang Yang272a5272007-05-14 11:00:38 +02008019 present = snd_hda_codec_read(codec, 0x1b, 0,
8020 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02008021 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8022 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
8023 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8024 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02008025}
8026
8027/* toggle RCA according to the front-jack state */
8028static void alc888_lenovo_ms7195_rca_automute(struct hda_codec *codec)
8029{
8030 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02008031
Kailang Yang272a5272007-05-14 11:00:38 +02008032 present = snd_hda_codec_read(codec, 0x14, 0,
8033 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02008034 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8035 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02008036}
Takashi Iwai47fd8302007-08-10 17:11:07 +02008037
Kailang Yang272a5272007-05-14 11:00:38 +02008038static void alc883_lenovo_ms7195_unsol_event(struct hda_codec *codec,
8039 unsigned int res)
8040{
8041 if ((res >> 26) == ALC880_HP_EVENT)
8042 alc888_lenovo_ms7195_front_automute(codec);
8043 if ((res >> 26) == ALC880_FRONT_EVENT)
8044 alc888_lenovo_ms7195_rca_automute(codec);
8045}
8046
8047static struct hda_verb alc883_medion_md2_verbs[] = {
8048 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8049 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8050
8051 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8052
8053 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8054 { } /* end */
8055};
8056
8057/* toggle speaker-output according to the hp-jack state */
8058static void alc883_medion_md2_automute(struct hda_codec *codec)
8059{
8060 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02008061
Kailang Yang272a5272007-05-14 11:00:38 +02008062 present = snd_hda_codec_read(codec, 0x14, 0,
8063 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02008064 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8065 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02008066}
8067
8068static void alc883_medion_md2_unsol_event(struct hda_codec *codec,
8069 unsigned int res)
8070{
8071 if ((res >> 26) == ALC880_HP_EVENT)
8072 alc883_medion_md2_automute(codec);
8073}
8074
Kailang Yangccc656c2006-10-17 12:32:26 +02008075/* toggle speaker-output according to the hp-jack state */
8076static void alc883_tagra_automute(struct hda_codec *codec)
8077{
8078 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008079 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02008080
8081 present = snd_hda_codec_read(codec, 0x14, 0,
8082 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02008083 bits = present ? HDA_AMP_MUTE : 0;
8084 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
8085 HDA_AMP_MUTE, bits);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02008086 snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
8087 present ? 1 : 3);
Kailang Yangccc656c2006-10-17 12:32:26 +02008088}
8089
8090static void alc883_tagra_unsol_event(struct hda_codec *codec, unsigned int res)
8091{
8092 if ((res >> 26) == ALC880_HP_EVENT)
8093 alc883_tagra_automute(codec);
8094}
8095
Jiang zhe368c7a92008-03-04 11:20:33 +01008096/* toggle speaker-output according to the hp-jack state */
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008097static void alc883_clevo_m720_hp_automute(struct hda_codec *codec)
Jiang zhe368c7a92008-03-04 11:20:33 +01008098{
8099 unsigned int present;
8100 unsigned char bits;
8101
8102 present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0)
8103 & AC_PINSENSE_PRESENCE;
8104 bits = present ? HDA_AMP_MUTE : 0;
8105 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8106 HDA_AMP_MUTE, bits);
8107}
8108
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008109static void alc883_clevo_m720_mic_automute(struct hda_codec *codec)
8110{
8111 unsigned int present;
8112
8113 present = snd_hda_codec_read(codec, 0x18, 0,
8114 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
8115 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
8116 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
8117}
8118
8119static void alc883_clevo_m720_automute(struct hda_codec *codec)
8120{
8121 alc883_clevo_m720_hp_automute(codec);
8122 alc883_clevo_m720_mic_automute(codec);
8123}
8124
8125static void alc883_clevo_m720_unsol_event(struct hda_codec *codec,
Jiang zhe368c7a92008-03-04 11:20:33 +01008126 unsigned int res)
8127{
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008128 switch (res >> 26) {
8129 case ALC880_HP_EVENT:
8130 alc883_clevo_m720_hp_automute(codec);
8131 break;
8132 case ALC880_MIC_EVENT:
8133 alc883_clevo_m720_mic_automute(codec);
8134 break;
8135 }
Jiang zhe368c7a92008-03-04 11:20:33 +01008136}
8137
Jiang zhefb97dc62008-03-06 11:07:11 +01008138/* toggle speaker-output according to the hp-jack state */
8139static void alc883_2ch_fujitsu_pi2515_automute(struct hda_codec *codec)
8140{
8141 unsigned int present;
8142 unsigned char bits;
8143
8144 present = snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0)
8145 & AC_PINSENSE_PRESENCE;
8146 bits = present ? HDA_AMP_MUTE : 0;
8147 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8148 HDA_AMP_MUTE, bits);
8149}
8150
8151static void alc883_2ch_fujitsu_pi2515_unsol_event(struct hda_codec *codec,
8152 unsigned int res)
8153{
8154 if ((res >> 26) == ALC880_HP_EVENT)
8155 alc883_2ch_fujitsu_pi2515_automute(codec);
8156}
8157
Kailang Yang189609a2007-08-20 11:31:23 +02008158static void alc883_haier_w66_automute(struct hda_codec *codec)
8159{
8160 unsigned int present;
8161 unsigned char bits;
8162
8163 present = snd_hda_codec_read(codec, 0x1b, 0,
8164 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
8165 bits = present ? 0x80 : 0;
8166 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8167 0x80, bits);
8168}
8169
8170static void alc883_haier_w66_unsol_event(struct hda_codec *codec,
8171 unsigned int res)
8172{
8173 if ((res >> 26) == ALC880_HP_EVENT)
8174 alc883_haier_w66_automute(codec);
8175}
8176
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008177static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
8178{
8179 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008180 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008181
8182 present = snd_hda_codec_read(codec, 0x14, 0,
8183 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02008184 bits = present ? HDA_AMP_MUTE : 0;
8185 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8186 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008187}
8188
8189static void alc883_lenovo_101e_all_automute(struct hda_codec *codec)
8190{
8191 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008192 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008193
8194 present = snd_hda_codec_read(codec, 0x1b, 0,
8195 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02008196 bits = present ? HDA_AMP_MUTE : 0;
8197 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8198 HDA_AMP_MUTE, bits);
8199 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8200 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008201}
8202
8203static void alc883_lenovo_101e_unsol_event(struct hda_codec *codec,
8204 unsigned int res)
8205{
8206 if ((res >> 26) == ALC880_HP_EVENT)
8207 alc883_lenovo_101e_all_automute(codec);
8208 if ((res >> 26) == ALC880_FRONT_EVENT)
8209 alc883_lenovo_101e_ispeaker_automute(codec);
8210}
8211
Takashi Iwai676a9b52007-08-16 15:23:35 +02008212/* toggle speaker-output according to the hp-jack state */
8213static void alc883_acer_aspire_automute(struct hda_codec *codec)
8214{
8215 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02008216
Takashi Iwai676a9b52007-08-16 15:23:35 +02008217 present = snd_hda_codec_read(codec, 0x14, 0,
8218 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
8219 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8220 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
8221 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
8222 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
8223}
8224
8225static void alc883_acer_aspire_unsol_event(struct hda_codec *codec,
8226 unsigned int res)
8227{
8228 if ((res >> 26) == ALC880_HP_EVENT)
8229 alc883_acer_aspire_automute(codec);
8230}
8231
Kailang Yangd1a991a2007-08-15 16:21:59 +02008232static struct hda_verb alc883_acer_eapd_verbs[] = {
8233 /* HP Pin: output 0 (0x0c) */
8234 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8235 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8236 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8237 /* Front Pin: output 0 (0x0c) */
Takashi Iwai676a9b52007-08-16 15:23:35 +02008238 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8239 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangd1a991a2007-08-15 16:21:59 +02008240 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangd1a991a2007-08-15 16:21:59 +02008241 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
8242 /* eanable EAPD on medion laptop */
8243 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
8244 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
Takashi Iwai676a9b52007-08-16 15:23:35 +02008245 /* enable unsolicited event */
8246 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yangd1a991a2007-08-15 16:21:59 +02008247 { }
8248};
8249
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008250static void alc888_6st_dell_front_automute(struct hda_codec *codec)
8251{
8252 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02008253
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008254 present = snd_hda_codec_read(codec, 0x1b, 0,
8255 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
8256 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8257 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
8258 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8259 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
8260 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
8261 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
8262 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
8263 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
8264}
8265
8266static void alc888_6st_dell_unsol_event(struct hda_codec *codec,
8267 unsigned int res)
8268{
8269 switch (res >> 26) {
8270 case ALC880_HP_EVENT:
Takashi Iwai939778a2009-02-05 15:57:55 +01008271 /* printk(KERN_DEBUG "hp_event\n"); */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008272 alc888_6st_dell_front_automute(codec);
8273 break;
8274 }
8275}
8276
Kailang Yange2757d52008-08-26 13:17:46 +02008277static void alc888_lenovo_sky_front_automute(struct hda_codec *codec)
8278{
8279 unsigned int mute;
8280 unsigned int present;
8281
8282 snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
8283 present = snd_hda_codec_read(codec, 0x1b, 0,
8284 AC_VERB_GET_PIN_SENSE, 0);
8285 present = (present & 0x80000000) != 0;
8286 if (present) {
8287 /* mute internal speaker */
8288 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8289 HDA_AMP_MUTE, HDA_AMP_MUTE);
8290 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8291 HDA_AMP_MUTE, HDA_AMP_MUTE);
8292 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
8293 HDA_AMP_MUTE, HDA_AMP_MUTE);
8294 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
8295 HDA_AMP_MUTE, HDA_AMP_MUTE);
8296 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0,
8297 HDA_AMP_MUTE, HDA_AMP_MUTE);
8298 } else {
8299 /* unmute internal speaker if necessary */
8300 mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
8301 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8302 HDA_AMP_MUTE, mute);
8303 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8304 HDA_AMP_MUTE, mute);
8305 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
8306 HDA_AMP_MUTE, mute);
8307 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
8308 HDA_AMP_MUTE, mute);
8309 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0,
8310 HDA_AMP_MUTE, mute);
8311 }
8312}
8313
8314static void alc883_lenovo_sky_unsol_event(struct hda_codec *codec,
8315 unsigned int res)
8316{
8317 if ((res >> 26) == ALC880_HP_EVENT)
8318 alc888_lenovo_sky_front_automute(codec);
8319}
8320
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008321/*
8322 * generic initialization of ADC, input mixers and output mixers
8323 */
8324static struct hda_verb alc883_auto_init_verbs[] = {
8325 /*
8326 * Unmute ADC0-2 and set the default input to mic-in
8327 */
8328 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8329 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8330 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8331 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8332
Takashi Iwaicb53c622007-08-10 17:21:45 +02008333 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008334 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008335 * Note: PASD motherboards uses the Line In 2 as the input for
8336 * front panel mic (mic 2)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008337 */
8338 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02008339 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8340 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8341 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8342 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8343 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008344
8345 /*
8346 * Set up output mixers (0x0c - 0x0f)
8347 */
8348 /* set vol=0 to output mixers */
8349 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8350 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8351 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8352 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8353 /* set up input amps for analog loopback */
8354 /* Amp Indices: DAC = 0, mixer = 1 */
8355 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8356 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8357 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8358 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8359 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8360 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8361 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8362 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8363 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8364 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8365
8366 /* FIXME: use matrix-type input source selection */
8367 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
8368 /* Input mixer1 */
8369 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8370 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8371 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008372 /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, */
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008373 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
8374 /* Input mixer2 */
8375 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8376 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8377 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008378 /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, */
Andy Shevchenkoe3cde642007-12-03 16:50:58 +01008379 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008380
8381 { }
8382};
8383
Kailang Yange2757d52008-08-26 13:17:46 +02008384static struct hda_verb alc888_asus_m90v_verbs[] = {
8385 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8386 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8387 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8388 /* enable unsolicited event */
8389 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8390 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
8391 { } /* end */
8392};
8393
8394static void alc883_nb_mic_automute(struct hda_codec *codec)
8395{
8396 unsigned int present;
8397
8398 present = snd_hda_codec_read(codec, 0x18, 0,
8399 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
8400 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
8401 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
8402 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
8403 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
8404}
8405
8406static void alc883_M90V_speaker_automute(struct hda_codec *codec)
8407{
8408 unsigned int present;
8409 unsigned char bits;
8410
8411 present = snd_hda_codec_read(codec, 0x1b, 0,
8412 AC_VERB_GET_PIN_SENSE, 0)
8413 & AC_PINSENSE_PRESENCE;
8414 bits = present ? 0 : PIN_OUT;
8415 snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
8416 bits);
8417 snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
8418 bits);
8419 snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
8420 bits);
8421}
8422
8423static void alc883_mode2_unsol_event(struct hda_codec *codec,
8424 unsigned int res)
8425{
8426 switch (res >> 26) {
8427 case ALC880_HP_EVENT:
8428 alc883_M90V_speaker_automute(codec);
8429 break;
8430 case ALC880_MIC_EVENT:
8431 alc883_nb_mic_automute(codec);
8432 break;
8433 }
8434}
8435
8436static void alc883_mode2_inithook(struct hda_codec *codec)
8437{
8438 alc883_M90V_speaker_automute(codec);
8439 alc883_nb_mic_automute(codec);
8440}
8441
8442static struct hda_verb alc888_asus_eee1601_verbs[] = {
8443 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8444 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8445 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8446 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8447 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8448 {0x20, AC_VERB_SET_COEF_INDEX, 0x0b},
8449 {0x20, AC_VERB_SET_PROC_COEF, 0x0838},
8450 /* enable unsolicited event */
8451 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8452 { } /* end */
8453};
8454
8455static void alc883_eee1601_speaker_automute(struct hda_codec *codec)
8456{
8457 unsigned int present;
8458 unsigned char bits;
8459
8460 present = snd_hda_codec_read(codec, 0x14, 0,
8461 AC_VERB_GET_PIN_SENSE, 0)
8462 & AC_PINSENSE_PRESENCE;
8463 bits = present ? 0 : PIN_OUT;
8464 snd_hda_codec_write(codec, 0x1b, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
8465 bits);
8466}
8467
8468static void alc883_eee1601_unsol_event(struct hda_codec *codec,
8469 unsigned int res)
8470{
8471 switch (res >> 26) {
8472 case ALC880_HP_EVENT:
8473 alc883_eee1601_speaker_automute(codec);
8474 break;
8475 }
8476}
8477
8478static void alc883_eee1601_inithook(struct hda_codec *codec)
8479{
8480 alc883_eee1601_speaker_automute(codec);
8481}
8482
Takashi Iwaicb53c622007-08-10 17:21:45 +02008483#ifdef CONFIG_SND_HDA_POWER_SAVE
8484#define alc883_loopbacks alc880_loopbacks
8485#endif
8486
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008487/* pcm configuration: identiacal with ALC880 */
8488#define alc883_pcm_analog_playback alc880_pcm_analog_playback
8489#define alc883_pcm_analog_capture alc880_pcm_analog_capture
Takashi Iwai63300792008-01-24 15:31:36 +01008490#define alc883_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008491#define alc883_pcm_digital_playback alc880_pcm_digital_playback
8492#define alc883_pcm_digital_capture alc880_pcm_digital_capture
8493
8494/*
8495 * configuration and preset
8496 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008497static const char *alc883_models[ALC883_MODEL_LAST] = {
8498 [ALC883_3ST_2ch_DIG] = "3stack-dig",
8499 [ALC883_3ST_6ch_DIG] = "3stack-6ch-dig",
8500 [ALC883_3ST_6ch] = "3stack-6ch",
8501 [ALC883_6ST_DIG] = "6stack-dig",
8502 [ALC883_TARGA_DIG] = "targa-dig",
8503 [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008504 [ALC883_ACER] = "acer",
Tobin Davis2880a862007-08-07 11:50:26 +02008505 [ALC883_ACER_ASPIRE] = "acer-aspire",
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08008506 [ALC888_ACER_ASPIRE_4930G] = "acer-aspire-4930g",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008507 [ALC883_MEDION] = "medion",
Kailang Yang272a5272007-05-14 11:00:38 +02008508 [ALC883_MEDION_MD2] = "medion-md2",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008509 [ALC883_LAPTOP_EAPD] = "laptop-eapd",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008510 [ALC883_LENOVO_101E_2ch] = "lenovo-101e",
Kailang Yang272a5272007-05-14 11:00:38 +02008511 [ALC883_LENOVO_NB0763] = "lenovo-nb0763",
8512 [ALC888_LENOVO_MS7195_DIG] = "lenovo-ms7195-dig",
Kailang Yange2757d52008-08-26 13:17:46 +02008513 [ALC888_LENOVO_SKY] = "lenovo-sky",
Kailang Yang189609a2007-08-20 11:31:23 +02008514 [ALC883_HAIER_W66] = "haier-w66",
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008515 [ALC888_3ST_HP] = "3stack-hp",
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008516 [ALC888_6ST_DELL] = "6stack-dell",
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008517 [ALC883_MITAC] = "mitac",
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008518 [ALC883_CLEVO_M720] = "clevo-m720",
Jiang zhefb97dc62008-03-06 11:07:11 +01008519 [ALC883_FUJITSU_PI2515] = "fujitsu-pi2515",
Vincent Petryef8ef5f2008-11-23 11:31:41 +08008520 [ALC888_FUJITSU_XA3530] = "fujitsu-xa3530",
Jiang zhe17bba1b2008-06-04 12:11:07 +02008521 [ALC883_3ST_6ch_INTEL] = "3stack-6ch-intel",
Wu Fengguang3ab90932008-11-17 09:51:09 +01008522 [ALC1200_ASUS_P5Q] = "asus-p5q",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008523 [ALC883_AUTO] = "auto",
8524};
8525
8526static struct snd_pci_quirk alc883_cfg_tbl[] = {
8527 SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC883_3ST_6ch_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008528 SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE),
Takashi Iwai69e50282008-11-03 10:07:43 +01008529 SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_ACER_ASPIRE),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008530 SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE),
8531 SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE),
Jaroslav Kysela0b18cb12008-07-28 17:07:07 +02008532 SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_ACER_ASPIRE),
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08008533 SND_PCI_QUIRK(0x1025, 0x013e, "Acer Aspire 4930G",
8534 ALC888_ACER_ASPIRE_4930G),
Lukasz Wojnilowicza8e4f9d2009-01-08 12:00:49 +01008535 SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G",
8536 ALC888_ACER_ASPIRE_4930G),
8537 SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G",
8538 ALC888_ACER_ASPIRE_4930G),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008539 SND_PCI_QUIRK(0x1025, 0, "Acer laptop", ALC883_ACER), /* default Acer */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008540 SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL),
Tobin Davisfebe3372007-06-12 11:27:46 +02008541 SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008542 SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP),
8543 SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP),
Herton Ronaldo Krzesinski5d85f8d2008-03-20 12:13:46 +01008544 SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG),
Chris Bagwell06bf3e12009-01-01 10:32:08 +01008545 SND_PCI_QUIRK(0x103c, 0x2a66, "HP Acacia", ALC888_3ST_HP),
Kailang Yanga01c30c2008-10-15 11:14:58 +02008546 SND_PCI_QUIRK(0x1043, 0x1873, "Asus M90V", ALC888_ASUS_M90V),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008547 SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG),
Wu Fengguang3ab90932008-11-17 09:51:09 +01008548 SND_PCI_QUIRK(0x1043, 0x82fe, "Asus P5Q-EM HDMI", ALC1200_ASUS_P5Q),
Kailang Yange2757d52008-08-26 13:17:46 +02008549 SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_ASUS_EEE1601),
Travis Place97ec7102008-05-23 18:31:46 +02008550 SND_PCI_QUIRK(0x105b, 0x0ce8, "Foxconn P35AX-S", ALC883_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008551 SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC883_6ST_DIG),
Luke Yelavich2de686d2009-01-16 15:08:02 +11008552 SND_PCI_QUIRK(0x1071, 0x8227, "Mitac 82801H", ALC883_MITAC),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008553 SND_PCI_QUIRK(0x1071, 0x8253, "Mitac 8252d", ALC883_MITAC),
8554 SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD),
Kailang Yange2757d52008-08-26 13:17:46 +02008555 SND_PCI_QUIRK(0x10f1, 0x2350, "TYAN-S2350", ALC888_6ST_DELL),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008556 SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch),
Tobin Davis57b14f22007-04-18 23:05:36 +02008557 SND_PCI_QUIRK(0x1458, 0xa002, "MSI", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008558 SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG),
8559 SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG),
8560 SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG),
Jiang zhe4383fae2008-04-14 12:58:57 +02008561 SND_PCI_QUIRK(0x1462, 0x2fb3, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008562 SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG),
Pascal Terjan82808232008-03-04 11:33:28 +01008563 SND_PCI_QUIRK(0x1462, 0x3783, "NEC S970", ALC883_TARGA_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008564 SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG),
8565 SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG),
8566 SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG),
8567 SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG),
8568 SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG),
8569 SND_PCI_QUIRK(0x1462, 0x3fdf, "MSI", ALC883_TARGA_DIG),
8570 SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG),
8571 SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG),
8572 SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008573 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG),
8574 SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG),
Tobin Davis799f88a2007-05-29 14:29:08 +02008575 SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG),
Takashi Iwaiee095432008-11-25 15:03:38 +01008576 SND_PCI_QUIRK(0x1462, 0x7260, "MSI 7260", ALC883_TARGA_DIG),
Herton Ronaldo Krzesinski86d34b72008-03-18 09:27:59 +01008577 SND_PCI_QUIRK(0x1462, 0x7267, "MSI", ALC883_3ST_6ch_DIG),
Leonard Norrgard2a296cb2007-01-08 11:28:22 +01008578 SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG),
Tobin Davis2dcd5222007-07-10 17:04:57 +02008579 SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008580 SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008581 SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG),
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008582 SND_PCI_QUIRK(0x1558, 0x0721, "Clevo laptop M720R", ALC883_CLEVO_M720),
8583 SND_PCI_QUIRK(0x1558, 0x0722, "Clevo laptop M720SR", ALC883_CLEVO_M720),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008584 SND_PCI_QUIRK(0x1558, 0, "Clevo laptop", ALC883_LAPTOP_EAPD),
Daniel T Chene60623b2007-05-29 03:41:55 -04008585 SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008586 SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION),
Takashi Iwaif67d8172009-02-04 23:30:19 +01008587 SND_PCI_QUIRK(0x1734, 0x1107, "FSC AMILO Xi2550",
8588 ALC883_FUJITSU_PI2515),
Jiang zhefb97dc62008-03-06 11:07:11 +01008589 SND_PCI_QUIRK(0x1734, 0x1108, "Fujitsu AMILO Pi2515", ALC883_FUJITSU_PI2515),
Vincent Petryef8ef5f2008-11-23 11:31:41 +08008590 SND_PCI_QUIRK(0x1734, 0x113d, "Fujitsu AMILO Xa3530",
8591 ALC888_FUJITSU_XA3530),
Kailang Yang272a5272007-05-14 11:00:38 +02008592 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch),
Kailang Yang272a5272007-05-14 11:00:38 +02008593 SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008594 SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763),
8595 SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Kailang Yange2757d52008-08-26 13:17:46 +02008596 SND_PCI_QUIRK(0x17aa, 0x101d, "Lenovo Sky", ALC888_LENOVO_SKY),
Kailang Yang272a5272007-05-14 11:00:38 +02008597 SND_PCI_QUIRK(0x17c0, 0x4071, "MEDION MD2", ALC883_MEDION_MD2),
Takashi Iwai959973b2008-11-05 11:30:56 +01008598 SND_PCI_QUIRK(0x17c0, 0x4085, "MEDION MD96630", ALC888_LENOVO_MS7195_DIG),
Andrew Paprocki0b167bf2008-02-03 10:15:44 +01008599 SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG),
Kailang Yang189609a2007-08-20 11:31:23 +02008600 SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66),
Jiang zhe17bba1b2008-06-04 12:11:07 +02008601 SND_PCI_QUIRK(0x8086, 0x0001, "DG33BUC", ALC883_3ST_6ch_INTEL),
8602 SND_PCI_QUIRK(0x8086, 0x0002, "DG33FBC", ALC883_3ST_6ch_INTEL),
Luke Yelavich2de686d2009-01-16 15:08:02 +11008603 SND_PCI_QUIRK(0x8086, 0x2503, "82801H", ALC883_MITAC),
Wu Fengguang4b558992009-01-12 09:18:58 +08008604 SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC883_3ST_6ch_INTEL),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008605 SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008606 {}
8607};
8608
Wu Fengguangb25c9da2009-02-06 15:02:27 +08008609static hda_nid_t alc1200_slave_dig_outs[] = {
8610 ALC883_DIGOUT_NID, 0,
8611};
8612
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008613static struct alc_config_preset alc883_presets[] = {
8614 [ALC883_3ST_2ch_DIG] = {
8615 .mixers = { alc883_3ST_2ch_mixer },
8616 .init_verbs = { alc883_init_verbs },
8617 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8618 .dac_nids = alc883_dac_nids,
8619 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008620 .dig_in_nid = ALC883_DIGIN_NID,
8621 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8622 .channel_mode = alc883_3ST_2ch_modes,
8623 .input_mux = &alc883_capture_source,
8624 },
8625 [ALC883_3ST_6ch_DIG] = {
8626 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
8627 .init_verbs = { alc883_init_verbs },
8628 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8629 .dac_nids = alc883_dac_nids,
8630 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008631 .dig_in_nid = ALC883_DIGIN_NID,
8632 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
8633 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02008634 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008635 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008636 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008637 [ALC883_3ST_6ch] = {
8638 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
8639 .init_verbs = { alc883_init_verbs },
8640 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8641 .dac_nids = alc883_dac_nids,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008642 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
8643 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02008644 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008645 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008646 },
Jiang zhe17bba1b2008-06-04 12:11:07 +02008647 [ALC883_3ST_6ch_INTEL] = {
8648 .mixers = { alc883_3ST_6ch_intel_mixer, alc883_chmode_mixer },
8649 .init_verbs = { alc883_init_verbs },
8650 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8651 .dac_nids = alc883_dac_nids,
8652 .dig_out_nid = ALC883_DIGOUT_NID,
8653 .dig_in_nid = ALC883_DIGIN_NID,
8654 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_intel_modes),
8655 .channel_mode = alc883_3ST_6ch_intel_modes,
8656 .need_dac_fix = 1,
8657 .input_mux = &alc883_3stack_6ch_intel,
8658 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008659 [ALC883_6ST_DIG] = {
8660 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
8661 .init_verbs = { alc883_init_verbs },
8662 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8663 .dac_nids = alc883_dac_nids,
8664 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008665 .dig_in_nid = ALC883_DIGIN_NID,
8666 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
8667 .channel_mode = alc883_sixstack_modes,
8668 .input_mux = &alc883_capture_source,
8669 },
Kailang Yangccc656c2006-10-17 12:32:26 +02008670 [ALC883_TARGA_DIG] = {
8671 .mixers = { alc883_tagra_mixer, alc883_chmode_mixer },
8672 .init_verbs = { alc883_init_verbs, alc883_tagra_verbs},
8673 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8674 .dac_nids = alc883_dac_nids,
8675 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +02008676 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
8677 .channel_mode = alc883_3ST_6ch_modes,
8678 .need_dac_fix = 1,
8679 .input_mux = &alc883_capture_source,
8680 .unsol_event = alc883_tagra_unsol_event,
8681 .init_hook = alc883_tagra_automute,
8682 },
8683 [ALC883_TARGA_2ch_DIG] = {
8684 .mixers = { alc883_tagra_2ch_mixer},
8685 .init_verbs = { alc883_init_verbs, alc883_tagra_verbs},
8686 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8687 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01008688 .adc_nids = alc883_adc_nids_alt,
8689 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Kailang Yangccc656c2006-10-17 12:32:26 +02008690 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +02008691 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8692 .channel_mode = alc883_3ST_2ch_modes,
8693 .input_mux = &alc883_capture_source,
8694 .unsol_event = alc883_tagra_unsol_event,
8695 .init_hook = alc883_tagra_automute,
8696 },
Vladimir Avdoninbab282b2006-08-22 13:31:58 +02008697 [ALC883_ACER] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02008698 .mixers = { alc883_base_mixer },
Vladimir Avdoninbab282b2006-08-22 13:31:58 +02008699 /* On TravelMate laptops, GPIO 0 enables the internal speaker
8700 * and the headphone jack. Turn this on and rely on the
8701 * standard mute methods whenever the user wants to turn
8702 * these outputs off.
8703 */
8704 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs },
8705 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8706 .dac_nids = alc883_dac_nids,
Vladimir Avdoninbab282b2006-08-22 13:31:58 +02008707 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8708 .channel_mode = alc883_3ST_2ch_modes,
8709 .input_mux = &alc883_capture_source,
8710 },
Tobin Davis2880a862007-08-07 11:50:26 +02008711 [ALC883_ACER_ASPIRE] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02008712 .mixers = { alc883_acer_aspire_mixer },
Kailang Yangd1a991a2007-08-15 16:21:59 +02008713 .init_verbs = { alc883_init_verbs, alc883_acer_eapd_verbs },
Tobin Davis2880a862007-08-07 11:50:26 +02008714 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8715 .dac_nids = alc883_dac_nids,
8716 .dig_out_nid = ALC883_DIGOUT_NID,
Tobin Davis2880a862007-08-07 11:50:26 +02008717 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8718 .channel_mode = alc883_3ST_2ch_modes,
8719 .input_mux = &alc883_capture_source,
Takashi Iwai676a9b52007-08-16 15:23:35 +02008720 .unsol_event = alc883_acer_aspire_unsol_event,
8721 .init_hook = alc883_acer_aspire_automute,
Kailang Yangd1a991a2007-08-15 16:21:59 +02008722 },
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08008723 [ALC888_ACER_ASPIRE_4930G] = {
Vincent Petryef8ef5f2008-11-23 11:31:41 +08008724 .mixers = { alc888_base_mixer,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08008725 alc883_chmode_mixer },
8726 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
8727 alc888_acer_aspire_4930g_verbs },
8728 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8729 .dac_nids = alc883_dac_nids,
8730 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
8731 .adc_nids = alc883_adc_nids_rev,
8732 .capsrc_nids = alc883_capsrc_nids_rev,
8733 .dig_out_nid = ALC883_DIGOUT_NID,
8734 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
8735 .channel_mode = alc883_3ST_6ch_modes,
8736 .need_dac_fix = 1,
8737 .num_mux_defs =
Vincent Petryef8ef5f2008-11-23 11:31:41 +08008738 ARRAY_SIZE(alc888_2_capture_sources),
8739 .input_mux = alc888_2_capture_sources,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08008740 .unsol_event = alc888_acer_aspire_4930g_unsol_event,
8741 .init_hook = alc888_acer_aspire_4930g_automute,
8742 },
Tobin Davisc07584c2006-10-13 12:32:16 +02008743 [ALC883_MEDION] = {
8744 .mixers = { alc883_fivestack_mixer,
8745 alc883_chmode_mixer },
8746 .init_verbs = { alc883_init_verbs,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008747 alc883_medion_eapd_verbs },
Tobin Davisc07584c2006-10-13 12:32:16 +02008748 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8749 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01008750 .adc_nids = alc883_adc_nids_alt,
8751 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Tobin Davisc07584c2006-10-13 12:32:16 +02008752 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
8753 .channel_mode = alc883_sixstack_modes,
8754 .input_mux = &alc883_capture_source,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008755 },
Kailang Yang272a5272007-05-14 11:00:38 +02008756 [ALC883_MEDION_MD2] = {
8757 .mixers = { alc883_medion_md2_mixer},
8758 .init_verbs = { alc883_init_verbs, alc883_medion_md2_verbs},
8759 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8760 .dac_nids = alc883_dac_nids,
8761 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang272a5272007-05-14 11:00:38 +02008762 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8763 .channel_mode = alc883_3ST_2ch_modes,
8764 .input_mux = &alc883_capture_source,
8765 .unsol_event = alc883_medion_md2_unsol_event,
8766 .init_hook = alc883_medion_md2_automute,
Kailang Yangea1fb292008-08-26 12:58:38 +02008767 },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008768 [ALC883_LAPTOP_EAPD] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02008769 .mixers = { alc883_base_mixer },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008770 .init_verbs = { alc883_init_verbs, alc882_eapd_verbs },
8771 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8772 .dac_nids = alc883_dac_nids,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008773 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8774 .channel_mode = alc883_3ST_2ch_modes,
8775 .input_mux = &alc883_capture_source,
8776 },
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008777 [ALC883_CLEVO_M720] = {
8778 .mixers = { alc883_clevo_m720_mixer },
8779 .init_verbs = { alc883_init_verbs, alc883_clevo_m720_verbs },
Jiang zhe368c7a92008-03-04 11:20:33 +01008780 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8781 .dac_nids = alc883_dac_nids,
8782 .dig_out_nid = ALC883_DIGOUT_NID,
8783 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8784 .channel_mode = alc883_3ST_2ch_modes,
8785 .input_mux = &alc883_capture_source,
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008786 .unsol_event = alc883_clevo_m720_unsol_event,
8787 .init_hook = alc883_clevo_m720_automute,
Jiang zhe368c7a92008-03-04 11:20:33 +01008788 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008789 [ALC883_LENOVO_101E_2ch] = {
8790 .mixers = { alc883_lenovo_101e_2ch_mixer},
8791 .init_verbs = { alc883_init_verbs, alc883_lenovo_101e_verbs},
8792 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8793 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01008794 .adc_nids = alc883_adc_nids_alt,
8795 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008796 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8797 .channel_mode = alc883_3ST_2ch_modes,
8798 .input_mux = &alc883_lenovo_101e_capture_source,
8799 .unsol_event = alc883_lenovo_101e_unsol_event,
8800 .init_hook = alc883_lenovo_101e_all_automute,
8801 },
Kailang Yang272a5272007-05-14 11:00:38 +02008802 [ALC883_LENOVO_NB0763] = {
8803 .mixers = { alc883_lenovo_nb0763_mixer },
8804 .init_verbs = { alc883_init_verbs, alc883_lenovo_nb0763_verbs},
8805 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8806 .dac_nids = alc883_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +02008807 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8808 .channel_mode = alc883_3ST_2ch_modes,
8809 .need_dac_fix = 1,
8810 .input_mux = &alc883_lenovo_nb0763_capture_source,
8811 .unsol_event = alc883_medion_md2_unsol_event,
8812 .init_hook = alc883_medion_md2_automute,
8813 },
8814 [ALC888_LENOVO_MS7195_DIG] = {
8815 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
8816 .init_verbs = { alc883_init_verbs, alc888_lenovo_ms7195_verbs},
8817 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8818 .dac_nids = alc883_dac_nids,
8819 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang272a5272007-05-14 11:00:38 +02008820 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
8821 .channel_mode = alc883_3ST_6ch_modes,
8822 .need_dac_fix = 1,
8823 .input_mux = &alc883_capture_source,
8824 .unsol_event = alc883_lenovo_ms7195_unsol_event,
8825 .init_hook = alc888_lenovo_ms7195_front_automute,
Kailang Yang189609a2007-08-20 11:31:23 +02008826 },
8827 [ALC883_HAIER_W66] = {
8828 .mixers = { alc883_tagra_2ch_mixer},
8829 .init_verbs = { alc883_init_verbs, alc883_haier_w66_verbs},
8830 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8831 .dac_nids = alc883_dac_nids,
8832 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang189609a2007-08-20 11:31:23 +02008833 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8834 .channel_mode = alc883_3ST_2ch_modes,
8835 .input_mux = &alc883_capture_source,
8836 .unsol_event = alc883_haier_w66_unsol_event,
8837 .init_hook = alc883_haier_w66_automute,
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +01008838 },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008839 [ALC888_3ST_HP] = {
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +01008840 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008841 .init_verbs = { alc883_init_verbs, alc888_3st_hp_verbs },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008842 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8843 .dac_nids = alc883_dac_nids,
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008844 .num_channel_mode = ARRAY_SIZE(alc888_3st_hp_modes),
8845 .channel_mode = alc888_3st_hp_modes,
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008846 .need_dac_fix = 1,
8847 .input_mux = &alc883_capture_source,
8848 },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008849 [ALC888_6ST_DELL] = {
Herton Ronaldo Krzesinskif24dbdc2008-03-20 12:14:28 +01008850 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008851 .init_verbs = { alc883_init_verbs, alc888_6st_dell_verbs },
8852 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8853 .dac_nids = alc883_dac_nids,
8854 .dig_out_nid = ALC883_DIGOUT_NID,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008855 .dig_in_nid = ALC883_DIGIN_NID,
8856 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
8857 .channel_mode = alc883_sixstack_modes,
8858 .input_mux = &alc883_capture_source,
8859 .unsol_event = alc888_6st_dell_unsol_event,
8860 .init_hook = alc888_6st_dell_front_automute,
8861 },
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008862 [ALC883_MITAC] = {
8863 .mixers = { alc883_mitac_mixer },
8864 .init_verbs = { alc883_init_verbs, alc883_mitac_verbs },
8865 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8866 .dac_nids = alc883_dac_nids,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008867 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8868 .channel_mode = alc883_3ST_2ch_modes,
8869 .input_mux = &alc883_capture_source,
8870 .unsol_event = alc883_mitac_unsol_event,
8871 .init_hook = alc883_mitac_automute,
8872 },
Jiang zhefb97dc62008-03-06 11:07:11 +01008873 [ALC883_FUJITSU_PI2515] = {
8874 .mixers = { alc883_2ch_fujitsu_pi2515_mixer },
8875 .init_verbs = { alc883_init_verbs,
8876 alc883_2ch_fujitsu_pi2515_verbs},
8877 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8878 .dac_nids = alc883_dac_nids,
8879 .dig_out_nid = ALC883_DIGOUT_NID,
8880 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8881 .channel_mode = alc883_3ST_2ch_modes,
8882 .input_mux = &alc883_fujitsu_pi2515_capture_source,
8883 .unsol_event = alc883_2ch_fujitsu_pi2515_unsol_event,
8884 .init_hook = alc883_2ch_fujitsu_pi2515_automute,
8885 },
Vincent Petryef8ef5f2008-11-23 11:31:41 +08008886 [ALC888_FUJITSU_XA3530] = {
8887 .mixers = { alc888_base_mixer, alc883_chmode_mixer },
8888 .init_verbs = { alc883_init_verbs,
8889 alc888_fujitsu_xa3530_verbs },
8890 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8891 .dac_nids = alc883_dac_nids,
8892 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
8893 .adc_nids = alc883_adc_nids_rev,
8894 .capsrc_nids = alc883_capsrc_nids_rev,
8895 .dig_out_nid = ALC883_DIGOUT_NID,
8896 .num_channel_mode = ARRAY_SIZE(alc888_4ST_8ch_intel_modes),
8897 .channel_mode = alc888_4ST_8ch_intel_modes,
8898 .num_mux_defs =
8899 ARRAY_SIZE(alc888_2_capture_sources),
8900 .input_mux = alc888_2_capture_sources,
8901 .unsol_event = alc888_fujitsu_xa3530_unsol_event,
8902 .init_hook = alc888_fujitsu_xa3530_automute,
8903 },
Kailang Yange2757d52008-08-26 13:17:46 +02008904 [ALC888_LENOVO_SKY] = {
8905 .mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer },
8906 .init_verbs = { alc883_init_verbs, alc888_lenovo_sky_verbs},
8907 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8908 .dac_nids = alc883_dac_nids,
8909 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yange2757d52008-08-26 13:17:46 +02008910 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
8911 .channel_mode = alc883_sixstack_modes,
8912 .need_dac_fix = 1,
8913 .input_mux = &alc883_lenovo_sky_capture_source,
8914 .unsol_event = alc883_lenovo_sky_unsol_event,
8915 .init_hook = alc888_lenovo_sky_front_automute,
8916 },
8917 [ALC888_ASUS_M90V] = {
8918 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
8919 .init_verbs = { alc883_init_verbs, alc888_asus_m90v_verbs },
8920 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8921 .dac_nids = alc883_dac_nids,
8922 .dig_out_nid = ALC883_DIGOUT_NID,
8923 .dig_in_nid = ALC883_DIGIN_NID,
8924 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
8925 .channel_mode = alc883_3ST_6ch_modes,
8926 .need_dac_fix = 1,
8927 .input_mux = &alc883_fujitsu_pi2515_capture_source,
8928 .unsol_event = alc883_mode2_unsol_event,
8929 .init_hook = alc883_mode2_inithook,
8930 },
8931 [ALC888_ASUS_EEE1601] = {
8932 .mixers = { alc883_asus_eee1601_mixer },
Takashi Iwaif9e336f2008-10-31 16:37:07 +01008933 .cap_mixer = alc883_asus_eee1601_cap_mixer,
Kailang Yange2757d52008-08-26 13:17:46 +02008934 .init_verbs = { alc883_init_verbs, alc888_asus_eee1601_verbs },
8935 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8936 .dac_nids = alc883_dac_nids,
8937 .dig_out_nid = ALC883_DIGOUT_NID,
8938 .dig_in_nid = ALC883_DIGIN_NID,
8939 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8940 .channel_mode = alc883_3ST_2ch_modes,
8941 .need_dac_fix = 1,
8942 .input_mux = &alc883_asus_eee1601_capture_source,
8943 .unsol_event = alc883_eee1601_unsol_event,
8944 .init_hook = alc883_eee1601_inithook,
8945 },
Wu Fengguang3ab90932008-11-17 09:51:09 +01008946 [ALC1200_ASUS_P5Q] = {
8947 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
8948 .init_verbs = { alc883_init_verbs },
8949 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8950 .dac_nids = alc883_dac_nids,
8951 .dig_out_nid = ALC1200_DIGOUT_NID,
8952 .dig_in_nid = ALC883_DIGIN_NID,
Wu Fengguangb25c9da2009-02-06 15:02:27 +08008953 .slave_dig_outs = alc1200_slave_dig_outs,
Wu Fengguang3ab90932008-11-17 09:51:09 +01008954 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
8955 .channel_mode = alc883_sixstack_modes,
8956 .input_mux = &alc883_capture_source,
8957 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008958};
8959
8960
8961/*
8962 * BIOS auto configuration
8963 */
8964static void alc883_auto_set_output_and_unmute(struct hda_codec *codec,
8965 hda_nid_t nid, int pin_type,
8966 int dac_idx)
8967{
8968 /* set as output */
8969 struct alc_spec *spec = codec->spec;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008970 int idx;
8971
Takashi Iwaif6c7e542008-02-12 18:32:23 +01008972 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008973 if (spec->multiout.dac_nids[dac_idx] == 0x25)
8974 idx = 4;
8975 else
8976 idx = spec->multiout.dac_nids[dac_idx] - 2;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008977 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
8978
8979}
8980
8981static void alc883_auto_init_multi_out(struct hda_codec *codec)
8982{
8983 struct alc_spec *spec = codec->spec;
8984 int i;
8985
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008986 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008987 for (i = 0; i <= HDA_SIDE; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008988 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02008989 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008990 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02008991 alc883_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008992 i);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008993 }
8994}
8995
8996static void alc883_auto_init_hp_out(struct hda_codec *codec)
8997{
8998 struct alc_spec *spec = codec->spec;
8999 hda_nid_t pin;
9000
Takashi Iwaieb06ed82006-09-20 17:10:27 +02009001 pin = spec->autocfg.hp_pins[0];
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009002 if (pin) /* connect to front */
9003 /* use dac 0 */
9004 alc883_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01009005 pin = spec->autocfg.speaker_pins[0];
9006 if (pin)
9007 alc883_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009008}
9009
9010#define alc883_is_input_pin(nid) alc880_is_input_pin(nid)
9011#define ALC883_PIN_CD_NID ALC880_PIN_CD_NID
9012
9013static void alc883_auto_init_analog_input(struct hda_codec *codec)
9014{
9015 struct alc_spec *spec = codec->spec;
9016 int i;
9017
9018 for (i = 0; i < AUTO_PIN_LAST; i++) {
9019 hda_nid_t nid = spec->autocfg.input_pins[i];
9020 if (alc883_is_input_pin(nid)) {
9021 snd_hda_codec_write(codec, nid, 0,
9022 AC_VERB_SET_PIN_WIDGET_CONTROL,
9023 (i <= AUTO_PIN_FRONT_MIC ?
9024 PIN_VREF80 : PIN_IN));
9025 if (nid != ALC883_PIN_CD_NID)
9026 snd_hda_codec_write(codec, nid, 0,
9027 AC_VERB_SET_AMP_GAIN_MUTE,
9028 AMP_OUT_MUTE);
9029 }
9030 }
9031}
9032
Takashi Iwaif511b012008-08-15 16:46:42 +02009033#define alc883_auto_init_input_src alc882_auto_init_input_src
9034
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009035/* almost identical with ALC880 parser... */
9036static int alc883_parse_auto_config(struct hda_codec *codec)
9037{
9038 struct alc_spec *spec = codec->spec;
9039 int err = alc880_parse_auto_config(codec);
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02009040 struct auto_pin_cfg *cfg = &spec->autocfg;
9041 int i;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009042
9043 if (err < 0)
9044 return err;
Takashi Iwai776e1842007-08-29 15:07:11 +02009045 else if (!err)
9046 return 0; /* no config found */
9047
9048 err = alc_auto_add_mic_boost(codec);
9049 if (err < 0)
9050 return err;
9051
9052 /* hack - override the init verbs */
9053 spec->init_verbs[0] = alc883_auto_init_verbs;
Takashi Iwai776e1842007-08-29 15:07:11 +02009054
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02009055 /* setup input_mux for ALC889 */
9056 if (codec->vendor_id == 0x10ec0889) {
9057 /* digital-mic input pin is excluded in alc880_auto_create..()
9058 * because it's under 0x18
9059 */
9060 if (cfg->input_pins[AUTO_PIN_MIC] == 0x12 ||
9061 cfg->input_pins[AUTO_PIN_FRONT_MIC] == 0x12) {
9062 struct hda_input_mux *imux = &spec->private_imux[0];
9063 for (i = 1; i < 3; i++)
9064 memcpy(&spec->private_imux[i],
9065 &spec->private_imux[0],
9066 sizeof(spec->private_imux[0]));
9067 imux->items[imux->num_items].label = "Int DMic";
9068 imux->items[imux->num_items].index = 0x0b;
9069 imux->num_items++;
9070 spec->num_mux_defs = 3;
9071 spec->input_mux = spec->private_imux;
9072 }
9073 }
9074
Takashi Iwai776e1842007-08-29 15:07:11 +02009075 return 1; /* config found */
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009076}
9077
9078/* additional initialization for auto-configuration model */
9079static void alc883_auto_init(struct hda_codec *codec)
9080{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01009081 struct alc_spec *spec = codec->spec;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009082 alc883_auto_init_multi_out(codec);
9083 alc883_auto_init_hp_out(codec);
9084 alc883_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +02009085 alc883_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01009086 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02009087 alc_inithook(codec);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009088}
9089
9090static int patch_alc883(struct hda_codec *codec)
9091{
9092 struct alc_spec *spec;
9093 int err, board_config;
9094
9095 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
9096 if (spec == NULL)
9097 return -ENOMEM;
9098
9099 codec->spec = spec;
9100
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02009101 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
9102
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009103 board_config = snd_hda_check_board_config(codec, ALC883_MODEL_LAST,
9104 alc883_models,
9105 alc883_cfg_tbl);
9106 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009107 printk(KERN_INFO "hda_codec: Unknown model for ALC883, "
9108 "trying auto-probe from BIOS...\n");
9109 board_config = ALC883_AUTO;
9110 }
9111
9112 if (board_config == ALC883_AUTO) {
9113 /* automatic parse from the BIOS config */
9114 err = alc883_parse_auto_config(codec);
9115 if (err < 0) {
9116 alc_free(codec);
9117 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009118 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009119 printk(KERN_INFO
9120 "hda_codec: Cannot set up configuration "
9121 "from BIOS. Using base mode...\n");
9122 board_config = ALC883_3ST_2ch_DIG;
9123 }
9124 }
9125
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09009126 err = snd_hda_attach_beep_device(codec, 0x1);
9127 if (err < 0) {
9128 alc_free(codec);
9129 return err;
9130 }
9131
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009132 if (board_config != ALC883_AUTO)
9133 setup_preset(spec, &alc883_presets[board_config]);
9134
Kailang Yang2f893282008-05-27 12:14:47 +02009135 switch (codec->vendor_id) {
9136 case 0x10ec0888:
Kailang Yang44426082008-10-15 11:18:05 +02009137 if (codec->revision_id == 0x100101) {
9138 spec->stream_name_analog = "ALC1200 Analog";
9139 spec->stream_name_digital = "ALC1200 Digital";
9140 } else {
9141 spec->stream_name_analog = "ALC888 Analog";
9142 spec->stream_name_digital = "ALC888 Digital";
9143 }
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02009144 if (!spec->num_adc_nids) {
9145 spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids);
9146 spec->adc_nids = alc883_adc_nids;
9147 }
9148 if (!spec->capsrc_nids)
9149 spec->capsrc_nids = alc883_capsrc_nids;
9150 spec->capture_style = CAPT_MIX; /* matrix-style capture */
Kailang Yang2f893282008-05-27 12:14:47 +02009151 break;
9152 case 0x10ec0889:
9153 spec->stream_name_analog = "ALC889 Analog";
9154 spec->stream_name_digital = "ALC889 Digital";
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02009155 if (!spec->num_adc_nids) {
9156 spec->num_adc_nids = ARRAY_SIZE(alc889_adc_nids);
9157 spec->adc_nids = alc889_adc_nids;
9158 }
9159 if (!spec->capsrc_nids)
9160 spec->capsrc_nids = alc889_capsrc_nids;
9161 spec->capture_style = CAPT_1MUX_MIX; /* 1mux/Nmix-style
9162 capture */
Kailang Yang2f893282008-05-27 12:14:47 +02009163 break;
9164 default:
9165 spec->stream_name_analog = "ALC883 Analog";
9166 spec->stream_name_digital = "ALC883 Digital";
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02009167 if (!spec->num_adc_nids) {
9168 spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids);
9169 spec->adc_nids = alc883_adc_nids;
9170 }
9171 if (!spec->capsrc_nids)
9172 spec->capsrc_nids = alc883_capsrc_nids;
9173 spec->capture_style = CAPT_MIX; /* matrix-style capture */
Kailang Yang2f893282008-05-27 12:14:47 +02009174 break;
9175 }
9176
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009177 spec->stream_analog_playback = &alc883_pcm_analog_playback;
9178 spec->stream_analog_capture = &alc883_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01009179 spec->stream_analog_alt_capture = &alc883_pcm_analog_alt_capture;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009180
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009181 spec->stream_digital_playback = &alc883_pcm_digital_playback;
9182 spec->stream_digital_capture = &alc883_pcm_digital_capture;
9183
Takashi Iwaif9e336f2008-10-31 16:37:07 +01009184 if (!spec->cap_mixer)
9185 set_capture_mixer(spec);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009186
Takashi Iwai2134ea42008-01-10 16:53:55 +01009187 spec->vmaster_nid = 0x0c;
9188
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009189 codec->patch_ops = alc_patch_ops;
9190 if (board_config == ALC883_AUTO)
9191 spec->init_hook = alc883_auto_init;
Kailang Yangf9423e72008-05-27 12:32:25 +02009192
Takashi Iwaicb53c622007-08-10 17:21:45 +02009193#ifdef CONFIG_SND_HDA_POWER_SAVE
9194 if (!spec->loopback.amplist)
9195 spec->loopback.amplist = alc883_loopbacks;
9196#endif
Takashi Iwaidaead532008-11-28 12:55:36 +01009197 codec->proc_widget_hook = print_realtek_coef;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009198
9199 return 0;
9200}
9201
9202/*
Kailang Yangdf694da2005-12-05 19:42:22 +01009203 * ALC262 support
9204 */
9205
9206#define ALC262_DIGOUT_NID ALC880_DIGOUT_NID
9207#define ALC262_DIGIN_NID ALC880_DIGIN_NID
9208
9209#define alc262_dac_nids alc260_dac_nids
9210#define alc262_adc_nids alc882_adc_nids
9211#define alc262_adc_nids_alt alc882_adc_nids_alt
Takashi Iwai88c71a92008-02-14 17:27:17 +01009212#define alc262_capsrc_nids alc882_capsrc_nids
9213#define alc262_capsrc_nids_alt alc882_capsrc_nids_alt
Kailang Yangdf694da2005-12-05 19:42:22 +01009214
9215#define alc262_modes alc260_modes
Takashi Iwaic5f2ea02005-12-06 18:54:31 +01009216#define alc262_capture_source alc882_capture_source
Kailang Yangdf694da2005-12-05 19:42:22 +01009217
Kailang Yang4e555fe2008-08-26 13:05:55 +02009218static hda_nid_t alc262_dmic_adc_nids[1] = {
9219 /* ADC0 */
9220 0x09
9221};
9222
9223static hda_nid_t alc262_dmic_capsrc_nids[1] = { 0x22 };
9224
Kailang Yangdf694da2005-12-05 19:42:22 +01009225static struct snd_kcontrol_new alc262_base_mixer[] = {
9226 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9227 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9228 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9229 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9230 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9231 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9232 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9233 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01009234 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01009235 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
9236 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01009237 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01009238 /* HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01009239 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT), */
Kailang Yangdf694da2005-12-05 19:42:22 +01009240 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),
9241 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9242 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
9243 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01009244 { } /* end */
Takashi Iwai834be882006-03-01 14:16:17 +01009245};
9246
Kailang Yangccc656c2006-10-17 12:32:26 +02009247static struct snd_kcontrol_new alc262_hippo1_mixer[] = {
9248 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9249 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9250 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9251 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9252 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9253 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9254 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9255 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01009256 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009257 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
9258 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01009259 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009260 /* HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01009261 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT), */
Kailang Yangccc656c2006-10-17 12:32:26 +02009262 /*HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),*/
9263 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
9264 { } /* end */
9265};
9266
Takashi Iwaice875f02008-01-28 18:17:43 +01009267/* update HP, line and mono-out pins according to the master switch */
9268static void alc262_hp_master_update(struct hda_codec *codec)
9269{
9270 struct alc_spec *spec = codec->spec;
9271 int val = spec->master_sw;
9272
9273 /* HP & line-out */
9274 snd_hda_codec_write_cache(codec, 0x1b, 0,
9275 AC_VERB_SET_PIN_WIDGET_CONTROL,
9276 val ? PIN_HP : 0);
9277 snd_hda_codec_write_cache(codec, 0x15, 0,
9278 AC_VERB_SET_PIN_WIDGET_CONTROL,
9279 val ? PIN_HP : 0);
9280 /* mono (speaker) depending on the HP jack sense */
9281 val = val && !spec->jack_present;
9282 snd_hda_codec_write_cache(codec, 0x16, 0,
9283 AC_VERB_SET_PIN_WIDGET_CONTROL,
9284 val ? PIN_OUT : 0);
9285}
9286
9287static void alc262_hp_bpc_automute(struct hda_codec *codec)
9288{
9289 struct alc_spec *spec = codec->spec;
9290 unsigned int presence;
9291 presence = snd_hda_codec_read(codec, 0x1b, 0,
9292 AC_VERB_GET_PIN_SENSE, 0);
9293 spec->jack_present = !!(presence & AC_PINSENSE_PRESENCE);
9294 alc262_hp_master_update(codec);
9295}
9296
9297static void alc262_hp_bpc_unsol_event(struct hda_codec *codec, unsigned int res)
9298{
9299 if ((res >> 26) != ALC880_HP_EVENT)
9300 return;
9301 alc262_hp_bpc_automute(codec);
9302}
9303
9304static void alc262_hp_wildwest_automute(struct hda_codec *codec)
9305{
9306 struct alc_spec *spec = codec->spec;
9307 unsigned int presence;
9308 presence = snd_hda_codec_read(codec, 0x15, 0,
9309 AC_VERB_GET_PIN_SENSE, 0);
9310 spec->jack_present = !!(presence & AC_PINSENSE_PRESENCE);
9311 alc262_hp_master_update(codec);
9312}
9313
9314static void alc262_hp_wildwest_unsol_event(struct hda_codec *codec,
9315 unsigned int res)
9316{
9317 if ((res >> 26) != ALC880_HP_EVENT)
9318 return;
9319 alc262_hp_wildwest_automute(codec);
9320}
9321
9322static int alc262_hp_master_sw_get(struct snd_kcontrol *kcontrol,
9323 struct snd_ctl_elem_value *ucontrol)
9324{
9325 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
9326 struct alc_spec *spec = codec->spec;
9327 *ucontrol->value.integer.value = spec->master_sw;
9328 return 0;
9329}
9330
9331static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol,
9332 struct snd_ctl_elem_value *ucontrol)
9333{
9334 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
9335 struct alc_spec *spec = codec->spec;
9336 int val = !!*ucontrol->value.integer.value;
9337
9338 if (val == spec->master_sw)
9339 return 0;
9340 spec->master_sw = val;
9341 alc262_hp_master_update(codec);
9342 return 1;
9343}
9344
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009345static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
Takashi Iwaice875f02008-01-28 18:17:43 +01009346 {
9347 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9348 .name = "Master Playback Switch",
9349 .info = snd_ctl_boolean_mono_info,
9350 .get = alc262_hp_master_sw_get,
9351 .put = alc262_hp_master_sw_put,
9352 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009353 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9354 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9355 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +01009356 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
9357 HDA_OUTPUT),
9358 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
9359 HDA_OUTPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009360 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9361 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01009362 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009363 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
9364 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01009365 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009366 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9367 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9368 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9369 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9370 HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
9371 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT),
9372 HDA_CODEC_VOLUME("AUX IN Playback Volume", 0x0b, 0x06, HDA_INPUT),
9373 HDA_CODEC_MUTE("AUX IN Playback Switch", 0x0b, 0x06, HDA_INPUT),
9374 { } /* end */
9375};
9376
Kailang Yangcd7509a2007-01-26 18:33:17 +01009377static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = {
Takashi Iwaice875f02008-01-28 18:17:43 +01009378 {
9379 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9380 .name = "Master Playback Switch",
9381 .info = snd_ctl_boolean_mono_info,
9382 .get = alc262_hp_master_sw_get,
9383 .put = alc262_hp_master_sw_put,
9384 },
Kailang Yangcd7509a2007-01-26 18:33:17 +01009385 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9386 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
9387 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
9388 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +01009389 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
9390 HDA_OUTPUT),
9391 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
9392 HDA_OUTPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +01009393 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT),
9394 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01009395 HDA_CODEC_VOLUME("Front Mic Boost", 0x1a, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +01009396 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
9397 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
9398 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9399 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9400 HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
9401 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT),
9402 { } /* end */
9403};
9404
9405static struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = {
9406 HDA_CODEC_VOLUME("Rear Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9407 HDA_CODEC_MUTE("Rear Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01009408 HDA_CODEC_VOLUME("Rear Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +01009409 { } /* end */
9410};
9411
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009412/* mute/unmute internal speaker according to the hp jack and mute state */
9413static void alc262_hp_t5735_automute(struct hda_codec *codec, int force)
9414{
9415 struct alc_spec *spec = codec->spec;
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009416
9417 if (force || !spec->sense_updated) {
9418 unsigned int present;
9419 present = snd_hda_codec_read(codec, 0x15, 0,
9420 AC_VERB_GET_PIN_SENSE, 0);
Takashi Iwai4bb26132008-01-28 18:12:42 +01009421 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009422 spec->sense_updated = 1;
9423 }
Takashi Iwai4bb26132008-01-28 18:12:42 +01009424 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0, HDA_AMP_MUTE,
9425 spec->jack_present ? HDA_AMP_MUTE : 0);
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009426}
9427
9428static void alc262_hp_t5735_unsol_event(struct hda_codec *codec,
9429 unsigned int res)
9430{
9431 if ((res >> 26) != ALC880_HP_EVENT)
9432 return;
9433 alc262_hp_t5735_automute(codec, 1);
9434}
9435
9436static void alc262_hp_t5735_init_hook(struct hda_codec *codec)
9437{
9438 alc262_hp_t5735_automute(codec, 1);
9439}
9440
9441static struct snd_kcontrol_new alc262_hp_t5735_mixer[] = {
Takashi Iwai86cd9292008-01-28 18:09:56 +01009442 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9443 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009444 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
9445 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9446 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9447 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9448 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9449 { } /* end */
9450};
9451
9452static struct hda_verb alc262_hp_t5735_verbs[] = {
9453 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9454 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9455
9456 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9457 { }
9458};
9459
Kailang Yang8c427222008-01-10 13:03:59 +01009460static struct snd_kcontrol_new alc262_hp_rp5700_mixer[] = {
Takashi Iwaif2f48e12008-01-28 18:14:43 +01009461 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9462 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01009463 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
9464 HDA_CODEC_MUTE("Speaker Playback Switch", 0x16, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +01009465 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
9466 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
9467 { } /* end */
9468};
9469
9470static struct hda_verb alc262_hp_rp5700_verbs[] = {
9471 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9472 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9473 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9474 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9475 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
9476 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
9477 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
9478 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
9479 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
9480 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
9481 {}
9482};
9483
9484static struct hda_input_mux alc262_hp_rp5700_capture_source = {
9485 .num_items = 1,
9486 .items = {
9487 { "Line", 0x1 },
9488 },
9489};
9490
Takashi Iwai0724ea22007-08-23 00:31:43 +02009491/* bind hp and internal speaker mute (with plug check) */
9492static int alc262_sony_master_sw_put(struct snd_kcontrol *kcontrol,
9493 struct snd_ctl_elem_value *ucontrol)
9494{
9495 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
9496 long *valp = ucontrol->value.integer.value;
9497 int change;
9498
9499 /* change hp mute */
9500 change = snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0,
9501 HDA_AMP_MUTE,
9502 valp[0] ? 0 : HDA_AMP_MUTE);
9503 change |= snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0,
9504 HDA_AMP_MUTE,
9505 valp[1] ? 0 : HDA_AMP_MUTE);
9506 if (change) {
9507 /* change speaker according to HP jack state */
9508 struct alc_spec *spec = codec->spec;
9509 unsigned int mute;
9510 if (spec->jack_present)
9511 mute = HDA_AMP_MUTE;
9512 else
9513 mute = snd_hda_codec_amp_read(codec, 0x15, 0,
9514 HDA_OUTPUT, 0);
9515 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9516 HDA_AMP_MUTE, mute);
9517 }
9518 return change;
9519}
Takashi Iwai5b319542007-07-26 11:49:22 +02009520
Kailang Yang272a5272007-05-14 11:00:38 +02009521static struct snd_kcontrol_new alc262_sony_mixer[] = {
Takashi Iwai0724ea22007-08-23 00:31:43 +02009522 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9523 {
9524 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9525 .name = "Master Playback Switch",
9526 .info = snd_hda_mixer_amp_switch_info,
9527 .get = snd_hda_mixer_amp_switch_get,
9528 .put = alc262_sony_master_sw_put,
9529 .private_value = HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
9530 },
Kailang Yang272a5272007-05-14 11:00:38 +02009531 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9532 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9533 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
9534 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
9535 { } /* end */
9536};
9537
Kailang Yang83c34212007-07-05 11:43:05 +02009538static struct snd_kcontrol_new alc262_benq_t31_mixer[] = {
9539 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9540 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9541 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9542 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9543 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9544 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
9545 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
9546 { } /* end */
9547};
Kailang Yang272a5272007-05-14 11:00:38 +02009548
Tony Vroonba340e82009-02-02 19:01:30 +00009549static struct snd_kcontrol_new alc262_tyan_mixer[] = {
9550 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9551 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
9552 HDA_CODEC_VOLUME("Aux Playback Volume", 0x0b, 0x06, HDA_INPUT),
9553 HDA_CODEC_MUTE("Aux Playback Switch", 0x0b, 0x06, HDA_INPUT),
9554 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9555 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9556 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9557 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9558 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9559 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
9560 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
9561 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
9562 { } /* end */
9563};
9564
9565static struct hda_verb alc262_tyan_verbs[] = {
9566 /* Headphone automute */
9567 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
9568 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9569 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9570
9571 /* P11 AUX_IN, white 4-pin connector */
9572 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
9573 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_1, 0xe1},
9574 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_2, 0x93},
9575 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0x19},
9576
9577 {}
9578};
9579
9580/* unsolicited event for HP jack sensing */
9581static void alc262_tyan_automute(struct hda_codec *codec)
9582{
9583 unsigned int mute;
9584 unsigned int present;
9585
9586 snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
9587 present = snd_hda_codec_read(codec, 0x1b, 0,
9588 AC_VERB_GET_PIN_SENSE, 0);
9589 present = (present & 0x80000000) != 0;
9590 if (present) {
9591 /* mute line output on ATX panel */
9592 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9593 HDA_AMP_MUTE, HDA_AMP_MUTE);
9594 } else {
9595 /* unmute line output if necessary */
9596 mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
9597 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9598 HDA_AMP_MUTE, mute);
9599 }
9600}
9601
9602static void alc262_tyan_unsol_event(struct hda_codec *codec,
9603 unsigned int res)
9604{
9605 if ((res >> 26) != ALC880_HP_EVENT)
9606 return;
9607 alc262_tyan_automute(codec);
9608}
9609
Kailang Yangdf694da2005-12-05 19:42:22 +01009610#define alc262_capture_mixer alc882_capture_mixer
9611#define alc262_capture_alt_mixer alc882_capture_alt_mixer
9612
9613/*
9614 * generic initialization of ADC, input mixers and output mixers
9615 */
9616static struct hda_verb alc262_init_verbs[] = {
9617 /*
9618 * Unmute ADC0-2 and set the default input to mic-in
9619 */
9620 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
9621 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9622 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
9623 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9624 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
9625 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9626
Takashi Iwaicb53c622007-08-10 17:21:45 +02009627 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +01009628 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009629 * Note: PASD motherboards uses the Line In 2 as the input for
9630 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01009631 */
9632 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02009633 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9634 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
9635 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
9636 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
9637 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01009638
9639 /*
9640 * Set up output mixers (0x0c - 0x0e)
9641 */
9642 /* set vol=0 to output mixers */
9643 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9644 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9645 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9646 /* set up input amps for analog loopback */
9647 /* Amp Indices: DAC = 0, mixer = 1 */
9648 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9649 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9650 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9651 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9652 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9653 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9654
9655 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
9656 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
9657 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
9658 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9659 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9660 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9661
9662 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
9663 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
9664 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
9665 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
9666 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Kailang Yangea1fb292008-08-26 12:58:38 +02009667
Kailang Yangdf694da2005-12-05 19:42:22 +01009668 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
9669 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Kailang Yangea1fb292008-08-26 12:58:38 +02009670
Kailang Yangdf694da2005-12-05 19:42:22 +01009671 /* FIXME: use matrix-type input source selection */
9672 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
9673 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
9674 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9675 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
9676 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
9677 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
9678 /* Input mixer2 */
9679 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9680 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
9681 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
9682 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
9683 /* Input mixer3 */
9684 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9685 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
9686 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009687 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
Kailang Yangdf694da2005-12-05 19:42:22 +01009688
9689 { }
9690};
9691
Kailang Yang4e555fe2008-08-26 13:05:55 +02009692static struct hda_verb alc262_eapd_verbs[] = {
9693 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
9694 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
9695 { }
9696};
9697
Kailang Yangccc656c2006-10-17 12:32:26 +02009698static struct hda_verb alc262_hippo_unsol_verbs[] = {
9699 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
9700 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9701 {}
9702};
9703
9704static struct hda_verb alc262_hippo1_unsol_verbs[] = {
9705 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
9706 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
9707 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
9708
9709 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
9710 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9711 {}
9712};
9713
Kailang Yang272a5272007-05-14 11:00:38 +02009714static struct hda_verb alc262_sony_unsol_verbs[] = {
9715 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
9716 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9717 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, // Front Mic
9718
9719 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
9720 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Akio Idehara7b1e8792008-06-09 22:46:07 +09009721 {}
Kailang Yang272a5272007-05-14 11:00:38 +02009722};
9723
Kailang Yang4e555fe2008-08-26 13:05:55 +02009724static struct hda_input_mux alc262_dmic_capture_source = {
9725 .num_items = 2,
9726 .items = {
9727 { "Int DMic", 0x9 },
9728 { "Mic", 0x0 },
9729 },
9730};
9731
9732static struct snd_kcontrol_new alc262_toshiba_s06_mixer[] = {
9733 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9734 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9735 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9736 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9737 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang4e555fe2008-08-26 13:05:55 +02009738 { } /* end */
9739};
9740
9741static struct hda_verb alc262_toshiba_s06_verbs[] = {
9742 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
9743 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9744 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9745 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9746 {0x22, AC_VERB_SET_CONNECT_SEL, 0x09},
9747 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9748 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
9749 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
9750 {}
9751};
9752
9753static void alc262_dmic_automute(struct hda_codec *codec)
9754{
9755 unsigned int present;
9756
9757 present = snd_hda_codec_read(codec, 0x18, 0,
9758 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
9759 snd_hda_codec_write(codec, 0x22, 0,
9760 AC_VERB_SET_CONNECT_SEL, present ? 0x0 : 0x09);
9761}
9762
9763/* toggle speaker-output according to the hp-jack state */
9764static void alc262_toshiba_s06_speaker_automute(struct hda_codec *codec)
9765{
9766 unsigned int present;
9767 unsigned char bits;
9768
9769 present = snd_hda_codec_read(codec, 0x15, 0,
9770 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
9771 bits = present ? 0 : PIN_OUT;
9772 snd_hda_codec_write(codec, 0x14, 0,
9773 AC_VERB_SET_PIN_WIDGET_CONTROL, bits);
9774}
9775
9776
9777
9778/* unsolicited event for HP jack sensing */
9779static void alc262_toshiba_s06_unsol_event(struct hda_codec *codec,
9780 unsigned int res)
9781{
9782 if ((res >> 26) == ALC880_HP_EVENT)
9783 alc262_toshiba_s06_speaker_automute(codec);
9784 if ((res >> 26) == ALC880_MIC_EVENT)
9785 alc262_dmic_automute(codec);
9786
9787}
9788
9789static void alc262_toshiba_s06_init_hook(struct hda_codec *codec)
9790{
9791 alc262_toshiba_s06_speaker_automute(codec);
9792 alc262_dmic_automute(codec);
9793}
9794
Kailang Yangccc656c2006-10-17 12:32:26 +02009795/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwai5b319542007-07-26 11:49:22 +02009796static void alc262_hippo_automute(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02009797{
9798 struct alc_spec *spec = codec->spec;
9799 unsigned int mute;
Takashi Iwai5b319542007-07-26 11:49:22 +02009800 unsigned int present;
Kailang Yangccc656c2006-10-17 12:32:26 +02009801
Takashi Iwai5b319542007-07-26 11:49:22 +02009802 /* need to execute and sync at first */
9803 snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0);
9804 present = snd_hda_codec_read(codec, 0x15, 0,
9805 AC_VERB_GET_PIN_SENSE, 0);
9806 spec->jack_present = (present & 0x80000000) != 0;
Kailang Yangccc656c2006-10-17 12:32:26 +02009807 if (spec->jack_present) {
9808 /* mute internal speaker */
Takashi Iwai47fd8302007-08-10 17:11:07 +02009809 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9810 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yangccc656c2006-10-17 12:32:26 +02009811 } else {
9812 /* unmute internal speaker if necessary */
9813 mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0);
Takashi Iwai47fd8302007-08-10 17:11:07 +02009814 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9815 HDA_AMP_MUTE, mute);
Kailang Yangccc656c2006-10-17 12:32:26 +02009816 }
9817}
9818
9819/* unsolicited event for HP jack sensing */
9820static void alc262_hippo_unsol_event(struct hda_codec *codec,
9821 unsigned int res)
9822{
9823 if ((res >> 26) != ALC880_HP_EVENT)
9824 return;
Takashi Iwai5b319542007-07-26 11:49:22 +02009825 alc262_hippo_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02009826}
9827
Takashi Iwai5b319542007-07-26 11:49:22 +02009828static void alc262_hippo1_automute(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02009829{
Kailang Yangccc656c2006-10-17 12:32:26 +02009830 unsigned int mute;
Takashi Iwai5b319542007-07-26 11:49:22 +02009831 unsigned int present;
Kailang Yangccc656c2006-10-17 12:32:26 +02009832
Takashi Iwai5b319542007-07-26 11:49:22 +02009833 snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
9834 present = snd_hda_codec_read(codec, 0x1b, 0,
9835 AC_VERB_GET_PIN_SENSE, 0);
9836 present = (present & 0x80000000) != 0;
9837 if (present) {
Kailang Yangccc656c2006-10-17 12:32:26 +02009838 /* mute internal speaker */
Takashi Iwai47fd8302007-08-10 17:11:07 +02009839 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9840 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yangccc656c2006-10-17 12:32:26 +02009841 } else {
9842 /* unmute internal speaker if necessary */
9843 mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
Takashi Iwai47fd8302007-08-10 17:11:07 +02009844 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9845 HDA_AMP_MUTE, mute);
Kailang Yangccc656c2006-10-17 12:32:26 +02009846 }
9847}
9848
9849/* unsolicited event for HP jack sensing */
9850static void alc262_hippo1_unsol_event(struct hda_codec *codec,
9851 unsigned int res)
9852{
9853 if ((res >> 26) != ALC880_HP_EVENT)
9854 return;
Takashi Iwai5b319542007-07-26 11:49:22 +02009855 alc262_hippo1_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02009856}
9857
Takashi Iwai834be882006-03-01 14:16:17 +01009858/*
Pascal Terjane8f9ae22008-08-04 14:36:05 +02009859 * nec model
9860 * 0x15 = headphone
9861 * 0x16 = internal speaker
9862 * 0x18 = external mic
9863 */
9864
9865static struct snd_kcontrol_new alc262_nec_mixer[] = {
9866 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
9867 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 0, 0x0, HDA_OUTPUT),
9868
9869 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9870 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9871 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9872
9873 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
9874 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9875 { } /* end */
9876};
9877
9878static struct hda_verb alc262_nec_verbs[] = {
9879 /* Unmute Speaker */
9880 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9881
9882 /* Headphone */
9883 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
9884 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9885
9886 /* External mic to headphone */
9887 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9888 /* External mic to speaker */
9889 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9890 {}
9891};
9892
9893/*
Takashi Iwai834be882006-03-01 14:16:17 +01009894 * fujitsu model
Tony Vroon5d9fab22008-03-14 17:09:18 +01009895 * 0x14 = headphone/spdif-out, 0x15 = internal speaker,
9896 * 0x1b = port replicator headphone out
Takashi Iwai834be882006-03-01 14:16:17 +01009897 */
9898
9899#define ALC_HP_EVENT 0x37
9900
9901static struct hda_verb alc262_fujitsu_unsol_verbs[] = {
9902 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
9903 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Tony Vroon5d9fab22008-03-14 17:09:18 +01009904 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
9905 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai834be882006-03-01 14:16:17 +01009906 {}
9907};
9908
Jiang zhe0e31daf2008-03-20 12:12:39 +01009909static struct hda_verb alc262_lenovo_3000_unsol_verbs[] = {
9910 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
9911 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9912 {}
9913};
9914
Takashi Iwai834be882006-03-01 14:16:17 +01009915static struct hda_input_mux alc262_fujitsu_capture_source = {
Takashi Iwai39d3ed32007-10-12 15:03:48 +02009916 .num_items = 3,
Takashi Iwai834be882006-03-01 14:16:17 +01009917 .items = {
9918 { "Mic", 0x0 },
Takashi Iwai39d3ed32007-10-12 15:03:48 +02009919 { "Int Mic", 0x1 },
Takashi Iwai834be882006-03-01 14:16:17 +01009920 { "CD", 0x4 },
9921 },
9922};
9923
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009924static struct hda_input_mux alc262_HP_capture_source = {
9925 .num_items = 5,
9926 .items = {
9927 { "Mic", 0x0 },
zhejiangaccbe492007-08-31 12:36:05 +02009928 { "Front Mic", 0x1 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009929 { "Line", 0x2 },
9930 { "CD", 0x4 },
9931 { "AUX IN", 0x6 },
9932 },
9933};
9934
zhejiangaccbe492007-08-31 12:36:05 +02009935static struct hda_input_mux alc262_HP_D7000_capture_source = {
9936 .num_items = 4,
9937 .items = {
9938 { "Mic", 0x0 },
9939 { "Front Mic", 0x2 },
9940 { "Line", 0x1 },
9941 { "CD", 0x4 },
9942 },
9943};
9944
Takashi Iwaiebc7a402008-05-20 09:23:05 +02009945/* mute/unmute internal speaker according to the hp jacks and mute state */
Takashi Iwai834be882006-03-01 14:16:17 +01009946static void alc262_fujitsu_automute(struct hda_codec *codec, int force)
9947{
9948 struct alc_spec *spec = codec->spec;
9949 unsigned int mute;
9950
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009951 if (force || !spec->sense_updated) {
Takashi Iwaiebc7a402008-05-20 09:23:05 +02009952 unsigned int present;
Takashi Iwai834be882006-03-01 14:16:17 +01009953 /* need to execute and sync at first */
9954 snd_hda_codec_read(codec, 0x14, 0, AC_VERB_SET_PIN_SENSE, 0);
Takashi Iwaiebc7a402008-05-20 09:23:05 +02009955 /* check laptop HP jack */
9956 present = snd_hda_codec_read(codec, 0x14, 0,
9957 AC_VERB_GET_PIN_SENSE, 0);
9958 /* need to execute and sync at first */
9959 snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
9960 /* check docking HP jack */
9961 present |= snd_hda_codec_read(codec, 0x1b, 0,
9962 AC_VERB_GET_PIN_SENSE, 0);
9963 if (present & AC_PINSENSE_PRESENCE)
9964 spec->jack_present = 1;
9965 else
9966 spec->jack_present = 0;
Takashi Iwai834be882006-03-01 14:16:17 +01009967 spec->sense_updated = 1;
9968 }
Takashi Iwaiebc7a402008-05-20 09:23:05 +02009969 /* unmute internal speaker only if both HPs are unplugged and
9970 * master switch is on
9971 */
9972 if (spec->jack_present)
9973 mute = HDA_AMP_MUTE;
9974 else
Takashi Iwai834be882006-03-01 14:16:17 +01009975 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
Takashi Iwaiebc7a402008-05-20 09:23:05 +02009976 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9977 HDA_AMP_MUTE, mute);
Takashi Iwai834be882006-03-01 14:16:17 +01009978}
9979
9980/* unsolicited event for HP jack sensing */
9981static void alc262_fujitsu_unsol_event(struct hda_codec *codec,
9982 unsigned int res)
9983{
9984 if ((res >> 26) != ALC_HP_EVENT)
9985 return;
9986 alc262_fujitsu_automute(codec, 1);
9987}
9988
Takashi Iwaiebc7a402008-05-20 09:23:05 +02009989static void alc262_fujitsu_init_hook(struct hda_codec *codec)
9990{
9991 alc262_fujitsu_automute(codec, 1);
9992}
9993
Takashi Iwai834be882006-03-01 14:16:17 +01009994/* bind volumes of both NID 0x0c and 0x0d */
Takashi Iwaicca3b372007-08-10 17:12:15 +02009995static struct hda_bind_ctls alc262_fujitsu_bind_master_vol = {
9996 .ops = &snd_hda_bind_vol,
9997 .values = {
9998 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT),
9999 HDA_COMPOSE_AMP_VAL(0x0d, 3, 0, HDA_OUTPUT),
10000 0
10001 },
10002};
Takashi Iwai834be882006-03-01 14:16:17 +010010003
Jiang zhe0e31daf2008-03-20 12:12:39 +010010004/* mute/unmute internal speaker according to the hp jack and mute state */
10005static void alc262_lenovo_3000_automute(struct hda_codec *codec, int force)
10006{
10007 struct alc_spec *spec = codec->spec;
10008 unsigned int mute;
10009
10010 if (force || !spec->sense_updated) {
10011 unsigned int present_int_hp;
10012 /* need to execute and sync at first */
10013 snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
10014 present_int_hp = snd_hda_codec_read(codec, 0x1b, 0,
10015 AC_VERB_GET_PIN_SENSE, 0);
10016 spec->jack_present = (present_int_hp & 0x80000000) != 0;
10017 spec->sense_updated = 1;
10018 }
10019 if (spec->jack_present) {
10020 /* mute internal speaker */
10021 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
10022 HDA_AMP_MUTE, HDA_AMP_MUTE);
10023 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
10024 HDA_AMP_MUTE, HDA_AMP_MUTE);
10025 } else {
10026 /* unmute internal speaker if necessary */
10027 mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
10028 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
10029 HDA_AMP_MUTE, mute);
10030 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
10031 HDA_AMP_MUTE, mute);
10032 }
10033}
10034
10035/* unsolicited event for HP jack sensing */
10036static void alc262_lenovo_3000_unsol_event(struct hda_codec *codec,
10037 unsigned int res)
10038{
10039 if ((res >> 26) != ALC_HP_EVENT)
10040 return;
10041 alc262_lenovo_3000_automute(codec, 1);
10042}
10043
Takashi Iwai834be882006-03-01 14:16:17 +010010044/* bind hp and internal speaker mute (with plug check) */
10045static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol,
10046 struct snd_ctl_elem_value *ucontrol)
10047{
10048 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
10049 long *valp = ucontrol->value.integer.value;
10050 int change;
10051
Tony Vroon5d9fab22008-03-14 17:09:18 +010010052 change = snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
10053 HDA_AMP_MUTE,
10054 valp ? 0 : HDA_AMP_MUTE);
10055 change |= snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
10056 HDA_AMP_MUTE,
10057 valp ? 0 : HDA_AMP_MUTE);
10058
Takashi Iwai82beb8f2007-08-10 17:09:26 +020010059 if (change)
10060 alc262_fujitsu_automute(codec, 0);
Takashi Iwai834be882006-03-01 14:16:17 +010010061 return change;
10062}
10063
10064static struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +020010065 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
Takashi Iwai834be882006-03-01 14:16:17 +010010066 {
10067 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10068 .name = "Master Playback Switch",
10069 .info = snd_hda_mixer_amp_switch_info,
10070 .get = snd_hda_mixer_amp_switch_get,
10071 .put = alc262_fujitsu_master_sw_put,
10072 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
10073 },
10074 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
10075 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Tony Vroon06a9c302008-04-14 13:31:45 +020010076 HDA_CODEC_VOLUME("PC Speaker Volume", 0x0b, 0x05, HDA_INPUT),
10077 HDA_CODEC_MUTE("PC Speaker Switch", 0x0b, 0x05, HDA_INPUT),
Takashi Iwai834be882006-03-01 14:16:17 +010010078 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10079 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10080 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai39d3ed32007-10-12 15:03:48 +020010081 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
10082 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
10083 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai834be882006-03-01 14:16:17 +010010084 { } /* end */
10085};
10086
Jiang zhe0e31daf2008-03-20 12:12:39 +010010087/* bind hp and internal speaker mute (with plug check) */
10088static int alc262_lenovo_3000_master_sw_put(struct snd_kcontrol *kcontrol,
10089 struct snd_ctl_elem_value *ucontrol)
10090{
10091 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
10092 long *valp = ucontrol->value.integer.value;
10093 int change;
10094
10095 change = snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
10096 HDA_AMP_MUTE,
10097 valp ? 0 : HDA_AMP_MUTE);
10098
10099 if (change)
10100 alc262_lenovo_3000_automute(codec, 0);
10101 return change;
10102}
10103
10104static struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = {
10105 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
10106 {
10107 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10108 .name = "Master Playback Switch",
10109 .info = snd_hda_mixer_amp_switch_info,
10110 .get = snd_hda_mixer_amp_switch_get,
10111 .put = alc262_lenovo_3000_master_sw_put,
10112 .private_value = HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
10113 },
10114 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
10115 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
10116 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10117 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10118 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
10119 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
10120 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
10121 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
10122 { } /* end */
10123};
10124
Hiroshi Miura9f99a632008-08-28 16:09:06 +020010125static struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = {
10126 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
10127 {
10128 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10129 .name = "Master Playback Switch",
10130 .info = snd_hda_mixer_amp_switch_info,
10131 .get = snd_hda_mixer_amp_switch_get,
10132 .put = alc262_sony_master_sw_put,
10133 .private_value = HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
10134 },
10135 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10136 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
10137 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10138 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
10139 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
10140 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
10141 { } /* end */
10142};
10143
Takashi Iwai304dcaa2006-07-25 14:51:16 +020010144/* additional init verbs for Benq laptops */
10145static struct hda_verb alc262_EAPD_verbs[] = {
10146 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
10147 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
10148 {}
10149};
10150
Kailang Yang83c34212007-07-05 11:43:05 +020010151static struct hda_verb alc262_benq_t31_EAPD_verbs[] = {
10152 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
10153 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
10154
10155 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
10156 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
10157 {}
10158};
10159
Tobin Davisf651b502007-10-26 12:40:47 +020010160/* Samsung Q1 Ultra Vista model setup */
10161static struct snd_kcontrol_new alc262_ultra_mixer[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010162 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
10163 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +020010164 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
10165 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
10166 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010167 HDA_CODEC_VOLUME("Headphone Mic Boost", 0x15, 0, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +020010168 { } /* end */
10169};
10170
10171static struct hda_verb alc262_ultra_verbs[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010172 /* output mixer */
10173 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
10174 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10175 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10176 /* speaker */
10177 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
10178 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10179 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10180 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
10181 /* HP */
Tobin Davisf651b502007-10-26 12:40:47 +020010182 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010183 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10184 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10185 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
10186 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
10187 /* internal mic */
10188 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
10189 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10190 /* ADC, choose mic */
10191 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
10192 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
10193 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10194 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
10195 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
10196 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
10197 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
10198 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
10199 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
10200 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(8)},
Tobin Davisf651b502007-10-26 12:40:47 +020010201 {}
10202};
10203
Tobin Davisf651b502007-10-26 12:40:47 +020010204/* mute/unmute internal speaker according to the hp jack and mute state */
10205static void alc262_ultra_automute(struct hda_codec *codec)
10206{
10207 struct alc_spec *spec = codec->spec;
10208 unsigned int mute;
Tobin Davisf651b502007-10-26 12:40:47 +020010209
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010210 mute = 0;
10211 /* auto-mute only when HP is used as HP */
10212 if (!spec->cur_mux[0]) {
10213 unsigned int present;
10214 /* need to execute and sync at first */
10215 snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0);
10216 present = snd_hda_codec_read(codec, 0x15, 0,
10217 AC_VERB_GET_PIN_SENSE, 0);
10218 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
10219 if (spec->jack_present)
10220 mute = HDA_AMP_MUTE;
Tobin Davisf651b502007-10-26 12:40:47 +020010221 }
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010222 /* mute/unmute internal speaker */
10223 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
10224 HDA_AMP_MUTE, mute);
10225 /* mute/unmute HP */
10226 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
10227 HDA_AMP_MUTE, mute ? 0 : HDA_AMP_MUTE);
Tobin Davisf651b502007-10-26 12:40:47 +020010228}
10229
10230/* unsolicited event for HP jack sensing */
10231static void alc262_ultra_unsol_event(struct hda_codec *codec,
10232 unsigned int res)
10233{
10234 if ((res >> 26) != ALC880_HP_EVENT)
10235 return;
10236 alc262_ultra_automute(codec);
10237}
10238
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010239static struct hda_input_mux alc262_ultra_capture_source = {
10240 .num_items = 2,
10241 .items = {
10242 { "Mic", 0x1 },
10243 { "Headphone", 0x7 },
10244 },
10245};
10246
10247static int alc262_ultra_mux_enum_put(struct snd_kcontrol *kcontrol,
10248 struct snd_ctl_elem_value *ucontrol)
10249{
10250 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
10251 struct alc_spec *spec = codec->spec;
10252 int ret;
10253
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010010254 ret = alc_mux_enum_put(kcontrol, ucontrol);
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010255 if (!ret)
10256 return 0;
10257 /* reprogram the HP pin as mic or HP according to the input source */
10258 snd_hda_codec_write_cache(codec, 0x15, 0,
10259 AC_VERB_SET_PIN_WIDGET_CONTROL,
10260 spec->cur_mux[0] ? PIN_VREF80 : PIN_HP);
10261 alc262_ultra_automute(codec); /* mute/unmute HP */
10262 return ret;
10263}
10264
10265static struct snd_kcontrol_new alc262_ultra_capture_mixer[] = {
10266 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
10267 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
10268 {
10269 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10270 .name = "Capture Source",
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010010271 .info = alc_mux_enum_info,
10272 .get = alc_mux_enum_get,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010273 .put = alc262_ultra_mux_enum_put,
10274 },
10275 { } /* end */
10276};
10277
Kailang Yangdf694da2005-12-05 19:42:22 +010010278/* add playback controls from the parsed DAC table */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010279static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
10280 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010010281{
10282 hda_nid_t nid;
10283 int err;
10284
10285 spec->multiout.num_dacs = 1; /* only use one dac */
10286 spec->multiout.dac_nids = spec->private_dac_nids;
10287 spec->multiout.dac_nids[0] = 2;
10288
10289 nid = cfg->line_out_pins[0];
10290 if (nid) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010291 err = add_control(spec, ALC_CTL_WIDGET_VOL,
10292 "Front Playback Volume",
10293 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT));
10294 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010295 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010296 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10297 "Front Playback Switch",
10298 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
10299 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010300 return err;
10301 }
10302
Takashi Iwai82bc9552006-03-21 11:24:42 +010010303 nid = cfg->speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010010304 if (nid) {
10305 if (nid == 0x16) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010306 err = add_control(spec, ALC_CTL_WIDGET_VOL,
10307 "Speaker Playback Volume",
10308 HDA_COMPOSE_AMP_VAL(0x0e, 2, 0,
10309 HDA_OUTPUT));
10310 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010311 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010312 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10313 "Speaker Playback Switch",
10314 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
10315 HDA_OUTPUT));
10316 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010317 return err;
10318 } else {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010319 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10320 "Speaker Playback Switch",
10321 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
10322 HDA_OUTPUT));
10323 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010324 return err;
10325 }
10326 }
Takashi Iwaieb06ed82006-09-20 17:10:27 +020010327 nid = cfg->hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010010328 if (nid) {
10329 /* spec->multiout.hp_nid = 2; */
10330 if (nid == 0x16) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010331 err = add_control(spec, ALC_CTL_WIDGET_VOL,
10332 "Headphone Playback Volume",
10333 HDA_COMPOSE_AMP_VAL(0x0e, 2, 0,
10334 HDA_OUTPUT));
10335 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010336 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010337 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10338 "Headphone Playback Switch",
10339 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
10340 HDA_OUTPUT));
10341 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010342 return err;
10343 } else {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010344 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10345 "Headphone Playback Switch",
10346 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
10347 HDA_OUTPUT));
10348 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010349 return err;
10350 }
10351 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010352 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +010010353}
10354
10355/* identical with ALC880 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010356#define alc262_auto_create_analog_input_ctls \
10357 alc880_auto_create_analog_input_ctls
Kailang Yangdf694da2005-12-05 19:42:22 +010010358
10359/*
10360 * generic initialization of ADC, input mixers and output mixers
10361 */
10362static struct hda_verb alc262_volume_init_verbs[] = {
10363 /*
10364 * Unmute ADC0-2 and set the default input to mic-in
10365 */
10366 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
10367 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10368 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
10369 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10370 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
10371 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10372
Takashi Iwaicb53c622007-08-10 17:21:45 +020010373 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +010010374 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010375 * Note: PASD motherboards uses the Line In 2 as the input for
10376 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +010010377 */
10378 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020010379 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
10380 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10381 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
10382 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
10383 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +010010384
10385 /*
10386 * Set up output mixers (0x0c - 0x0f)
10387 */
10388 /* set vol=0 to output mixers */
10389 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10390 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10391 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yangea1fb292008-08-26 12:58:38 +020010392
Kailang Yangdf694da2005-12-05 19:42:22 +010010393 /* set up input amps for analog loopback */
10394 /* Amp Indices: DAC = 0, mixer = 1 */
10395 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10396 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10397 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10398 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10399 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10400 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10401
10402 /* FIXME: use matrix-type input source selection */
10403 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
10404 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
10405 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10406 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
10407 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
10408 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
10409 /* Input mixer2 */
10410 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10411 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
10412 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
10413 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
10414 /* Input mixer3 */
10415 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10416 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
10417 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
10418 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
10419
10420 { }
10421};
10422
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010423static struct hda_verb alc262_HP_BPC_init_verbs[] = {
10424 /*
10425 * Unmute ADC0-2 and set the default input to mic-in
10426 */
10427 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
10428 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10429 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
10430 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10431 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
10432 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10433
Takashi Iwaicb53c622007-08-10 17:21:45 +020010434 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010435 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010436 * Note: PASD motherboards uses the Line In 2 as the input for
10437 * front panel mic (mic 2)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010438 */
10439 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020010440 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
10441 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10442 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
10443 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
10444 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
10445 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
10446 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
Kailang Yangea1fb292008-08-26 12:58:38 +020010447
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010448 /*
10449 * Set up output mixers (0x0c - 0x0e)
10450 */
10451 /* set vol=0 to output mixers */
10452 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10453 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10454 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10455
10456 /* set up input amps for analog loopback */
10457 /* Amp Indices: DAC = 0, mixer = 1 */
10458 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10459 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10460 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10461 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10462 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10463 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10464
Takashi Iwaice875f02008-01-28 18:17:43 +010010465 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010466 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
10467 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
10468
10469 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
10470 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
10471
10472 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
10473 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
10474
10475 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10476 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
10477 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
10478 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10479 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10480
10481 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
10482 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10483 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10484 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
10485 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10486 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10487
10488
10489 /* FIXME: use matrix-type input source selection */
10490 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
10491 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
10492 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10493 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
10494 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
10495 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
10496 /* Input mixer2 */
10497 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10498 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
10499 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
10500 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
10501 /* Input mixer3 */
10502 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10503 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
10504 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
10505 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
10506
Takashi Iwaice875f02008-01-28 18:17:43 +010010507 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
10508
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010509 { }
10510};
10511
Kailang Yangcd7509a2007-01-26 18:33:17 +010010512static struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = {
10513 /*
10514 * Unmute ADC0-2 and set the default input to mic-in
10515 */
10516 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
10517 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10518 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
10519 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10520 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
10521 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10522
Takashi Iwaicb53c622007-08-10 17:21:45 +020010523 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangcd7509a2007-01-26 18:33:17 +010010524 * mixer widget
10525 * Note: PASD motherboards uses the Line In 2 as the input for front
10526 * panel mic (mic 2)
10527 */
10528 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020010529 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
10530 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10531 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
10532 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
10533 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
10534 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
10535 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
10536 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Kailang Yangcd7509a2007-01-26 18:33:17 +010010537 /*
10538 * Set up output mixers (0x0c - 0x0e)
10539 */
10540 /* set vol=0 to output mixers */
10541 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10542 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10543 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10544
10545 /* set up input amps for analog loopback */
10546 /* Amp Indices: DAC = 0, mixer = 1 */
10547 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10548 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10549 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10550 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10551 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10552 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10553
10554
10555 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP */
10556 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Mono */
10557 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* rear MIC */
10558 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* Line in */
10559 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
10560 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Line out */
10561 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD in */
10562
10563 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
10564 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
10565
10566 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
10567 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
10568
10569 /* {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, */
10570 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10571 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10572 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
10573 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10574 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10575
10576 /* FIXME: use matrix-type input source selection */
10577 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
10578 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
10579 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, /*rear MIC*/
10580 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, /*Line in*/
10581 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, /*F MIC*/
10582 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, /*Front*/
10583 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, /*CD*/
10584 /* {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
10585 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, /*HP*/
10586 /* Input mixer2 */
10587 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10588 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
10589 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
10590 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
10591 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
10592 /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
10593 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
10594 /* Input mixer3 */
10595 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10596 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
10597 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
10598 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
10599 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
10600 /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
10601 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
10602
Takashi Iwaice875f02008-01-28 18:17:43 +010010603 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
10604
Kailang Yangcd7509a2007-01-26 18:33:17 +010010605 { }
10606};
10607
Hiroshi Miura9f99a632008-08-28 16:09:06 +020010608static struct hda_verb alc262_toshiba_rx1_unsol_verbs[] = {
10609
10610 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Front Speaker */
10611 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
10612 {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
10613
10614 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* MIC jack */
10615 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
10616 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
10617 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
10618
10619 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP jack */
10620 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
10621 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
10622 {}
10623};
10624
10625
Takashi Iwaicb53c622007-08-10 17:21:45 +020010626#ifdef CONFIG_SND_HDA_POWER_SAVE
10627#define alc262_loopbacks alc880_loopbacks
10628#endif
10629
Kailang Yangdf694da2005-12-05 19:42:22 +010010630/* pcm configuration: identiacal with ALC880 */
10631#define alc262_pcm_analog_playback alc880_pcm_analog_playback
10632#define alc262_pcm_analog_capture alc880_pcm_analog_capture
10633#define alc262_pcm_digital_playback alc880_pcm_digital_playback
10634#define alc262_pcm_digital_capture alc880_pcm_digital_capture
10635
10636/*
10637 * BIOS auto configuration
10638 */
10639static int alc262_parse_auto_config(struct hda_codec *codec)
10640{
10641 struct alc_spec *spec = codec->spec;
10642 int err;
10643 static hda_nid_t alc262_ignore[] = { 0x1d, 0 };
10644
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010645 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
10646 alc262_ignore);
10647 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010648 return err;
Takashi Iwaie64f14f2009-01-20 18:32:55 +010010649 if (!spec->autocfg.line_outs) {
10650 if (spec->autocfg.dig_out_pin || spec->autocfg.dig_in_pin) {
10651 spec->multiout.max_channels = 2;
10652 spec->no_analog = 1;
10653 goto dig_only;
10654 }
Kailang Yangdf694da2005-12-05 19:42:22 +010010655 return 0; /* can't find valid BIOS pin config */
Takashi Iwaie64f14f2009-01-20 18:32:55 +010010656 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010657 err = alc262_auto_create_multi_out_ctls(spec, &spec->autocfg);
10658 if (err < 0)
10659 return err;
10660 err = alc262_auto_create_analog_input_ctls(spec, &spec->autocfg);
10661 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010662 return err;
10663
10664 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
10665
Takashi Iwaie64f14f2009-01-20 18:32:55 +010010666 dig_only:
10667 if (spec->autocfg.dig_out_pin) {
Kailang Yangdf694da2005-12-05 19:42:22 +010010668 spec->multiout.dig_out_nid = ALC262_DIGOUT_NID;
Takashi Iwaie64f14f2009-01-20 18:32:55 +010010669 spec->dig_out_type = spec->autocfg.dig_out_type;
10670 }
Kailang Yangdf694da2005-12-05 19:42:22 +010010671 if (spec->autocfg.dig_in_pin)
10672 spec->dig_in_nid = ALC262_DIGIN_NID;
10673
Takashi Iwai603c4012008-07-30 15:01:44 +020010674 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010010675 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +010010676
Takashi Iwaid88897e2008-10-31 15:01:37 +010010677 add_verb(spec, alc262_volume_init_verbs);
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020010678 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020010679 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010010680
Takashi Iwai776e1842007-08-29 15:07:11 +020010681 err = alc_auto_add_mic_boost(codec);
10682 if (err < 0)
10683 return err;
10684
Takashi Iwaie044c392008-10-27 16:56:24 +010010685 store_pin_configs(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010010686 return 1;
10687}
10688
10689#define alc262_auto_init_multi_out alc882_auto_init_multi_out
10690#define alc262_auto_init_hp_out alc882_auto_init_hp_out
10691#define alc262_auto_init_analog_input alc882_auto_init_analog_input
Takashi Iwaif511b012008-08-15 16:46:42 +020010692#define alc262_auto_init_input_src alc882_auto_init_input_src
Kailang Yangdf694da2005-12-05 19:42:22 +010010693
10694
10695/* init callback for auto-configuration model -- overriding the default init */
Takashi Iwaiae6b8132006-03-03 16:47:17 +010010696static void alc262_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010010697{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010698 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010010699 alc262_auto_init_multi_out(codec);
10700 alc262_auto_init_hp_out(codec);
10701 alc262_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020010702 alc262_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010703 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020010704 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010010705}
10706
10707/*
10708 * configuration and preset
10709 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010710static const char *alc262_models[ALC262_MODEL_LAST] = {
10711 [ALC262_BASIC] = "basic",
10712 [ALC262_HIPPO] = "hippo",
10713 [ALC262_HIPPO_1] = "hippo_1",
10714 [ALC262_FUJITSU] = "fujitsu",
10715 [ALC262_HP_BPC] = "hp-bpc",
Kailang Yangcd7509a2007-01-26 18:33:17 +010010716 [ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000",
Takashi Iwai61dc35d2007-11-14 12:26:44 +010010717 [ALC262_HP_TC_T5735] = "hp-tc-t5735",
Kailang Yang8c427222008-01-10 13:03:59 +010010718 [ALC262_HP_RP5700] = "hp-rp5700",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010719 [ALC262_BENQ_ED8] = "benq",
Takashi Iwai0f405022007-07-06 12:24:11 +020010720 [ALC262_BENQ_T31] = "benq-t31",
10721 [ALC262_SONY_ASSAMD] = "sony-assamd",
Takashi Iwai2922c9a2008-08-27 18:12:42 +020010722 [ALC262_TOSHIBA_S06] = "toshiba-s06",
Hiroshi Miura9f99a632008-08-28 16:09:06 +020010723 [ALC262_TOSHIBA_RX1] = "toshiba-rx1",
Tobin Davisf651b502007-10-26 12:40:47 +020010724 [ALC262_ULTRA] = "ultra",
Jiang zhe0e31daf2008-03-20 12:12:39 +010010725 [ALC262_LENOVO_3000] = "lenovo-3000",
Pascal Terjane8f9ae22008-08-04 14:36:05 +020010726 [ALC262_NEC] = "nec",
Tony Vroonba340e82009-02-02 19:01:30 +000010727 [ALC262_TYAN] = "tyan",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010728 [ALC262_AUTO] = "auto",
10729};
10730
10731static struct snd_pci_quirk alc262_cfg_tbl[] = {
10732 SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO),
Pascal Terjane8f9ae22008-08-04 14:36:05 +020010733 SND_PCI_QUIRK(0x1033, 0x8895, "NEC Versa S9100", ALC262_NEC),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010734 SND_PCI_QUIRK(0x103c, 0x12fe, "HP xw9400", ALC262_HP_BPC),
Kailang Yang7d87de22007-06-05 12:17:21 +020010735 SND_PCI_QUIRK(0x103c, 0x12ff, "HP xw4550", ALC262_HP_BPC),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010736 SND_PCI_QUIRK(0x103c, 0x1306, "HP xw8600", ALC262_HP_BPC),
10737 SND_PCI_QUIRK(0x103c, 0x1307, "HP xw6600", ALC262_HP_BPC),
Kailang Yang7d87de22007-06-05 12:17:21 +020010738 SND_PCI_QUIRK(0x103c, 0x1308, "HP xw4600", ALC262_HP_BPC),
Takashi Iwaib98f9332007-11-07 14:18:01 +010010739 SND_PCI_QUIRK(0x103c, 0x1309, "HP xw4*00", ALC262_HP_BPC),
Takashi Iwaib98f9332007-11-07 14:18:01 +010010740 SND_PCI_QUIRK(0x103c, 0x130a, "HP xw6*00", ALC262_HP_BPC),
Takashi Iwaib98f9332007-11-07 14:18:01 +010010741 SND_PCI_QUIRK(0x103c, 0x130b, "HP xw8*00", ALC262_HP_BPC),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010742 SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010743 SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010744 SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010745 SND_PCI_QUIRK(0x103c, 0x2803, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010746 SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010747 SND_PCI_QUIRK(0x103c, 0x2805, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010748 SND_PCI_QUIRK(0x103c, 0x2806, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010749 SND_PCI_QUIRK(0x103c, 0x2807, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010750 SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC),
10751 SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC),
10752 SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC),
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010753 SND_PCI_QUIRK(0x103c, 0x302f, "HP Thin Client T5735",
10754 ALC262_HP_TC_T5735),
Kailang Yang8c427222008-01-10 13:03:59 +010010755 SND_PCI_QUIRK(0x103c, 0x2817, "HP RP5700", ALC262_HP_RP5700),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010756 SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010757 SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010758 SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD),
10759 SND_PCI_QUIRK(0x104d, 0x900e, "Sony ASSAMD", ALC262_SONY_ASSAMD),
10760 SND_PCI_QUIRK(0x104d, 0x9015, "Sony 0x9015", ALC262_SONY_ASSAMD),
Takashi Iwai57a5ef42008-11-28 14:46:28 +010010761 SND_PCI_QUIRK(0x104d, 0x9033, "Sony VAIO VGN-SR19XN",
10762 ALC262_SONY_ASSAMD),
Akio Idehara36ca6e12008-06-09 22:57:40 +090010763 SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1",
Hiroshi Miura9f99a632008-08-28 16:09:06 +020010764 ALC262_TOSHIBA_RX1),
Kailang Yang80ffe862008-10-15 11:23:27 +020010765 SND_PCI_QUIRK(0x1179, 0xff7b, "Toshiba S06", ALC262_TOSHIBA_S06),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010766 SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU),
Tony Vroon3f1eeae2008-02-25 16:44:13 +010010767 SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU),
Tony Vroonba340e82009-02-02 19:01:30 +000010768 SND_PCI_QUIRK(0x10f1, 0x2915, "Tyan Thunder n6650W", ALC262_TYAN),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010769 SND_PCI_QUIRK(0x144d, 0xc032, "Samsung Q1 Ultra", ALC262_ULTRA),
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010770 SND_PCI_QUIRK(0x144d, 0xc039, "Samsung Q1U EL", ALC262_ULTRA),
Luke Yelavich3e420e72008-12-16 12:37:47 +110010771 SND_PCI_QUIRK(0x144d, 0xc510, "Samsung Q45", ALC262_HIPPO),
Jiang zhe0e31daf2008-03-20 12:12:39 +010010772 SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 y410", ALC262_LENOVO_3000),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010773 SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8),
Kailang Yang83c34212007-07-05 11:43:05 +020010774 SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010775 SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1),
Kailang Yangdf694da2005-12-05 19:42:22 +010010776 {}
10777};
10778
10779static struct alc_config_preset alc262_presets[] = {
10780 [ALC262_BASIC] = {
10781 .mixers = { alc262_base_mixer },
10782 .init_verbs = { alc262_init_verbs },
10783 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10784 .dac_nids = alc262_dac_nids,
10785 .hp_nid = 0x03,
10786 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10787 .channel_mode = alc262_modes,
Takashi Iwaia3bcba32005-12-06 19:05:29 +010010788 .input_mux = &alc262_capture_source,
Kailang Yangdf694da2005-12-05 19:42:22 +010010789 },
Kailang Yangccc656c2006-10-17 12:32:26 +020010790 [ALC262_HIPPO] = {
10791 .mixers = { alc262_base_mixer },
10792 .init_verbs = { alc262_init_verbs, alc262_hippo_unsol_verbs},
10793 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10794 .dac_nids = alc262_dac_nids,
10795 .hp_nid = 0x03,
10796 .dig_out_nid = ALC262_DIGOUT_NID,
10797 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10798 .channel_mode = alc262_modes,
10799 .input_mux = &alc262_capture_source,
10800 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +020010801 .init_hook = alc262_hippo_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020010802 },
10803 [ALC262_HIPPO_1] = {
10804 .mixers = { alc262_hippo1_mixer },
10805 .init_verbs = { alc262_init_verbs, alc262_hippo1_unsol_verbs},
10806 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10807 .dac_nids = alc262_dac_nids,
10808 .hp_nid = 0x02,
10809 .dig_out_nid = ALC262_DIGOUT_NID,
10810 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10811 .channel_mode = alc262_modes,
10812 .input_mux = &alc262_capture_source,
10813 .unsol_event = alc262_hippo1_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +020010814 .init_hook = alc262_hippo1_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020010815 },
Takashi Iwai834be882006-03-01 14:16:17 +010010816 [ALC262_FUJITSU] = {
10817 .mixers = { alc262_fujitsu_mixer },
Takashi Iwai39d3ed32007-10-12 15:03:48 +020010818 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
10819 alc262_fujitsu_unsol_verbs },
Takashi Iwai834be882006-03-01 14:16:17 +010010820 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10821 .dac_nids = alc262_dac_nids,
10822 .hp_nid = 0x03,
10823 .dig_out_nid = ALC262_DIGOUT_NID,
10824 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10825 .channel_mode = alc262_modes,
10826 .input_mux = &alc262_fujitsu_capture_source,
Takashi Iwaiae6b8132006-03-03 16:47:17 +010010827 .unsol_event = alc262_fujitsu_unsol_event,
Takashi Iwaiebc7a402008-05-20 09:23:05 +020010828 .init_hook = alc262_fujitsu_init_hook,
Takashi Iwai834be882006-03-01 14:16:17 +010010829 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010830 [ALC262_HP_BPC] = {
10831 .mixers = { alc262_HP_BPC_mixer },
10832 .init_verbs = { alc262_HP_BPC_init_verbs },
10833 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10834 .dac_nids = alc262_dac_nids,
10835 .hp_nid = 0x03,
10836 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10837 .channel_mode = alc262_modes,
10838 .input_mux = &alc262_HP_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010010839 .unsol_event = alc262_hp_bpc_unsol_event,
10840 .init_hook = alc262_hp_bpc_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010841 },
Kailang Yangcd7509a2007-01-26 18:33:17 +010010842 [ALC262_HP_BPC_D7000_WF] = {
10843 .mixers = { alc262_HP_BPC_WildWest_mixer },
10844 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
10845 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10846 .dac_nids = alc262_dac_nids,
10847 .hp_nid = 0x03,
10848 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10849 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +020010850 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010010851 .unsol_event = alc262_hp_wildwest_unsol_event,
10852 .init_hook = alc262_hp_wildwest_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010853 },
Kailang Yangcd7509a2007-01-26 18:33:17 +010010854 [ALC262_HP_BPC_D7000_WL] = {
10855 .mixers = { alc262_HP_BPC_WildWest_mixer,
10856 alc262_HP_BPC_WildWest_option_mixer },
10857 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
10858 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10859 .dac_nids = alc262_dac_nids,
10860 .hp_nid = 0x03,
10861 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10862 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +020010863 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010010864 .unsol_event = alc262_hp_wildwest_unsol_event,
10865 .init_hook = alc262_hp_wildwest_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010866 },
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010867 [ALC262_HP_TC_T5735] = {
10868 .mixers = { alc262_hp_t5735_mixer },
10869 .init_verbs = { alc262_init_verbs, alc262_hp_t5735_verbs },
10870 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10871 .dac_nids = alc262_dac_nids,
10872 .hp_nid = 0x03,
10873 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10874 .channel_mode = alc262_modes,
10875 .input_mux = &alc262_capture_source,
10876 .unsol_event = alc262_hp_t5735_unsol_event,
10877 .init_hook = alc262_hp_t5735_init_hook,
Kailang Yang8c427222008-01-10 13:03:59 +010010878 },
10879 [ALC262_HP_RP5700] = {
10880 .mixers = { alc262_hp_rp5700_mixer },
10881 .init_verbs = { alc262_init_verbs, alc262_hp_rp5700_verbs },
10882 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10883 .dac_nids = alc262_dac_nids,
10884 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10885 .channel_mode = alc262_modes,
10886 .input_mux = &alc262_hp_rp5700_capture_source,
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010887 },
Takashi Iwai304dcaa2006-07-25 14:51:16 +020010888 [ALC262_BENQ_ED8] = {
10889 .mixers = { alc262_base_mixer },
10890 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs },
10891 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10892 .dac_nids = alc262_dac_nids,
10893 .hp_nid = 0x03,
10894 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10895 .channel_mode = alc262_modes,
10896 .input_mux = &alc262_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010897 },
Kailang Yang272a5272007-05-14 11:00:38 +020010898 [ALC262_SONY_ASSAMD] = {
10899 .mixers = { alc262_sony_mixer },
10900 .init_verbs = { alc262_init_verbs, alc262_sony_unsol_verbs},
10901 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10902 .dac_nids = alc262_dac_nids,
10903 .hp_nid = 0x02,
10904 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10905 .channel_mode = alc262_modes,
10906 .input_mux = &alc262_capture_source,
10907 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +020010908 .init_hook = alc262_hippo_automute,
Kailang Yang83c34212007-07-05 11:43:05 +020010909 },
10910 [ALC262_BENQ_T31] = {
10911 .mixers = { alc262_benq_t31_mixer },
10912 .init_verbs = { alc262_init_verbs, alc262_benq_t31_EAPD_verbs, alc262_hippo_unsol_verbs },
10913 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10914 .dac_nids = alc262_dac_nids,
10915 .hp_nid = 0x03,
10916 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10917 .channel_mode = alc262_modes,
10918 .input_mux = &alc262_capture_source,
10919 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +020010920 .init_hook = alc262_hippo_automute,
Kailang Yangea1fb292008-08-26 12:58:38 +020010921 },
Tobin Davisf651b502007-10-26 12:40:47 +020010922 [ALC262_ULTRA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010923 .mixers = { alc262_ultra_mixer },
10924 .cap_mixer = alc262_ultra_capture_mixer,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010925 .init_verbs = { alc262_ultra_verbs },
Tobin Davisf651b502007-10-26 12:40:47 +020010926 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10927 .dac_nids = alc262_dac_nids,
Tobin Davisf651b502007-10-26 12:40:47 +020010928 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10929 .channel_mode = alc262_modes,
10930 .input_mux = &alc262_ultra_capture_source,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010931 .adc_nids = alc262_adc_nids, /* ADC0 */
10932 .capsrc_nids = alc262_capsrc_nids,
10933 .num_adc_nids = 1, /* single ADC */
Tobin Davisf651b502007-10-26 12:40:47 +020010934 .unsol_event = alc262_ultra_unsol_event,
10935 .init_hook = alc262_ultra_automute,
10936 },
Jiang zhe0e31daf2008-03-20 12:12:39 +010010937 [ALC262_LENOVO_3000] = {
10938 .mixers = { alc262_lenovo_3000_mixer },
10939 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
10940 alc262_lenovo_3000_unsol_verbs },
10941 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10942 .dac_nids = alc262_dac_nids,
10943 .hp_nid = 0x03,
10944 .dig_out_nid = ALC262_DIGOUT_NID,
10945 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10946 .channel_mode = alc262_modes,
10947 .input_mux = &alc262_fujitsu_capture_source,
10948 .unsol_event = alc262_lenovo_3000_unsol_event,
10949 },
Pascal Terjane8f9ae22008-08-04 14:36:05 +020010950 [ALC262_NEC] = {
10951 .mixers = { alc262_nec_mixer },
10952 .init_verbs = { alc262_nec_verbs },
10953 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10954 .dac_nids = alc262_dac_nids,
10955 .hp_nid = 0x03,
10956 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10957 .channel_mode = alc262_modes,
10958 .input_mux = &alc262_capture_source,
10959 },
Kailang Yang4e555fe2008-08-26 13:05:55 +020010960 [ALC262_TOSHIBA_S06] = {
10961 .mixers = { alc262_toshiba_s06_mixer },
10962 .init_verbs = { alc262_init_verbs, alc262_toshiba_s06_verbs,
10963 alc262_eapd_verbs },
10964 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10965 .capsrc_nids = alc262_dmic_capsrc_nids,
10966 .dac_nids = alc262_dac_nids,
10967 .adc_nids = alc262_dmic_adc_nids, /* ADC0 */
10968 .dig_out_nid = ALC262_DIGOUT_NID,
10969 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10970 .channel_mode = alc262_modes,
10971 .input_mux = &alc262_dmic_capture_source,
10972 .unsol_event = alc262_toshiba_s06_unsol_event,
10973 .init_hook = alc262_toshiba_s06_init_hook,
10974 },
Hiroshi Miura9f99a632008-08-28 16:09:06 +020010975 [ALC262_TOSHIBA_RX1] = {
10976 .mixers = { alc262_toshiba_rx1_mixer },
10977 .init_verbs = { alc262_init_verbs, alc262_toshiba_rx1_unsol_verbs },
10978 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10979 .dac_nids = alc262_dac_nids,
10980 .hp_nid = 0x03,
10981 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10982 .channel_mode = alc262_modes,
10983 .input_mux = &alc262_capture_source,
10984 .unsol_event = alc262_hippo_unsol_event,
10985 .init_hook = alc262_hippo_automute,
10986 },
Tony Vroonba340e82009-02-02 19:01:30 +000010987 [ALC262_TYAN] = {
10988 .mixers = { alc262_tyan_mixer },
10989 .init_verbs = { alc262_init_verbs, alc262_tyan_verbs},
10990 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10991 .dac_nids = alc262_dac_nids,
10992 .hp_nid = 0x02,
10993 .dig_out_nid = ALC262_DIGOUT_NID,
10994 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10995 .channel_mode = alc262_modes,
10996 .input_mux = &alc262_capture_source,
10997 .unsol_event = alc262_tyan_unsol_event,
10998 .init_hook = alc262_tyan_automute,
10999 },
Kailang Yangdf694da2005-12-05 19:42:22 +010011000};
11001
11002static int patch_alc262(struct hda_codec *codec)
11003{
11004 struct alc_spec *spec;
11005 int board_config;
11006 int err;
11007
Robert P. J. Daydc041e02006-12-19 14:44:15 +010011008 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010011009 if (spec == NULL)
11010 return -ENOMEM;
11011
11012 codec->spec = spec;
11013#if 0
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011014 /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is
11015 * under-run
11016 */
Kailang Yangdf694da2005-12-05 19:42:22 +010011017 {
11018 int tmp;
11019 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
11020 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
11021 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
11022 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80);
11023 }
11024#endif
11025
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020011026 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
11027
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011028 board_config = snd_hda_check_board_config(codec, ALC262_MODEL_LAST,
11029 alc262_models,
11030 alc262_cfg_tbl);
Kailang Yangcd7509a2007-01-26 18:33:17 +010011031
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011032 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011033 printk(KERN_INFO "hda_codec: Unknown model for ALC262, "
11034 "trying auto-probe from BIOS...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010011035 board_config = ALC262_AUTO;
11036 }
11037
11038 if (board_config == ALC262_AUTO) {
11039 /* automatic parse from the BIOS config */
11040 err = alc262_parse_auto_config(codec);
11041 if (err < 0) {
11042 alc_free(codec);
11043 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011044 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011045 printk(KERN_INFO
11046 "hda_codec: Cannot set up configuration "
11047 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010011048 board_config = ALC262_BASIC;
11049 }
11050 }
11051
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090011052 err = snd_hda_attach_beep_device(codec, 0x1);
11053 if (err < 0) {
11054 alc_free(codec);
11055 return err;
11056 }
11057
Kailang Yangdf694da2005-12-05 19:42:22 +010011058 if (board_config != ALC262_AUTO)
11059 setup_preset(spec, &alc262_presets[board_config]);
11060
11061 spec->stream_name_analog = "ALC262 Analog";
11062 spec->stream_analog_playback = &alc262_pcm_analog_playback;
11063 spec->stream_analog_capture = &alc262_pcm_analog_capture;
Kailang Yangea1fb292008-08-26 12:58:38 +020011064
Kailang Yangdf694da2005-12-05 19:42:22 +010011065 spec->stream_name_digital = "ALC262 Digital";
11066 spec->stream_digital_playback = &alc262_pcm_digital_playback;
11067 spec->stream_digital_capture = &alc262_pcm_digital_capture;
11068
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020011069 spec->capture_style = CAPT_MIX;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011070 if (!spec->adc_nids && spec->input_mux) {
Kailang Yangdf694da2005-12-05 19:42:22 +010011071 /* check whether NID 0x07 is valid */
Takashi Iwai4a471b72005-12-07 13:56:29 +010011072 unsigned int wcap = get_wcaps(codec, 0x07);
11073
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011074 /* get type */
11075 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Kailang Yangdf694da2005-12-05 19:42:22 +010011076 if (wcap != AC_WID_AUD_IN) {
11077 spec->adc_nids = alc262_adc_nids_alt;
11078 spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids_alt);
Takashi Iwai88c71a92008-02-14 17:27:17 +010011079 spec->capsrc_nids = alc262_capsrc_nids_alt;
Kailang Yangdf694da2005-12-05 19:42:22 +010011080 } else {
11081 spec->adc_nids = alc262_adc_nids;
11082 spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids);
Takashi Iwai88c71a92008-02-14 17:27:17 +010011083 spec->capsrc_nids = alc262_capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +010011084 }
11085 }
Takashi Iwaie64f14f2009-01-20 18:32:55 +010011086 if (!spec->cap_mixer && !spec->no_analog)
Takashi Iwaif9e336f2008-10-31 16:37:07 +010011087 set_capture_mixer(spec);
Kailang Yangdf694da2005-12-05 19:42:22 +010011088
Takashi Iwai2134ea42008-01-10 16:53:55 +010011089 spec->vmaster_nid = 0x0c;
11090
Kailang Yangdf694da2005-12-05 19:42:22 +010011091 codec->patch_ops = alc_patch_ops;
11092 if (board_config == ALC262_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +010011093 spec->init_hook = alc262_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020011094#ifdef CONFIG_SND_HDA_POWER_SAVE
11095 if (!spec->loopback.amplist)
11096 spec->loopback.amplist = alc262_loopbacks;
11097#endif
Takashi Iwaidaead532008-11-28 12:55:36 +010011098 codec->proc_widget_hook = print_realtek_coef;
Kailang Yangea1fb292008-08-26 12:58:38 +020011099
Kailang Yangdf694da2005-12-05 19:42:22 +010011100 return 0;
11101}
11102
Kailang Yangdf694da2005-12-05 19:42:22 +010011103/*
Kailang Yanga361d842007-06-05 12:30:55 +020011104 * ALC268 channel source setting (2 channel)
11105 */
11106#define ALC268_DIGOUT_NID ALC880_DIGOUT_NID
11107#define alc268_modes alc260_modes
Kailang Yangea1fb292008-08-26 12:58:38 +020011108
Kailang Yanga361d842007-06-05 12:30:55 +020011109static hda_nid_t alc268_dac_nids[2] = {
11110 /* front, hp */
11111 0x02, 0x03
11112};
11113
11114static hda_nid_t alc268_adc_nids[2] = {
11115 /* ADC0-1 */
11116 0x08, 0x07
11117};
11118
11119static hda_nid_t alc268_adc_nids_alt[1] = {
11120 /* ADC0 */
11121 0x08
11122};
11123
Takashi Iwaie1406342008-02-11 18:32:32 +010011124static hda_nid_t alc268_capsrc_nids[2] = { 0x23, 0x24 };
11125
Kailang Yanga361d842007-06-05 12:30:55 +020011126static struct snd_kcontrol_new alc268_base_mixer[] = {
11127 /* output mixer control */
11128 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
11129 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11130 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
11131 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai33bf17a2007-08-21 11:51:42 +020011132 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11133 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
11134 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
Kailang Yanga361d842007-06-05 12:30:55 +020011135 { }
11136};
11137
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011138/* bind Beep switches of both NID 0x0f and 0x10 */
11139static struct hda_bind_ctls alc268_bind_beep_sw = {
11140 .ops = &snd_hda_bind_sw,
11141 .values = {
11142 HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT),
11143 HDA_COMPOSE_AMP_VAL(0x10, 3, 1, HDA_INPUT),
11144 0
11145 },
11146};
11147
11148static struct snd_kcontrol_new alc268_beep_mixer[] = {
11149 HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT),
11150 HDA_BIND_SW("Beep Playback Switch", &alc268_bind_beep_sw),
11151 { }
11152};
11153
Kailang Yangd1a991a2007-08-15 16:21:59 +020011154static struct hda_verb alc268_eapd_verbs[] = {
11155 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
11156 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
11157 { }
11158};
11159
Takashi Iwaid2738092007-08-16 14:59:45 +020011160/* Toshiba specific */
11161#define alc268_toshiba_automute alc262_hippo_automute
11162
11163static struct hda_verb alc268_toshiba_verbs[] = {
11164 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
11165 { } /* end */
11166};
11167
Kailang Yang8ef355d2008-08-26 13:10:22 +020011168static struct hda_input_mux alc268_acer_lc_capture_source = {
11169 .num_items = 2,
11170 .items = {
11171 { "i-Mic", 0x6 },
11172 { "E-Mic", 0x0 },
11173 },
11174};
11175
Takashi Iwaid2738092007-08-16 14:59:45 +020011176/* Acer specific */
Takashi Iwai889c4392007-08-23 18:56:52 +020011177/* bind volumes of both NID 0x02 and 0x03 */
Takashi Iwai6bc96852007-08-17 09:02:12 +020011178static struct hda_bind_ctls alc268_acer_bind_master_vol = {
11179 .ops = &snd_hda_bind_vol,
11180 .values = {
11181 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
11182 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
11183 0
11184 },
11185};
11186
Takashi Iwai889c4392007-08-23 18:56:52 +020011187/* mute/unmute internal speaker according to the hp jack and mute state */
11188static void alc268_acer_automute(struct hda_codec *codec, int force)
11189{
11190 struct alc_spec *spec = codec->spec;
11191 unsigned int mute;
11192
11193 if (force || !spec->sense_updated) {
11194 unsigned int present;
11195 present = snd_hda_codec_read(codec, 0x14, 0,
11196 AC_VERB_GET_PIN_SENSE, 0);
11197 spec->jack_present = (present & 0x80000000) != 0;
11198 spec->sense_updated = 1;
11199 }
11200 if (spec->jack_present)
11201 mute = HDA_AMP_MUTE; /* mute internal speaker */
11202 else /* unmute internal speaker if necessary */
11203 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
11204 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
11205 HDA_AMP_MUTE, mute);
11206}
11207
11208
11209/* bind hp and internal speaker mute (with plug check) */
11210static int alc268_acer_master_sw_put(struct snd_kcontrol *kcontrol,
11211 struct snd_ctl_elem_value *ucontrol)
11212{
11213 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
11214 long *valp = ucontrol->value.integer.value;
11215 int change;
11216
11217 change = snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0,
11218 HDA_AMP_MUTE,
11219 valp[0] ? 0 : HDA_AMP_MUTE);
11220 change |= snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0,
11221 HDA_AMP_MUTE,
11222 valp[1] ? 0 : HDA_AMP_MUTE);
11223 if (change)
11224 alc268_acer_automute(codec, 0);
11225 return change;
11226}
Takashi Iwaid2738092007-08-16 14:59:45 +020011227
Kailang Yang8ef355d2008-08-26 13:10:22 +020011228static struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = {
11229 /* output mixer control */
11230 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
11231 {
11232 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11233 .name = "Master Playback Switch",
11234 .info = snd_hda_mixer_amp_switch_info,
11235 .get = snd_hda_mixer_amp_switch_get,
11236 .put = alc268_acer_master_sw_put,
11237 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
11238 },
11239 HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x18, 0, HDA_INPUT),
11240 { }
11241};
11242
Takashi Iwaid2738092007-08-16 14:59:45 +020011243static struct snd_kcontrol_new alc268_acer_mixer[] = {
11244 /* output mixer control */
11245 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
11246 {
11247 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11248 .name = "Master Playback Switch",
11249 .info = snd_hda_mixer_amp_switch_info,
11250 .get = snd_hda_mixer_amp_switch_get,
11251 .put = alc268_acer_master_sw_put,
11252 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
11253 },
Takashi Iwai33bf17a2007-08-21 11:51:42 +020011254 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11255 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
11256 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
Takashi Iwaid2738092007-08-16 14:59:45 +020011257 { }
11258};
11259
Takashi Iwaic238b4f2008-11-05 14:57:20 +010011260static struct snd_kcontrol_new alc268_acer_dmic_mixer[] = {
11261 /* output mixer control */
11262 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
11263 {
11264 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11265 .name = "Master Playback Switch",
11266 .info = snd_hda_mixer_amp_switch_info,
11267 .get = snd_hda_mixer_amp_switch_get,
11268 .put = alc268_acer_master_sw_put,
11269 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
11270 },
11271 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11272 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
11273 { }
11274};
11275
Kailang Yang8ef355d2008-08-26 13:10:22 +020011276static struct hda_verb alc268_acer_aspire_one_verbs[] = {
11277 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11278 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11279 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
11280 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
11281 {0x23, AC_VERB_SET_CONNECT_SEL, 0x06},
11282 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, 0xa017},
11283 { }
11284};
11285
Takashi Iwaid2738092007-08-16 14:59:45 +020011286static struct hda_verb alc268_acer_verbs[] = {
Takashi Iwai0ccb5412008-03-06 16:58:35 +010011287 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* internal dmic? */
11288 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaid2738092007-08-16 14:59:45 +020011289 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11290 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai0ccb5412008-03-06 16:58:35 +010011291 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
11292 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaid2738092007-08-16 14:59:45 +020011293 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
11294 { }
11295};
11296
11297/* unsolicited event for HP jack sensing */
11298static void alc268_toshiba_unsol_event(struct hda_codec *codec,
11299 unsigned int res)
11300{
Takashi Iwai889c4392007-08-23 18:56:52 +020011301 if ((res >> 26) != ALC880_HP_EVENT)
Takashi Iwaid2738092007-08-16 14:59:45 +020011302 return;
11303 alc268_toshiba_automute(codec);
11304}
11305
11306static void alc268_acer_unsol_event(struct hda_codec *codec,
11307 unsigned int res)
11308{
Takashi Iwai889c4392007-08-23 18:56:52 +020011309 if ((res >> 26) != ALC880_HP_EVENT)
Takashi Iwaid2738092007-08-16 14:59:45 +020011310 return;
11311 alc268_acer_automute(codec, 1);
11312}
11313
Takashi Iwai889c4392007-08-23 18:56:52 +020011314static void alc268_acer_init_hook(struct hda_codec *codec)
11315{
11316 alc268_acer_automute(codec, 1);
11317}
11318
Kailang Yang8ef355d2008-08-26 13:10:22 +020011319/* toggle speaker-output according to the hp-jack state */
11320static void alc268_aspire_one_speaker_automute(struct hda_codec *codec)
11321{
11322 unsigned int present;
11323 unsigned char bits;
11324
11325 present = snd_hda_codec_read(codec, 0x15, 0,
11326 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
11327 bits = present ? AMP_IN_MUTE(0) : 0;
11328 snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 0,
11329 AMP_IN_MUTE(0), bits);
11330 snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 1,
11331 AMP_IN_MUTE(0), bits);
11332}
11333
11334
11335static void alc268_acer_mic_automute(struct hda_codec *codec)
11336{
11337 unsigned int present;
11338
11339 present = snd_hda_codec_read(codec, 0x18, 0,
11340 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
11341 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_CONNECT_SEL,
11342 present ? 0x0 : 0x6);
11343}
11344
11345static void alc268_acer_lc_unsol_event(struct hda_codec *codec,
11346 unsigned int res)
11347{
11348 if ((res >> 26) == ALC880_HP_EVENT)
11349 alc268_aspire_one_speaker_automute(codec);
11350 if ((res >> 26) == ALC880_MIC_EVENT)
11351 alc268_acer_mic_automute(codec);
11352}
11353
11354static void alc268_acer_lc_init_hook(struct hda_codec *codec)
11355{
11356 alc268_aspire_one_speaker_automute(codec);
11357 alc268_acer_mic_automute(codec);
11358}
11359
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011360static struct snd_kcontrol_new alc268_dell_mixer[] = {
11361 /* output mixer control */
11362 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
11363 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11364 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
11365 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11366 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11367 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
11368 { }
11369};
11370
11371static struct hda_verb alc268_dell_verbs[] = {
11372 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11373 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11374 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
11375 { }
11376};
11377
11378/* mute/unmute internal speaker according to the hp jack and mute state */
11379static void alc268_dell_automute(struct hda_codec *codec)
11380{
11381 unsigned int present;
11382 unsigned int mute;
11383
11384 present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0);
11385 if (present & 0x80000000)
11386 mute = HDA_AMP_MUTE;
11387 else
11388 mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0);
11389 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
11390 HDA_AMP_MUTE, mute);
11391}
11392
11393static void alc268_dell_unsol_event(struct hda_codec *codec,
11394 unsigned int res)
11395{
11396 if ((res >> 26) != ALC880_HP_EVENT)
11397 return;
11398 alc268_dell_automute(codec);
11399}
11400
11401#define alc268_dell_init_hook alc268_dell_automute
11402
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020011403static struct snd_kcontrol_new alc267_quanta_il1_mixer[] = {
11404 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x2, 0x0, HDA_OUTPUT),
11405 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11406 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
11407 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11408 HDA_CODEC_VOLUME("Mic Capture Volume", 0x23, 0x0, HDA_OUTPUT),
11409 HDA_BIND_MUTE("Mic Capture Switch", 0x23, 2, HDA_OUTPUT),
11410 HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
11411 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
11412 { }
11413};
11414
11415static struct hda_verb alc267_quanta_il1_verbs[] = {
11416 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
11417 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
11418 { }
11419};
11420
11421static void alc267_quanta_il1_hp_automute(struct hda_codec *codec)
11422{
11423 unsigned int present;
11424
11425 present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0)
11426 & AC_PINSENSE_PRESENCE;
11427 snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
11428 present ? 0 : PIN_OUT);
11429}
11430
11431static void alc267_quanta_il1_mic_automute(struct hda_codec *codec)
11432{
11433 unsigned int present;
11434
11435 present = snd_hda_codec_read(codec, 0x18, 0,
11436 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
11437 snd_hda_codec_write(codec, 0x23, 0,
11438 AC_VERB_SET_CONNECT_SEL,
11439 present ? 0x00 : 0x01);
11440}
11441
11442static void alc267_quanta_il1_automute(struct hda_codec *codec)
11443{
11444 alc267_quanta_il1_hp_automute(codec);
11445 alc267_quanta_il1_mic_automute(codec);
11446}
11447
11448static void alc267_quanta_il1_unsol_event(struct hda_codec *codec,
11449 unsigned int res)
11450{
11451 switch (res >> 26) {
11452 case ALC880_HP_EVENT:
11453 alc267_quanta_il1_hp_automute(codec);
11454 break;
11455 case ALC880_MIC_EVENT:
11456 alc267_quanta_il1_mic_automute(codec);
11457 break;
11458 }
11459}
11460
Kailang Yanga361d842007-06-05 12:30:55 +020011461/*
11462 * generic initialization of ADC, input mixers and output mixers
11463 */
11464static struct hda_verb alc268_base_init_verbs[] = {
11465 /* Unmute DAC0-1 and set vol = 0 */
11466 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020011467 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020011468
11469 /*
11470 * Set up output mixers (0x0c - 0x0e)
11471 */
11472 /* set vol=0 to output mixers */
11473 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yanga361d842007-06-05 12:30:55 +020011474 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
11475
11476 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11477 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11478
11479 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
11480 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
11481 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
11482 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11483 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11484 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11485 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11486 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11487
11488 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11489 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11490 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11491 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020011492 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011493
11494 /* set PCBEEP vol = 0, mute connections */
11495 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11496 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11497 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020011498
Jiang Zhea9b3aa82007-12-20 13:13:13 +010011499 /* Unmute Selector 23h,24h and set the default input to mic-in */
Kailang Yangea1fb292008-08-26 12:58:38 +020011500
Jiang Zhea9b3aa82007-12-20 13:13:13 +010011501 {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
11502 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11503 {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
11504 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020011505
Kailang Yanga361d842007-06-05 12:30:55 +020011506 { }
11507};
11508
11509/*
11510 * generic initialization of ADC, input mixers and output mixers
11511 */
11512static struct hda_verb alc268_volume_init_verbs[] = {
11513 /* set output DAC */
Takashi Iwai4cfb91c2009-01-23 12:53:09 +010011514 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11515 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020011516
11517 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11518 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11519 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11520 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11521 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11522
Kailang Yanga361d842007-06-05 12:30:55 +020011523 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yanga361d842007-06-05 12:30:55 +020011524 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11525 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11526
11527 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020011528 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020011529
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011530 /* set PCBEEP vol = 0, mute connections */
11531 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11532 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11533 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020011534
11535 { }
11536};
11537
Kailang Yanga361d842007-06-05 12:30:55 +020011538static struct snd_kcontrol_new alc268_capture_alt_mixer[] = {
11539 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
11540 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
11541 {
11542 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11543 /* The multiple "Capture Source" controls confuse alsamixer
11544 * So call somewhat different..
Kailang Yanga361d842007-06-05 12:30:55 +020011545 */
11546 /* .name = "Capture Source", */
11547 .name = "Input Source",
11548 .count = 1,
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010011549 .info = alc_mux_enum_info,
11550 .get = alc_mux_enum_get,
11551 .put = alc_mux_enum_put,
Kailang Yanga361d842007-06-05 12:30:55 +020011552 },
11553 { } /* end */
11554};
11555
11556static struct snd_kcontrol_new alc268_capture_mixer[] = {
11557 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
11558 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
11559 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x24, 0x0, HDA_OUTPUT),
11560 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x24, 0x0, HDA_OUTPUT),
11561 {
11562 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11563 /* The multiple "Capture Source" controls confuse alsamixer
11564 * So call somewhat different..
Kailang Yanga361d842007-06-05 12:30:55 +020011565 */
11566 /* .name = "Capture Source", */
11567 .name = "Input Source",
11568 .count = 2,
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010011569 .info = alc_mux_enum_info,
11570 .get = alc_mux_enum_get,
11571 .put = alc_mux_enum_put,
Kailang Yanga361d842007-06-05 12:30:55 +020011572 },
11573 { } /* end */
11574};
11575
11576static struct hda_input_mux alc268_capture_source = {
11577 .num_items = 4,
11578 .items = {
11579 { "Mic", 0x0 },
11580 { "Front Mic", 0x1 },
11581 { "Line", 0x2 },
11582 { "CD", 0x3 },
11583 },
11584};
11585
Takashi Iwai0ccb5412008-03-06 16:58:35 +010011586static struct hda_input_mux alc268_acer_capture_source = {
11587 .num_items = 3,
11588 .items = {
11589 { "Mic", 0x0 },
Takashi Iwaic238b4f2008-11-05 14:57:20 +010011590 { "Internal Mic", 0x1 },
11591 { "Line", 0x2 },
11592 },
11593};
11594
11595static struct hda_input_mux alc268_acer_dmic_capture_source = {
11596 .num_items = 3,
11597 .items = {
11598 { "Mic", 0x0 },
Takashi Iwai0ccb5412008-03-06 16:58:35 +010011599 { "Internal Mic", 0x6 },
11600 { "Line", 0x2 },
11601 },
11602};
11603
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010011604#ifdef CONFIG_SND_DEBUG
11605static struct snd_kcontrol_new alc268_test_mixer[] = {
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010011606 /* Volume widgets */
11607 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x02, 0x0, HDA_OUTPUT),
11608 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x03, 0x0, HDA_OUTPUT),
11609 HDA_BIND_MUTE_MONO("Mono sum Playback Switch", 0x0e, 1, 2, HDA_INPUT),
11610 HDA_BIND_MUTE("LINE-OUT sum Playback Switch", 0x0f, 2, HDA_INPUT),
11611 HDA_BIND_MUTE("HP-OUT sum Playback Switch", 0x10, 2, HDA_INPUT),
11612 HDA_BIND_MUTE("LINE-OUT Playback Switch", 0x14, 2, HDA_OUTPUT),
11613 HDA_BIND_MUTE("HP-OUT Playback Switch", 0x15, 2, HDA_OUTPUT),
11614 HDA_BIND_MUTE("Mono Playback Switch", 0x16, 2, HDA_OUTPUT),
11615 HDA_CODEC_VOLUME("MIC1 Capture Volume", 0x18, 0x0, HDA_INPUT),
11616 HDA_BIND_MUTE("MIC1 Capture Switch", 0x18, 2, HDA_OUTPUT),
11617 HDA_CODEC_VOLUME("MIC2 Capture Volume", 0x19, 0x0, HDA_INPUT),
11618 HDA_CODEC_VOLUME("LINE1 Capture Volume", 0x1a, 0x0, HDA_INPUT),
11619 HDA_BIND_MUTE("LINE1 Capture Switch", 0x1a, 2, HDA_OUTPUT),
Takashi Iwaif0747ee2008-01-15 11:41:41 +010011620 /* The below appears problematic on some hardwares */
11621 /*HDA_CODEC_VOLUME("PCBEEP Playback Volume", 0x1d, 0x0, HDA_INPUT),*/
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010011622 HDA_CODEC_VOLUME("PCM-IN1 Capture Volume", 0x23, 0x0, HDA_OUTPUT),
11623 HDA_BIND_MUTE("PCM-IN1 Capture Switch", 0x23, 2, HDA_OUTPUT),
11624 HDA_CODEC_VOLUME("PCM-IN2 Capture Volume", 0x24, 0x0, HDA_OUTPUT),
11625 HDA_BIND_MUTE("PCM-IN2 Capture Switch", 0x24, 2, HDA_OUTPUT),
11626
11627 /* Modes for retasking pin widgets */
11628 ALC_PIN_MODE("LINE-OUT pin mode", 0x14, ALC_PIN_DIR_INOUT),
11629 ALC_PIN_MODE("HP-OUT pin mode", 0x15, ALC_PIN_DIR_INOUT),
11630 ALC_PIN_MODE("MIC1 pin mode", 0x18, ALC_PIN_DIR_INOUT),
11631 ALC_PIN_MODE("LINE1 pin mode", 0x1a, ALC_PIN_DIR_INOUT),
11632
11633 /* Controls for GPIO pins, assuming they are configured as outputs */
11634 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
11635 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
11636 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
11637 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
11638
11639 /* Switches to allow the digital SPDIF output pin to be enabled.
11640 * The ALC268 does not have an SPDIF input.
11641 */
11642 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x06, 0x01),
11643
11644 /* A switch allowing EAPD to be enabled. Some laptops seem to use
11645 * this output to turn on an external amplifier.
11646 */
11647 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
11648 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
11649
11650 { } /* end */
11651};
11652#endif
11653
Kailang Yanga361d842007-06-05 12:30:55 +020011654/* create input playback/capture controls for the given pin */
11655static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
11656 const char *ctlname, int idx)
11657{
11658 char name[32];
11659 int err;
11660
11661 sprintf(name, "%s Playback Volume", ctlname);
11662 if (nid == 0x14) {
11663 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
11664 HDA_COMPOSE_AMP_VAL(0x02, 3, idx,
11665 HDA_OUTPUT));
11666 if (err < 0)
11667 return err;
11668 } else if (nid == 0x15) {
11669 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
11670 HDA_COMPOSE_AMP_VAL(0x03, 3, idx,
11671 HDA_OUTPUT));
11672 if (err < 0)
11673 return err;
11674 } else
11675 return -1;
11676 sprintf(name, "%s Playback Switch", ctlname);
11677 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
11678 HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
11679 if (err < 0)
11680 return err;
11681 return 0;
11682}
11683
11684/* add playback controls from the parsed DAC table */
11685static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
11686 const struct auto_pin_cfg *cfg)
11687{
11688 hda_nid_t nid;
11689 int err;
11690
11691 spec->multiout.num_dacs = 2; /* only use one dac */
11692 spec->multiout.dac_nids = spec->private_dac_nids;
11693 spec->multiout.dac_nids[0] = 2;
11694 spec->multiout.dac_nids[1] = 3;
11695
11696 nid = cfg->line_out_pins[0];
11697 if (nid)
Kailang Yangea1fb292008-08-26 12:58:38 +020011698 alc268_new_analog_output(spec, nid, "Front", 0);
Kailang Yanga361d842007-06-05 12:30:55 +020011699
11700 nid = cfg->speaker_pins[0];
11701 if (nid == 0x1d) {
11702 err = add_control(spec, ALC_CTL_WIDGET_VOL,
11703 "Speaker Playback Volume",
11704 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
11705 if (err < 0)
11706 return err;
11707 }
11708 nid = cfg->hp_pins[0];
11709 if (nid)
11710 alc268_new_analog_output(spec, nid, "Headphone", 0);
11711
11712 nid = cfg->line_out_pins[1] | cfg->line_out_pins[2];
11713 if (nid == 0x16) {
11714 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
11715 "Mono Playback Switch",
11716 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_INPUT));
11717 if (err < 0)
11718 return err;
11719 }
Kailang Yangea1fb292008-08-26 12:58:38 +020011720 return 0;
Kailang Yanga361d842007-06-05 12:30:55 +020011721}
11722
11723/* create playback/capture controls for input pins */
11724static int alc268_auto_create_analog_input_ctls(struct alc_spec *spec,
11725 const struct auto_pin_cfg *cfg)
11726{
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020011727 struct hda_input_mux *imux = &spec->private_imux[0];
Kailang Yanga361d842007-06-05 12:30:55 +020011728 int i, idx1;
11729
11730 for (i = 0; i < AUTO_PIN_LAST; i++) {
11731 switch(cfg->input_pins[i]) {
11732 case 0x18:
11733 idx1 = 0; /* Mic 1 */
11734 break;
11735 case 0x19:
11736 idx1 = 1; /* Mic 2 */
11737 break;
11738 case 0x1a:
11739 idx1 = 2; /* Line In */
11740 break;
Kailang Yangea1fb292008-08-26 12:58:38 +020011741 case 0x1c:
Kailang Yanga361d842007-06-05 12:30:55 +020011742 idx1 = 3; /* CD */
11743 break;
Takashi Iwai7194cae2008-03-06 16:58:17 +010011744 case 0x12:
11745 case 0x13:
11746 idx1 = 6; /* digital mics */
11747 break;
Kailang Yanga361d842007-06-05 12:30:55 +020011748 default:
11749 continue;
11750 }
11751 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
11752 imux->items[imux->num_items].index = idx1;
Kailang Yangea1fb292008-08-26 12:58:38 +020011753 imux->num_items++;
Kailang Yanga361d842007-06-05 12:30:55 +020011754 }
11755 return 0;
11756}
11757
11758static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec)
11759{
11760 struct alc_spec *spec = codec->spec;
11761 hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
11762 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
11763 hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
11764 unsigned int dac_vol1, dac_vol2;
11765
11766 if (speaker_nid) {
11767 snd_hda_codec_write(codec, speaker_nid, 0,
11768 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
11769 snd_hda_codec_write(codec, 0x0f, 0,
11770 AC_VERB_SET_AMP_GAIN_MUTE,
11771 AMP_IN_UNMUTE(1));
11772 snd_hda_codec_write(codec, 0x10, 0,
11773 AC_VERB_SET_AMP_GAIN_MUTE,
11774 AMP_IN_UNMUTE(1));
11775 } else {
11776 snd_hda_codec_write(codec, 0x0f, 0,
11777 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
11778 snd_hda_codec_write(codec, 0x10, 0,
11779 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
11780 }
11781
11782 dac_vol1 = dac_vol2 = 0xb000 | 0x40; /* set max volume */
Kailang Yangea1fb292008-08-26 12:58:38 +020011783 if (line_nid == 0x14)
Kailang Yanga361d842007-06-05 12:30:55 +020011784 dac_vol2 = AMP_OUT_ZERO;
11785 else if (line_nid == 0x15)
11786 dac_vol1 = AMP_OUT_ZERO;
Kailang Yangea1fb292008-08-26 12:58:38 +020011787 if (hp_nid == 0x14)
Kailang Yanga361d842007-06-05 12:30:55 +020011788 dac_vol2 = AMP_OUT_ZERO;
11789 else if (hp_nid == 0x15)
11790 dac_vol1 = AMP_OUT_ZERO;
11791 if (line_nid != 0x16 || hp_nid != 0x16 ||
11792 spec->autocfg.line_out_pins[1] != 0x16 ||
11793 spec->autocfg.line_out_pins[2] != 0x16)
11794 dac_vol1 = dac_vol2 = AMP_OUT_ZERO;
11795
11796 snd_hda_codec_write(codec, 0x02, 0,
11797 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol1);
11798 snd_hda_codec_write(codec, 0x03, 0,
11799 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol2);
11800}
11801
11802/* pcm configuration: identiacal with ALC880 */
11803#define alc268_pcm_analog_playback alc880_pcm_analog_playback
11804#define alc268_pcm_analog_capture alc880_pcm_analog_capture
Takashi Iwai63300792008-01-24 15:31:36 +010011805#define alc268_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
Kailang Yanga361d842007-06-05 12:30:55 +020011806#define alc268_pcm_digital_playback alc880_pcm_digital_playback
11807
11808/*
11809 * BIOS auto configuration
11810 */
11811static int alc268_parse_auto_config(struct hda_codec *codec)
11812{
11813 struct alc_spec *spec = codec->spec;
11814 int err;
11815 static hda_nid_t alc268_ignore[] = { 0 };
11816
11817 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
11818 alc268_ignore);
11819 if (err < 0)
11820 return err;
11821 if (!spec->autocfg.line_outs)
11822 return 0; /* can't find valid BIOS pin config */
11823
11824 err = alc268_auto_create_multi_out_ctls(spec, &spec->autocfg);
11825 if (err < 0)
11826 return err;
11827 err = alc268_auto_create_analog_input_ctls(spec, &spec->autocfg);
11828 if (err < 0)
11829 return err;
11830
11831 spec->multiout.max_channels = 2;
11832
11833 /* digital only support output */
11834 if (spec->autocfg.dig_out_pin)
11835 spec->multiout.dig_out_nid = ALC268_DIGOUT_NID;
11836
Takashi Iwai603c4012008-07-30 15:01:44 +020011837 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010011838 add_mixer(spec, spec->kctls.list);
Kailang Yanga361d842007-06-05 12:30:55 +020011839
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011840 if (spec->autocfg.speaker_pins[0] != 0x1d)
Takashi Iwaid88897e2008-10-31 15:01:37 +010011841 add_mixer(spec, alc268_beep_mixer);
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011842
Takashi Iwaid88897e2008-10-31 15:01:37 +010011843 add_verb(spec, alc268_volume_init_verbs);
Kailang Yanga361d842007-06-05 12:30:55 +020011844 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020011845 spec->input_mux = &spec->private_imux[0];
Kailang Yanga361d842007-06-05 12:30:55 +020011846
Takashi Iwai776e1842007-08-29 15:07:11 +020011847 err = alc_auto_add_mic_boost(codec);
11848 if (err < 0)
11849 return err;
11850
Takashi Iwaie044c392008-10-27 16:56:24 +010011851 store_pin_configs(codec);
Kailang Yanga361d842007-06-05 12:30:55 +020011852 return 1;
11853}
11854
11855#define alc268_auto_init_multi_out alc882_auto_init_multi_out
11856#define alc268_auto_init_hp_out alc882_auto_init_hp_out
11857#define alc268_auto_init_analog_input alc882_auto_init_analog_input
11858
11859/* init callback for auto-configuration model -- overriding the default init */
11860static void alc268_auto_init(struct hda_codec *codec)
11861{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010011862 struct alc_spec *spec = codec->spec;
Kailang Yanga361d842007-06-05 12:30:55 +020011863 alc268_auto_init_multi_out(codec);
11864 alc268_auto_init_hp_out(codec);
11865 alc268_auto_init_mono_speaker_out(codec);
11866 alc268_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010011867 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020011868 alc_inithook(codec);
Kailang Yanga361d842007-06-05 12:30:55 +020011869}
11870
11871/*
11872 * configuration and preset
11873 */
11874static const char *alc268_models[ALC268_MODEL_LAST] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020011875 [ALC267_QUANTA_IL1] = "quanta-il1",
Kailang Yanga361d842007-06-05 12:30:55 +020011876 [ALC268_3ST] = "3stack",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020011877 [ALC268_TOSHIBA] = "toshiba",
Takashi Iwaid2738092007-08-16 14:59:45 +020011878 [ALC268_ACER] = "acer",
Takashi Iwaic238b4f2008-11-05 14:57:20 +010011879 [ALC268_ACER_DMIC] = "acer-dmic",
Kailang Yang8ef355d2008-08-26 13:10:22 +020011880 [ALC268_ACER_ASPIRE_ONE] = "acer-aspire",
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011881 [ALC268_DELL] = "dell",
Mirco Tischlerf12462c2008-02-04 12:33:59 +010011882 [ALC268_ZEPTO] = "zepto",
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010011883#ifdef CONFIG_SND_DEBUG
11884 [ALC268_TEST] = "test",
11885#endif
Kailang Yanga361d842007-06-05 12:30:55 +020011886 [ALC268_AUTO] = "auto",
11887};
11888
11889static struct snd_pci_quirk alc268_cfg_tbl[] = {
Takashi Iwaia0b8f7d2008-04-22 19:39:49 +020011890 SND_PCI_QUIRK(0x1025, 0x011e, "Acer Aspire 5720z", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011891 SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER),
Andy Shevchenkodafc8352008-01-25 11:53:50 +010011892 SND_PCI_QUIRK(0x1025, 0x012e, "Acer Aspire 5310", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011893 SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER),
Andy Shevchenko29a52c22008-01-24 17:29:00 +010011894 SND_PCI_QUIRK(0x1025, 0x0136, "Acer Aspire 5315", ALC268_ACER),
Kailang Yang8ef355d2008-08-26 13:10:22 +020011895 SND_PCI_QUIRK(0x1025, 0x015b, "Acer Aspire One",
11896 ALC268_ACER_ASPIRE_ONE),
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011897 SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL),
Takashi Iwai57d13922009-01-08 15:52:09 +010011898 SND_PCI_QUIRK(0x1028, 0x02b0, "Dell Inspiron Mini9", ALC268_DELL),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011899 SND_PCI_QUIRK(0x103c, 0x30cc, "TOSHIBA", ALC268_TOSHIBA),
Kailang Yanga361d842007-06-05 12:30:55 +020011900 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST),
Kailang Yangd1a991a2007-08-15 16:21:59 +020011901 SND_PCI_QUIRK(0x1179, 0xff10, "TOSHIBA A205", ALC268_TOSHIBA),
Takashi Iwai8e7f00f2007-09-07 10:58:58 +020011902 SND_PCI_QUIRK(0x1179, 0xff50, "TOSHIBA A305", ALC268_TOSHIBA),
Travis Place2346d0c2008-09-01 08:24:00 +020011903 SND_PCI_QUIRK(0x1179, 0xff64, "TOSHIBA L305", ALC268_TOSHIBA),
Tony Vroon378bd6a2008-06-04 12:08:30 +020011904 SND_PCI_QUIRK(0x14c0, 0x0025, "COMPAL IFL90/JFL-92", ALC268_TOSHIBA),
Takashi Iwaib875bf32007-09-06 15:00:27 +020011905 SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER),
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020011906 SND_PCI_QUIRK(0x152d, 0x0771, "Quanta IL1", ALC267_QUANTA_IL1),
Mirco Tischlerf12462c2008-02-04 12:33:59 +010011907 SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO),
Kailang Yanga361d842007-06-05 12:30:55 +020011908 {}
11909};
11910
11911static struct alc_config_preset alc268_presets[] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020011912 [ALC267_QUANTA_IL1] = {
11913 .mixers = { alc267_quanta_il1_mixer },
11914 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
11915 alc267_quanta_il1_verbs },
11916 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11917 .dac_nids = alc268_dac_nids,
11918 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
11919 .adc_nids = alc268_adc_nids_alt,
11920 .hp_nid = 0x03,
11921 .num_channel_mode = ARRAY_SIZE(alc268_modes),
11922 .channel_mode = alc268_modes,
11923 .input_mux = &alc268_capture_source,
11924 .unsol_event = alc267_quanta_il1_unsol_event,
11925 .init_hook = alc267_quanta_il1_automute,
11926 },
Kailang Yanga361d842007-06-05 12:30:55 +020011927 [ALC268_3ST] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011928 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
11929 alc268_beep_mixer },
Kailang Yanga361d842007-06-05 12:30:55 +020011930 .init_verbs = { alc268_base_init_verbs },
11931 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11932 .dac_nids = alc268_dac_nids,
11933 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
11934 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010011935 .capsrc_nids = alc268_capsrc_nids,
Kailang Yanga361d842007-06-05 12:30:55 +020011936 .hp_nid = 0x03,
11937 .dig_out_nid = ALC268_DIGOUT_NID,
11938 .num_channel_mode = ARRAY_SIZE(alc268_modes),
11939 .channel_mode = alc268_modes,
11940 .input_mux = &alc268_capture_source,
11941 },
Kailang Yangd1a991a2007-08-15 16:21:59 +020011942 [ALC268_TOSHIBA] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011943 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
11944 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020011945 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
11946 alc268_toshiba_verbs },
Kailang Yangd1a991a2007-08-15 16:21:59 +020011947 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11948 .dac_nids = alc268_dac_nids,
11949 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
11950 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010011951 .capsrc_nids = alc268_capsrc_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020011952 .hp_nid = 0x03,
11953 .num_channel_mode = ARRAY_SIZE(alc268_modes),
11954 .channel_mode = alc268_modes,
11955 .input_mux = &alc268_capture_source,
Takashi Iwaid2738092007-08-16 14:59:45 +020011956 .unsol_event = alc268_toshiba_unsol_event,
11957 .init_hook = alc268_toshiba_automute,
11958 },
11959 [ALC268_ACER] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011960 .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer,
11961 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020011962 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
11963 alc268_acer_verbs },
11964 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11965 .dac_nids = alc268_dac_nids,
11966 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
11967 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010011968 .capsrc_nids = alc268_capsrc_nids,
Takashi Iwaid2738092007-08-16 14:59:45 +020011969 .hp_nid = 0x02,
11970 .num_channel_mode = ARRAY_SIZE(alc268_modes),
11971 .channel_mode = alc268_modes,
Takashi Iwai0ccb5412008-03-06 16:58:35 +010011972 .input_mux = &alc268_acer_capture_source,
Takashi Iwaid2738092007-08-16 14:59:45 +020011973 .unsol_event = alc268_acer_unsol_event,
Takashi Iwai889c4392007-08-23 18:56:52 +020011974 .init_hook = alc268_acer_init_hook,
Kailang Yangd1a991a2007-08-15 16:21:59 +020011975 },
Takashi Iwaic238b4f2008-11-05 14:57:20 +010011976 [ALC268_ACER_DMIC] = {
11977 .mixers = { alc268_acer_dmic_mixer, alc268_capture_alt_mixer,
11978 alc268_beep_mixer },
11979 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
11980 alc268_acer_verbs },
11981 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11982 .dac_nids = alc268_dac_nids,
11983 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
11984 .adc_nids = alc268_adc_nids_alt,
11985 .capsrc_nids = alc268_capsrc_nids,
11986 .hp_nid = 0x02,
11987 .num_channel_mode = ARRAY_SIZE(alc268_modes),
11988 .channel_mode = alc268_modes,
11989 .input_mux = &alc268_acer_dmic_capture_source,
11990 .unsol_event = alc268_acer_unsol_event,
11991 .init_hook = alc268_acer_init_hook,
11992 },
Kailang Yang8ef355d2008-08-26 13:10:22 +020011993 [ALC268_ACER_ASPIRE_ONE] = {
11994 .mixers = { alc268_acer_aspire_one_mixer,
11995 alc268_capture_alt_mixer },
11996 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
11997 alc268_acer_aspire_one_verbs },
11998 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11999 .dac_nids = alc268_dac_nids,
12000 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
12001 .adc_nids = alc268_adc_nids_alt,
12002 .capsrc_nids = alc268_capsrc_nids,
12003 .hp_nid = 0x03,
12004 .num_channel_mode = ARRAY_SIZE(alc268_modes),
12005 .channel_mode = alc268_modes,
12006 .input_mux = &alc268_acer_lc_capture_source,
12007 .unsol_event = alc268_acer_lc_unsol_event,
12008 .init_hook = alc268_acer_lc_init_hook,
12009 },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012010 [ALC268_DELL] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012011 .mixers = { alc268_dell_mixer, alc268_beep_mixer },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012012 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
12013 alc268_dell_verbs },
12014 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
12015 .dac_nids = alc268_dac_nids,
12016 .hp_nid = 0x02,
12017 .num_channel_mode = ARRAY_SIZE(alc268_modes),
12018 .channel_mode = alc268_modes,
12019 .unsol_event = alc268_dell_unsol_event,
12020 .init_hook = alc268_dell_init_hook,
12021 .input_mux = &alc268_capture_source,
12022 },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010012023 [ALC268_ZEPTO] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012024 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
12025 alc268_beep_mixer },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010012026 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
12027 alc268_toshiba_verbs },
12028 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
12029 .dac_nids = alc268_dac_nids,
12030 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
12031 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010012032 .capsrc_nids = alc268_capsrc_nids,
Mirco Tischlerf12462c2008-02-04 12:33:59 +010012033 .hp_nid = 0x03,
12034 .dig_out_nid = ALC268_DIGOUT_NID,
12035 .num_channel_mode = ARRAY_SIZE(alc268_modes),
12036 .channel_mode = alc268_modes,
12037 .input_mux = &alc268_capture_source,
12038 .unsol_event = alc268_toshiba_unsol_event,
12039 .init_hook = alc268_toshiba_automute
12040 },
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010012041#ifdef CONFIG_SND_DEBUG
12042 [ALC268_TEST] = {
12043 .mixers = { alc268_test_mixer, alc268_capture_mixer },
12044 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
12045 alc268_volume_init_verbs },
12046 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
12047 .dac_nids = alc268_dac_nids,
12048 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
12049 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010012050 .capsrc_nids = alc268_capsrc_nids,
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010012051 .hp_nid = 0x03,
12052 .dig_out_nid = ALC268_DIGOUT_NID,
12053 .num_channel_mode = ARRAY_SIZE(alc268_modes),
12054 .channel_mode = alc268_modes,
12055 .input_mux = &alc268_capture_source,
12056 },
12057#endif
Kailang Yanga361d842007-06-05 12:30:55 +020012058};
12059
12060static int patch_alc268(struct hda_codec *codec)
12061{
12062 struct alc_spec *spec;
12063 int board_config;
12064 int err;
12065
12066 spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
12067 if (spec == NULL)
12068 return -ENOMEM;
12069
12070 codec->spec = spec;
12071
12072 board_config = snd_hda_check_board_config(codec, ALC268_MODEL_LAST,
12073 alc268_models,
12074 alc268_cfg_tbl);
12075
12076 if (board_config < 0 || board_config >= ALC268_MODEL_LAST) {
12077 printk(KERN_INFO "hda_codec: Unknown model for ALC268, "
12078 "trying auto-probe from BIOS...\n");
12079 board_config = ALC268_AUTO;
12080 }
12081
12082 if (board_config == ALC268_AUTO) {
12083 /* automatic parse from the BIOS config */
12084 err = alc268_parse_auto_config(codec);
12085 if (err < 0) {
12086 alc_free(codec);
12087 return err;
12088 } else if (!err) {
12089 printk(KERN_INFO
12090 "hda_codec: Cannot set up configuration "
12091 "from BIOS. Using base mode...\n");
12092 board_config = ALC268_3ST;
12093 }
12094 }
12095
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090012096 err = snd_hda_attach_beep_device(codec, 0x1);
12097 if (err < 0) {
12098 alc_free(codec);
12099 return err;
12100 }
12101
Kailang Yanga361d842007-06-05 12:30:55 +020012102 if (board_config != ALC268_AUTO)
12103 setup_preset(spec, &alc268_presets[board_config]);
12104
Kailang Yang2f893282008-05-27 12:14:47 +020012105 if (codec->vendor_id == 0x10ec0267) {
12106 spec->stream_name_analog = "ALC267 Analog";
12107 spec->stream_name_digital = "ALC267 Digital";
12108 } else {
12109 spec->stream_name_analog = "ALC268 Analog";
12110 spec->stream_name_digital = "ALC268 Digital";
12111 }
12112
Kailang Yanga361d842007-06-05 12:30:55 +020012113 spec->stream_analog_playback = &alc268_pcm_analog_playback;
12114 spec->stream_analog_capture = &alc268_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +010012115 spec->stream_analog_alt_capture = &alc268_pcm_analog_alt_capture;
Kailang Yanga361d842007-06-05 12:30:55 +020012116
Kailang Yanga361d842007-06-05 12:30:55 +020012117 spec->stream_digital_playback = &alc268_pcm_digital_playback;
12118
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012119 if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
12120 /* override the amp caps for beep generator */
12121 snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT,
12122 (0x0c << AC_AMPCAP_OFFSET_SHIFT) |
12123 (0x0c << AC_AMPCAP_NUM_STEPS_SHIFT) |
12124 (0x07 << AC_AMPCAP_STEP_SIZE_SHIFT) |
12125 (0 << AC_AMPCAP_MUTE_SHIFT));
12126
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012127 if (!spec->adc_nids && spec->input_mux) {
12128 /* check whether NID 0x07 is valid */
12129 unsigned int wcap = get_wcaps(codec, 0x07);
Takashi Iwai85860c02008-02-19 15:00:15 +010012130 int i;
Kailang Yanga361d842007-06-05 12:30:55 +020012131
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012132 /* get type */
12133 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Takashi Iwai67ebcb02008-02-19 15:03:57 +010012134 if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012135 spec->adc_nids = alc268_adc_nids_alt;
12136 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt);
Takashi Iwaid88897e2008-10-31 15:01:37 +010012137 add_mixer(spec, alc268_capture_alt_mixer);
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012138 } else {
12139 spec->adc_nids = alc268_adc_nids;
12140 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids);
Takashi Iwaid88897e2008-10-31 15:01:37 +010012141 add_mixer(spec, alc268_capture_mixer);
Kailang Yanga361d842007-06-05 12:30:55 +020012142 }
Takashi Iwaie1406342008-02-11 18:32:32 +010012143 spec->capsrc_nids = alc268_capsrc_nids;
Takashi Iwai85860c02008-02-19 15:00:15 +010012144 /* set default input source */
12145 for (i = 0; i < spec->num_adc_nids; i++)
12146 snd_hda_codec_write_cache(codec, alc268_capsrc_nids[i],
12147 0, AC_VERB_SET_CONNECT_SEL,
12148 spec->input_mux->items[0].index);
Kailang Yanga361d842007-06-05 12:30:55 +020012149 }
Takashi Iwai2134ea42008-01-10 16:53:55 +010012150
12151 spec->vmaster_nid = 0x02;
12152
Kailang Yanga361d842007-06-05 12:30:55 +020012153 codec->patch_ops = alc_patch_ops;
12154 if (board_config == ALC268_AUTO)
12155 spec->init_hook = alc268_auto_init;
Kailang Yangea1fb292008-08-26 12:58:38 +020012156
Takashi Iwaidaead532008-11-28 12:55:36 +010012157 codec->proc_widget_hook = print_realtek_coef;
12158
Kailang Yanga361d842007-06-05 12:30:55 +020012159 return 0;
12160}
12161
12162/*
Kailang Yangf6a92242007-12-13 16:52:54 +010012163 * ALC269 channel source setting (2 channel)
12164 */
12165#define ALC269_DIGOUT_NID ALC880_DIGOUT_NID
12166
12167#define alc269_dac_nids alc260_dac_nids
12168
12169static hda_nid_t alc269_adc_nids[1] = {
12170 /* ADC1 */
Kailang Yangf53281e2008-07-18 12:36:43 +020012171 0x08,
12172};
12173
Takashi Iwaie01bf502008-08-21 16:25:07 +020012174static hda_nid_t alc269_capsrc_nids[1] = {
12175 0x23,
12176};
12177
12178/* NOTE: ADC2 (0x07) is connected from a recording *MIXER* (0x24),
12179 * not a mux!
12180 */
12181
Kailang Yangf53281e2008-07-18 12:36:43 +020012182static struct hda_input_mux alc269_eeepc_dmic_capture_source = {
12183 .num_items = 2,
12184 .items = {
12185 { "i-Mic", 0x5 },
12186 { "e-Mic", 0x0 },
12187 },
12188};
12189
12190static struct hda_input_mux alc269_eeepc_amic_capture_source = {
12191 .num_items = 2,
12192 .items = {
12193 { "i-Mic", 0x1 },
12194 { "e-Mic", 0x0 },
12195 },
Kailang Yangf6a92242007-12-13 16:52:54 +010012196};
12197
12198#define alc269_modes alc260_modes
12199#define alc269_capture_source alc880_lg_lw_capture_source
12200
12201static struct snd_kcontrol_new alc269_base_mixer[] = {
12202 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
12203 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
12204 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
12205 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
12206 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
12207 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai2005af22008-08-20 18:38:26 +020012208 HDA_CODEC_VOLUME("Beep Playback Volume", 0x0b, 0x4, HDA_INPUT),
12209 HDA_CODEC_MUTE("Beep Playback Switch", 0x0b, 0x4, HDA_INPUT),
Kailang Yangf6a92242007-12-13 16:52:54 +010012210 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12211 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
12212 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
12213 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
12214 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
12215 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
12216 { } /* end */
12217};
12218
Kailang Yang60db6b52008-08-26 13:13:00 +020012219static struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = {
12220 /* output mixer control */
12221 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
12222 {
12223 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12224 .name = "Master Playback Switch",
12225 .info = snd_hda_mixer_amp_switch_info,
12226 .get = snd_hda_mixer_amp_switch_get,
12227 .put = alc268_acer_master_sw_put,
12228 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
12229 },
12230 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
12231 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
12232 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12233 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
12234 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
12235 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
12236 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x04, HDA_INPUT),
12237 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x04, HDA_INPUT),
12238 { }
12239};
12240
Tony Vroon64154832008-11-06 15:08:49 +000012241static struct snd_kcontrol_new alc269_lifebook_mixer[] = {
12242 /* output mixer control */
12243 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
12244 {
12245 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12246 .name = "Master Playback Switch",
12247 .info = snd_hda_mixer_amp_switch_info,
12248 .get = snd_hda_mixer_amp_switch_get,
12249 .put = alc268_acer_master_sw_put,
12250 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
12251 },
12252 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
12253 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
12254 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12255 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
12256 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
12257 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
12258 HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x0b, 0x03, HDA_INPUT),
12259 HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x0b, 0x03, HDA_INPUT),
12260 HDA_CODEC_VOLUME("Dock Mic Boost", 0x1b, 0, HDA_INPUT),
12261 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x04, HDA_INPUT),
12262 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x04, HDA_INPUT),
12263 { }
12264};
12265
Kailang Yangf53281e2008-07-18 12:36:43 +020012266/* bind volumes of both NID 0x0c and 0x0d */
12267static struct hda_bind_ctls alc269_epc_bind_vol = {
12268 .ops = &snd_hda_bind_vol,
12269 .values = {
12270 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
12271 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
12272 0
12273 },
12274};
12275
12276static struct snd_kcontrol_new alc269_eeepc_mixer[] = {
12277 HDA_CODEC_MUTE("iSpeaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
12278 HDA_BIND_VOL("LineOut Playback Volume", &alc269_epc_bind_vol),
12279 HDA_CODEC_MUTE("LineOut Playback Switch", 0x15, 0x0, HDA_OUTPUT),
12280 { } /* end */
12281};
12282
Kailang Yangf6a92242007-12-13 16:52:54 +010012283/* capture mixer elements */
Kailang Yangf53281e2008-07-18 12:36:43 +020012284static struct snd_kcontrol_new alc269_epc_capture_mixer[] = {
12285 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
12286 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
Takashi Iwai26f5df22008-11-03 17:39:46 +010012287 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12288 { } /* end */
12289};
12290
12291/* FSC amilo */
12292static struct snd_kcontrol_new alc269_fujitsu_mixer[] = {
12293 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
12294 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
12295 HDA_BIND_VOL("PCM Playback Volume", &alc269_epc_bind_vol),
Kailang Yangf53281e2008-07-18 12:36:43 +020012296 { } /* end */
12297};
12298
Takashi Iwai2005af22008-08-20 18:38:26 +020012299/* beep control */
12300static struct snd_kcontrol_new alc269_beep_mixer[] = {
12301 HDA_CODEC_VOLUME("Beep Playback Volume", 0x0b, 0x4, HDA_INPUT),
12302 HDA_CODEC_MUTE("Beep Playback Switch", 0x0b, 0x4, HDA_INPUT),
12303 { } /* end */
12304};
12305
Kailang Yang60db6b52008-08-26 13:13:00 +020012306static struct hda_verb alc269_quanta_fl1_verbs[] = {
12307 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
12308 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12309 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12310 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12311 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
12312 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12313 { }
12314};
12315
Tony Vroon64154832008-11-06 15:08:49 +000012316static struct hda_verb alc269_lifebook_verbs[] = {
12317 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
12318 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
12319 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12320 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12321 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12322 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12323 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12324 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12325 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
12326 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12327 { }
12328};
12329
Kailang Yang60db6b52008-08-26 13:13:00 +020012330/* toggle speaker-output according to the hp-jack state */
12331static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec)
12332{
12333 unsigned int present;
12334 unsigned char bits;
12335
12336 present = snd_hda_codec_read(codec, 0x15, 0,
12337 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
12338 bits = present ? AMP_IN_MUTE(0) : 0;
12339 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
12340 AMP_IN_MUTE(0), bits);
12341 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
12342 AMP_IN_MUTE(0), bits);
12343
12344 snd_hda_codec_write(codec, 0x20, 0,
12345 AC_VERB_SET_COEF_INDEX, 0x0c);
12346 snd_hda_codec_write(codec, 0x20, 0,
12347 AC_VERB_SET_PROC_COEF, 0x680);
12348
12349 snd_hda_codec_write(codec, 0x20, 0,
12350 AC_VERB_SET_COEF_INDEX, 0x0c);
12351 snd_hda_codec_write(codec, 0x20, 0,
12352 AC_VERB_SET_PROC_COEF, 0x480);
12353}
12354
Tony Vroon64154832008-11-06 15:08:49 +000012355/* toggle speaker-output according to the hp-jacks state */
12356static void alc269_lifebook_speaker_automute(struct hda_codec *codec)
12357{
12358 unsigned int present;
12359 unsigned char bits;
12360
12361 /* Check laptop headphone socket */
12362 present = snd_hda_codec_read(codec, 0x15, 0,
12363 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
12364
12365 /* Check port replicator headphone socket */
12366 present |= snd_hda_codec_read(codec, 0x1a, 0,
12367 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
12368
12369 bits = present ? AMP_IN_MUTE(0) : 0;
12370 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
12371 AMP_IN_MUTE(0), bits);
12372 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
12373 AMP_IN_MUTE(0), bits);
12374
12375 snd_hda_codec_write(codec, 0x20, 0,
12376 AC_VERB_SET_COEF_INDEX, 0x0c);
12377 snd_hda_codec_write(codec, 0x20, 0,
12378 AC_VERB_SET_PROC_COEF, 0x680);
12379
12380 snd_hda_codec_write(codec, 0x20, 0,
12381 AC_VERB_SET_COEF_INDEX, 0x0c);
12382 snd_hda_codec_write(codec, 0x20, 0,
12383 AC_VERB_SET_PROC_COEF, 0x480);
12384}
12385
Kailang Yang60db6b52008-08-26 13:13:00 +020012386static void alc269_quanta_fl1_mic_automute(struct hda_codec *codec)
12387{
12388 unsigned int present;
12389
12390 present = snd_hda_codec_read(codec, 0x18, 0,
12391 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
12392 snd_hda_codec_write(codec, 0x23, 0,
12393 AC_VERB_SET_CONNECT_SEL, present ? 0x0 : 0x1);
12394}
12395
Tony Vroon64154832008-11-06 15:08:49 +000012396static void alc269_lifebook_mic_autoswitch(struct hda_codec *codec)
12397{
12398 unsigned int present_laptop;
12399 unsigned int present_dock;
12400
12401 present_laptop = snd_hda_codec_read(codec, 0x18, 0,
12402 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
12403
12404 present_dock = snd_hda_codec_read(codec, 0x1b, 0,
12405 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
12406
12407 /* Laptop mic port overrides dock mic port, design decision */
12408 if (present_dock)
12409 snd_hda_codec_write(codec, 0x23, 0,
12410 AC_VERB_SET_CONNECT_SEL, 0x3);
12411 if (present_laptop)
12412 snd_hda_codec_write(codec, 0x23, 0,
12413 AC_VERB_SET_CONNECT_SEL, 0x0);
12414 if (!present_dock && !present_laptop)
12415 snd_hda_codec_write(codec, 0x23, 0,
12416 AC_VERB_SET_CONNECT_SEL, 0x1);
12417}
12418
Kailang Yang60db6b52008-08-26 13:13:00 +020012419static void alc269_quanta_fl1_unsol_event(struct hda_codec *codec,
12420 unsigned int res)
12421{
12422 if ((res >> 26) == ALC880_HP_EVENT)
12423 alc269_quanta_fl1_speaker_automute(codec);
12424 if ((res >> 26) == ALC880_MIC_EVENT)
12425 alc269_quanta_fl1_mic_automute(codec);
12426}
12427
Tony Vroon64154832008-11-06 15:08:49 +000012428static void alc269_lifebook_unsol_event(struct hda_codec *codec,
12429 unsigned int res)
12430{
12431 if ((res >> 26) == ALC880_HP_EVENT)
12432 alc269_lifebook_speaker_automute(codec);
12433 if ((res >> 26) == ALC880_MIC_EVENT)
12434 alc269_lifebook_mic_autoswitch(codec);
12435}
12436
Kailang Yang60db6b52008-08-26 13:13:00 +020012437static void alc269_quanta_fl1_init_hook(struct hda_codec *codec)
12438{
12439 alc269_quanta_fl1_speaker_automute(codec);
12440 alc269_quanta_fl1_mic_automute(codec);
12441}
12442
Tony Vroon64154832008-11-06 15:08:49 +000012443static void alc269_lifebook_init_hook(struct hda_codec *codec)
12444{
12445 alc269_lifebook_speaker_automute(codec);
12446 alc269_lifebook_mic_autoswitch(codec);
12447}
12448
Kailang Yang60db6b52008-08-26 13:13:00 +020012449static struct hda_verb alc269_eeepc_dmic_init_verbs[] = {
12450 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
12451 {0x23, AC_VERB_SET_CONNECT_SEL, 0x05},
12452 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
12453 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
12454 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12455 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
12456 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
12457 {}
12458};
12459
12460static struct hda_verb alc269_eeepc_amic_init_verbs[] = {
12461 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
12462 {0x23, AC_VERB_SET_CONNECT_SEL, 0x01},
12463 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
12464 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x701b | (0x00 << 8))},
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
12470/* toggle speaker-output according to the hp-jack state */
12471static void alc269_speaker_automute(struct hda_codec *codec)
12472{
12473 unsigned int present;
12474 unsigned char bits;
12475
12476 present = snd_hda_codec_read(codec, 0x15, 0,
12477 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
12478 bits = present ? AMP_IN_MUTE(0) : 0;
12479 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
12480 AMP_IN_MUTE(0), bits);
12481 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
12482 AMP_IN_MUTE(0), bits);
12483}
12484
12485static void alc269_eeepc_dmic_automute(struct hda_codec *codec)
12486{
12487 unsigned int present;
12488
12489 present = snd_hda_codec_read(codec, 0x18, 0,
12490 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
12491 snd_hda_codec_write(codec, 0x23, 0,
12492 AC_VERB_SET_CONNECT_SEL, (present ? 0 : 5));
12493}
12494
12495static void alc269_eeepc_amic_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, 0x24, 0, AC_VERB_SET_AMP_GAIN_MUTE,
12502 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
12503 snd_hda_codec_write(codec, 0x24, 0, AC_VERB_SET_AMP_GAIN_MUTE,
12504 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
12505}
12506
12507/* unsolicited event for HP jack sensing */
12508static void alc269_eeepc_dmic_unsol_event(struct hda_codec *codec,
12509 unsigned int res)
12510{
12511 if ((res >> 26) == ALC880_HP_EVENT)
12512 alc269_speaker_automute(codec);
12513
12514 if ((res >> 26) == ALC880_MIC_EVENT)
12515 alc269_eeepc_dmic_automute(codec);
12516}
12517
12518static void alc269_eeepc_dmic_inithook(struct hda_codec *codec)
12519{
12520 alc269_speaker_automute(codec);
12521 alc269_eeepc_dmic_automute(codec);
12522}
12523
12524/* unsolicited event for HP jack sensing */
12525static void alc269_eeepc_amic_unsol_event(struct hda_codec *codec,
12526 unsigned int res)
12527{
12528 if ((res >> 26) == ALC880_HP_EVENT)
12529 alc269_speaker_automute(codec);
12530
12531 if ((res >> 26) == ALC880_MIC_EVENT)
12532 alc269_eeepc_amic_automute(codec);
12533}
12534
12535static void alc269_eeepc_amic_inithook(struct hda_codec *codec)
12536{
12537 alc269_speaker_automute(codec);
12538 alc269_eeepc_amic_automute(codec);
12539}
12540
Kailang Yangf6a92242007-12-13 16:52:54 +010012541/*
12542 * generic initialization of ADC, input mixers and output mixers
12543 */
12544static struct hda_verb alc269_init_verbs[] = {
12545 /*
12546 * Unmute ADC0 and set the default input to mic-in
12547 */
Kailang Yang60db6b52008-08-26 13:13:00 +020012548 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangf6a92242007-12-13 16:52:54 +010012549
12550 /* Mute input amps (PCBeep, Line In, Mic 1 & Mic 2) of the
12551 * analog-loopback mixer widget
12552 * Note: PASD motherboards uses the Line In 2 as the input for
12553 * front panel mic (mic 2)
12554 */
12555 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
12556 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12557 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12558 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12559 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12560 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
12561
12562 /*
12563 * Set up output mixers (0x0c - 0x0e)
12564 */
12565 /* set vol=0 to output mixers */
12566 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12567 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12568
12569 /* set up input amps for analog loopback */
12570 /* Amp Indices: DAC = 0, mixer = 1 */
12571 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12572 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12573 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12574 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12575 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12576 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12577
12578 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12579 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12580 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12581 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
12582 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
12583 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12584 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12585
12586 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12587 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12588 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12589 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12590 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12591 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12592 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12593
12594 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
12595 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
12596
12597 /* FIXME: use matrix-type input source selection */
12598 /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
12599 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yang60db6b52008-08-26 13:13:00 +020012600 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12601 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangf6a92242007-12-13 16:52:54 +010012602 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12603 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12604
12605 /* set EAPD */
12606 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
12607 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
12608 { }
12609};
12610
12611/* add playback controls from the parsed DAC table */
12612static int alc269_auto_create_multi_out_ctls(struct alc_spec *spec,
12613 const struct auto_pin_cfg *cfg)
12614{
12615 hda_nid_t nid;
12616 int err;
12617
12618 spec->multiout.num_dacs = 1; /* only use one dac */
12619 spec->multiout.dac_nids = spec->private_dac_nids;
12620 spec->multiout.dac_nids[0] = 2;
12621
12622 nid = cfg->line_out_pins[0];
12623 if (nid) {
12624 err = add_control(spec, ALC_CTL_WIDGET_VOL,
12625 "Front Playback Volume",
12626 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT));
12627 if (err < 0)
12628 return err;
12629 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
12630 "Front Playback Switch",
12631 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
12632 if (err < 0)
12633 return err;
12634 }
12635
12636 nid = cfg->speaker_pins[0];
12637 if (nid) {
12638 if (!cfg->line_out_pins[0]) {
12639 err = add_control(spec, ALC_CTL_WIDGET_VOL,
12640 "Speaker Playback Volume",
12641 HDA_COMPOSE_AMP_VAL(0x02, 3, 0,
12642 HDA_OUTPUT));
12643 if (err < 0)
12644 return err;
12645 }
12646 if (nid == 0x16) {
12647 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
12648 "Speaker Playback Switch",
12649 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
12650 HDA_OUTPUT));
12651 if (err < 0)
12652 return err;
12653 } else {
12654 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
12655 "Speaker Playback Switch",
12656 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
12657 HDA_OUTPUT));
12658 if (err < 0)
12659 return err;
12660 }
12661 }
12662 nid = cfg->hp_pins[0];
12663 if (nid) {
12664 /* spec->multiout.hp_nid = 2; */
12665 if (!cfg->line_out_pins[0] && !cfg->speaker_pins[0]) {
12666 err = add_control(spec, ALC_CTL_WIDGET_VOL,
12667 "Headphone Playback Volume",
12668 HDA_COMPOSE_AMP_VAL(0x02, 3, 0,
12669 HDA_OUTPUT));
12670 if (err < 0)
12671 return err;
12672 }
12673 if (nid == 0x16) {
12674 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
12675 "Headphone Playback Switch",
12676 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
12677 HDA_OUTPUT));
12678 if (err < 0)
12679 return err;
12680 } else {
12681 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
12682 "Headphone Playback Switch",
12683 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
12684 HDA_OUTPUT));
12685 if (err < 0)
12686 return err;
12687 }
12688 }
12689 return 0;
12690}
12691
Takashi Iwaiee956e02008-10-31 17:16:31 +010012692static int alc269_auto_create_analog_input_ctls(struct alc_spec *spec,
12693 const struct auto_pin_cfg *cfg)
12694{
12695 int err;
12696
12697 err = alc880_auto_create_analog_input_ctls(spec, cfg);
12698 if (err < 0)
12699 return err;
12700 /* digital-mic input pin is excluded in alc880_auto_create..()
12701 * because it's under 0x18
12702 */
12703 if (cfg->input_pins[AUTO_PIN_MIC] == 0x12 ||
12704 cfg->input_pins[AUTO_PIN_FRONT_MIC] == 0x12) {
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020012705 struct hda_input_mux *imux = &spec->private_imux[0];
Takashi Iwaiee956e02008-10-31 17:16:31 +010012706 imux->items[imux->num_items].label = "Int Mic";
12707 imux->items[imux->num_items].index = 0x05;
12708 imux->num_items++;
12709 }
12710 return 0;
12711}
Kailang Yangf6a92242007-12-13 16:52:54 +010012712
12713#ifdef CONFIG_SND_HDA_POWER_SAVE
12714#define alc269_loopbacks alc880_loopbacks
12715#endif
12716
12717/* pcm configuration: identiacal with ALC880 */
12718#define alc269_pcm_analog_playback alc880_pcm_analog_playback
12719#define alc269_pcm_analog_capture alc880_pcm_analog_capture
12720#define alc269_pcm_digital_playback alc880_pcm_digital_playback
12721#define alc269_pcm_digital_capture alc880_pcm_digital_capture
12722
12723/*
12724 * BIOS auto configuration
12725 */
12726static int alc269_parse_auto_config(struct hda_codec *codec)
12727{
12728 struct alc_spec *spec = codec->spec;
Takashi Iwai2005af22008-08-20 18:38:26 +020012729 int i, err;
Kailang Yangf6a92242007-12-13 16:52:54 +010012730 static hda_nid_t alc269_ignore[] = { 0x1d, 0 };
12731
12732 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
12733 alc269_ignore);
12734 if (err < 0)
12735 return err;
12736
12737 err = alc269_auto_create_multi_out_ctls(spec, &spec->autocfg);
12738 if (err < 0)
12739 return err;
12740 err = alc269_auto_create_analog_input_ctls(spec, &spec->autocfg);
12741 if (err < 0)
12742 return err;
12743
12744 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
12745
12746 if (spec->autocfg.dig_out_pin)
12747 spec->multiout.dig_out_nid = ALC269_DIGOUT_NID;
12748
Takashi Iwai603c4012008-07-30 15:01:44 +020012749 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010012750 add_mixer(spec, spec->kctls.list);
Kailang Yangf6a92242007-12-13 16:52:54 +010012751
Takashi Iwai2005af22008-08-20 18:38:26 +020012752 /* create a beep mixer control if the pin 0x1d isn't assigned */
12753 for (i = 0; i < ARRAY_SIZE(spec->autocfg.input_pins); i++)
12754 if (spec->autocfg.input_pins[i] == 0x1d)
12755 break;
12756 if (i >= ARRAY_SIZE(spec->autocfg.input_pins))
Takashi Iwaid88897e2008-10-31 15:01:37 +010012757 add_mixer(spec, alc269_beep_mixer);
Takashi Iwai2005af22008-08-20 18:38:26 +020012758
Takashi Iwaid88897e2008-10-31 15:01:37 +010012759 add_verb(spec, alc269_init_verbs);
Kailang Yangf6a92242007-12-13 16:52:54 +010012760 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020012761 spec->input_mux = &spec->private_imux[0];
Takashi Iwaie01bf502008-08-21 16:25:07 +020012762 /* set default input source */
12763 snd_hda_codec_write_cache(codec, alc269_capsrc_nids[0],
12764 0, AC_VERB_SET_CONNECT_SEL,
12765 spec->input_mux->items[0].index);
Kailang Yangf6a92242007-12-13 16:52:54 +010012766
12767 err = alc_auto_add_mic_boost(codec);
12768 if (err < 0)
12769 return err;
12770
Takashi Iwaif9e336f2008-10-31 16:37:07 +010012771 if (!spec->cap_mixer)
12772 set_capture_mixer(spec);
Kailang Yangf53281e2008-07-18 12:36:43 +020012773
Takashi Iwaie044c392008-10-27 16:56:24 +010012774 store_pin_configs(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010012775 return 1;
12776}
12777
12778#define alc269_auto_init_multi_out alc882_auto_init_multi_out
12779#define alc269_auto_init_hp_out alc882_auto_init_hp_out
12780#define alc269_auto_init_analog_input alc882_auto_init_analog_input
12781
12782
12783/* init callback for auto-configuration model -- overriding the default init */
12784static void alc269_auto_init(struct hda_codec *codec)
12785{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012786 struct alc_spec *spec = codec->spec;
Kailang Yangf6a92242007-12-13 16:52:54 +010012787 alc269_auto_init_multi_out(codec);
12788 alc269_auto_init_hp_out(codec);
12789 alc269_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012790 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020012791 alc_inithook(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010012792}
12793
12794/*
12795 * configuration and preset
12796 */
12797static const char *alc269_models[ALC269_MODEL_LAST] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020012798 [ALC269_BASIC] = "basic",
Takashi Iwai2922c9a2008-08-27 18:12:42 +020012799 [ALC269_QUANTA_FL1] = "quanta",
12800 [ALC269_ASUS_EEEPC_P703] = "eeepc-p703",
Takashi Iwai26f5df22008-11-03 17:39:46 +010012801 [ALC269_ASUS_EEEPC_P901] = "eeepc-p901",
Tony Vroon64154832008-11-06 15:08:49 +000012802 [ALC269_FUJITSU] = "fujitsu",
12803 [ALC269_LIFEBOOK] = "lifebook"
Kailang Yangf6a92242007-12-13 16:52:54 +010012804};
12805
12806static struct snd_pci_quirk alc269_cfg_tbl[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020012807 SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_QUANTA_FL1),
Kailang Yangf53281e2008-07-18 12:36:43 +020012808 SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A",
12809 ALC269_ASUS_EEEPC_P703),
12810 SND_PCI_QUIRK(0x1043, 0x831a, "ASUS Eeepc P901",
12811 ALC269_ASUS_EEEPC_P901),
Kailang Yang60db6b52008-08-26 13:13:00 +020012812 SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101",
12813 ALC269_ASUS_EEEPC_P901),
Takashi Iwai26f5df22008-11-03 17:39:46 +010012814 SND_PCI_QUIRK(0x1734, 0x115d, "FSC Amilo", ALC269_FUJITSU),
Tony Vroon64154832008-11-06 15:08:49 +000012815 SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook ICH9M-based", ALC269_LIFEBOOK),
Kailang Yangf6a92242007-12-13 16:52:54 +010012816 {}
12817};
12818
12819static struct alc_config_preset alc269_presets[] = {
12820 [ALC269_BASIC] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010012821 .mixers = { alc269_base_mixer },
Kailang Yangf6a92242007-12-13 16:52:54 +010012822 .init_verbs = { alc269_init_verbs },
12823 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
12824 .dac_nids = alc269_dac_nids,
12825 .hp_nid = 0x03,
12826 .num_channel_mode = ARRAY_SIZE(alc269_modes),
12827 .channel_mode = alc269_modes,
12828 .input_mux = &alc269_capture_source,
12829 },
Kailang Yang60db6b52008-08-26 13:13:00 +020012830 [ALC269_QUANTA_FL1] = {
12831 .mixers = { alc269_quanta_fl1_mixer },
12832 .init_verbs = { alc269_init_verbs, alc269_quanta_fl1_verbs },
12833 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
12834 .dac_nids = alc269_dac_nids,
12835 .hp_nid = 0x03,
12836 .num_channel_mode = ARRAY_SIZE(alc269_modes),
12837 .channel_mode = alc269_modes,
12838 .input_mux = &alc269_capture_source,
12839 .unsol_event = alc269_quanta_fl1_unsol_event,
12840 .init_hook = alc269_quanta_fl1_init_hook,
12841 },
Kailang Yangf53281e2008-07-18 12:36:43 +020012842 [ALC269_ASUS_EEEPC_P703] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010012843 .mixers = { alc269_eeepc_mixer },
12844 .cap_mixer = alc269_epc_capture_mixer,
Kailang Yangf53281e2008-07-18 12:36:43 +020012845 .init_verbs = { alc269_init_verbs,
12846 alc269_eeepc_amic_init_verbs },
12847 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
12848 .dac_nids = alc269_dac_nids,
12849 .hp_nid = 0x03,
12850 .num_channel_mode = ARRAY_SIZE(alc269_modes),
12851 .channel_mode = alc269_modes,
12852 .input_mux = &alc269_eeepc_amic_capture_source,
12853 .unsol_event = alc269_eeepc_amic_unsol_event,
12854 .init_hook = alc269_eeepc_amic_inithook,
12855 },
12856 [ALC269_ASUS_EEEPC_P901] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010012857 .mixers = { alc269_eeepc_mixer },
12858 .cap_mixer = alc269_epc_capture_mixer,
Kailang Yangf53281e2008-07-18 12:36:43 +020012859 .init_verbs = { alc269_init_verbs,
12860 alc269_eeepc_dmic_init_verbs },
12861 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
12862 .dac_nids = alc269_dac_nids,
12863 .hp_nid = 0x03,
12864 .num_channel_mode = ARRAY_SIZE(alc269_modes),
12865 .channel_mode = alc269_modes,
12866 .input_mux = &alc269_eeepc_dmic_capture_source,
12867 .unsol_event = alc269_eeepc_dmic_unsol_event,
12868 .init_hook = alc269_eeepc_dmic_inithook,
12869 },
Takashi Iwai26f5df22008-11-03 17:39:46 +010012870 [ALC269_FUJITSU] = {
12871 .mixers = { alc269_fujitsu_mixer, alc269_beep_mixer },
12872 .cap_mixer = alc269_epc_capture_mixer,
12873 .init_verbs = { alc269_init_verbs,
12874 alc269_eeepc_dmic_init_verbs },
12875 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
12876 .dac_nids = alc269_dac_nids,
12877 .hp_nid = 0x03,
12878 .num_channel_mode = ARRAY_SIZE(alc269_modes),
12879 .channel_mode = alc269_modes,
12880 .input_mux = &alc269_eeepc_dmic_capture_source,
12881 .unsol_event = alc269_eeepc_dmic_unsol_event,
12882 .init_hook = alc269_eeepc_dmic_inithook,
12883 },
Tony Vroon64154832008-11-06 15:08:49 +000012884 [ALC269_LIFEBOOK] = {
12885 .mixers = { alc269_lifebook_mixer },
12886 .init_verbs = { alc269_init_verbs, alc269_lifebook_verbs },
12887 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
12888 .dac_nids = alc269_dac_nids,
12889 .hp_nid = 0x03,
12890 .num_channel_mode = ARRAY_SIZE(alc269_modes),
12891 .channel_mode = alc269_modes,
12892 .input_mux = &alc269_capture_source,
12893 .unsol_event = alc269_lifebook_unsol_event,
12894 .init_hook = alc269_lifebook_init_hook,
12895 },
Kailang Yangf6a92242007-12-13 16:52:54 +010012896};
12897
12898static int patch_alc269(struct hda_codec *codec)
12899{
12900 struct alc_spec *spec;
12901 int board_config;
12902 int err;
12903
12904 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
12905 if (spec == NULL)
12906 return -ENOMEM;
12907
12908 codec->spec = spec;
12909
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020012910 alc_fix_pll_init(codec, 0x20, 0x04, 15);
12911
Kailang Yangf6a92242007-12-13 16:52:54 +010012912 board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST,
12913 alc269_models,
12914 alc269_cfg_tbl);
12915
12916 if (board_config < 0) {
12917 printk(KERN_INFO "hda_codec: Unknown model for ALC269, "
12918 "trying auto-probe from BIOS...\n");
12919 board_config = ALC269_AUTO;
12920 }
12921
12922 if (board_config == ALC269_AUTO) {
12923 /* automatic parse from the BIOS config */
12924 err = alc269_parse_auto_config(codec);
12925 if (err < 0) {
12926 alc_free(codec);
12927 return err;
12928 } else if (!err) {
12929 printk(KERN_INFO
12930 "hda_codec: Cannot set up configuration "
12931 "from BIOS. Using base mode...\n");
12932 board_config = ALC269_BASIC;
12933 }
12934 }
12935
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090012936 err = snd_hda_attach_beep_device(codec, 0x1);
12937 if (err < 0) {
12938 alc_free(codec);
12939 return err;
12940 }
12941
Kailang Yangf6a92242007-12-13 16:52:54 +010012942 if (board_config != ALC269_AUTO)
12943 setup_preset(spec, &alc269_presets[board_config]);
12944
12945 spec->stream_name_analog = "ALC269 Analog";
12946 spec->stream_analog_playback = &alc269_pcm_analog_playback;
12947 spec->stream_analog_capture = &alc269_pcm_analog_capture;
12948
12949 spec->stream_name_digital = "ALC269 Digital";
12950 spec->stream_digital_playback = &alc269_pcm_digital_playback;
12951 spec->stream_digital_capture = &alc269_pcm_digital_capture;
12952
12953 spec->adc_nids = alc269_adc_nids;
12954 spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids);
Takashi Iwaie01bf502008-08-21 16:25:07 +020012955 spec->capsrc_nids = alc269_capsrc_nids;
Takashi Iwaif9e336f2008-10-31 16:37:07 +010012956 if (!spec->cap_mixer)
12957 set_capture_mixer(spec);
Kailang Yangf6a92242007-12-13 16:52:54 +010012958
12959 codec->patch_ops = alc_patch_ops;
12960 if (board_config == ALC269_AUTO)
12961 spec->init_hook = alc269_auto_init;
12962#ifdef CONFIG_SND_HDA_POWER_SAVE
12963 if (!spec->loopback.amplist)
12964 spec->loopback.amplist = alc269_loopbacks;
12965#endif
Takashi Iwaidaead532008-11-28 12:55:36 +010012966 codec->proc_widget_hook = print_realtek_coef;
Kailang Yangf6a92242007-12-13 16:52:54 +010012967
12968 return 0;
12969}
12970
12971/*
Kailang Yangdf694da2005-12-05 19:42:22 +010012972 * ALC861 channel source setting (2/6 channel selection for 3-stack)
12973 */
12974
12975/*
12976 * set the path ways for 2 channel output
12977 * need to set the codec line out and mic 1 pin widgets to inputs
12978 */
12979static struct hda_verb alc861_threestack_ch2_init[] = {
12980 /* set pin widget 1Ah (line in) for input */
12981 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012982 /* set pin widget 18h (mic1/2) for input, for mic also enable
12983 * the vref
12984 */
Kailang Yangdf694da2005-12-05 19:42:22 +010012985 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12986
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012987 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
12988#if 0
12989 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
12990 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
12991#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010012992 { } /* end */
12993};
12994/*
12995 * 6ch mode
12996 * need to set the codec line out and mic 1 pin widgets to outputs
12997 */
12998static struct hda_verb alc861_threestack_ch6_init[] = {
12999 /* set pin widget 1Ah (line in) for output (Back Surround)*/
13000 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13001 /* set pin widget 18h (mic1) for output (CLFE)*/
13002 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13003
13004 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013005 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010013006
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013007 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
13008#if 0
13009 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
13010 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
13011#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010013012 { } /* end */
13013};
13014
13015static struct hda_channel_mode alc861_threestack_modes[2] = {
13016 { 2, alc861_threestack_ch2_init },
13017 { 6, alc861_threestack_ch6_init },
13018};
Takashi Iwai22309c32006-08-09 16:57:28 +020013019/* Set mic1 as input and unmute the mixer */
13020static struct hda_verb alc861_uniwill_m31_ch2_init[] = {
13021 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13022 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
13023 { } /* end */
13024};
13025/* Set mic1 as output and mute mixer */
13026static struct hda_verb alc861_uniwill_m31_ch4_init[] = {
13027 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13028 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
13029 { } /* end */
13030};
13031
13032static struct hda_channel_mode alc861_uniwill_m31_modes[2] = {
13033 { 2, alc861_uniwill_m31_ch2_init },
13034 { 4, alc861_uniwill_m31_ch4_init },
13035};
Kailang Yangdf694da2005-12-05 19:42:22 +010013036
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013037/* Set mic1 and line-in as input and unmute the mixer */
13038static struct hda_verb alc861_asus_ch2_init[] = {
13039 /* set pin widget 1Ah (line in) for input */
13040 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013041 /* set pin widget 18h (mic1/2) for input, for mic also enable
13042 * the vref
13043 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013044 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13045
13046 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
13047#if 0
13048 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
13049 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
13050#endif
13051 { } /* end */
13052};
13053/* Set mic1 nad line-in as output and mute mixer */
13054static struct hda_verb alc861_asus_ch6_init[] = {
13055 /* set pin widget 1Ah (line in) for output (Back Surround)*/
13056 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13057 /* { 0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
13058 /* set pin widget 18h (mic1) for output (CLFE)*/
13059 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13060 /* { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
13061 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
13062 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
13063
13064 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
13065#if 0
13066 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
13067 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
13068#endif
13069 { } /* end */
13070};
13071
13072static struct hda_channel_mode alc861_asus_modes[2] = {
13073 { 2, alc861_asus_ch2_init },
13074 { 6, alc861_asus_ch6_init },
13075};
13076
Kailang Yangdf694da2005-12-05 19:42:22 +010013077/* patch-ALC861 */
13078
13079static struct snd_kcontrol_new alc861_base_mixer[] = {
13080 /* output mixer control */
13081 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
13082 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
13083 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
13084 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
13085 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
13086
13087 /*Input mixer control */
13088 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
13089 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
13090 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
13091 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
13092 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
13093 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
13094 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
13095 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
13096 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
13097 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013098
Kailang Yangdf694da2005-12-05 19:42:22 +010013099 { } /* end */
13100};
13101
13102static struct snd_kcontrol_new alc861_3ST_mixer[] = {
13103 /* output mixer control */
13104 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
13105 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
13106 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
13107 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
13108 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
13109
13110 /* Input mixer control */
13111 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
13112 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
13113 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
13114 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
13115 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
13116 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
13117 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
13118 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
13119 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
13120 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013121
Kailang Yangdf694da2005-12-05 19:42:22 +010013122 {
13123 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13124 .name = "Channel Mode",
13125 .info = alc_ch_mode_info,
13126 .get = alc_ch_mode_get,
13127 .put = alc_ch_mode_put,
13128 .private_value = ARRAY_SIZE(alc861_threestack_modes),
13129 },
13130 { } /* end */
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013131};
13132
Takashi Iwaid1d985f2006-11-23 19:27:12 +010013133static struct snd_kcontrol_new alc861_toshiba_mixer[] = {
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013134 /* output mixer control */
13135 HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT),
13136 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
13137 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
Kailang Yangea1fb292008-08-26 12:58:38 +020013138
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013139 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013140};
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013141
Takashi Iwai22309c32006-08-09 16:57:28 +020013142static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = {
13143 /* output mixer control */
13144 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
13145 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
13146 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
13147 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
13148 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
13149
13150 /* Input mixer control */
13151 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
13152 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
13153 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
13154 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
13155 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
13156 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
13157 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
13158 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
13159 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
13160 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013161
Takashi Iwai22309c32006-08-09 16:57:28 +020013162 {
13163 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13164 .name = "Channel Mode",
13165 .info = alc_ch_mode_info,
13166 .get = alc_ch_mode_get,
13167 .put = alc_ch_mode_put,
13168 .private_value = ARRAY_SIZE(alc861_uniwill_m31_modes),
13169 },
13170 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013171};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013172
13173static struct snd_kcontrol_new alc861_asus_mixer[] = {
13174 /* output mixer control */
13175 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
13176 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
13177 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
13178 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
13179 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
13180
13181 /* Input mixer control */
13182 HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
13183 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT),
13184 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
13185 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
13186 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
13187 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
13188 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
13189 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
13190 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013191 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_OUTPUT),
13192
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013193 {
13194 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13195 .name = "Channel Mode",
13196 .info = alc_ch_mode_info,
13197 .get = alc_ch_mode_get,
13198 .put = alc_ch_mode_put,
13199 .private_value = ARRAY_SIZE(alc861_asus_modes),
13200 },
13201 { }
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010013202};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013203
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010013204/* additional mixer */
Takashi Iwaid1d985f2006-11-23 19:27:12 +010013205static struct snd_kcontrol_new alc861_asus_laptop_mixer[] = {
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010013206 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
13207 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
13208 HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x23, 0x0, HDA_OUTPUT),
13209 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x23, 0x0, HDA_OUTPUT),
13210 { }
13211};
13212
Kailang Yangdf694da2005-12-05 19:42:22 +010013213/*
13214 * generic initialization of ADC, input mixers and output mixers
13215 */
13216static struct hda_verb alc861_base_init_verbs[] = {
13217 /*
13218 * Unmute ADC0 and set the default input to mic-in
13219 */
13220 /* port-A for surround (rear panel) */
13221 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13222 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x00 },
13223 /* port-B for mic-in (rear panel) with vref */
13224 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13225 /* port-C for line-in (rear panel) */
13226 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
13227 /* port-D for Front */
13228 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13229 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
13230 /* port-E for HP out (front panel) */
13231 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
13232 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010013233 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010013234 /* port-F for mic-in (front panel) with vref */
13235 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13236 /* port-G for CLFE (rear panel) */
13237 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13238 { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x00 },
13239 /* port-H for side (rear panel) */
13240 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13241 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x00 },
13242 /* CD-in */
13243 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
13244 /* route front mic to ADC1*/
13245 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
13246 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020013247
Kailang Yangdf694da2005-12-05 19:42:22 +010013248 /* Unmute DAC0~3 & spdif out*/
13249 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13250 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13251 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13252 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13253 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020013254
Kailang Yangdf694da2005-12-05 19:42:22 +010013255 /* Unmute Mixer 14 (mic) 1c (Line in)*/
13256 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13257 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13258 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13259 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020013260
Kailang Yangdf694da2005-12-05 19:42:22 +010013261 /* Unmute Stereo Mixer 15 */
13262 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13263 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13264 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013265 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010013266
13267 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13268 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13269 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13270 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13271 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13272 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13273 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13274 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013275 /* hp used DAC 3 (Front) */
13276 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010013277 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
13278
13279 { }
13280};
13281
13282static struct hda_verb alc861_threestack_init_verbs[] = {
13283 /*
13284 * Unmute ADC0 and set the default input to mic-in
13285 */
13286 /* port-A for surround (rear panel) */
13287 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
13288 /* port-B for mic-in (rear panel) with vref */
13289 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13290 /* port-C for line-in (rear panel) */
13291 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
13292 /* port-D for Front */
13293 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13294 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
13295 /* port-E for HP out (front panel) */
13296 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
13297 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010013298 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010013299 /* port-F for mic-in (front panel) with vref */
13300 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13301 /* port-G for CLFE (rear panel) */
13302 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
13303 /* port-H for side (rear panel) */
13304 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
13305 /* CD-in */
13306 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
13307 /* route front mic to ADC1*/
13308 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
13309 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13310 /* Unmute DAC0~3 & spdif out*/
13311 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13312 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13313 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13314 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13315 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020013316
Kailang Yangdf694da2005-12-05 19:42:22 +010013317 /* Unmute Mixer 14 (mic) 1c (Line in)*/
13318 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13319 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13320 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13321 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020013322
Kailang Yangdf694da2005-12-05 19:42:22 +010013323 /* Unmute Stereo Mixer 15 */
13324 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13325 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13326 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013327 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010013328
13329 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13330 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13331 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13332 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13333 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13334 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13335 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13336 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013337 /* hp used DAC 3 (Front) */
13338 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010013339 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
13340 { }
13341};
Takashi Iwai22309c32006-08-09 16:57:28 +020013342
13343static struct hda_verb alc861_uniwill_m31_init_verbs[] = {
13344 /*
13345 * Unmute ADC0 and set the default input to mic-in
13346 */
13347 /* port-A for surround (rear panel) */
13348 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
13349 /* port-B for mic-in (rear panel) with vref */
13350 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13351 /* port-C for line-in (rear panel) */
13352 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
13353 /* port-D for Front */
13354 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13355 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
13356 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013357 /* this has to be set to VREF80 */
13358 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Takashi Iwai22309c32006-08-09 16:57:28 +020013359 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010013360 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai22309c32006-08-09 16:57:28 +020013361 /* port-F for mic-in (front panel) with vref */
13362 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13363 /* port-G for CLFE (rear panel) */
13364 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
13365 /* port-H for side (rear panel) */
13366 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
13367 /* CD-in */
13368 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
13369 /* route front mic to ADC1*/
13370 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
13371 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13372 /* Unmute DAC0~3 & spdif out*/
13373 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13374 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13375 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13376 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13377 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020013378
Takashi Iwai22309c32006-08-09 16:57:28 +020013379 /* Unmute Mixer 14 (mic) 1c (Line in)*/
13380 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13381 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13382 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13383 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020013384
Takashi Iwai22309c32006-08-09 16:57:28 +020013385 /* Unmute Stereo Mixer 15 */
13386 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13387 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13388 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013389 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Takashi Iwai22309c32006-08-09 16:57:28 +020013390
13391 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13392 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13393 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13394 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13395 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13396 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13397 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13398 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013399 /* hp used DAC 3 (Front) */
13400 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Takashi Iwai22309c32006-08-09 16:57:28 +020013401 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
13402 { }
13403};
13404
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013405static struct hda_verb alc861_asus_init_verbs[] = {
13406 /*
13407 * Unmute ADC0 and set the default input to mic-in
13408 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013409 /* port-A for surround (rear panel)
13410 * according to codec#0 this is the HP jack
13411 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013412 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* was 0x00 */
13413 /* route front PCM to HP */
13414 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x01 },
13415 /* port-B for mic-in (rear panel) with vref */
13416 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13417 /* port-C for line-in (rear panel) */
13418 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
13419 /* port-D for Front */
13420 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13421 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
13422 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013423 /* this has to be set to VREF80 */
13424 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013425 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010013426 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013427 /* port-F for mic-in (front panel) with vref */
13428 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13429 /* port-G for CLFE (rear panel) */
13430 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13431 /* port-H for side (rear panel) */
13432 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13433 /* CD-in */
13434 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
13435 /* route front mic to ADC1*/
13436 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
13437 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13438 /* Unmute DAC0~3 & spdif out*/
13439 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13440 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13441 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13442 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13443 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13444 /* Unmute Mixer 14 (mic) 1c (Line in)*/
13445 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13446 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13447 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13448 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020013449
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013450 /* Unmute Stereo Mixer 15 */
13451 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13452 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13453 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013454 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013455
13456 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13457 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13458 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13459 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13460 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13461 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13462 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13463 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013464 /* hp used DAC 3 (Front) */
13465 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013466 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
13467 { }
13468};
13469
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010013470/* additional init verbs for ASUS laptops */
13471static struct hda_verb alc861_asus_laptop_init_verbs[] = {
13472 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x45 }, /* HP-out */
13473 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2) }, /* mute line-in */
13474 { }
13475};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013476
Kailang Yangdf694da2005-12-05 19:42:22 +010013477/*
13478 * generic initialization of ADC, input mixers and output mixers
13479 */
13480static struct hda_verb alc861_auto_init_verbs[] = {
13481 /*
13482 * Unmute ADC0 and set the default input to mic-in
13483 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013484 /* {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, */
Kailang Yangdf694da2005-12-05 19:42:22 +010013485 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020013486
Kailang Yangdf694da2005-12-05 19:42:22 +010013487 /* Unmute DAC0~3 & spdif out*/
13488 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13489 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13490 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13491 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13492 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020013493
Kailang Yangdf694da2005-12-05 19:42:22 +010013494 /* Unmute Mixer 14 (mic) 1c (Line in)*/
13495 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13496 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13497 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13498 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020013499
Kailang Yangdf694da2005-12-05 19:42:22 +010013500 /* Unmute Stereo Mixer 15 */
13501 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13502 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13503 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
13504 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c},
13505
13506 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13507 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13508 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13509 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13510 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13511 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13512 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13513 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13514
13515 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13516 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013517 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
13518 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010013519 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13520 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013521 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
13522 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010013523
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013524 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, /* set Mic 1 */
Kailang Yangdf694da2005-12-05 19:42:22 +010013525
13526 { }
13527};
13528
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013529static struct hda_verb alc861_toshiba_init_verbs[] = {
13530 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013531
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013532 { }
13533};
13534
13535/* toggle speaker-output according to the hp-jack state */
13536static void alc861_toshiba_automute(struct hda_codec *codec)
13537{
13538 unsigned int present;
13539
13540 present = snd_hda_codec_read(codec, 0x0f, 0,
13541 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020013542 snd_hda_codec_amp_stereo(codec, 0x16, HDA_INPUT, 0,
13543 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
13544 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_INPUT, 3,
13545 HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE);
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013546}
13547
13548static void alc861_toshiba_unsol_event(struct hda_codec *codec,
13549 unsigned int res)
13550{
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013551 if ((res >> 26) == ALC880_HP_EVENT)
13552 alc861_toshiba_automute(codec);
13553}
13554
Kailang Yangdf694da2005-12-05 19:42:22 +010013555/* pcm configuration: identiacal with ALC880 */
13556#define alc861_pcm_analog_playback alc880_pcm_analog_playback
13557#define alc861_pcm_analog_capture alc880_pcm_analog_capture
13558#define alc861_pcm_digital_playback alc880_pcm_digital_playback
13559#define alc861_pcm_digital_capture alc880_pcm_digital_capture
13560
13561
13562#define ALC861_DIGOUT_NID 0x07
13563
13564static struct hda_channel_mode alc861_8ch_modes[1] = {
13565 { 8, NULL }
13566};
13567
13568static hda_nid_t alc861_dac_nids[4] = {
13569 /* front, surround, clfe, side */
13570 0x03, 0x06, 0x05, 0x04
13571};
13572
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013573static hda_nid_t alc660_dac_nids[3] = {
13574 /* front, clfe, surround */
13575 0x03, 0x05, 0x06
13576};
13577
Kailang Yangdf694da2005-12-05 19:42:22 +010013578static hda_nid_t alc861_adc_nids[1] = {
13579 /* ADC0-2 */
13580 0x08,
13581};
13582
13583static struct hda_input_mux alc861_capture_source = {
13584 .num_items = 5,
13585 .items = {
13586 { "Mic", 0x0 },
13587 { "Front Mic", 0x3 },
13588 { "Line", 0x1 },
13589 { "CD", 0x4 },
13590 { "Mixer", 0x5 },
13591 },
13592};
13593
13594/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013595static int alc861_auto_fill_dac_nids(struct alc_spec *spec,
13596 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010013597{
13598 int i;
13599 hda_nid_t nid;
13600
13601 spec->multiout.dac_nids = spec->private_dac_nids;
13602 for (i = 0; i < cfg->line_outs; i++) {
13603 nid = cfg->line_out_pins[i];
13604 if (nid) {
13605 if (i >= ARRAY_SIZE(alc861_dac_nids))
13606 continue;
13607 spec->multiout.dac_nids[i] = alc861_dac_nids[i];
13608 }
13609 }
13610 spec->multiout.num_dacs = cfg->line_outs;
13611 return 0;
13612}
13613
13614/* add playback controls from the parsed DAC table */
13615static int alc861_auto_create_multi_out_ctls(struct alc_spec *spec,
13616 const struct auto_pin_cfg *cfg)
13617{
13618 char name[32];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013619 static const char *chname[4] = {
13620 "Front", "Surround", NULL /*CLFE*/, "Side"
13621 };
Kailang Yangdf694da2005-12-05 19:42:22 +010013622 hda_nid_t nid;
13623 int i, idx, err;
13624
13625 for (i = 0; i < cfg->line_outs; i++) {
13626 nid = spec->multiout.dac_nids[i];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013627 if (!nid)
Kailang Yangdf694da2005-12-05 19:42:22 +010013628 continue;
13629 if (nid == 0x05) {
13630 /* Center/LFE */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013631 err = add_control(spec, ALC_CTL_BIND_MUTE,
13632 "Center Playback Switch",
13633 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
13634 HDA_OUTPUT));
13635 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010013636 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013637 err = add_control(spec, ALC_CTL_BIND_MUTE,
13638 "LFE Playback Switch",
13639 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
13640 HDA_OUTPUT));
13641 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010013642 return err;
13643 } else {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013644 for (idx = 0; idx < ARRAY_SIZE(alc861_dac_nids) - 1;
13645 idx++)
Kailang Yangdf694da2005-12-05 19:42:22 +010013646 if (nid == alc861_dac_nids[idx])
13647 break;
13648 sprintf(name, "%s Playback Switch", chname[idx]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013649 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
13650 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
13651 HDA_OUTPUT));
13652 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010013653 return err;
13654 }
13655 }
13656 return 0;
13657}
13658
13659static int alc861_auto_create_hp_ctls(struct alc_spec *spec, hda_nid_t pin)
13660{
13661 int err;
13662 hda_nid_t nid;
13663
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013664 if (!pin)
Kailang Yangdf694da2005-12-05 19:42:22 +010013665 return 0;
13666
13667 if ((pin >= 0x0b && pin <= 0x10) || pin == 0x1f || pin == 0x20) {
13668 nid = 0x03;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013669 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
13670 "Headphone Playback Switch",
13671 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
13672 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010013673 return err;
13674 spec->multiout.hp_nid = nid;
13675 }
13676 return 0;
13677}
13678
13679/* create playback/capture controls for input pins */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013680static int alc861_auto_create_analog_input_ctls(struct alc_spec *spec,
13681 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010013682{
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020013683 struct hda_input_mux *imux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010013684 int i, err, idx, idx1;
13685
13686 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013687 switch (cfg->input_pins[i]) {
Kailang Yangdf694da2005-12-05 19:42:22 +010013688 case 0x0c:
13689 idx1 = 1;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013690 idx = 2; /* Line In */
Kailang Yangdf694da2005-12-05 19:42:22 +010013691 break;
13692 case 0x0f:
13693 idx1 = 2;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013694 idx = 2; /* Line In */
Kailang Yangdf694da2005-12-05 19:42:22 +010013695 break;
13696 case 0x0d:
13697 idx1 = 0;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013698 idx = 1; /* Mic In */
Kailang Yangdf694da2005-12-05 19:42:22 +010013699 break;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013700 case 0x10:
Kailang Yangdf694da2005-12-05 19:42:22 +010013701 idx1 = 3;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013702 idx = 1; /* Mic In */
Kailang Yangdf694da2005-12-05 19:42:22 +010013703 break;
13704 case 0x11:
13705 idx1 = 4;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013706 idx = 0; /* CD */
Kailang Yangdf694da2005-12-05 19:42:22 +010013707 break;
13708 default:
13709 continue;
13710 }
13711
Takashi Iwai4a471b72005-12-07 13:56:29 +010013712 err = new_analog_input(spec, cfg->input_pins[i],
13713 auto_pin_cfg_labels[i], idx, 0x15);
Kailang Yangdf694da2005-12-05 19:42:22 +010013714 if (err < 0)
13715 return err;
13716
Takashi Iwai4a471b72005-12-07 13:56:29 +010013717 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
Kailang Yangdf694da2005-12-05 19:42:22 +010013718 imux->items[imux->num_items].index = idx1;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013719 imux->num_items++;
Kailang Yangdf694da2005-12-05 19:42:22 +010013720 }
13721 return 0;
13722}
13723
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013724static void alc861_auto_set_output_and_unmute(struct hda_codec *codec,
13725 hda_nid_t nid,
Kailang Yangdf694da2005-12-05 19:42:22 +010013726 int pin_type, int dac_idx)
13727{
Jacek Luczak564c5be2008-05-03 18:41:23 +020013728 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
13729 pin_type);
13730 snd_hda_codec_write(codec, dac_idx, 0, AC_VERB_SET_AMP_GAIN_MUTE,
13731 AMP_OUT_UNMUTE);
Kailang Yangdf694da2005-12-05 19:42:22 +010013732}
13733
13734static void alc861_auto_init_multi_out(struct hda_codec *codec)
13735{
13736 struct alc_spec *spec = codec->spec;
13737 int i;
13738
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013739 alc_subsystem_id(codec, 0x0e, 0x0f, 0x0b);
Kailang Yangdf694da2005-12-05 19:42:22 +010013740 for (i = 0; i < spec->autocfg.line_outs; i++) {
13741 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020013742 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangdf694da2005-12-05 19:42:22 +010013743 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020013744 alc861_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013745 spec->multiout.dac_nids[i]);
Kailang Yangdf694da2005-12-05 19:42:22 +010013746 }
13747}
13748
13749static void alc861_auto_init_hp_out(struct hda_codec *codec)
13750{
13751 struct alc_spec *spec = codec->spec;
13752 hda_nid_t pin;
13753
Takashi Iwaieb06ed82006-09-20 17:10:27 +020013754 pin = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010013755 if (pin) /* connect to front */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013756 alc861_auto_set_output_and_unmute(codec, pin, PIN_HP,
13757 spec->multiout.dac_nids[0]);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013758 pin = spec->autocfg.speaker_pins[0];
13759 if (pin)
13760 alc861_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Kailang Yangdf694da2005-12-05 19:42:22 +010013761}
13762
13763static void alc861_auto_init_analog_input(struct hda_codec *codec)
13764{
13765 struct alc_spec *spec = codec->spec;
13766 int i;
13767
13768 for (i = 0; i < AUTO_PIN_LAST; i++) {
13769 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013770 if (nid >= 0x0c && nid <= 0x11) {
13771 snd_hda_codec_write(codec, nid, 0,
13772 AC_VERB_SET_PIN_WIDGET_CONTROL,
13773 i <= AUTO_PIN_FRONT_MIC ?
13774 PIN_VREF80 : PIN_IN);
Kailang Yangdf694da2005-12-05 19:42:22 +010013775 }
13776 }
13777}
13778
13779/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013780/* return 1 if successful, 0 if the proper config is not found,
13781 * or a negative error code
13782 */
Kailang Yangdf694da2005-12-05 19:42:22 +010013783static int alc861_parse_auto_config(struct hda_codec *codec)
13784{
13785 struct alc_spec *spec = codec->spec;
13786 int err;
13787 static hda_nid_t alc861_ignore[] = { 0x1d, 0 };
13788
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013789 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
13790 alc861_ignore);
13791 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010013792 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013793 if (!spec->autocfg.line_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +010013794 return 0; /* can't find valid BIOS pin config */
13795
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013796 err = alc861_auto_fill_dac_nids(spec, &spec->autocfg);
13797 if (err < 0)
13798 return err;
13799 err = alc861_auto_create_multi_out_ctls(spec, &spec->autocfg);
13800 if (err < 0)
13801 return err;
13802 err = alc861_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
13803 if (err < 0)
13804 return err;
13805 err = alc861_auto_create_analog_input_ctls(spec, &spec->autocfg);
13806 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010013807 return err;
13808
13809 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
13810
13811 if (spec->autocfg.dig_out_pin)
13812 spec->multiout.dig_out_nid = ALC861_DIGOUT_NID;
13813
Takashi Iwai603c4012008-07-30 15:01:44 +020013814 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010013815 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +010013816
Takashi Iwaid88897e2008-10-31 15:01:37 +010013817 add_verb(spec, alc861_auto_init_verbs);
Kailang Yangdf694da2005-12-05 19:42:22 +010013818
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020013819 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020013820 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010013821
13822 spec->adc_nids = alc861_adc_nids;
13823 spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids);
Takashi Iwaif9e336f2008-10-31 16:37:07 +010013824 set_capture_mixer(spec);
Kailang Yangdf694da2005-12-05 19:42:22 +010013825
Takashi Iwaie044c392008-10-27 16:56:24 +010013826 store_pin_configs(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010013827 return 1;
13828}
13829
Takashi Iwaiae6b8132006-03-03 16:47:17 +010013830/* additional initialization for auto-configuration model */
13831static void alc861_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010013832{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013833 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010013834 alc861_auto_init_multi_out(codec);
13835 alc861_auto_init_hp_out(codec);
13836 alc861_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013837 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020013838 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010013839}
13840
Takashi Iwaicb53c622007-08-10 17:21:45 +020013841#ifdef CONFIG_SND_HDA_POWER_SAVE
13842static struct hda_amp_list alc861_loopbacks[] = {
13843 { 0x15, HDA_INPUT, 0 },
13844 { 0x15, HDA_INPUT, 1 },
13845 { 0x15, HDA_INPUT, 2 },
13846 { 0x15, HDA_INPUT, 3 },
13847 { } /* end */
13848};
13849#endif
13850
Kailang Yangdf694da2005-12-05 19:42:22 +010013851
13852/*
13853 * configuration and preset
13854 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010013855static const char *alc861_models[ALC861_MODEL_LAST] = {
13856 [ALC861_3ST] = "3stack",
13857 [ALC660_3ST] = "3stack-660",
13858 [ALC861_3ST_DIG] = "3stack-dig",
13859 [ALC861_6ST_DIG] = "6stack-dig",
13860 [ALC861_UNIWILL_M31] = "uniwill-m31",
13861 [ALC861_TOSHIBA] = "toshiba",
13862 [ALC861_ASUS] = "asus",
13863 [ALC861_ASUS_LAPTOP] = "asus-laptop",
13864 [ALC861_AUTO] = "auto",
13865};
13866
13867static struct snd_pci_quirk alc861_cfg_tbl[] = {
Takashi Iwai687a47b2007-01-10 11:25:58 +010013868 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010013869 SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP),
13870 SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP),
13871 SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013872 SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP),
Kailang Yang83c34212007-07-05 11:43:05 +020013873 SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS P1-AH2", ALC861_3ST_DIG),
Tobin Davisad5e7732007-01-08 10:57:32 +010013874 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA),
Takashi Iwai341d4eb2007-07-09 17:53:18 +020013875 /* FIXME: the entry below breaks Toshiba A100 (model=auto works!)
13876 * Any other models that need this preset?
13877 */
13878 /* SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), */
Claudio Matsuokaef64adb2007-07-14 00:26:16 +020013879 SND_PCI_QUIRK(0x1462, 0x7254, "HP dx2200 (MSI MS-7254)", ALC861_3ST),
13880 SND_PCI_QUIRK(0x1462, 0x7297, "HP dx2250 (MSI MS-7297)", ALC861_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013881 SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31),
13882 SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31),
13883 SND_PCI_QUIRK(0x1584, 0x9075, "Airis Praxis N1212", ALC861_ASUS_LAPTOP),
13884 /* FIXME: the below seems conflict */
13885 /* SND_PCI_QUIRK(0x1584, 0x9075, "Uniwill", ALC861_UNIWILL_M31), */
13886 SND_PCI_QUIRK(0x1849, 0x0660, "Asrock 939SLI32", ALC660_3ST),
13887 SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST),
Kailang Yangdf694da2005-12-05 19:42:22 +010013888 {}
13889};
13890
13891static struct alc_config_preset alc861_presets[] = {
13892 [ALC861_3ST] = {
13893 .mixers = { alc861_3ST_mixer },
13894 .init_verbs = { alc861_threestack_init_verbs },
13895 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
13896 .dac_nids = alc861_dac_nids,
13897 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
13898 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020013899 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010013900 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13901 .adc_nids = alc861_adc_nids,
13902 .input_mux = &alc861_capture_source,
13903 },
13904 [ALC861_3ST_DIG] = {
13905 .mixers = { alc861_base_mixer },
13906 .init_verbs = { alc861_threestack_init_verbs },
13907 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
13908 .dac_nids = alc861_dac_nids,
13909 .dig_out_nid = ALC861_DIGOUT_NID,
13910 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
13911 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020013912 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010013913 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13914 .adc_nids = alc861_adc_nids,
13915 .input_mux = &alc861_capture_source,
13916 },
13917 [ALC861_6ST_DIG] = {
13918 .mixers = { alc861_base_mixer },
13919 .init_verbs = { alc861_base_init_verbs },
13920 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
13921 .dac_nids = alc861_dac_nids,
13922 .dig_out_nid = ALC861_DIGOUT_NID,
13923 .num_channel_mode = ARRAY_SIZE(alc861_8ch_modes),
13924 .channel_mode = alc861_8ch_modes,
13925 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13926 .adc_nids = alc861_adc_nids,
13927 .input_mux = &alc861_capture_source,
13928 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013929 [ALC660_3ST] = {
13930 .mixers = { alc861_3ST_mixer },
13931 .init_verbs = { alc861_threestack_init_verbs },
13932 .num_dacs = ARRAY_SIZE(alc660_dac_nids),
13933 .dac_nids = alc660_dac_nids,
13934 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
13935 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020013936 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013937 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13938 .adc_nids = alc861_adc_nids,
13939 .input_mux = &alc861_capture_source,
13940 },
Takashi Iwai22309c32006-08-09 16:57:28 +020013941 [ALC861_UNIWILL_M31] = {
13942 .mixers = { alc861_uniwill_m31_mixer },
13943 .init_verbs = { alc861_uniwill_m31_init_verbs },
13944 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
13945 .dac_nids = alc861_dac_nids,
13946 .dig_out_nid = ALC861_DIGOUT_NID,
13947 .num_channel_mode = ARRAY_SIZE(alc861_uniwill_m31_modes),
13948 .channel_mode = alc861_uniwill_m31_modes,
13949 .need_dac_fix = 1,
13950 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13951 .adc_nids = alc861_adc_nids,
13952 .input_mux = &alc861_capture_source,
13953 },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013954 [ALC861_TOSHIBA] = {
13955 .mixers = { alc861_toshiba_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013956 .init_verbs = { alc861_base_init_verbs,
13957 alc861_toshiba_init_verbs },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013958 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
13959 .dac_nids = alc861_dac_nids,
13960 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
13961 .channel_mode = alc883_3ST_2ch_modes,
13962 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13963 .adc_nids = alc861_adc_nids,
13964 .input_mux = &alc861_capture_source,
13965 .unsol_event = alc861_toshiba_unsol_event,
13966 .init_hook = alc861_toshiba_automute,
13967 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013968 [ALC861_ASUS] = {
13969 .mixers = { alc861_asus_mixer },
13970 .init_verbs = { alc861_asus_init_verbs },
13971 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
13972 .dac_nids = alc861_dac_nids,
13973 .dig_out_nid = ALC861_DIGOUT_NID,
13974 .num_channel_mode = ARRAY_SIZE(alc861_asus_modes),
13975 .channel_mode = alc861_asus_modes,
13976 .need_dac_fix = 1,
13977 .hp_nid = 0x06,
13978 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13979 .adc_nids = alc861_adc_nids,
13980 .input_mux = &alc861_capture_source,
13981 },
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010013982 [ALC861_ASUS_LAPTOP] = {
13983 .mixers = { alc861_toshiba_mixer, alc861_asus_laptop_mixer },
13984 .init_verbs = { alc861_asus_init_verbs,
13985 alc861_asus_laptop_init_verbs },
13986 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
13987 .dac_nids = alc861_dac_nids,
13988 .dig_out_nid = ALC861_DIGOUT_NID,
13989 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
13990 .channel_mode = alc883_3ST_2ch_modes,
13991 .need_dac_fix = 1,
13992 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13993 .adc_nids = alc861_adc_nids,
13994 .input_mux = &alc861_capture_source,
13995 },
13996};
Kailang Yangdf694da2005-12-05 19:42:22 +010013997
13998
13999static int patch_alc861(struct hda_codec *codec)
14000{
14001 struct alc_spec *spec;
14002 int board_config;
14003 int err;
14004
Robert P. J. Daydc041e02006-12-19 14:44:15 +010014005 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010014006 if (spec == NULL)
14007 return -ENOMEM;
14008
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014009 codec->spec = spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010014010
Takashi Iwaif5fcc132006-11-24 17:07:44 +010014011 board_config = snd_hda_check_board_config(codec, ALC861_MODEL_LAST,
14012 alc861_models,
14013 alc861_cfg_tbl);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014014
Takashi Iwaif5fcc132006-11-24 17:07:44 +010014015 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014016 printk(KERN_INFO "hda_codec: Unknown model for ALC861, "
14017 "trying auto-probe from BIOS...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010014018 board_config = ALC861_AUTO;
14019 }
14020
14021 if (board_config == ALC861_AUTO) {
14022 /* automatic parse from the BIOS config */
14023 err = alc861_parse_auto_config(codec);
14024 if (err < 0) {
14025 alc_free(codec);
14026 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014027 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014028 printk(KERN_INFO
14029 "hda_codec: Cannot set up configuration "
14030 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010014031 board_config = ALC861_3ST_DIG;
14032 }
14033 }
14034
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090014035 err = snd_hda_attach_beep_device(codec, 0x23);
14036 if (err < 0) {
14037 alc_free(codec);
14038 return err;
14039 }
14040
Kailang Yangdf694da2005-12-05 19:42:22 +010014041 if (board_config != ALC861_AUTO)
14042 setup_preset(spec, &alc861_presets[board_config]);
14043
14044 spec->stream_name_analog = "ALC861 Analog";
14045 spec->stream_analog_playback = &alc861_pcm_analog_playback;
14046 spec->stream_analog_capture = &alc861_pcm_analog_capture;
14047
14048 spec->stream_name_digital = "ALC861 Digital";
14049 spec->stream_digital_playback = &alc861_pcm_digital_playback;
14050 spec->stream_digital_capture = &alc861_pcm_digital_capture;
14051
Takashi Iwai2134ea42008-01-10 16:53:55 +010014052 spec->vmaster_nid = 0x03;
14053
Kailang Yangdf694da2005-12-05 19:42:22 +010014054 codec->patch_ops = alc_patch_ops;
14055 if (board_config == ALC861_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +010014056 spec->init_hook = alc861_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020014057#ifdef CONFIG_SND_HDA_POWER_SAVE
14058 if (!spec->loopback.amplist)
14059 spec->loopback.amplist = alc861_loopbacks;
14060#endif
Takashi Iwaidaead532008-11-28 12:55:36 +010014061 codec->proc_widget_hook = print_realtek_coef;
Kailang Yangea1fb292008-08-26 12:58:38 +020014062
Kailang Yangdf694da2005-12-05 19:42:22 +010014063 return 0;
14064}
14065
14066/*
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014067 * ALC861-VD support
14068 *
14069 * Based on ALC882
14070 *
14071 * In addition, an independent DAC
14072 */
14073#define ALC861VD_DIGOUT_NID 0x06
14074
14075static hda_nid_t alc861vd_dac_nids[4] = {
14076 /* front, surr, clfe, side surr */
14077 0x02, 0x03, 0x04, 0x05
14078};
14079
14080/* dac_nids for ALC660vd are in a different order - according to
14081 * Realtek's driver.
14082 * This should probably tesult in a different mixer for 6stack models
14083 * of ALC660vd codecs, but for now there is only 3stack mixer
14084 * - and it is the same as in 861vd.
14085 * adc_nids in ALC660vd are (is) the same as in 861vd
14086 */
14087static hda_nid_t alc660vd_dac_nids[3] = {
14088 /* front, rear, clfe, rear_surr */
14089 0x02, 0x04, 0x03
14090};
14091
14092static hda_nid_t alc861vd_adc_nids[1] = {
14093 /* ADC0 */
14094 0x09,
14095};
14096
Takashi Iwaie1406342008-02-11 18:32:32 +010014097static hda_nid_t alc861vd_capsrc_nids[1] = { 0x22 };
14098
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014099/* input MUX */
14100/* FIXME: should be a matrix-type input source selection */
14101static struct hda_input_mux alc861vd_capture_source = {
14102 .num_items = 4,
14103 .items = {
14104 { "Mic", 0x0 },
14105 { "Front Mic", 0x1 },
14106 { "Line", 0x2 },
14107 { "CD", 0x4 },
14108 },
14109};
14110
Kailang Yang272a5272007-05-14 11:00:38 +020014111static struct hda_input_mux alc861vd_dallas_capture_source = {
Tobin Davisb419f342008-03-07 11:57:51 +010014112 .num_items = 2,
Kailang Yang272a5272007-05-14 11:00:38 +020014113 .items = {
Tobin Davisb419f342008-03-07 11:57:51 +010014114 { "Ext Mic", 0x0 },
14115 { "Int Mic", 0x1 },
Kailang Yang272a5272007-05-14 11:00:38 +020014116 },
14117};
14118
Kailang Yangd1a991a2007-08-15 16:21:59 +020014119static struct hda_input_mux alc861vd_hp_capture_source = {
14120 .num_items = 2,
14121 .items = {
14122 { "Front Mic", 0x0 },
14123 { "ATAPI Mic", 0x1 },
14124 },
14125};
14126
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014127/*
14128 * 2ch mode
14129 */
14130static struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = {
14131 { 2, NULL }
14132};
14133
14134/*
14135 * 6ch mode
14136 */
14137static struct hda_verb alc861vd_6stack_ch6_init[] = {
14138 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
14139 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14140 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14141 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14142 { } /* end */
14143};
14144
14145/*
14146 * 8ch mode
14147 */
14148static struct hda_verb alc861vd_6stack_ch8_init[] = {
14149 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14150 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14151 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14152 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14153 { } /* end */
14154};
14155
14156static struct hda_channel_mode alc861vd_6stack_modes[2] = {
14157 { 6, alc861vd_6stack_ch6_init },
14158 { 8, alc861vd_6stack_ch8_init },
14159};
14160
14161static struct snd_kcontrol_new alc861vd_chmode_mixer[] = {
14162 {
14163 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
14164 .name = "Channel Mode",
14165 .info = alc_ch_mode_info,
14166 .get = alc_ch_mode_get,
14167 .put = alc_ch_mode_put,
14168 },
14169 { } /* end */
14170};
14171
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014172/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
14173 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
14174 */
14175static struct snd_kcontrol_new alc861vd_6st_mixer[] = {
14176 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14177 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
14178
14179 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
14180 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
14181
14182 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0,
14183 HDA_OUTPUT),
14184 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0,
14185 HDA_OUTPUT),
14186 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
14187 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
14188
14189 HDA_CODEC_VOLUME("Side Playback Volume", 0x05, 0x0, HDA_OUTPUT),
14190 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
14191
14192 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
14193
14194 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
14195 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14196 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14197
14198 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
14199 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14200 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14201
14202 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
14203 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
14204
14205 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
14206 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
14207
14208 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
14209 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
14210
14211 { } /* end */
14212};
14213
14214static struct snd_kcontrol_new alc861vd_3st_mixer[] = {
14215 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14216 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
14217
14218 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
14219
14220 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
14221 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14222 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14223
14224 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
14225 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14226 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14227
14228 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
14229 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
14230
14231 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
14232 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
14233
14234 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
14235 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
14236
14237 { } /* end */
14238};
14239
Kailang Yangbdd148a2007-05-08 15:19:08 +020014240static struct snd_kcontrol_new alc861vd_lenovo_mixer[] = {
14241 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14242 /*HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),*/
14243 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
14244
14245 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
14246
14247 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
14248 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14249 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14250
14251 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
14252 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14253 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14254
14255 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
14256 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
14257
14258 { } /* end */
14259};
14260
Tobin Davisb419f342008-03-07 11:57:51 +010014261/* Pin assignment: Speaker=0x14, HP = 0x15,
14262 * Ext Mic=0x18, Int Mic = 0x19, CD = 0x1c, PC Beep = 0x1d
Kailang Yang272a5272007-05-14 11:00:38 +020014263 */
14264static struct snd_kcontrol_new alc861vd_dallas_mixer[] = {
Tobin Davisb419f342008-03-07 11:57:51 +010014265 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14266 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020014267 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
14268 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
Tobin Davisb419f342008-03-07 11:57:51 +010014269 HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
14270 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14271 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14272 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
14273 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14274 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14275 HDA_CODEC_VOLUME("PC Beep Volume", 0x0b, 0x05, HDA_INPUT),
14276 HDA_CODEC_MUTE("PC Beep Switch", 0x0b, 0x05, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020014277 { } /* end */
14278};
14279
Kailang Yangd1a991a2007-08-15 16:21:59 +020014280/* Pin assignment: Speaker=0x14, Line-out = 0x15,
14281 * Front Mic=0x18, ATAPI Mic = 0x19,
14282 */
14283static struct snd_kcontrol_new alc861vd_hp_mixer[] = {
14284 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14285 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
14286 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
14287 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
14288 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14289 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14290 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14291 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangea1fb292008-08-26 12:58:38 +020014292
Kailang Yangd1a991a2007-08-15 16:21:59 +020014293 { } /* end */
14294};
14295
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014296/*
14297 * generic initialization of ADC, input mixers and output mixers
14298 */
14299static struct hda_verb alc861vd_volume_init_verbs[] = {
14300 /*
14301 * Unmute ADC0 and set the default input to mic-in
14302 */
14303 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
14304 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14305
14306 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of
14307 * the analog-loopback mixer widget
14308 */
14309 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020014310 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14311 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
14312 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
14313 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
14314 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014315
14316 /* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yangbdd148a2007-05-08 15:19:08 +020014317 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14318 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14319 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014320 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014321
14322 /*
14323 * Set up output mixers (0x02 - 0x05)
14324 */
14325 /* set vol=0 to output mixers */
14326 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14327 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14328 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14329 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14330
14331 /* set up input amps for analog loopback */
14332 /* Amp Indices: DAC = 0, mixer = 1 */
14333 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14334 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
14335 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14336 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
14337 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14338 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
14339 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14340 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
14341
14342 { }
14343};
14344
14345/*
14346 * 3-stack pin configuration:
14347 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
14348 */
14349static struct hda_verb alc861vd_3stack_init_verbs[] = {
14350 /*
14351 * Set pin mode and muting
14352 */
14353 /* set front pin widgets 0x14 for output */
14354 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14355 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14356 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
14357
14358 /* Mic (rear) pin: input vref at 80% */
14359 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14360 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14361 /* Front Mic pin: input vref at 80% */
14362 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14363 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14364 /* Line In pin: input */
14365 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14366 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14367 /* Line-2 In: Headphone output (output 0 - 0x0c) */
14368 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14369 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14370 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
14371 /* CD pin widget for input */
14372 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14373
14374 { }
14375};
14376
14377/*
14378 * 6-stack pin configuration:
14379 */
14380static struct hda_verb alc861vd_6stack_init_verbs[] = {
14381 /*
14382 * Set pin mode and muting
14383 */
14384 /* set front pin widgets 0x14 for output */
14385 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14386 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14387 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
14388
14389 /* Rear Pin: output 1 (0x0d) */
14390 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14391 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14392 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
14393 /* CLFE Pin: output 2 (0x0e) */
14394 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14395 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14396 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
14397 /* Side Pin: output 3 (0x0f) */
14398 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14399 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14400 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
14401
14402 /* Mic (rear) pin: input vref at 80% */
14403 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14404 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14405 /* Front Mic pin: input vref at 80% */
14406 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14407 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14408 /* Line In pin: input */
14409 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14410 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14411 /* Line-2 In: Headphone output (output 0 - 0x0c) */
14412 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14413 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14414 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
14415 /* CD pin widget for input */
14416 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14417
14418 { }
14419};
14420
Kailang Yangbdd148a2007-05-08 15:19:08 +020014421static struct hda_verb alc861vd_eapd_verbs[] = {
14422 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
14423 { }
14424};
14425
Kailang Yangf9423e72008-05-27 12:32:25 +020014426static struct hda_verb alc660vd_eapd_verbs[] = {
14427 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
14428 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
14429 { }
14430};
14431
Kailang Yangbdd148a2007-05-08 15:19:08 +020014432static struct hda_verb alc861vd_lenovo_unsol_verbs[] = {
14433 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14434 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14435 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
14436 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Kailang Yangea1fb292008-08-26 12:58:38 +020014437 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
Kailang Yangbdd148a2007-05-08 15:19:08 +020014438 {}
14439};
14440
14441/* toggle speaker-output according to the hp-jack state */
14442static void alc861vd_lenovo_hp_automute(struct hda_codec *codec)
14443{
14444 unsigned int present;
14445 unsigned char bits;
14446
14447 present = snd_hda_codec_read(codec, 0x1b, 0,
14448 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020014449 bits = present ? HDA_AMP_MUTE : 0;
14450 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
14451 HDA_AMP_MUTE, bits);
Kailang Yangbdd148a2007-05-08 15:19:08 +020014452}
14453
14454static void alc861vd_lenovo_mic_automute(struct hda_codec *codec)
14455{
14456 unsigned int present;
14457 unsigned char bits;
14458
14459 present = snd_hda_codec_read(codec, 0x18, 0,
14460 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020014461 bits = present ? HDA_AMP_MUTE : 0;
14462 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
14463 HDA_AMP_MUTE, bits);
Kailang Yangbdd148a2007-05-08 15:19:08 +020014464}
14465
14466static void alc861vd_lenovo_automute(struct hda_codec *codec)
14467{
14468 alc861vd_lenovo_hp_automute(codec);
14469 alc861vd_lenovo_mic_automute(codec);
14470}
14471
14472static void alc861vd_lenovo_unsol_event(struct hda_codec *codec,
14473 unsigned int res)
14474{
14475 switch (res >> 26) {
14476 case ALC880_HP_EVENT:
14477 alc861vd_lenovo_hp_automute(codec);
14478 break;
14479 case ALC880_MIC_EVENT:
14480 alc861vd_lenovo_mic_automute(codec);
14481 break;
14482 }
14483}
14484
Kailang Yang272a5272007-05-14 11:00:38 +020014485static struct hda_verb alc861vd_dallas_verbs[] = {
14486 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14487 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14488 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14489 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14490
14491 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14492 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14493 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14494 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
14495 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14496 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
14497 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14498 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020014499
Kailang Yang272a5272007-05-14 11:00:38 +020014500 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14501 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14502 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14503 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14504 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14505 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14506 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14507 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14508
14509 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
14510 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14511 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
14512 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14513 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14514 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14515 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14516 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14517
14518 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14519 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
14520 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
14521 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
14522
14523 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020014524 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yang272a5272007-05-14 11:00:38 +020014525 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14526
14527 { } /* end */
14528};
14529
14530/* toggle speaker-output according to the hp-jack state */
14531static void alc861vd_dallas_automute(struct hda_codec *codec)
14532{
14533 unsigned int present;
14534
14535 present = snd_hda_codec_read(codec, 0x15, 0,
14536 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020014537 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
14538 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +020014539}
14540
14541static void alc861vd_dallas_unsol_event(struct hda_codec *codec, unsigned int res)
14542{
14543 if ((res >> 26) == ALC880_HP_EVENT)
14544 alc861vd_dallas_automute(codec);
14545}
14546
Takashi Iwaicb53c622007-08-10 17:21:45 +020014547#ifdef CONFIG_SND_HDA_POWER_SAVE
14548#define alc861vd_loopbacks alc880_loopbacks
14549#endif
14550
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014551/* pcm configuration: identiacal with ALC880 */
14552#define alc861vd_pcm_analog_playback alc880_pcm_analog_playback
14553#define alc861vd_pcm_analog_capture alc880_pcm_analog_capture
14554#define alc861vd_pcm_digital_playback alc880_pcm_digital_playback
14555#define alc861vd_pcm_digital_capture alc880_pcm_digital_capture
14556
14557/*
14558 * configuration and preset
14559 */
14560static const char *alc861vd_models[ALC861VD_MODEL_LAST] = {
14561 [ALC660VD_3ST] = "3stack-660",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020014562 [ALC660VD_3ST_DIG] = "3stack-660-digout",
Takashi Iwai13c94742008-11-05 08:06:08 +010014563 [ALC660VD_ASUS_V1S] = "asus-v1s",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014564 [ALC861VD_3ST] = "3stack",
14565 [ALC861VD_3ST_DIG] = "3stack-digout",
14566 [ALC861VD_6ST_DIG] = "6stack-digout",
Kailang Yangbdd148a2007-05-08 15:19:08 +020014567 [ALC861VD_LENOVO] = "lenovo",
Kailang Yang272a5272007-05-14 11:00:38 +020014568 [ALC861VD_DALLAS] = "dallas",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020014569 [ALC861VD_HP] = "hp",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014570 [ALC861VD_AUTO] = "auto",
14571};
14572
14573static struct snd_pci_quirk alc861vd_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +010014574 SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST),
14575 SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP),
Takashi Iwai07e038b2007-02-15 18:23:41 +010014576 SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014577 SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),
Takashi Iwai13c94742008-11-05 08:06:08 +010014578 SND_PCI_QUIRK(0x1043, 0x1633, "Asus V1Sn", ALC660VD_ASUS_V1S),
Mike Crash6963f842007-06-25 12:12:51 +020014579 SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014580 SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010014581 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO),
Takashi Iwai38baf5a2007-08-16 17:52:43 +020014582 /*SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS),*/ /*lenovo*/
Kailang Yang272a5272007-05-14 11:00:38 +020014583 SND_PCI_QUIRK(0x1179, 0xff01, "DALLAS", ALC861VD_DALLAS),
Takashi Iwai542d7c62007-08-16 18:57:30 +020014584 SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO),
Tobin Davisb419f342008-03-07 11:57:51 +010014585 SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_DALLAS),
Takashi Iwai39c5d412007-08-15 16:24:17 +020014586 SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010014587 SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo", ALC861VD_LENOVO),
14588 SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo 3000 C200", ALC861VD_LENOVO),
Takashi Iwaibe321a82008-07-07 16:04:04 +020014589 SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 N200", ALC861VD_LENOVO),
Tobin Davis625dc0b2007-07-30 21:42:10 +020014590 SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014591 {}
14592};
14593
14594static struct alc_config_preset alc861vd_presets[] = {
14595 [ALC660VD_3ST] = {
14596 .mixers = { alc861vd_3st_mixer },
14597 .init_verbs = { alc861vd_volume_init_verbs,
14598 alc861vd_3stack_init_verbs },
14599 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
14600 .dac_nids = alc660vd_dac_nids,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014601 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14602 .channel_mode = alc861vd_3stack_2ch_modes,
14603 .input_mux = &alc861vd_capture_source,
14604 },
Mike Crash6963f842007-06-25 12:12:51 +020014605 [ALC660VD_3ST_DIG] = {
14606 .mixers = { alc861vd_3st_mixer },
14607 .init_verbs = { alc861vd_volume_init_verbs,
14608 alc861vd_3stack_init_verbs },
14609 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
14610 .dac_nids = alc660vd_dac_nids,
14611 .dig_out_nid = ALC861VD_DIGOUT_NID,
Mike Crash6963f842007-06-25 12:12:51 +020014612 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14613 .channel_mode = alc861vd_3stack_2ch_modes,
14614 .input_mux = &alc861vd_capture_source,
14615 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014616 [ALC861VD_3ST] = {
14617 .mixers = { alc861vd_3st_mixer },
14618 .init_verbs = { alc861vd_volume_init_verbs,
14619 alc861vd_3stack_init_verbs },
14620 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
14621 .dac_nids = alc861vd_dac_nids,
14622 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14623 .channel_mode = alc861vd_3stack_2ch_modes,
14624 .input_mux = &alc861vd_capture_source,
14625 },
14626 [ALC861VD_3ST_DIG] = {
14627 .mixers = { alc861vd_3st_mixer },
14628 .init_verbs = { alc861vd_volume_init_verbs,
14629 alc861vd_3stack_init_verbs },
14630 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
14631 .dac_nids = alc861vd_dac_nids,
14632 .dig_out_nid = ALC861VD_DIGOUT_NID,
14633 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14634 .channel_mode = alc861vd_3stack_2ch_modes,
14635 .input_mux = &alc861vd_capture_source,
14636 },
14637 [ALC861VD_6ST_DIG] = {
14638 .mixers = { alc861vd_6st_mixer, alc861vd_chmode_mixer },
14639 .init_verbs = { alc861vd_volume_init_verbs,
14640 alc861vd_6stack_init_verbs },
14641 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
14642 .dac_nids = alc861vd_dac_nids,
14643 .dig_out_nid = ALC861VD_DIGOUT_NID,
14644 .num_channel_mode = ARRAY_SIZE(alc861vd_6stack_modes),
14645 .channel_mode = alc861vd_6stack_modes,
14646 .input_mux = &alc861vd_capture_source,
14647 },
Kailang Yangbdd148a2007-05-08 15:19:08 +020014648 [ALC861VD_LENOVO] = {
14649 .mixers = { alc861vd_lenovo_mixer },
14650 .init_verbs = { alc861vd_volume_init_verbs,
14651 alc861vd_3stack_init_verbs,
14652 alc861vd_eapd_verbs,
14653 alc861vd_lenovo_unsol_verbs },
14654 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
14655 .dac_nids = alc660vd_dac_nids,
Kailang Yangbdd148a2007-05-08 15:19:08 +020014656 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14657 .channel_mode = alc861vd_3stack_2ch_modes,
14658 .input_mux = &alc861vd_capture_source,
14659 .unsol_event = alc861vd_lenovo_unsol_event,
14660 .init_hook = alc861vd_lenovo_automute,
14661 },
Kailang Yang272a5272007-05-14 11:00:38 +020014662 [ALC861VD_DALLAS] = {
14663 .mixers = { alc861vd_dallas_mixer },
14664 .init_verbs = { alc861vd_dallas_verbs },
14665 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
14666 .dac_nids = alc861vd_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +020014667 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14668 .channel_mode = alc861vd_3stack_2ch_modes,
14669 .input_mux = &alc861vd_dallas_capture_source,
14670 .unsol_event = alc861vd_dallas_unsol_event,
14671 .init_hook = alc861vd_dallas_automute,
Kailang Yangd1a991a2007-08-15 16:21:59 +020014672 },
14673 [ALC861VD_HP] = {
14674 .mixers = { alc861vd_hp_mixer },
14675 .init_verbs = { alc861vd_dallas_verbs, alc861vd_eapd_verbs },
14676 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
14677 .dac_nids = alc861vd_dac_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020014678 .dig_out_nid = ALC861VD_DIGOUT_NID,
Kailang Yangd1a991a2007-08-15 16:21:59 +020014679 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14680 .channel_mode = alc861vd_3stack_2ch_modes,
14681 .input_mux = &alc861vd_hp_capture_source,
14682 .unsol_event = alc861vd_dallas_unsol_event,
14683 .init_hook = alc861vd_dallas_automute,
Kailang Yangea1fb292008-08-26 12:58:38 +020014684 },
Takashi Iwai13c94742008-11-05 08:06:08 +010014685 [ALC660VD_ASUS_V1S] = {
14686 .mixers = { alc861vd_lenovo_mixer },
14687 .init_verbs = { alc861vd_volume_init_verbs,
14688 alc861vd_3stack_init_verbs,
14689 alc861vd_eapd_verbs,
14690 alc861vd_lenovo_unsol_verbs },
14691 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
14692 .dac_nids = alc660vd_dac_nids,
14693 .dig_out_nid = ALC861VD_DIGOUT_NID,
14694 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14695 .channel_mode = alc861vd_3stack_2ch_modes,
14696 .input_mux = &alc861vd_capture_source,
14697 .unsol_event = alc861vd_lenovo_unsol_event,
14698 .init_hook = alc861vd_lenovo_automute,
14699 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014700};
14701
14702/*
14703 * BIOS auto configuration
14704 */
14705static void alc861vd_auto_set_output_and_unmute(struct hda_codec *codec,
14706 hda_nid_t nid, int pin_type, int dac_idx)
14707{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014708 alc_set_pin_output(codec, nid, pin_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014709}
14710
14711static void alc861vd_auto_init_multi_out(struct hda_codec *codec)
14712{
14713 struct alc_spec *spec = codec->spec;
14714 int i;
14715
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014716 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014717 for (i = 0; i <= HDA_SIDE; i++) {
14718 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020014719 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014720 if (nid)
14721 alc861vd_auto_set_output_and_unmute(codec, nid,
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020014722 pin_type, i);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014723 }
14724}
14725
14726
14727static void alc861vd_auto_init_hp_out(struct hda_codec *codec)
14728{
14729 struct alc_spec *spec = codec->spec;
14730 hda_nid_t pin;
14731
14732 pin = spec->autocfg.hp_pins[0];
14733 if (pin) /* connect to front and use dac 0 */
14734 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014735 pin = spec->autocfg.speaker_pins[0];
14736 if (pin)
14737 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014738}
14739
14740#define alc861vd_is_input_pin(nid) alc880_is_input_pin(nid)
14741#define ALC861VD_PIN_CD_NID ALC880_PIN_CD_NID
14742
14743static void alc861vd_auto_init_analog_input(struct hda_codec *codec)
14744{
14745 struct alc_spec *spec = codec->spec;
14746 int i;
14747
14748 for (i = 0; i < AUTO_PIN_LAST; i++) {
14749 hda_nid_t nid = spec->autocfg.input_pins[i];
14750 if (alc861vd_is_input_pin(nid)) {
14751 snd_hda_codec_write(codec, nid, 0,
14752 AC_VERB_SET_PIN_WIDGET_CONTROL,
14753 i <= AUTO_PIN_FRONT_MIC ?
14754 PIN_VREF80 : PIN_IN);
14755 if (nid != ALC861VD_PIN_CD_NID)
14756 snd_hda_codec_write(codec, nid, 0,
14757 AC_VERB_SET_AMP_GAIN_MUTE,
14758 AMP_OUT_MUTE);
14759 }
14760 }
14761}
14762
Takashi Iwaif511b012008-08-15 16:46:42 +020014763#define alc861vd_auto_init_input_src alc882_auto_init_input_src
14764
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014765#define alc861vd_idx_to_mixer_vol(nid) ((nid) + 0x02)
14766#define alc861vd_idx_to_mixer_switch(nid) ((nid) + 0x0c)
14767
14768/* add playback controls from the parsed DAC table */
14769/* Based on ALC880 version. But ALC861VD has separate,
14770 * different NIDs for mute/unmute switch and volume control */
14771static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
14772 const struct auto_pin_cfg *cfg)
14773{
14774 char name[32];
14775 static const char *chname[4] = {"Front", "Surround", "CLFE", "Side"};
14776 hda_nid_t nid_v, nid_s;
14777 int i, err;
14778
14779 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014780 if (!spec->multiout.dac_nids[i])
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014781 continue;
14782 nid_v = alc861vd_idx_to_mixer_vol(
14783 alc880_dac_to_idx(
14784 spec->multiout.dac_nids[i]));
14785 nid_s = alc861vd_idx_to_mixer_switch(
14786 alc880_dac_to_idx(
14787 spec->multiout.dac_nids[i]));
14788
14789 if (i == 2) {
14790 /* Center/LFE */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014791 err = add_control(spec, ALC_CTL_WIDGET_VOL,
14792 "Center Playback Volume",
14793 HDA_COMPOSE_AMP_VAL(nid_v, 1, 0,
14794 HDA_OUTPUT));
14795 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014796 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014797 err = add_control(spec, ALC_CTL_WIDGET_VOL,
14798 "LFE Playback Volume",
14799 HDA_COMPOSE_AMP_VAL(nid_v, 2, 0,
14800 HDA_OUTPUT));
14801 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014802 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014803 err = add_control(spec, ALC_CTL_BIND_MUTE,
14804 "Center Playback Switch",
14805 HDA_COMPOSE_AMP_VAL(nid_s, 1, 2,
14806 HDA_INPUT));
14807 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014808 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014809 err = add_control(spec, ALC_CTL_BIND_MUTE,
14810 "LFE Playback Switch",
14811 HDA_COMPOSE_AMP_VAL(nid_s, 2, 2,
14812 HDA_INPUT));
14813 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014814 return err;
14815 } else {
14816 sprintf(name, "%s Playback Volume", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014817 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
14818 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0,
14819 HDA_OUTPUT));
14820 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014821 return err;
14822 sprintf(name, "%s Playback Switch", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014823 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
Kailang Yangbdd148a2007-05-08 15:19:08 +020014824 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014825 HDA_INPUT));
14826 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014827 return err;
14828 }
14829 }
14830 return 0;
14831}
14832
14833/* add playback controls for speaker and HP outputs */
14834/* Based on ALC880 version. But ALC861VD has separate,
14835 * different NIDs for mute/unmute switch and volume control */
14836static int alc861vd_auto_create_extra_out(struct alc_spec *spec,
14837 hda_nid_t pin, const char *pfx)
14838{
14839 hda_nid_t nid_v, nid_s;
14840 int err;
14841 char name[32];
14842
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014843 if (!pin)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014844 return 0;
14845
14846 if (alc880_is_fixed_pin(pin)) {
14847 nid_v = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
14848 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014849 if (!spec->multiout.hp_nid)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014850 spec->multiout.hp_nid = nid_v;
14851 else
14852 spec->multiout.extra_out_nid[0] = nid_v;
14853 /* control HP volume/switch on the output mixer amp */
14854 nid_v = alc861vd_idx_to_mixer_vol(
14855 alc880_fixed_pin_idx(pin));
14856 nid_s = alc861vd_idx_to_mixer_switch(
14857 alc880_fixed_pin_idx(pin));
14858
14859 sprintf(name, "%s Playback Volume", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014860 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
14861 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0, HDA_OUTPUT));
14862 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014863 return err;
14864 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014865 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
14866 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2, HDA_INPUT));
14867 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014868 return err;
14869 } else if (alc880_is_multi_pin(pin)) {
14870 /* set manual connection */
14871 /* we have only a switch on HP-out PIN */
14872 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014873 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
14874 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
14875 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014876 return err;
14877 }
14878 return 0;
14879}
14880
14881/* parse the BIOS configuration and set up the alc_spec
14882 * return 1 if successful, 0 if the proper config is not found,
14883 * or a negative error code
14884 * Based on ALC880 version - had to change it to override
14885 * alc880_auto_create_extra_out and alc880_auto_create_multi_out_ctls */
14886static int alc861vd_parse_auto_config(struct hda_codec *codec)
14887{
14888 struct alc_spec *spec = codec->spec;
14889 int err;
14890 static hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
14891
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014892 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
14893 alc861vd_ignore);
14894 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014895 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014896 if (!spec->autocfg.line_outs)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014897 return 0; /* can't find valid BIOS pin config */
14898
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014899 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
14900 if (err < 0)
14901 return err;
14902 err = alc861vd_auto_create_multi_out_ctls(spec, &spec->autocfg);
14903 if (err < 0)
14904 return err;
14905 err = alc861vd_auto_create_extra_out(spec,
14906 spec->autocfg.speaker_pins[0],
14907 "Speaker");
14908 if (err < 0)
14909 return err;
14910 err = alc861vd_auto_create_extra_out(spec,
14911 spec->autocfg.hp_pins[0],
14912 "Headphone");
14913 if (err < 0)
14914 return err;
14915 err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg);
14916 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014917 return err;
14918
14919 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
14920
14921 if (spec->autocfg.dig_out_pin)
14922 spec->multiout.dig_out_nid = ALC861VD_DIGOUT_NID;
14923
Takashi Iwai603c4012008-07-30 15:01:44 +020014924 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010014925 add_mixer(spec, spec->kctls.list);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014926
Takashi Iwaid88897e2008-10-31 15:01:37 +010014927 add_verb(spec, alc861vd_volume_init_verbs);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014928
14929 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020014930 spec->input_mux = &spec->private_imux[0];
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014931
Takashi Iwai776e1842007-08-29 15:07:11 +020014932 err = alc_auto_add_mic_boost(codec);
14933 if (err < 0)
14934 return err;
14935
Takashi Iwaie044c392008-10-27 16:56:24 +010014936 store_pin_configs(codec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014937 return 1;
14938}
14939
14940/* additional initialization for auto-configuration model */
14941static void alc861vd_auto_init(struct hda_codec *codec)
14942{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014943 struct alc_spec *spec = codec->spec;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014944 alc861vd_auto_init_multi_out(codec);
14945 alc861vd_auto_init_hp_out(codec);
14946 alc861vd_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020014947 alc861vd_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014948 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020014949 alc_inithook(codec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014950}
14951
14952static int patch_alc861vd(struct hda_codec *codec)
14953{
14954 struct alc_spec *spec;
14955 int err, board_config;
14956
14957 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
14958 if (spec == NULL)
14959 return -ENOMEM;
14960
14961 codec->spec = spec;
14962
14963 board_config = snd_hda_check_board_config(codec, ALC861VD_MODEL_LAST,
14964 alc861vd_models,
14965 alc861vd_cfg_tbl);
14966
14967 if (board_config < 0 || board_config >= ALC861VD_MODEL_LAST) {
14968 printk(KERN_INFO "hda_codec: Unknown model for ALC660VD/"
14969 "ALC861VD, trying auto-probe from BIOS...\n");
14970 board_config = ALC861VD_AUTO;
14971 }
14972
14973 if (board_config == ALC861VD_AUTO) {
14974 /* automatic parse from the BIOS config */
14975 err = alc861vd_parse_auto_config(codec);
14976 if (err < 0) {
14977 alc_free(codec);
14978 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014979 } else if (!err) {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014980 printk(KERN_INFO
14981 "hda_codec: Cannot set up configuration "
14982 "from BIOS. Using base mode...\n");
14983 board_config = ALC861VD_3ST;
14984 }
14985 }
14986
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090014987 err = snd_hda_attach_beep_device(codec, 0x23);
14988 if (err < 0) {
14989 alc_free(codec);
14990 return err;
14991 }
14992
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014993 if (board_config != ALC861VD_AUTO)
14994 setup_preset(spec, &alc861vd_presets[board_config]);
14995
Kailang Yang2f893282008-05-27 12:14:47 +020014996 if (codec->vendor_id == 0x10ec0660) {
14997 spec->stream_name_analog = "ALC660-VD Analog";
14998 spec->stream_name_digital = "ALC660-VD Digital";
Kailang Yangf9423e72008-05-27 12:32:25 +020014999 /* always turn on EAPD */
Takashi Iwaid88897e2008-10-31 15:01:37 +010015000 add_verb(spec, alc660vd_eapd_verbs);
Kailang Yang2f893282008-05-27 12:14:47 +020015001 } else {
15002 spec->stream_name_analog = "ALC861VD Analog";
15003 spec->stream_name_digital = "ALC861VD Digital";
15004 }
15005
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015006 spec->stream_analog_playback = &alc861vd_pcm_analog_playback;
15007 spec->stream_analog_capture = &alc861vd_pcm_analog_capture;
15008
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015009 spec->stream_digital_playback = &alc861vd_pcm_digital_playback;
15010 spec->stream_digital_capture = &alc861vd_pcm_digital_capture;
15011
15012 spec->adc_nids = alc861vd_adc_nids;
15013 spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids);
Takashi Iwaie1406342008-02-11 18:32:32 +010015014 spec->capsrc_nids = alc861vd_capsrc_nids;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020015015 spec->capture_style = CAPT_MIX;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015016
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015017 set_capture_mixer(spec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015018
Takashi Iwai2134ea42008-01-10 16:53:55 +010015019 spec->vmaster_nid = 0x02;
15020
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015021 codec->patch_ops = alc_patch_ops;
15022
15023 if (board_config == ALC861VD_AUTO)
15024 spec->init_hook = alc861vd_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020015025#ifdef CONFIG_SND_HDA_POWER_SAVE
15026 if (!spec->loopback.amplist)
15027 spec->loopback.amplist = alc861vd_loopbacks;
15028#endif
Takashi Iwaidaead532008-11-28 12:55:36 +010015029 codec->proc_widget_hook = print_realtek_coef;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015030
15031 return 0;
15032}
15033
15034/*
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015035 * ALC662 support
15036 *
15037 * ALC662 is almost identical with ALC880 but has cleaner and more flexible
15038 * configuration. Each pin widget can choose any input DACs and a mixer.
15039 * Each ADC is connected from a mixer of all inputs. This makes possible
15040 * 6-channel independent captures.
15041 *
15042 * In addition, an independent DAC for the multi-playback (not used in this
15043 * driver yet).
15044 */
15045#define ALC662_DIGOUT_NID 0x06
15046#define ALC662_DIGIN_NID 0x0a
15047
15048static hda_nid_t alc662_dac_nids[4] = {
15049 /* front, rear, clfe, rear_surr */
15050 0x02, 0x03, 0x04
15051};
15052
15053static hda_nid_t alc662_adc_nids[1] = {
15054 /* ADC1-2 */
15055 0x09,
15056};
Takashi Iwaie1406342008-02-11 18:32:32 +010015057
Kailang Yang77a261b2008-02-19 11:38:05 +010015058static hda_nid_t alc662_capsrc_nids[1] = { 0x22 };
Takashi Iwaie1406342008-02-11 18:32:32 +010015059
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015060/* input MUX */
15061/* FIXME: should be a matrix-type input source selection */
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015062static struct hda_input_mux alc662_capture_source = {
15063 .num_items = 4,
15064 .items = {
15065 { "Mic", 0x0 },
15066 { "Front Mic", 0x1 },
15067 { "Line", 0x2 },
15068 { "CD", 0x4 },
15069 },
15070};
15071
15072static struct hda_input_mux alc662_lenovo_101e_capture_source = {
15073 .num_items = 2,
15074 .items = {
15075 { "Mic", 0x1 },
15076 { "Line", 0x2 },
15077 },
15078};
Kailang Yang291702f2007-10-16 14:28:03 +020015079
15080static struct hda_input_mux alc662_eeepc_capture_source = {
15081 .num_items = 2,
15082 .items = {
15083 { "i-Mic", 0x1 },
15084 { "e-Mic", 0x0 },
15085 },
15086};
15087
Kailang Yang6dda9f42008-05-27 12:05:31 +020015088static struct hda_input_mux alc663_capture_source = {
15089 .num_items = 3,
15090 .items = {
15091 { "Mic", 0x0 },
15092 { "Front Mic", 0x1 },
15093 { "Line", 0x2 },
15094 },
15095};
15096
15097static struct hda_input_mux alc663_m51va_capture_source = {
15098 .num_items = 2,
15099 .items = {
15100 { "Ext-Mic", 0x0 },
15101 { "D-Mic", 0x9 },
15102 },
15103};
15104
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015105/*
15106 * 2ch mode
15107 */
15108static struct hda_channel_mode alc662_3ST_2ch_modes[1] = {
15109 { 2, NULL }
15110};
15111
15112/*
15113 * 2ch mode
15114 */
15115static struct hda_verb alc662_3ST_ch2_init[] = {
15116 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
15117 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
15118 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
15119 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
15120 { } /* end */
15121};
15122
15123/*
15124 * 6ch mode
15125 */
15126static struct hda_verb alc662_3ST_ch6_init[] = {
15127 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15128 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
15129 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
15130 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15131 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
15132 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
15133 { } /* end */
15134};
15135
15136static struct hda_channel_mode alc662_3ST_6ch_modes[2] = {
15137 { 2, alc662_3ST_ch2_init },
15138 { 6, alc662_3ST_ch6_init },
15139};
15140
15141/*
15142 * 2ch mode
15143 */
15144static struct hda_verb alc662_sixstack_ch6_init[] = {
15145 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15146 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15147 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15148 { } /* end */
15149};
15150
15151/*
15152 * 6ch mode
15153 */
15154static struct hda_verb alc662_sixstack_ch8_init[] = {
15155 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15156 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15157 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15158 { } /* end */
15159};
15160
15161static struct hda_channel_mode alc662_5stack_modes[2] = {
15162 { 2, alc662_sixstack_ch6_init },
15163 { 6, alc662_sixstack_ch8_init },
15164};
15165
15166/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
15167 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
15168 */
15169
15170static struct snd_kcontrol_new alc662_base_mixer[] = {
15171 /* output mixer control */
15172 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010015173 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015174 HDA_CODEC_VOLUME("Surround Playback Volume", 0x3, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010015175 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015176 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
15177 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010015178 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
15179 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015180 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
15181
15182 /*Input mixer control */
15183 HDA_CODEC_VOLUME("CD Playback Volume", 0xb, 0x4, HDA_INPUT),
15184 HDA_CODEC_MUTE("CD Playback Switch", 0xb, 0x4, HDA_INPUT),
15185 HDA_CODEC_VOLUME("Line Playback Volume", 0xb, 0x02, HDA_INPUT),
15186 HDA_CODEC_MUTE("Line Playback Switch", 0xb, 0x02, HDA_INPUT),
15187 HDA_CODEC_VOLUME("Mic Playback Volume", 0xb, 0x0, HDA_INPUT),
15188 HDA_CODEC_MUTE("Mic Playback Switch", 0xb, 0x0, HDA_INPUT),
15189 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0xb, 0x01, HDA_INPUT),
15190 HDA_CODEC_MUTE("Front Mic Playback Switch", 0xb, 0x01, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015191 { } /* end */
15192};
15193
15194static struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = {
15195 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010015196 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015197 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
15198 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
15199 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
15200 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
15201 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
15202 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15203 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15204 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15205 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
15206 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
15207 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015208 { } /* end */
15209};
15210
15211static struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = {
15212 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010015213 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015214 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010015215 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015216 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
15217 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010015218 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
15219 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015220 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
15221 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
15222 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
15223 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
15224 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
15225 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15226 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15227 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15228 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
15229 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
15230 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015231 { } /* end */
15232};
15233
15234static struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = {
15235 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15236 HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010015237 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x03, 0x0, HDA_OUTPUT),
15238 HDA_BIND_MUTE("Speaker Playback Switch", 0x03, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015239 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
15240 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
15241 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
15242 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15243 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015244 { } /* end */
15245};
15246
Kailang Yang291702f2007-10-16 14:28:03 +020015247static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = {
Takashi Iwai86cd9292008-01-28 18:09:56 +010015248 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang291702f2007-10-16 14:28:03 +020015249
Herton Ronaldo Krzesinskib4818492008-02-23 11:34:12 +010015250 HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15251 HDA_CODEC_MUTE("Line-Out Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yang291702f2007-10-16 14:28:03 +020015252
15253 HDA_CODEC_VOLUME("e-Mic Boost", 0x18, 0, HDA_INPUT),
15254 HDA_CODEC_VOLUME("e-Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15255 HDA_CODEC_MUTE("e-Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15256
15257 HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT),
15258 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15259 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
15260 { } /* end */
15261};
15262
Kailang Yang8c427222008-01-10 13:03:59 +010015263static struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = {
Takashi Iwai31bffaa2008-02-27 16:10:44 +010015264 HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15265 HDA_CODEC_MUTE("Line-Out Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010015266 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
15267 HDA_BIND_MUTE("Surround Playback Switch", 0x03, 2, HDA_INPUT),
15268 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
15269 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
15270 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x04, 1, 2, HDA_INPUT),
15271 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x04, 2, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010015272 HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010015273 HDA_BIND_MUTE("MuteCtrl Playback Switch", 0x0c, 2, HDA_INPUT),
15274 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
15275 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
15276 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15277 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15278 { } /* end */
15279};
15280
Kailang Yangf1d4e282008-08-26 14:03:29 +020015281static struct hda_bind_ctls alc663_asus_bind_master_vol = {
15282 .ops = &snd_hda_bind_vol,
15283 .values = {
15284 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
15285 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
15286 0
15287 },
15288};
15289
15290static struct hda_bind_ctls alc663_asus_one_bind_switch = {
15291 .ops = &snd_hda_bind_sw,
15292 .values = {
15293 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
15294 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
15295 0
15296 },
15297};
15298
Kailang Yang6dda9f42008-05-27 12:05:31 +020015299static struct snd_kcontrol_new alc663_m51va_mixer[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020015300 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
15301 HDA_BIND_SW("Master Playback Switch", &alc663_asus_one_bind_switch),
15302 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15303 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15304 { } /* end */
15305};
15306
15307static struct hda_bind_ctls alc663_asus_tree_bind_switch = {
15308 .ops = &snd_hda_bind_sw,
15309 .values = {
15310 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
15311 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
15312 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
15313 0
15314 },
15315};
15316
15317static struct snd_kcontrol_new alc663_two_hp_m1_mixer[] = {
15318 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
15319 HDA_BIND_SW("Master Playback Switch", &alc663_asus_tree_bind_switch),
15320 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15321 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15322 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15323 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
15324
15325 { } /* end */
15326};
15327
15328static struct hda_bind_ctls alc663_asus_four_bind_switch = {
15329 .ops = &snd_hda_bind_sw,
15330 .values = {
15331 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
15332 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
15333 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
15334 0
15335 },
15336};
15337
15338static struct snd_kcontrol_new alc663_two_hp_m2_mixer[] = {
15339 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
15340 HDA_BIND_SW("Master Playback Switch", &alc663_asus_four_bind_switch),
15341 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15342 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15343 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15344 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
15345 { } /* end */
15346};
15347
15348static struct snd_kcontrol_new alc662_1bjd_mixer[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020015349 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15350 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020015351 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
15352 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15353 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15354 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15355 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
15356 { } /* end */
15357};
15358
15359static struct hda_bind_ctls alc663_asus_two_bind_master_vol = {
15360 .ops = &snd_hda_bind_vol,
15361 .values = {
15362 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
15363 HDA_COMPOSE_AMP_VAL(0x04, 3, 0, HDA_OUTPUT),
15364 0
15365 },
15366};
15367
15368static struct hda_bind_ctls alc663_asus_two_bind_switch = {
15369 .ops = &snd_hda_bind_sw,
15370 .values = {
15371 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
15372 HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT),
15373 0
15374 },
15375};
15376
15377static struct snd_kcontrol_new alc663_asus_21jd_clfe_mixer[] = {
15378 HDA_BIND_VOL("Master Playback Volume",
15379 &alc663_asus_two_bind_master_vol),
15380 HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
15381 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020015382 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
15383 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15384 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020015385 { } /* end */
15386};
15387
15388static struct snd_kcontrol_new alc663_asus_15jd_clfe_mixer[] = {
15389 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
15390 HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
15391 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
15392 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
15393 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15394 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020015395 { } /* end */
15396};
15397
15398static struct snd_kcontrol_new alc663_g71v_mixer[] = {
15399 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15400 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
15401 HDA_CODEC_VOLUME("Front Playback Volume", 0x03, 0x0, HDA_OUTPUT),
15402 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
15403 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
15404
15405 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15406 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15407 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15408 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
15409 { } /* end */
15410};
15411
15412static struct snd_kcontrol_new alc663_g50v_mixer[] = {
15413 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15414 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
15415 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
15416
15417 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15418 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15419 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15420 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
15421 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
15422 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
15423 { } /* end */
15424};
15425
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015426static struct snd_kcontrol_new alc662_chmode_mixer[] = {
15427 {
15428 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
15429 .name = "Channel Mode",
15430 .info = alc_ch_mode_info,
15431 .get = alc_ch_mode_get,
15432 .put = alc_ch_mode_put,
15433 },
15434 { } /* end */
15435};
15436
15437static struct hda_verb alc662_init_verbs[] = {
15438 /* ADC: mute amp left and right */
15439 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15440 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
15441 /* Front mixer: unmute input/output amp left and right (volume = 0) */
15442
Takashi Iwaicb53c622007-08-10 17:21:45 +020015443 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15444 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15445 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
15446 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
15447 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015448
Kailang Yangb60dd392007-09-20 12:50:29 +020015449 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15450 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15451 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15452 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15453 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15454 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015455
15456 /* Front Pin: output 0 (0x0c) */
15457 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
15458 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15459
15460 /* Rear Pin: output 1 (0x0d) */
15461 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
15462 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15463
15464 /* CLFE Pin: output 2 (0x0e) */
15465 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
15466 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15467
15468 /* Mic (rear) pin: input vref at 80% */
15469 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
15470 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15471 /* Front Mic pin: input vref at 80% */
15472 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
15473 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15474 /* Line In pin: input */
15475 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15476 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15477 /* Line-2 In: Headphone output (output 0 - 0x0c) */
15478 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15479 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15480 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
15481 /* CD pin widget for input */
15482 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15483
15484 /* FIXME: use matrix-type input source selection */
15485 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
15486 /* Input mixer */
15487 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15488 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15489 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15490 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Kailang Yang291702f2007-10-16 14:28:03 +020015491
15492 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15493 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15494 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15495 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Kailang Yang6dda9f42008-05-27 12:05:31 +020015496
15497 /* always trun on EAPD */
15498 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
15499 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
15500
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015501 { }
15502};
15503
15504static struct hda_verb alc662_sue_init_verbs[] = {
15505 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
15506 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
Kailang Yang291702f2007-10-16 14:28:03 +020015507 {}
15508};
15509
15510static struct hda_verb alc662_eeepc_sue_init_verbs[] = {
15511 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15512 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15513 {}
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015514};
15515
Kailang Yang8c427222008-01-10 13:03:59 +010015516/* Set Unsolicited Event*/
15517static struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = {
15518 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
15519 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15520 {}
15521};
15522
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015523/*
15524 * generic initialization of ADC, input mixers and output mixers
15525 */
15526static struct hda_verb alc662_auto_init_verbs[] = {
15527 /*
15528 * Unmute ADC and set the default input to mic-in
15529 */
15530 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
15531 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15532
15533 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
15534 * mixer widget
15535 * Note: PASD motherboards uses the Line In 2 as the input for front
15536 * panel mic (mic 2)
15537 */
15538 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020015539 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15540 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15541 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
15542 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
15543 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015544
15545 /*
15546 * Set up output mixers (0x0c - 0x0f)
15547 */
15548 /* set vol=0 to output mixers */
15549 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
15550 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
15551 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
15552
15553 /* set up input amps for analog loopback */
15554 /* Amp Indices: DAC = 0, mixer = 1 */
Kailang Yangb60dd392007-09-20 12:50:29 +020015555 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15556 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15557 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15558 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15559 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15560 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015561
15562
15563 /* FIXME: use matrix-type input source selection */
15564 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
15565 /* Input mixer */
15566 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangd1a991a2007-08-15 16:21:59 +020015567 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015568 { }
15569};
15570
Takashi Iwai24fb9172008-09-02 14:48:20 +020015571/* additional verbs for ALC663 */
15572static struct hda_verb alc663_auto_init_verbs[] = {
15573 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15574 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15575 { }
15576};
15577
Kailang Yang6dda9f42008-05-27 12:05:31 +020015578static struct hda_verb alc663_m51va_init_verbs[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020015579 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15580 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yang6dda9f42008-05-27 12:05:31 +020015581 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15582 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangf1d4e282008-08-26 14:03:29 +020015583 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
15584 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15585 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
Kailang Yang6dda9f42008-05-27 12:05:31 +020015586 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15587 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15588 {}
15589};
15590
Kailang Yangf1d4e282008-08-26 14:03:29 +020015591static struct hda_verb alc663_21jd_amic_init_verbs[] = {
15592 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15593 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15594 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
15595 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15596 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15597 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15598 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15599 {}
15600};
15601
15602static struct hda_verb alc662_1bjd_amic_init_verbs[] = {
15603 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15604 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15605 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15606 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
15607 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15608 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15609 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15610 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15611 {}
15612};
15613
15614static struct hda_verb alc663_15jd_amic_init_verbs[] = {
15615 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15616 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15617 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
15618 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15619 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15620 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15621 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15622 {}
15623};
15624
15625static struct hda_verb alc663_two_hp_amic_m1_init_verbs[] = {
15626 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15627 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15628 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15629 {0x21, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */
15630 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15631 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15632 {0x15, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */
15633 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15634 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15635 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15636 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15637 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15638 {}
15639};
15640
15641static struct hda_verb alc663_two_hp_amic_m2_init_verbs[] = {
15642 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15643 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15644 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15645 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
15646 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15647 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15648 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
15649 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15650 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15651 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15652 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15653 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15654 {}
15655};
15656
Kailang Yang6dda9f42008-05-27 12:05:31 +020015657static struct hda_verb alc663_g71v_init_verbs[] = {
15658 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15659 /* {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
15660 /* {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, */ /* Headphone */
15661
15662 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15663 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15664 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
15665
15666 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
15667 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_MIC_EVENT},
15668 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
15669 {}
15670};
15671
15672static struct hda_verb alc663_g50v_init_verbs[] = {
15673 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15674 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15675 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
15676
15677 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15678 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15679 {}
15680};
15681
Kailang Yangf1d4e282008-08-26 14:03:29 +020015682static struct hda_verb alc662_ecs_init_verbs[] = {
15683 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
15684 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15685 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15686 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15687 {}
15688};
15689
Kailang Yangf1d4e282008-08-26 14:03:29 +020015690static struct snd_kcontrol_new alc662_auto_capture_mixer[] = {
15691 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
15692 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
15693 { } /* end */
15694};
15695
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015696static void alc662_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
15697{
15698 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015699 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015700
15701 present = snd_hda_codec_read(codec, 0x14, 0,
15702 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020015703 bits = present ? HDA_AMP_MUTE : 0;
15704 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
15705 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015706}
15707
15708static void alc662_lenovo_101e_all_automute(struct hda_codec *codec)
15709{
15710 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015711 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015712
15713 present = snd_hda_codec_read(codec, 0x1b, 0,
15714 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020015715 bits = present ? HDA_AMP_MUTE : 0;
15716 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
15717 HDA_AMP_MUTE, bits);
15718 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
15719 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015720}
15721
15722static void alc662_lenovo_101e_unsol_event(struct hda_codec *codec,
15723 unsigned int res)
15724{
15725 if ((res >> 26) == ALC880_HP_EVENT)
15726 alc662_lenovo_101e_all_automute(codec);
15727 if ((res >> 26) == ALC880_FRONT_EVENT)
15728 alc662_lenovo_101e_ispeaker_automute(codec);
15729}
15730
Kailang Yang291702f2007-10-16 14:28:03 +020015731static void alc662_eeepc_mic_automute(struct hda_codec *codec)
15732{
15733 unsigned int present;
15734
15735 present = snd_hda_codec_read(codec, 0x18, 0,
15736 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
15737 snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
15738 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
15739 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
15740 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
15741 snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
15742 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
15743 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
15744 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
15745}
15746
15747/* unsolicited event for HP jack sensing */
15748static void alc662_eeepc_unsol_event(struct hda_codec *codec,
15749 unsigned int res)
15750{
15751 if ((res >> 26) == ALC880_HP_EVENT)
15752 alc262_hippo1_automute( codec );
15753
15754 if ((res >> 26) == ALC880_MIC_EVENT)
15755 alc662_eeepc_mic_automute(codec);
15756}
15757
15758static void alc662_eeepc_inithook(struct hda_codec *codec)
15759{
15760 alc262_hippo1_automute( codec );
15761 alc662_eeepc_mic_automute(codec);
15762}
15763
Kailang Yang8c427222008-01-10 13:03:59 +010015764static void alc662_eeepc_ep20_automute(struct hda_codec *codec)
15765{
15766 unsigned int mute;
15767 unsigned int present;
15768
15769 snd_hda_codec_read(codec, 0x14, 0, AC_VERB_SET_PIN_SENSE, 0);
15770 present = snd_hda_codec_read(codec, 0x14, 0,
15771 AC_VERB_GET_PIN_SENSE, 0);
15772 present = (present & 0x80000000) != 0;
15773 if (present) {
15774 /* mute internal speaker */
15775 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +020015776 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yang8c427222008-01-10 13:03:59 +010015777 } else {
15778 /* unmute internal speaker if necessary */
15779 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
15780 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +020015781 HDA_AMP_MUTE, mute);
Kailang Yang8c427222008-01-10 13:03:59 +010015782 }
15783}
15784
15785/* unsolicited event for HP jack sensing */
15786static void alc662_eeepc_ep20_unsol_event(struct hda_codec *codec,
15787 unsigned int res)
15788{
15789 if ((res >> 26) == ALC880_HP_EVENT)
15790 alc662_eeepc_ep20_automute(codec);
15791}
15792
15793static void alc662_eeepc_ep20_inithook(struct hda_codec *codec)
15794{
15795 alc662_eeepc_ep20_automute(codec);
15796}
15797
Kailang Yang6dda9f42008-05-27 12:05:31 +020015798static void alc663_m51va_speaker_automute(struct hda_codec *codec)
15799{
15800 unsigned int present;
15801 unsigned char bits;
15802
15803 present = snd_hda_codec_read(codec, 0x21, 0,
Kailang Yangf1d4e282008-08-26 14:03:29 +020015804 AC_VERB_GET_PIN_SENSE, 0)
15805 & AC_PINSENSE_PRESENCE;
Kailang Yang6dda9f42008-05-27 12:05:31 +020015806 bits = present ? HDA_AMP_MUTE : 0;
Kailang Yangf1d4e282008-08-26 14:03:29 +020015807 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
15808 AMP_IN_MUTE(0), bits);
15809 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
15810 AMP_IN_MUTE(0), bits);
15811}
15812
15813static void alc663_21jd_two_speaker_automute(struct hda_codec *codec)
15814{
15815 unsigned int present;
15816 unsigned char bits;
15817
15818 present = snd_hda_codec_read(codec, 0x21, 0,
15819 AC_VERB_GET_PIN_SENSE, 0)
15820 & AC_PINSENSE_PRESENCE;
15821 bits = present ? HDA_AMP_MUTE : 0;
15822 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
15823 AMP_IN_MUTE(0), bits);
15824 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
15825 AMP_IN_MUTE(0), bits);
15826 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0,
15827 AMP_IN_MUTE(0), bits);
15828 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1,
15829 AMP_IN_MUTE(0), bits);
15830}
15831
15832static void alc663_15jd_two_speaker_automute(struct hda_codec *codec)
15833{
15834 unsigned int present;
15835 unsigned char bits;
15836
15837 present = snd_hda_codec_read(codec, 0x15, 0,
15838 AC_VERB_GET_PIN_SENSE, 0)
15839 & AC_PINSENSE_PRESENCE;
15840 bits = present ? HDA_AMP_MUTE : 0;
15841 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
15842 AMP_IN_MUTE(0), bits);
15843 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
15844 AMP_IN_MUTE(0), bits);
15845 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0,
15846 AMP_IN_MUTE(0), bits);
15847 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1,
15848 AMP_IN_MUTE(0), bits);
15849}
15850
15851static void alc662_f5z_speaker_automute(struct hda_codec *codec)
15852{
15853 unsigned int present;
15854 unsigned char bits;
15855
15856 present = snd_hda_codec_read(codec, 0x1b, 0,
15857 AC_VERB_GET_PIN_SENSE, 0)
15858 & AC_PINSENSE_PRESENCE;
15859 bits = present ? 0 : PIN_OUT;
15860 snd_hda_codec_write(codec, 0x14, 0,
15861 AC_VERB_SET_PIN_WIDGET_CONTROL, bits);
15862}
15863
15864static void alc663_two_hp_m1_speaker_automute(struct hda_codec *codec)
15865{
15866 unsigned int present1, present2;
15867
15868 present1 = snd_hda_codec_read(codec, 0x21, 0,
15869 AC_VERB_GET_PIN_SENSE, 0)
15870 & AC_PINSENSE_PRESENCE;
15871 present2 = snd_hda_codec_read(codec, 0x15, 0,
15872 AC_VERB_GET_PIN_SENSE, 0)
15873 & AC_PINSENSE_PRESENCE;
15874
15875 if (present1 || present2) {
15876 snd_hda_codec_write_cache(codec, 0x14, 0,
15877 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
15878 } else {
15879 snd_hda_codec_write_cache(codec, 0x14, 0,
15880 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
15881 }
15882}
15883
15884static void alc663_two_hp_m2_speaker_automute(struct hda_codec *codec)
15885{
15886 unsigned int present1, present2;
15887
15888 present1 = snd_hda_codec_read(codec, 0x1b, 0,
15889 AC_VERB_GET_PIN_SENSE, 0)
15890 & AC_PINSENSE_PRESENCE;
15891 present2 = snd_hda_codec_read(codec, 0x15, 0,
15892 AC_VERB_GET_PIN_SENSE, 0)
15893 & AC_PINSENSE_PRESENCE;
15894
15895 if (present1 || present2) {
15896 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
15897 AMP_IN_MUTE(0), AMP_IN_MUTE(0));
15898 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
15899 AMP_IN_MUTE(0), AMP_IN_MUTE(0));
15900 } else {
15901 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
15902 AMP_IN_MUTE(0), 0);
15903 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
15904 AMP_IN_MUTE(0), 0);
15905 }
Kailang Yang6dda9f42008-05-27 12:05:31 +020015906}
15907
15908static void alc663_m51va_mic_automute(struct hda_codec *codec)
15909{
15910 unsigned int present;
15911
15912 present = snd_hda_codec_read(codec, 0x18, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +020015913 AC_VERB_GET_PIN_SENSE, 0)
15914 & AC_PINSENSE_PRESENCE;
Kailang Yang6dda9f42008-05-27 12:05:31 +020015915 snd_hda_codec_write_cache(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangea1fb292008-08-26 12:58:38 +020015916 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
Kailang Yang6dda9f42008-05-27 12:05:31 +020015917 snd_hda_codec_write_cache(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangea1fb292008-08-26 12:58:38 +020015918 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
Kailang Yang6dda9f42008-05-27 12:05:31 +020015919 snd_hda_codec_write_cache(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangea1fb292008-08-26 12:58:38 +020015920 0x7000 | (0x09 << 8) | (present ? 0x80 : 0));
Kailang Yang6dda9f42008-05-27 12:05:31 +020015921 snd_hda_codec_write_cache(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangea1fb292008-08-26 12:58:38 +020015922 0x7000 | (0x09 << 8) | (present ? 0x80 : 0));
Kailang Yang6dda9f42008-05-27 12:05:31 +020015923}
15924
15925static void alc663_m51va_unsol_event(struct hda_codec *codec,
15926 unsigned int res)
15927{
15928 switch (res >> 26) {
15929 case ALC880_HP_EVENT:
15930 alc663_m51va_speaker_automute(codec);
15931 break;
15932 case ALC880_MIC_EVENT:
15933 alc663_m51va_mic_automute(codec);
15934 break;
15935 }
15936}
15937
15938static void alc663_m51va_inithook(struct hda_codec *codec)
15939{
15940 alc663_m51va_speaker_automute(codec);
15941 alc663_m51va_mic_automute(codec);
15942}
15943
Kailang Yangf1d4e282008-08-26 14:03:29 +020015944/* ***************** Mode1 ******************************/
15945static void alc663_mode1_unsol_event(struct hda_codec *codec,
15946 unsigned int res)
15947{
15948 switch (res >> 26) {
15949 case ALC880_HP_EVENT:
15950 alc663_m51va_speaker_automute(codec);
15951 break;
15952 case ALC880_MIC_EVENT:
15953 alc662_eeepc_mic_automute(codec);
15954 break;
15955 }
15956}
15957
15958static void alc663_mode1_inithook(struct hda_codec *codec)
15959{
15960 alc663_m51va_speaker_automute(codec);
15961 alc662_eeepc_mic_automute(codec);
15962}
15963/* ***************** Mode2 ******************************/
15964static void alc662_mode2_unsol_event(struct hda_codec *codec,
15965 unsigned int res)
15966{
15967 switch (res >> 26) {
15968 case ALC880_HP_EVENT:
15969 alc662_f5z_speaker_automute(codec);
15970 break;
15971 case ALC880_MIC_EVENT:
15972 alc662_eeepc_mic_automute(codec);
15973 break;
15974 }
15975}
15976
15977static void alc662_mode2_inithook(struct hda_codec *codec)
15978{
15979 alc662_f5z_speaker_automute(codec);
15980 alc662_eeepc_mic_automute(codec);
15981}
15982/* ***************** Mode3 ******************************/
15983static void alc663_mode3_unsol_event(struct hda_codec *codec,
15984 unsigned int res)
15985{
15986 switch (res >> 26) {
15987 case ALC880_HP_EVENT:
15988 alc663_two_hp_m1_speaker_automute(codec);
15989 break;
15990 case ALC880_MIC_EVENT:
15991 alc662_eeepc_mic_automute(codec);
15992 break;
15993 }
15994}
15995
15996static void alc663_mode3_inithook(struct hda_codec *codec)
15997{
15998 alc663_two_hp_m1_speaker_automute(codec);
15999 alc662_eeepc_mic_automute(codec);
16000}
16001/* ***************** Mode4 ******************************/
16002static void alc663_mode4_unsol_event(struct hda_codec *codec,
16003 unsigned int res)
16004{
16005 switch (res >> 26) {
16006 case ALC880_HP_EVENT:
16007 alc663_21jd_two_speaker_automute(codec);
16008 break;
16009 case ALC880_MIC_EVENT:
16010 alc662_eeepc_mic_automute(codec);
16011 break;
16012 }
16013}
16014
16015static void alc663_mode4_inithook(struct hda_codec *codec)
16016{
16017 alc663_21jd_two_speaker_automute(codec);
16018 alc662_eeepc_mic_automute(codec);
16019}
16020/* ***************** Mode5 ******************************/
16021static void alc663_mode5_unsol_event(struct hda_codec *codec,
16022 unsigned int res)
16023{
16024 switch (res >> 26) {
16025 case ALC880_HP_EVENT:
16026 alc663_15jd_two_speaker_automute(codec);
16027 break;
16028 case ALC880_MIC_EVENT:
16029 alc662_eeepc_mic_automute(codec);
16030 break;
16031 }
16032}
16033
16034static void alc663_mode5_inithook(struct hda_codec *codec)
16035{
16036 alc663_15jd_two_speaker_automute(codec);
16037 alc662_eeepc_mic_automute(codec);
16038}
16039/* ***************** Mode6 ******************************/
16040static void alc663_mode6_unsol_event(struct hda_codec *codec,
16041 unsigned int res)
16042{
16043 switch (res >> 26) {
16044 case ALC880_HP_EVENT:
16045 alc663_two_hp_m2_speaker_automute(codec);
16046 break;
16047 case ALC880_MIC_EVENT:
16048 alc662_eeepc_mic_automute(codec);
16049 break;
16050 }
16051}
16052
16053static void alc663_mode6_inithook(struct hda_codec *codec)
16054{
16055 alc663_two_hp_m2_speaker_automute(codec);
16056 alc662_eeepc_mic_automute(codec);
16057}
16058
Kailang Yang6dda9f42008-05-27 12:05:31 +020016059static void alc663_g71v_hp_automute(struct hda_codec *codec)
16060{
16061 unsigned int present;
16062 unsigned char bits;
16063
16064 present = snd_hda_codec_read(codec, 0x21, 0,
16065 AC_VERB_GET_PIN_SENSE, 0)
16066 & AC_PINSENSE_PRESENCE;
16067 bits = present ? HDA_AMP_MUTE : 0;
16068 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
16069 HDA_AMP_MUTE, bits);
16070 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
16071 HDA_AMP_MUTE, bits);
16072}
16073
16074static void alc663_g71v_front_automute(struct hda_codec *codec)
16075{
16076 unsigned int present;
16077 unsigned char bits;
16078
16079 present = snd_hda_codec_read(codec, 0x15, 0,
16080 AC_VERB_GET_PIN_SENSE, 0)
16081 & AC_PINSENSE_PRESENCE;
16082 bits = present ? HDA_AMP_MUTE : 0;
16083 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
16084 HDA_AMP_MUTE, bits);
16085}
16086
16087static void alc663_g71v_unsol_event(struct hda_codec *codec,
16088 unsigned int res)
16089{
16090 switch (res >> 26) {
16091 case ALC880_HP_EVENT:
16092 alc663_g71v_hp_automute(codec);
16093 break;
16094 case ALC880_FRONT_EVENT:
16095 alc663_g71v_front_automute(codec);
16096 break;
16097 case ALC880_MIC_EVENT:
16098 alc662_eeepc_mic_automute(codec);
16099 break;
16100 }
16101}
16102
16103static void alc663_g71v_inithook(struct hda_codec *codec)
16104{
16105 alc663_g71v_front_automute(codec);
16106 alc663_g71v_hp_automute(codec);
16107 alc662_eeepc_mic_automute(codec);
16108}
16109
16110static void alc663_g50v_unsol_event(struct hda_codec *codec,
16111 unsigned int res)
16112{
16113 switch (res >> 26) {
16114 case ALC880_HP_EVENT:
16115 alc663_m51va_speaker_automute(codec);
16116 break;
16117 case ALC880_MIC_EVENT:
16118 alc662_eeepc_mic_automute(codec);
16119 break;
16120 }
16121}
16122
16123static void alc663_g50v_inithook(struct hda_codec *codec)
16124{
16125 alc663_m51va_speaker_automute(codec);
16126 alc662_eeepc_mic_automute(codec);
16127}
16128
Kailang Yangf1d4e282008-08-26 14:03:29 +020016129/* bind hp and internal speaker mute (with plug check) */
16130static int alc662_ecs_master_sw_put(struct snd_kcontrol *kcontrol,
16131 struct snd_ctl_elem_value *ucontrol)
16132{
16133 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
16134 long *valp = ucontrol->value.integer.value;
16135 int change;
16136
16137 change = snd_hda_codec_amp_update(codec, 0x1b, 0, HDA_OUTPUT, 0,
16138 HDA_AMP_MUTE,
16139 valp[0] ? 0 : HDA_AMP_MUTE);
16140 change |= snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0,
16141 HDA_AMP_MUTE,
16142 valp[1] ? 0 : HDA_AMP_MUTE);
16143 if (change)
16144 alc262_hippo1_automute(codec);
16145 return change;
16146}
16147
16148static struct snd_kcontrol_new alc662_ecs_mixer[] = {
16149 HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16150 {
16151 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
16152 .name = "Master Playback Switch",
16153 .info = snd_hda_mixer_amp_switch_info,
16154 .get = snd_hda_mixer_amp_switch_get,
16155 .put = alc662_ecs_master_sw_put,
16156 .private_value = HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
16157 },
16158
16159 HDA_CODEC_VOLUME("e-Mic/LineIn Boost", 0x18, 0, HDA_INPUT),
16160 HDA_CODEC_VOLUME("e-Mic/LineIn Playback Volume", 0x0b, 0x0, HDA_INPUT),
16161 HDA_CODEC_MUTE("e-Mic/LineIn Playback Switch", 0x0b, 0x0, HDA_INPUT),
16162
16163 HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT),
16164 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16165 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16166 { } /* end */
16167};
16168
Takashi Iwaicb53c622007-08-10 17:21:45 +020016169#ifdef CONFIG_SND_HDA_POWER_SAVE
16170#define alc662_loopbacks alc880_loopbacks
16171#endif
16172
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016173
16174/* pcm configuration: identiacal with ALC880 */
16175#define alc662_pcm_analog_playback alc880_pcm_analog_playback
16176#define alc662_pcm_analog_capture alc880_pcm_analog_capture
16177#define alc662_pcm_digital_playback alc880_pcm_digital_playback
16178#define alc662_pcm_digital_capture alc880_pcm_digital_capture
16179
16180/*
16181 * configuration and preset
16182 */
16183static const char *alc662_models[ALC662_MODEL_LAST] = {
16184 [ALC662_3ST_2ch_DIG] = "3stack-dig",
16185 [ALC662_3ST_6ch_DIG] = "3stack-6ch-dig",
16186 [ALC662_3ST_6ch] = "3stack-6ch",
16187 [ALC662_5ST_DIG] = "6stack-dig",
16188 [ALC662_LENOVO_101E] = "lenovo-101e",
Takashi Iwaib995d762007-10-17 10:41:06 +020016189 [ALC662_ASUS_EEEPC_P701] = "eeepc-p701",
Kailang Yang8c427222008-01-10 13:03:59 +010016190 [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20",
Kailang Yangf1d4e282008-08-26 14:03:29 +020016191 [ALC662_ECS] = "ecs",
Kailang Yang6dda9f42008-05-27 12:05:31 +020016192 [ALC663_ASUS_M51VA] = "m51va",
16193 [ALC663_ASUS_G71V] = "g71v",
16194 [ALC663_ASUS_H13] = "h13",
16195 [ALC663_ASUS_G50V] = "g50v",
Kailang Yangf1d4e282008-08-26 14:03:29 +020016196 [ALC663_ASUS_MODE1] = "asus-mode1",
16197 [ALC662_ASUS_MODE2] = "asus-mode2",
16198 [ALC663_ASUS_MODE3] = "asus-mode3",
16199 [ALC663_ASUS_MODE4] = "asus-mode4",
16200 [ALC663_ASUS_MODE5] = "asus-mode5",
16201 [ALC663_ASUS_MODE6] = "asus-mode6",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016202 [ALC662_AUTO] = "auto",
16203};
16204
16205static struct snd_pci_quirk alc662_cfg_tbl[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020016206 SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M51VA", ALC663_ASUS_M51VA),
Kailang Yang80ffe862008-10-15 11:23:27 +020016207 SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS G50V", ALC663_ASUS_G50V),
Herton Ronaldo Krzesinski3da23ca2008-03-14 12:52:59 +010016208 SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG),
Kailang Yang291702f2007-10-16 14:28:03 +020016209 SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701),
Kailang Yang8c427222008-01-10 13:03:59 +010016210 SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20),
Kailang Yangf1d4e282008-08-26 14:03:29 +020016211 SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC663_ASUS_MODE1),
16212 SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M50Vr", ALC663_ASUS_MODE1),
16213 SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC663_ASUS_MODE1),
16214 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC663_ASUS_MODE1),
16215 SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC663_ASUS_MODE1),
16216 SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS NB", ALC663_ASUS_MODE1),
16217 SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC663_ASUS_MODE1),
16218 SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC663_ASUS_MODE1),
16219 SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC663_ASUS_MODE1),
Kailang Yang80ffe862008-10-15 11:23:27 +020016220 SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC663_ASUS_MODE1),
Kailang Yangf1d4e282008-08-26 14:03:29 +020016221 SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_ASUS_MODE2),
16222 SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_ASUS_MODE2),
16223 SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_ASUS_MODE2),
16224 SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_ASUS_MODE2),
16225 SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_ASUS_MODE2),
16226 SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_ASUS_MODE2),
16227 SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_ASUS_MODE2),
16228 SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_ASUS_MODE2),
16229 SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_ASUS_MODE2),
16230 SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_ASUS_MODE2),
16231 SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_ASUS_MODE2),
16232 SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_ASUS_MODE2),
16233 SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC663_ASUS_MODE3),
16234 SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC663_ASUS_MODE3),
16235 SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC663_ASUS_MODE3),
16236 SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC663_ASUS_MODE3),
16237 SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC663_ASUS_MODE3),
16238 SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC663_ASUS_MODE4),
16239 SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC663_ASUS_MODE5),
16240 SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC663_ASUS_MODE6),
16241 SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC663_ASUS_MODE6),
16242 SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC663_ASUS_MODE6),
Herton Ronaldo Krzesinski95fe5f22008-09-26 23:48:45 -030016243 SND_PCI_QUIRK(0x105b, 0x0d47, "Foxconn 45CMX/45GMX/45CMX-K",
16244 ALC662_3ST_6ch_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010016245 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E),
Kailang Yangf1d4e282008-08-26 14:03:29 +020016246 SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_ECS),
16247 SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS),
Herton Ronaldo Krzesinskicb559742008-09-26 23:47:45 -030016248 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L",
16249 ALC662_3ST_6ch_DIG),
Vedran Miletic19c009a2008-09-29 20:29:25 +020016250 SND_PCI_QUIRK(0x1565, 0x820f, "Biostar TA780G M2+", ALC662_3ST_6ch_DIG),
Takashi Iwai238713d2008-10-05 10:57:39 +020016251 SND_PCI_QUIRK(0x1849, 0x3662, "ASROCK K10N78FullHD-hSLI R3.0",
Vedran Miletic19c009a2008-09-29 20:29:25 +020016252 ALC662_3ST_6ch_DIG),
Kailang Yang6dda9f42008-05-27 12:05:31 +020016253 SND_PCI_QUIRK(0x1854, 0x2000, "ASUS H13-2000", ALC663_ASUS_H13),
16254 SND_PCI_QUIRK(0x1854, 0x2001, "ASUS H13-2001", ALC663_ASUS_H13),
16255 SND_PCI_QUIRK(0x1854, 0x2002, "ASUS H13-2002", ALC663_ASUS_H13),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016256 {}
16257};
16258
16259static struct alc_config_preset alc662_presets[] = {
16260 [ALC662_3ST_2ch_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016261 .mixers = { alc662_3ST_2ch_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016262 .init_verbs = { alc662_init_verbs },
16263 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16264 .dac_nids = alc662_dac_nids,
16265 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016266 .dig_in_nid = ALC662_DIGIN_NID,
16267 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16268 .channel_mode = alc662_3ST_2ch_modes,
16269 .input_mux = &alc662_capture_source,
16270 },
16271 [ALC662_3ST_6ch_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016272 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016273 .init_verbs = { alc662_init_verbs },
16274 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16275 .dac_nids = alc662_dac_nids,
16276 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016277 .dig_in_nid = ALC662_DIGIN_NID,
16278 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
16279 .channel_mode = alc662_3ST_6ch_modes,
16280 .need_dac_fix = 1,
16281 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016282 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016283 [ALC662_3ST_6ch] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016284 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016285 .init_verbs = { alc662_init_verbs },
16286 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16287 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016288 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
16289 .channel_mode = alc662_3ST_6ch_modes,
16290 .need_dac_fix = 1,
16291 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016292 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016293 [ALC662_5ST_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016294 .mixers = { alc662_base_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016295 .init_verbs = { alc662_init_verbs },
16296 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16297 .dac_nids = alc662_dac_nids,
16298 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016299 .dig_in_nid = ALC662_DIGIN_NID,
16300 .num_channel_mode = ARRAY_SIZE(alc662_5stack_modes),
16301 .channel_mode = alc662_5stack_modes,
16302 .input_mux = &alc662_capture_source,
16303 },
16304 [ALC662_LENOVO_101E] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016305 .mixers = { alc662_lenovo_101e_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016306 .init_verbs = { alc662_init_verbs, alc662_sue_init_verbs },
16307 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16308 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016309 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16310 .channel_mode = alc662_3ST_2ch_modes,
16311 .input_mux = &alc662_lenovo_101e_capture_source,
16312 .unsol_event = alc662_lenovo_101e_unsol_event,
16313 .init_hook = alc662_lenovo_101e_all_automute,
16314 },
Kailang Yang291702f2007-10-16 14:28:03 +020016315 [ALC662_ASUS_EEEPC_P701] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016316 .mixers = { alc662_eeepc_p701_mixer },
Kailang Yang291702f2007-10-16 14:28:03 +020016317 .init_verbs = { alc662_init_verbs,
16318 alc662_eeepc_sue_init_verbs },
16319 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16320 .dac_nids = alc662_dac_nids,
Kailang Yang291702f2007-10-16 14:28:03 +020016321 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16322 .channel_mode = alc662_3ST_2ch_modes,
16323 .input_mux = &alc662_eeepc_capture_source,
16324 .unsol_event = alc662_eeepc_unsol_event,
16325 .init_hook = alc662_eeepc_inithook,
16326 },
Kailang Yang8c427222008-01-10 13:03:59 +010016327 [ALC662_ASUS_EEEPC_EP20] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016328 .mixers = { alc662_eeepc_ep20_mixer,
Kailang Yang8c427222008-01-10 13:03:59 +010016329 alc662_chmode_mixer },
16330 .init_verbs = { alc662_init_verbs,
16331 alc662_eeepc_ep20_sue_init_verbs },
16332 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16333 .dac_nids = alc662_dac_nids,
Kailang Yang8c427222008-01-10 13:03:59 +010016334 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
16335 .channel_mode = alc662_3ST_6ch_modes,
16336 .input_mux = &alc662_lenovo_101e_capture_source,
16337 .unsol_event = alc662_eeepc_ep20_unsol_event,
16338 .init_hook = alc662_eeepc_ep20_inithook,
16339 },
Kailang Yangf1d4e282008-08-26 14:03:29 +020016340 [ALC662_ECS] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016341 .mixers = { alc662_ecs_mixer },
Kailang Yangf1d4e282008-08-26 14:03:29 +020016342 .init_verbs = { alc662_init_verbs,
16343 alc662_ecs_init_verbs },
16344 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16345 .dac_nids = alc662_dac_nids,
16346 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16347 .channel_mode = alc662_3ST_2ch_modes,
16348 .input_mux = &alc662_eeepc_capture_source,
16349 .unsol_event = alc662_eeepc_unsol_event,
16350 .init_hook = alc662_eeepc_inithook,
16351 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020016352 [ALC663_ASUS_M51VA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016353 .mixers = { alc663_m51va_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020016354 .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
16355 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16356 .dac_nids = alc662_dac_nids,
16357 .dig_out_nid = ALC662_DIGOUT_NID,
16358 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16359 .channel_mode = alc662_3ST_2ch_modes,
16360 .input_mux = &alc663_m51va_capture_source,
16361 .unsol_event = alc663_m51va_unsol_event,
16362 .init_hook = alc663_m51va_inithook,
16363 },
16364 [ALC663_ASUS_G71V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016365 .mixers = { alc663_g71v_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020016366 .init_verbs = { alc662_init_verbs, alc663_g71v_init_verbs },
16367 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16368 .dac_nids = alc662_dac_nids,
16369 .dig_out_nid = ALC662_DIGOUT_NID,
16370 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16371 .channel_mode = alc662_3ST_2ch_modes,
16372 .input_mux = &alc662_eeepc_capture_source,
16373 .unsol_event = alc663_g71v_unsol_event,
16374 .init_hook = alc663_g71v_inithook,
16375 },
16376 [ALC663_ASUS_H13] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016377 .mixers = { alc663_m51va_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020016378 .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
16379 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16380 .dac_nids = alc662_dac_nids,
16381 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16382 .channel_mode = alc662_3ST_2ch_modes,
16383 .input_mux = &alc663_m51va_capture_source,
16384 .unsol_event = alc663_m51va_unsol_event,
16385 .init_hook = alc663_m51va_inithook,
16386 },
16387 [ALC663_ASUS_G50V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016388 .mixers = { alc663_g50v_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020016389 .init_verbs = { alc662_init_verbs, alc663_g50v_init_verbs },
16390 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16391 .dac_nids = alc662_dac_nids,
16392 .dig_out_nid = ALC662_DIGOUT_NID,
16393 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
16394 .channel_mode = alc662_3ST_6ch_modes,
16395 .input_mux = &alc663_capture_source,
16396 .unsol_event = alc663_g50v_unsol_event,
16397 .init_hook = alc663_g50v_inithook,
16398 },
Kailang Yangf1d4e282008-08-26 14:03:29 +020016399 [ALC663_ASUS_MODE1] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016400 .mixers = { alc663_m51va_mixer },
16401 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020016402 .init_verbs = { alc662_init_verbs,
16403 alc663_21jd_amic_init_verbs },
16404 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16405 .hp_nid = 0x03,
16406 .dac_nids = alc662_dac_nids,
16407 .dig_out_nid = ALC662_DIGOUT_NID,
16408 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16409 .channel_mode = alc662_3ST_2ch_modes,
16410 .input_mux = &alc662_eeepc_capture_source,
16411 .unsol_event = alc663_mode1_unsol_event,
16412 .init_hook = alc663_mode1_inithook,
16413 },
16414 [ALC662_ASUS_MODE2] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016415 .mixers = { alc662_1bjd_mixer },
16416 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020016417 .init_verbs = { alc662_init_verbs,
16418 alc662_1bjd_amic_init_verbs },
16419 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16420 .dac_nids = alc662_dac_nids,
16421 .dig_out_nid = ALC662_DIGOUT_NID,
16422 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16423 .channel_mode = alc662_3ST_2ch_modes,
16424 .input_mux = &alc662_eeepc_capture_source,
16425 .unsol_event = alc662_mode2_unsol_event,
16426 .init_hook = alc662_mode2_inithook,
16427 },
16428 [ALC663_ASUS_MODE3] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016429 .mixers = { alc663_two_hp_m1_mixer },
16430 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020016431 .init_verbs = { alc662_init_verbs,
16432 alc663_two_hp_amic_m1_init_verbs },
16433 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16434 .hp_nid = 0x03,
16435 .dac_nids = alc662_dac_nids,
16436 .dig_out_nid = ALC662_DIGOUT_NID,
16437 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16438 .channel_mode = alc662_3ST_2ch_modes,
16439 .input_mux = &alc662_eeepc_capture_source,
16440 .unsol_event = alc663_mode3_unsol_event,
16441 .init_hook = alc663_mode3_inithook,
16442 },
16443 [ALC663_ASUS_MODE4] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016444 .mixers = { alc663_asus_21jd_clfe_mixer },
16445 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020016446 .init_verbs = { alc662_init_verbs,
16447 alc663_21jd_amic_init_verbs},
16448 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16449 .hp_nid = 0x03,
16450 .dac_nids = alc662_dac_nids,
16451 .dig_out_nid = ALC662_DIGOUT_NID,
16452 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16453 .channel_mode = alc662_3ST_2ch_modes,
16454 .input_mux = &alc662_eeepc_capture_source,
16455 .unsol_event = alc663_mode4_unsol_event,
16456 .init_hook = alc663_mode4_inithook,
16457 },
16458 [ALC663_ASUS_MODE5] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016459 .mixers = { alc663_asus_15jd_clfe_mixer },
16460 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020016461 .init_verbs = { alc662_init_verbs,
16462 alc663_15jd_amic_init_verbs },
16463 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16464 .hp_nid = 0x03,
16465 .dac_nids = alc662_dac_nids,
16466 .dig_out_nid = ALC662_DIGOUT_NID,
16467 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16468 .channel_mode = alc662_3ST_2ch_modes,
16469 .input_mux = &alc662_eeepc_capture_source,
16470 .unsol_event = alc663_mode5_unsol_event,
16471 .init_hook = alc663_mode5_inithook,
16472 },
16473 [ALC663_ASUS_MODE6] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016474 .mixers = { alc663_two_hp_m2_mixer },
16475 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020016476 .init_verbs = { alc662_init_verbs,
16477 alc663_two_hp_amic_m2_init_verbs },
16478 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16479 .hp_nid = 0x03,
16480 .dac_nids = alc662_dac_nids,
16481 .dig_out_nid = ALC662_DIGOUT_NID,
16482 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16483 .channel_mode = alc662_3ST_2ch_modes,
16484 .input_mux = &alc662_eeepc_capture_source,
16485 .unsol_event = alc663_mode6_unsol_event,
16486 .init_hook = alc663_mode6_inithook,
16487 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016488};
16489
16490
16491/*
16492 * BIOS auto configuration
16493 */
16494
16495/* add playback controls from the parsed DAC table */
16496static int alc662_auto_create_multi_out_ctls(struct alc_spec *spec,
16497 const struct auto_pin_cfg *cfg)
16498{
16499 char name[32];
16500 static const char *chname[4] = {
16501 "Front", "Surround", NULL /*CLFE*/, "Side"
16502 };
16503 hda_nid_t nid;
16504 int i, err;
16505
16506 for (i = 0; i < cfg->line_outs; i++) {
16507 if (!spec->multiout.dac_nids[i])
16508 continue;
Kailang Yangb60dd392007-09-20 12:50:29 +020016509 nid = alc880_idx_to_dac(i);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016510 if (i == 2) {
16511 /* Center/LFE */
16512 err = add_control(spec, ALC_CTL_WIDGET_VOL,
16513 "Center Playback Volume",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016514 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
16515 HDA_OUTPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016516 if (err < 0)
16517 return err;
16518 err = add_control(spec, ALC_CTL_WIDGET_VOL,
16519 "LFE Playback Volume",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016520 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
16521 HDA_OUTPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016522 if (err < 0)
16523 return err;
Herton Ronaldo Krzesinskib69ce012008-09-18 16:41:49 -030016524 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016525 "Center Playback Switch",
Herton Ronaldo Krzesinskib69ce012008-09-18 16:41:49 -030016526 HDA_COMPOSE_AMP_VAL(0x0e, 1, 0,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016527 HDA_INPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016528 if (err < 0)
16529 return err;
Herton Ronaldo Krzesinskib69ce012008-09-18 16:41:49 -030016530 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016531 "LFE Playback Switch",
Herton Ronaldo Krzesinskib69ce012008-09-18 16:41:49 -030016532 HDA_COMPOSE_AMP_VAL(0x0e, 2, 0,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016533 HDA_INPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016534 if (err < 0)
16535 return err;
16536 } else {
16537 sprintf(name, "%s Playback Volume", chname[i]);
16538 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016539 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
16540 HDA_OUTPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016541 if (err < 0)
16542 return err;
16543 sprintf(name, "%s Playback Switch", chname[i]);
Herton Ronaldo Krzesinskib69ce012008-09-18 16:41:49 -030016544 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
16545 HDA_COMPOSE_AMP_VAL(alc880_idx_to_mixer(i),
16546 3, 0, HDA_INPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016547 if (err < 0)
16548 return err;
16549 }
16550 }
16551 return 0;
16552}
16553
16554/* add playback controls for speaker and HP outputs */
16555static int alc662_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
16556 const char *pfx)
16557{
16558 hda_nid_t nid;
16559 int err;
16560 char name[32];
16561
16562 if (!pin)
16563 return 0;
16564
Takashi Iwai24fb9172008-09-02 14:48:20 +020016565 if (pin == 0x17) {
16566 /* ALC663 has a mono output pin on 0x17 */
16567 sprintf(name, "%s Playback Switch", pfx);
16568 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
16569 HDA_COMPOSE_AMP_VAL(pin, 2, 0, HDA_OUTPUT));
16570 return err;
16571 }
16572
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016573 if (alc880_is_fixed_pin(pin)) {
16574 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
Takashi Iwai939778a2009-02-05 15:57:55 +010016575 /* printk(KERN_DEBUG "DAC nid=%x\n",nid); */
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016576 /* specify the DAC as the extra output */
16577 if (!spec->multiout.hp_nid)
16578 spec->multiout.hp_nid = nid;
16579 else
16580 spec->multiout.extra_out_nid[0] = nid;
16581 /* control HP volume/switch on the output mixer amp */
16582 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
16583 sprintf(name, "%s Playback Volume", pfx);
16584 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
16585 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
16586 if (err < 0)
16587 return err;
16588 sprintf(name, "%s Playback Switch", pfx);
16589 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
16590 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
16591 if (err < 0)
16592 return err;
16593 } else if (alc880_is_multi_pin(pin)) {
16594 /* set manual connection */
16595 /* we have only a switch on HP-out PIN */
16596 sprintf(name, "%s Playback Switch", pfx);
16597 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
16598 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
16599 if (err < 0)
16600 return err;
16601 }
16602 return 0;
16603}
16604
16605/* create playback/capture controls for input pins */
16606static int alc662_auto_create_analog_input_ctls(struct alc_spec *spec,
16607 const struct auto_pin_cfg *cfg)
16608{
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020016609 struct hda_input_mux *imux = &spec->private_imux[0];
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016610 int i, err, idx;
16611
16612 for (i = 0; i < AUTO_PIN_LAST; i++) {
16613 if (alc880_is_input_pin(cfg->input_pins[i])) {
16614 idx = alc880_input_pin_idx(cfg->input_pins[i]);
16615 err = new_analog_input(spec, cfg->input_pins[i],
16616 auto_pin_cfg_labels[i],
16617 idx, 0x0b);
16618 if (err < 0)
16619 return err;
16620 imux->items[imux->num_items].label =
16621 auto_pin_cfg_labels[i];
16622 imux->items[imux->num_items].index =
16623 alc880_input_pin_idx(cfg->input_pins[i]);
16624 imux->num_items++;
16625 }
16626 }
16627 return 0;
16628}
16629
16630static void alc662_auto_set_output_and_unmute(struct hda_codec *codec,
16631 hda_nid_t nid, int pin_type,
16632 int dac_idx)
16633{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016634 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016635 /* need the manual connection? */
16636 if (alc880_is_multi_pin(nid)) {
16637 struct alc_spec *spec = codec->spec;
16638 int idx = alc880_multi_pin_idx(nid);
16639 snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
16640 AC_VERB_SET_CONNECT_SEL,
16641 alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
16642 }
16643}
16644
16645static void alc662_auto_init_multi_out(struct hda_codec *codec)
16646{
16647 struct alc_spec *spec = codec->spec;
16648 int i;
16649
Kailang Yang8c427222008-01-10 13:03:59 +010016650 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016651 for (i = 0; i <= HDA_SIDE; i++) {
16652 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020016653 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016654 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020016655 alc662_auto_set_output_and_unmute(codec, nid, pin_type,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016656 i);
16657 }
16658}
16659
16660static void alc662_auto_init_hp_out(struct hda_codec *codec)
16661{
16662 struct alc_spec *spec = codec->spec;
16663 hda_nid_t pin;
16664
16665 pin = spec->autocfg.hp_pins[0];
16666 if (pin) /* connect to front */
16667 /* use dac 0 */
16668 alc662_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016669 pin = spec->autocfg.speaker_pins[0];
16670 if (pin)
16671 alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016672}
16673
16674#define alc662_is_input_pin(nid) alc880_is_input_pin(nid)
16675#define ALC662_PIN_CD_NID ALC880_PIN_CD_NID
16676
16677static void alc662_auto_init_analog_input(struct hda_codec *codec)
16678{
16679 struct alc_spec *spec = codec->spec;
16680 int i;
16681
16682 for (i = 0; i < AUTO_PIN_LAST; i++) {
16683 hda_nid_t nid = spec->autocfg.input_pins[i];
16684 if (alc662_is_input_pin(nid)) {
16685 snd_hda_codec_write(codec, nid, 0,
16686 AC_VERB_SET_PIN_WIDGET_CONTROL,
16687 (i <= AUTO_PIN_FRONT_MIC ?
16688 PIN_VREF80 : PIN_IN));
16689 if (nid != ALC662_PIN_CD_NID)
16690 snd_hda_codec_write(codec, nid, 0,
16691 AC_VERB_SET_AMP_GAIN_MUTE,
16692 AMP_OUT_MUTE);
16693 }
16694 }
16695}
16696
Takashi Iwaif511b012008-08-15 16:46:42 +020016697#define alc662_auto_init_input_src alc882_auto_init_input_src
16698
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016699static int alc662_parse_auto_config(struct hda_codec *codec)
16700{
16701 struct alc_spec *spec = codec->spec;
16702 int err;
16703 static hda_nid_t alc662_ignore[] = { 0x1d, 0 };
16704
16705 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
16706 alc662_ignore);
16707 if (err < 0)
16708 return err;
16709 if (!spec->autocfg.line_outs)
16710 return 0; /* can't find valid BIOS pin config */
16711
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016712 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
16713 if (err < 0)
16714 return err;
16715 err = alc662_auto_create_multi_out_ctls(spec, &spec->autocfg);
16716 if (err < 0)
16717 return err;
16718 err = alc662_auto_create_extra_out(spec,
16719 spec->autocfg.speaker_pins[0],
16720 "Speaker");
16721 if (err < 0)
16722 return err;
16723 err = alc662_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
16724 "Headphone");
16725 if (err < 0)
16726 return err;
16727 err = alc662_auto_create_analog_input_ctls(spec, &spec->autocfg);
16728 if (err < 0)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016729 return err;
16730
16731 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
16732
16733 if (spec->autocfg.dig_out_pin)
16734 spec->multiout.dig_out_nid = ALC880_DIGOUT_NID;
16735
Takashi Iwai603c4012008-07-30 15:01:44 +020016736 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010016737 add_mixer(spec, spec->kctls.list);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016738
16739 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020016740 spec->input_mux = &spec->private_imux[0];
Kailang Yangea1fb292008-08-26 12:58:38 +020016741
Takashi Iwaid88897e2008-10-31 15:01:37 +010016742 add_verb(spec, alc662_auto_init_verbs);
Takashi Iwai24fb9172008-09-02 14:48:20 +020016743 if (codec->vendor_id == 0x10ec0663)
Takashi Iwaid88897e2008-10-31 15:01:37 +010016744 add_verb(spec, alc663_auto_init_verbs);
Takashi Iwaiee979a142008-09-02 15:42:20 +020016745
16746 err = alc_auto_add_mic_boost(codec);
16747 if (err < 0)
16748 return err;
16749
Takashi Iwaie044c392008-10-27 16:56:24 +010016750 store_pin_configs(codec);
Takashi Iwai8c872862007-06-19 12:11:16 +020016751 return 1;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016752}
16753
16754/* additional initialization for auto-configuration model */
16755static void alc662_auto_init(struct hda_codec *codec)
16756{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016757 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016758 alc662_auto_init_multi_out(codec);
16759 alc662_auto_init_hp_out(codec);
16760 alc662_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020016761 alc662_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016762 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020016763 alc_inithook(codec);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016764}
16765
16766static int patch_alc662(struct hda_codec *codec)
16767{
16768 struct alc_spec *spec;
16769 int err, board_config;
16770
16771 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
16772 if (!spec)
16773 return -ENOMEM;
16774
16775 codec->spec = spec;
16776
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020016777 alc_fix_pll_init(codec, 0x20, 0x04, 15);
16778
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016779 board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST,
16780 alc662_models,
16781 alc662_cfg_tbl);
16782 if (board_config < 0) {
16783 printk(KERN_INFO "hda_codec: Unknown model for ALC662, "
16784 "trying auto-probe from BIOS...\n");
16785 board_config = ALC662_AUTO;
16786 }
16787
16788 if (board_config == ALC662_AUTO) {
16789 /* automatic parse from the BIOS config */
16790 err = alc662_parse_auto_config(codec);
16791 if (err < 0) {
16792 alc_free(codec);
16793 return err;
Takashi Iwai8c872862007-06-19 12:11:16 +020016794 } else if (!err) {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016795 printk(KERN_INFO
16796 "hda_codec: Cannot set up configuration "
16797 "from BIOS. Using base mode...\n");
16798 board_config = ALC662_3ST_2ch_DIG;
16799 }
16800 }
16801
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090016802 err = snd_hda_attach_beep_device(codec, 0x1);
16803 if (err < 0) {
16804 alc_free(codec);
16805 return err;
16806 }
16807
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016808 if (board_config != ALC662_AUTO)
16809 setup_preset(spec, &alc662_presets[board_config]);
16810
Kailang Yang6dda9f42008-05-27 12:05:31 +020016811 if (codec->vendor_id == 0x10ec0663) {
16812 spec->stream_name_analog = "ALC663 Analog";
16813 spec->stream_name_digital = "ALC663 Digital";
Kailang Yang01afd412008-10-15 11:22:09 +020016814 } else if (codec->vendor_id == 0x10ec0272) {
16815 spec->stream_name_analog = "ALC272 Analog";
16816 spec->stream_name_digital = "ALC272 Digital";
Kailang Yang6dda9f42008-05-27 12:05:31 +020016817 } else {
16818 spec->stream_name_analog = "ALC662 Analog";
16819 spec->stream_name_digital = "ALC662 Digital";
16820 }
16821
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016822 spec->stream_analog_playback = &alc662_pcm_analog_playback;
16823 spec->stream_analog_capture = &alc662_pcm_analog_capture;
16824
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016825 spec->stream_digital_playback = &alc662_pcm_digital_playback;
16826 spec->stream_digital_capture = &alc662_pcm_digital_capture;
16827
Takashi Iwaie1406342008-02-11 18:32:32 +010016828 spec->adc_nids = alc662_adc_nids;
16829 spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids);
16830 spec->capsrc_nids = alc662_capsrc_nids;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020016831 spec->capture_style = CAPT_MIX;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016832
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016833 if (!spec->cap_mixer)
16834 set_capture_mixer(spec);
16835
Takashi Iwai2134ea42008-01-10 16:53:55 +010016836 spec->vmaster_nid = 0x02;
16837
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016838 codec->patch_ops = alc_patch_ops;
16839 if (board_config == ALC662_AUTO)
16840 spec->init_hook = alc662_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020016841#ifdef CONFIG_SND_HDA_POWER_SAVE
16842 if (!spec->loopback.amplist)
16843 spec->loopback.amplist = alc662_loopbacks;
16844#endif
Takashi Iwaidaead532008-11-28 12:55:36 +010016845 codec->proc_widget_hook = print_realtek_coef;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016846
16847 return 0;
16848}
16849
16850/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070016851 * patch entries
16852 */
Takashi Iwai1289e9e2008-11-27 15:47:11 +010016853static struct hda_codec_preset snd_hda_preset_realtek[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070016854 { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
Kailang Yangdf694da2005-12-05 19:42:22 +010016855 { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
Kailang Yangf6a92242007-12-13 16:52:54 +010016856 { .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 },
Kailang Yanga361d842007-06-05 12:30:55 +020016857 { .id = 0x10ec0268, .name = "ALC268", .patch = patch_alc268 },
Kailang Yangf6a92242007-12-13 16:52:54 +010016858 { .id = 0x10ec0269, .name = "ALC269", .patch = patch_alc269 },
Kailang Yang01afd412008-10-15 11:22:09 +020016859 { .id = 0x10ec0272, .name = "ALC272", .patch = patch_alc662 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016860 { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016861 .patch = patch_alc861 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016862 { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
16863 { .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 },
16864 { .id = 0x10ec0862, .name = "ALC861-VD", .patch = patch_alc861vd },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016865 { .id = 0x10ec0662, .rev = 0x100002, .name = "ALC662 rev2",
16866 .patch = patch_alc883 },
16867 { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1",
16868 .patch = patch_alc662 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020016869 { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016870 { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070016871 { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020016872 { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc883 },
Clive Messer669faba2008-09-30 15:49:13 +020016873 { .id = 0x10ec0885, .rev = 0x100101, .name = "ALC889A",
16874 .patch = patch_alc882 }, /* should be patch_alc883() in future */
Takashi Iwaicb308f92008-04-16 14:13:29 +020016875 { .id = 0x10ec0885, .rev = 0x100103, .name = "ALC889A",
Takashi Iwai7943a8a2008-04-16 17:29:09 +020016876 .patch = patch_alc882 }, /* should be patch_alc883() in future */
Kailang Yangdf694da2005-12-05 19:42:22 +010016877 { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
Kailang Yanga385a522008-10-15 11:20:21 +020016878 { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc883 },
Kailang Yang44426082008-10-15 11:18:05 +020016879 { .id = 0x10ec0888, .rev = 0x100101, .name = "ALC1200",
16880 .patch = patch_alc883 },
Wu Fengguang3fea2cb2008-12-26 12:20:43 +080016881 { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc883 },
Kailang Yangf6a92242007-12-13 16:52:54 +010016882 { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc883 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070016883 {} /* terminator */
16884};
Takashi Iwai1289e9e2008-11-27 15:47:11 +010016885
16886MODULE_ALIAS("snd-hda-codec-id:10ec*");
16887
16888MODULE_LICENSE("GPL");
16889MODULE_DESCRIPTION("Realtek HD-audio codec");
16890
16891static struct hda_codec_preset_list realtek_list = {
16892 .preset = snd_hda_preset_realtek,
16893 .owner = THIS_MODULE,
16894};
16895
16896static int __init patch_realtek_init(void)
16897{
16898 return snd_hda_add_codec_preset(&realtek_list);
16899}
16900
16901static void __exit patch_realtek_exit(void)
16902{
16903 snd_hda_delete_codec_preset(&realtek_list);
16904}
16905
16906module_init(patch_realtek_init)
16907module_exit(patch_realtek_exit)