blob: 0fd258eba3a57e917c07cc88fc18096e0b6bc1e0 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Universal Interface for Intel High Definition Audio Codec
3 *
4 * HD audio interface patch for ALC 260/880/882 codecs
5 *
Kailang Yangdf694da2005-12-05 19:42:22 +01006 * Copyright (c) 2004 Kailang Yang <kailang@realtek.com.tw>
7 * PeiSen Hou <pshou@realtek.com.tw>
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 * Takashi Iwai <tiwai@suse.de>
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01009 * Jonathan Woithe <jwoithe@physics.adelaide.edu.au>
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 *
11 * This driver is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This driver is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <linux/init.h>
27#include <linux/delay.h>
28#include <linux/slab.h>
29#include <linux/pci.h>
30#include <sound/core.h>
31#include "hda_codec.h"
32#include "hda_local.h"
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090033#include "hda_beep.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070034
Kailang Yangccc656c2006-10-17 12:32:26 +020035#define ALC880_FRONT_EVENT 0x01
36#define ALC880_DCVOL_EVENT 0x02
37#define ALC880_HP_EVENT 0x04
38#define ALC880_MIC_EVENT 0x08
Linus Torvalds1da177e2005-04-16 15:20:36 -070039
40/* ALC880 board config type */
41enum {
Linus Torvalds1da177e2005-04-16 15:20:36 -070042 ALC880_3ST,
43 ALC880_3ST_DIG,
44 ALC880_5ST,
45 ALC880_5ST_DIG,
46 ALC880_W810,
Takashi Iwaidfc0ff62005-05-12 14:31:49 +020047 ALC880_Z71V,
Takashi Iwaib6482d42005-06-27 15:32:43 +020048 ALC880_6ST,
Takashi Iwai16ded522005-06-10 19:58:24 +020049 ALC880_6ST_DIG,
50 ALC880_F1734,
51 ALC880_ASUS,
52 ALC880_ASUS_DIG,
53 ALC880_ASUS_W1V,
Kailang Yangdf694da2005-12-05 19:42:22 +010054 ALC880_ASUS_DIG2,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +010055 ALC880_FUJITSU,
Takashi Iwai16ded522005-06-10 19:58:24 +020056 ALC880_UNIWILL_DIG,
Kailang Yangccc656c2006-10-17 12:32:26 +020057 ALC880_UNIWILL,
58 ALC880_UNIWILL_P53,
Kailang Yangdf694da2005-12-05 19:42:22 +010059 ALC880_CLEVO,
60 ALC880_TCL_S700,
Takashi Iwaiae6b8132006-03-03 16:47:17 +010061 ALC880_LG,
Takashi Iwaid6815182006-03-23 16:06:23 +010062 ALC880_LG_LW,
Takashi Iwaidf99cd32008-04-25 15:25:04 +020063 ALC880_MEDION_RIM,
Takashi Iwaie9edcee2005-06-13 14:16:38 +020064#ifdef CONFIG_SND_DEBUG
65 ALC880_TEST,
66#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010067 ALC880_AUTO,
Takashi Iwai16ded522005-06-10 19:58:24 +020068 ALC880_MODEL_LAST /* last tag */
69};
70
71/* ALC260 models */
72enum {
73 ALC260_BASIC,
74 ALC260_HP,
Kailang Yang3f878302008-08-26 13:02:23 +020075 ALC260_HP_DC7600,
Kailang Yangdf694da2005-12-05 19:42:22 +010076 ALC260_HP_3013,
77 ALC260_FUJITSU_S702X,
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +010078 ALC260_ACER,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020079 ALC260_WILL,
80 ALC260_REPLACER_672V,
Michael Schwingencc959482009-02-22 18:58:45 +010081 ALC260_FAVORIT100,
Jonathan Woithe7cf51e42006-02-09 12:01:26 +010082#ifdef CONFIG_SND_DEBUG
83 ALC260_TEST,
84#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010085 ALC260_AUTO,
Takashi Iwai16ded522005-06-10 19:58:24 +020086 ALC260_MODEL_LAST /* last tag */
Linus Torvalds1da177e2005-04-16 15:20:36 -070087};
88
Kailang Yangdf694da2005-12-05 19:42:22 +010089/* ALC262 models */
90enum {
91 ALC262_BASIC,
Kailang Yangccc656c2006-10-17 12:32:26 +020092 ALC262_HIPPO,
93 ALC262_HIPPO_1,
Takashi Iwai834be882006-03-01 14:16:17 +010094 ALC262_FUJITSU,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020095 ALC262_HP_BPC,
Kailang Yangcd7509a2007-01-26 18:33:17 +010096 ALC262_HP_BPC_D7000_WL,
97 ALC262_HP_BPC_D7000_WF,
Kailang Yang66d2a9d2007-11-14 12:06:21 +010098 ALC262_HP_TC_T5735,
Kailang Yang8c427222008-01-10 13:03:59 +010099 ALC262_HP_RP5700,
Takashi Iwai304dcaa2006-07-25 14:51:16 +0200100 ALC262_BENQ_ED8,
Kailang Yang272a5272007-05-14 11:00:38 +0200101 ALC262_SONY_ASSAMD,
Kailang Yang83c34212007-07-05 11:43:05 +0200102 ALC262_BENQ_T31,
Tobin Davisf651b502007-10-26 12:40:47 +0200103 ALC262_ULTRA,
Jiang zhe0e31daf2008-03-20 12:12:39 +0100104 ALC262_LENOVO_3000,
Pascal Terjane8f9ae22008-08-04 14:36:05 +0200105 ALC262_NEC,
Kailang Yang4e555fe2008-08-26 13:05:55 +0200106 ALC262_TOSHIBA_S06,
Hiroshi Miura9f99a632008-08-28 16:09:06 +0200107 ALC262_TOSHIBA_RX1,
Tony Vroonba340e82009-02-02 19:01:30 +0000108 ALC262_TYAN,
Kailang Yangdf694da2005-12-05 19:42:22 +0100109 ALC262_AUTO,
110 ALC262_MODEL_LAST /* last tag */
111};
112
Kailang Yanga361d842007-06-05 12:30:55 +0200113/* ALC268 models */
114enum {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +0200115 ALC267_QUANTA_IL1,
Kailang Yanga361d842007-06-05 12:30:55 +0200116 ALC268_3ST,
Kailang Yangd1a991a2007-08-15 16:21:59 +0200117 ALC268_TOSHIBA,
Takashi Iwaid2738092007-08-16 14:59:45 +0200118 ALC268_ACER,
Takashi Iwaic238b4f2008-11-05 14:57:20 +0100119 ALC268_ACER_DMIC,
Kailang Yang8ef355d2008-08-26 13:10:22 +0200120 ALC268_ACER_ASPIRE_ONE,
Takashi Iwai3866f0b2008-01-15 12:37:42 +0100121 ALC268_DELL,
Mirco Tischlerf12462c2008-02-04 12:33:59 +0100122 ALC268_ZEPTO,
Jonathan Woithe86c53bd2008-01-08 12:33:19 +0100123#ifdef CONFIG_SND_DEBUG
124 ALC268_TEST,
125#endif
Kailang Yanga361d842007-06-05 12:30:55 +0200126 ALC268_AUTO,
127 ALC268_MODEL_LAST /* last tag */
128};
129
Kailang Yangf6a92242007-12-13 16:52:54 +0100130/* ALC269 models */
131enum {
132 ALC269_BASIC,
Kailang Yang60db6b52008-08-26 13:13:00 +0200133 ALC269_QUANTA_FL1,
Kailang Yangf53281e2008-07-18 12:36:43 +0200134 ALC269_ASUS_EEEPC_P703,
135 ALC269_ASUS_EEEPC_P901,
Takashi Iwai26f5df22008-11-03 17:39:46 +0100136 ALC269_FUJITSU,
Tony Vroon64154832008-11-06 15:08:49 +0000137 ALC269_LIFEBOOK,
Kailang Yangf6a92242007-12-13 16:52:54 +0100138 ALC269_AUTO,
139 ALC269_MODEL_LAST /* last tag */
140};
141
Kailang Yangdf694da2005-12-05 19:42:22 +0100142/* ALC861 models */
143enum {
144 ALC861_3ST,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200145 ALC660_3ST,
Kailang Yangdf694da2005-12-05 19:42:22 +0100146 ALC861_3ST_DIG,
147 ALC861_6ST_DIG,
Takashi Iwai22309c32006-08-09 16:57:28 +0200148 ALC861_UNIWILL_M31,
Tobin Davisa53d1ae2006-10-17 12:00:28 +0200149 ALC861_TOSHIBA,
Mariusz Domanski7cdbff92006-10-23 13:42:56 +0200150 ALC861_ASUS,
Takashi Iwai56bb0ca2006-11-22 11:52:52 +0100151 ALC861_ASUS_LAPTOP,
Kailang Yangdf694da2005-12-05 19:42:22 +0100152 ALC861_AUTO,
153 ALC861_MODEL_LAST,
154};
155
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100156/* ALC861-VD models */
157enum {
158 ALC660VD_3ST,
Mike Crash6963f842007-06-25 12:12:51 +0200159 ALC660VD_3ST_DIG,
Takashi Iwai13c94742008-11-05 08:06:08 +0100160 ALC660VD_ASUS_V1S,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100161 ALC861VD_3ST,
162 ALC861VD_3ST_DIG,
163 ALC861VD_6ST_DIG,
Kailang Yangbdd148a2007-05-08 15:19:08 +0200164 ALC861VD_LENOVO,
Kailang Yang272a5272007-05-14 11:00:38 +0200165 ALC861VD_DALLAS,
Kailang Yangd1a991a2007-08-15 16:21:59 +0200166 ALC861VD_HP,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100167 ALC861VD_AUTO,
168 ALC861VD_MODEL_LAST,
169};
170
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200171/* ALC662 models */
172enum {
173 ALC662_3ST_2ch_DIG,
174 ALC662_3ST_6ch_DIG,
175 ALC662_3ST_6ch,
176 ALC662_5ST_DIG,
177 ALC662_LENOVO_101E,
Kailang Yang291702f2007-10-16 14:28:03 +0200178 ALC662_ASUS_EEEPC_P701,
Kailang Yang8c427222008-01-10 13:03:59 +0100179 ALC662_ASUS_EEEPC_EP20,
Kailang Yang6dda9f42008-05-27 12:05:31 +0200180 ALC663_ASUS_M51VA,
181 ALC663_ASUS_G71V,
182 ALC663_ASUS_H13,
183 ALC663_ASUS_G50V,
Kailang Yangf1d4e282008-08-26 14:03:29 +0200184 ALC662_ECS,
185 ALC663_ASUS_MODE1,
186 ALC662_ASUS_MODE2,
187 ALC663_ASUS_MODE3,
188 ALC663_ASUS_MODE4,
189 ALC663_ASUS_MODE5,
190 ALC663_ASUS_MODE6,
Kailang Yang622e84c2009-04-21 07:39:04 +0200191 ALC272_DELL,
192 ALC272_DELL_ZM1,
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200193 ALC662_AUTO,
194 ALC662_MODEL_LAST,
195};
196
Kailang Yangdf694da2005-12-05 19:42:22 +0100197/* ALC882 models */
198enum {
199 ALC882_3ST_DIG,
200 ALC882_6ST_DIG,
Takashi Iwai4b146cb2006-07-28 14:42:36 +0200201 ALC882_ARIMA,
Kailang Yangbdd148a2007-05-08 15:19:08 +0200202 ALC882_W2JC,
Kailang Yang272a5272007-05-14 11:00:38 +0200203 ALC882_TARGA,
204 ALC882_ASUS_A7J,
Takashi Iwai914759b2007-09-06 14:52:04 +0200205 ALC882_ASUS_A7M,
Tobin Davis9102cd12006-12-15 10:02:12 +0100206 ALC885_MACPRO,
Takashi Iwai87350ad2007-08-16 18:19:38 +0200207 ALC885_MBP3,
Nicola Fagnanic54728d2007-07-19 23:28:52 +0200208 ALC885_IMAC24,
Kailang Yang272a5272007-05-14 11:00:38 +0200209 ALC882_AUTO,
Kailang Yangdf694da2005-12-05 19:42:22 +0100210 ALC882_MODEL_LAST,
211};
212
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200213/* ALC883 models */
214enum {
215 ALC883_3ST_2ch_DIG,
216 ALC883_3ST_6ch_DIG,
217 ALC883_3ST_6ch,
218 ALC883_6ST_DIG,
Kailang Yangccc656c2006-10-17 12:32:26 +0200219 ALC883_TARGA_DIG,
220 ALC883_TARGA_2ch_DIG,
Vladimir Avdoninbab282b2006-08-22 13:31:58 +0200221 ALC883_ACER,
Tobin Davis2880a862007-08-07 11:50:26 +0200222 ALC883_ACER_ASPIRE,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +0800223 ALC888_ACER_ASPIRE_4930G,
Tobin Davisc07584c2006-10-13 12:32:16 +0200224 ALC883_MEDION,
Kailang Yangea1fb292008-08-26 12:58:38 +0200225 ALC883_MEDION_MD2,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +0100226 ALC883_LAPTOP_EAPD,
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200227 ALC883_LENOVO_101E_2ch,
Kailang Yang272a5272007-05-14 11:00:38 +0200228 ALC883_LENOVO_NB0763,
Kailang Yang189609a2007-08-20 11:31:23 +0200229 ALC888_LENOVO_MS7195_DIG,
Kailang Yange2757d52008-08-26 13:17:46 +0200230 ALC888_LENOVO_SKY,
Kailang Yangea1fb292008-08-26 12:58:38 +0200231 ALC883_HAIER_W66,
Claudio Matsuoka4723c022007-07-13 14:36:19 +0200232 ALC888_3ST_HP,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +0100233 ALC888_6ST_DELL,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +0100234 ALC883_MITAC,
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +0100235 ALC883_CLEVO_M720,
Jiang zhefb97dc62008-03-06 11:07:11 +0100236 ALC883_FUJITSU_PI2515,
Vincent Petryef8ef5f2008-11-23 11:31:41 +0800237 ALC888_FUJITSU_XA3530,
Jiang zhe17bba1b2008-06-04 12:11:07 +0200238 ALC883_3ST_6ch_INTEL,
Kailang Yange2757d52008-08-26 13:17:46 +0200239 ALC888_ASUS_M90V,
240 ALC888_ASUS_EEE1601,
Wu Fengguang3ab90932008-11-17 09:51:09 +0100241 ALC1200_ASUS_P5Q,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200242 ALC883_AUTO,
243 ALC883_MODEL_LAST,
244};
245
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -0200246/* styles of capture selection */
247enum {
248 CAPT_MUX = 0, /* only mux based */
249 CAPT_MIX, /* only mixer based */
250 CAPT_1MUX_MIX, /* first mux and other mixers */
251};
252
Kailang Yangdf694da2005-12-05 19:42:22 +0100253/* for GPIO Poll */
254#define GPIO_MASK 0x03
255
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256struct alc_spec {
257 /* codec parameterization */
Kailang Yangdf694da2005-12-05 19:42:22 +0100258 struct snd_kcontrol_new *mixers[5]; /* mixer arrays */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259 unsigned int num_mixers;
Takashi Iwaif9e336f2008-10-31 16:37:07 +0100260 struct snd_kcontrol_new *cap_mixer; /* capture mixer */
Takashi Iwai45bdd1c2009-02-06 16:11:25 +0100261 unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262
Kailang Yangdf694da2005-12-05 19:42:22 +0100263 const struct hda_verb *init_verbs[5]; /* initialization verbs
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200264 * don't forget NULL
265 * termination!
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200266 */
267 unsigned int num_init_verbs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268
Takashi Iwai16ded522005-06-10 19:58:24 +0200269 char *stream_name_analog; /* analog PCM stream */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 struct hda_pcm_stream *stream_analog_playback;
271 struct hda_pcm_stream *stream_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +0100272 struct hda_pcm_stream *stream_analog_alt_playback;
273 struct hda_pcm_stream *stream_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200275 char *stream_name_digital; /* digital PCM stream */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 struct hda_pcm_stream *stream_digital_playback;
277 struct hda_pcm_stream *stream_digital_capture;
278
279 /* playback */
Takashi Iwai16ded522005-06-10 19:58:24 +0200280 struct hda_multi_out multiout; /* playback set-up
281 * max_channels, dacs must be set
282 * dig_out_nid and hp_nid are optional
283 */
Takashi Iwai63300792008-01-24 15:31:36 +0100284 hda_nid_t alt_dac_nid;
Takashi Iwai6a05ac42009-02-13 11:19:09 +0100285 hda_nid_t slave_dig_outs[3]; /* optional - for auto-parsing */
Takashi Iwai8c441982009-01-20 18:30:20 +0100286 int dig_out_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287
288 /* capture */
289 unsigned int num_adc_nids;
290 hda_nid_t *adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100291 hda_nid_t *capsrc_nids;
Takashi Iwai16ded522005-06-10 19:58:24 +0200292 hda_nid_t dig_in_nid; /* digital-in NID; optional */
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -0200293 int capture_style; /* capture style (CAPT_*) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294
295 /* capture source */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200296 unsigned int num_mux_defs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 const struct hda_input_mux *input_mux;
298 unsigned int cur_mux[3];
299
300 /* channel model */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100301 const struct hda_channel_mode *channel_mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 int num_channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200303 int need_dac_fix;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304
305 /* PCM information */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100306 struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */
Takashi Iwai41e41f12005-06-08 14:48:49 +0200307
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200308 /* dynamic controls, init_verbs and input_mux */
309 struct auto_pin_cfg autocfg;
Takashi Iwai603c4012008-07-30 15:01:44 +0200310 struct snd_array kctls;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -0200311 struct hda_input_mux private_imux[3];
Takashi Iwai41923e42007-10-22 17:20:10 +0200312 hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
Takashi Iwai834be882006-03-01 14:16:17 +0100313
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100314 /* hooks */
315 void (*init_hook)(struct hda_codec *codec);
316 void (*unsol_event)(struct hda_codec *codec, unsigned int res);
317
Takashi Iwai834be882006-03-01 14:16:17 +0100318 /* for pin sensing */
319 unsigned int sense_updated: 1;
320 unsigned int jack_present: 1;
Takashi Iwaibec15c32008-01-28 18:16:30 +0100321 unsigned int master_sw: 1;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200322
Takashi Iwaie64f14f2009-01-20 18:32:55 +0100323 /* other flags */
324 unsigned int no_analog :1; /* digital I/O only */
325
Takashi Iwai2134ea42008-01-10 16:53:55 +0100326 /* for virtual master */
327 hda_nid_t vmaster_nid;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200328#ifdef CONFIG_SND_HDA_POWER_SAVE
329 struct hda_loopback_check loopback;
330#endif
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +0200331
332 /* for PLL fix */
333 hda_nid_t pll_nid;
334 unsigned int pll_coef_idx, pll_coef_bit;
Kailang Yangdf694da2005-12-05 19:42:22 +0100335};
336
337/*
338 * configuration template - to be copied to the spec instance
339 */
340struct alc_config_preset {
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200341 struct snd_kcontrol_new *mixers[5]; /* should be identical size
342 * with spec
343 */
Takashi Iwaif9e336f2008-10-31 16:37:07 +0100344 struct snd_kcontrol_new *cap_mixer; /* capture mixer */
Kailang Yangdf694da2005-12-05 19:42:22 +0100345 const struct hda_verb *init_verbs[5];
346 unsigned int num_dacs;
347 hda_nid_t *dac_nids;
348 hda_nid_t dig_out_nid; /* optional */
349 hda_nid_t hp_nid; /* optional */
Wu Fengguangb25c9da2009-02-06 15:02:27 +0800350 hda_nid_t *slave_dig_outs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100351 unsigned int num_adc_nids;
352 hda_nid_t *adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100353 hda_nid_t *capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +0100354 hda_nid_t dig_in_nid;
355 unsigned int num_channel_mode;
356 const struct hda_channel_mode *channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200357 int need_dac_fix;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200358 unsigned int num_mux_defs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100359 const struct hda_input_mux *input_mux;
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100360 void (*unsol_event)(struct hda_codec *, unsigned int);
361 void (*init_hook)(struct hda_codec *);
Takashi Iwaicb53c622007-08-10 17:21:45 +0200362#ifdef CONFIG_SND_HDA_POWER_SAVE
363 struct hda_amp_list *loopbacks;
364#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365};
366
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367
368/*
369 * input MUX handling
370 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200371static int alc_mux_enum_info(struct snd_kcontrol *kcontrol,
372 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373{
374 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
375 struct alc_spec *spec = codec->spec;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200376 unsigned int mux_idx = snd_ctl_get_ioffidx(kcontrol, &uinfo->id);
377 if (mux_idx >= spec->num_mux_defs)
378 mux_idx = 0;
379 return snd_hda_input_mux_info(&spec->input_mux[mux_idx], uinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380}
381
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200382static int alc_mux_enum_get(struct snd_kcontrol *kcontrol,
383 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384{
385 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
386 struct alc_spec *spec = codec->spec;
387 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
388
389 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
390 return 0;
391}
392
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200393static int alc_mux_enum_put(struct snd_kcontrol *kcontrol,
394 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395{
396 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
397 struct alc_spec *spec = codec->spec;
Takashi Iwaicd896c32008-11-18 12:36:33 +0100398 const struct hda_input_mux *imux;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Takashi Iwaicd896c32008-11-18 12:36:33 +0100400 unsigned int mux_idx;
Takashi Iwaie1406342008-02-11 18:32:32 +0100401 hda_nid_t nid = spec->capsrc_nids ?
402 spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403
Takashi Iwaicd896c32008-11-18 12:36:33 +0100404 mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx;
405 imux = &spec->input_mux[mux_idx];
406
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -0200407 if (spec->capture_style &&
408 !(spec->capture_style == CAPT_1MUX_MIX && !adc_idx)) {
Takashi Iwai54cbc9a2008-10-31 15:24:04 +0100409 /* Matrix-mixer style (e.g. ALC882) */
410 unsigned int *cur_val = &spec->cur_mux[adc_idx];
411 unsigned int i, idx;
412
413 idx = ucontrol->value.enumerated.item[0];
414 if (idx >= imux->num_items)
415 idx = imux->num_items - 1;
416 if (*cur_val == idx)
417 return 0;
418 for (i = 0; i < imux->num_items; i++) {
419 unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE;
420 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT,
421 imux->items[i].index,
422 HDA_AMP_MUTE, v);
423 }
424 *cur_val = idx;
425 return 1;
426 } else {
427 /* MUX style (e.g. ALC880) */
Takashi Iwaicd896c32008-11-18 12:36:33 +0100428 return snd_hda_input_mux_put(codec, imux, ucontrol, nid,
Takashi Iwai54cbc9a2008-10-31 15:24:04 +0100429 &spec->cur_mux[adc_idx]);
430 }
431}
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200432
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433/*
434 * channel mode setting
435 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200436static int alc_ch_mode_info(struct snd_kcontrol *kcontrol,
437 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438{
439 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
440 struct alc_spec *spec = codec->spec;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100441 return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode,
442 spec->num_channel_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443}
444
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200445static int alc_ch_mode_get(struct snd_kcontrol *kcontrol,
446 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447{
448 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
449 struct alc_spec *spec = codec->spec;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100450 return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200451 spec->num_channel_mode,
452 spec->multiout.max_channels);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453}
454
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200455static int alc_ch_mode_put(struct snd_kcontrol *kcontrol,
456 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457{
458 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
459 struct alc_spec *spec = codec->spec;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200460 int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
461 spec->num_channel_mode,
462 &spec->multiout.max_channels);
Takashi Iwaibd2033f2006-10-10 19:49:31 +0200463 if (err >= 0 && spec->need_dac_fix)
Takashi Iwai4e195a72006-07-28 14:47:34 +0200464 spec->multiout.num_dacs = spec->multiout.max_channels / 2;
465 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466}
467
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468/*
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100469 * Control the mode of pin widget settings via the mixer. "pc" is used
Kailang Yangea1fb292008-08-26 12:58:38 +0200470 * instead of "%" to avoid consequences of accidently treating the % as
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100471 * being part of a format specifier. Maximum allowed length of a value is
472 * 63 characters plus NULL terminator.
Jonathan Woithe7cf51e42006-02-09 12:01:26 +0100473 *
474 * Note: some retasking pin complexes seem to ignore requests for input
475 * states other than HiZ (eg: PIN_VREFxx) and revert to HiZ if any of these
476 * are requested. Therefore order this list so that this behaviour will not
477 * cause problems when mixer clients move through the enum sequentially.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200478 * NIDs 0x0f and 0x10 have been observed to have this behaviour as of
479 * March 2006.
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200480 */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100481static char *alc_pin_mode_names[] = {
Jonathan Woithe7cf51e42006-02-09 12:01:26 +0100482 "Mic 50pc bias", "Mic 80pc bias",
483 "Line in", "Line out", "Headphone out",
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100484};
485static unsigned char alc_pin_mode_values[] = {
Jonathan Woithe7cf51e42006-02-09 12:01:26 +0100486 PIN_VREF50, PIN_VREF80, PIN_IN, PIN_OUT, PIN_HP,
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100487};
488/* The control can present all 5 options, or it can limit the options based
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200489 * in the pin being assumed to be exclusively an input or an output pin. In
490 * addition, "input" pins may or may not process the mic bias option
491 * depending on actual widget capability (NIDs 0x0f and 0x10 don't seem to
492 * accept requests for bias as of chip versions up to March 2006) and/or
493 * wiring in the computer.
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100494 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200495#define ALC_PIN_DIR_IN 0x00
496#define ALC_PIN_DIR_OUT 0x01
497#define ALC_PIN_DIR_INOUT 0x02
498#define ALC_PIN_DIR_IN_NOMICBIAS 0x03
499#define ALC_PIN_DIR_INOUT_NOMICBIAS 0x04
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100500
Kailang Yangea1fb292008-08-26 12:58:38 +0200501/* Info about the pin modes supported by the different pin direction modes.
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100502 * For each direction the minimum and maximum values are given.
503 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200504static signed char alc_pin_mode_dir_info[5][2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100505 { 0, 2 }, /* ALC_PIN_DIR_IN */
506 { 3, 4 }, /* ALC_PIN_DIR_OUT */
507 { 0, 4 }, /* ALC_PIN_DIR_INOUT */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200508 { 2, 2 }, /* ALC_PIN_DIR_IN_NOMICBIAS */
509 { 2, 4 }, /* ALC_PIN_DIR_INOUT_NOMICBIAS */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100510};
511#define alc_pin_mode_min(_dir) (alc_pin_mode_dir_info[_dir][0])
512#define alc_pin_mode_max(_dir) (alc_pin_mode_dir_info[_dir][1])
513#define alc_pin_mode_n_items(_dir) \
514 (alc_pin_mode_max(_dir)-alc_pin_mode_min(_dir)+1)
515
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200516static int alc_pin_mode_info(struct snd_kcontrol *kcontrol,
517 struct snd_ctl_elem_info *uinfo)
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200518{
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100519 unsigned int item_num = uinfo->value.enumerated.item;
520 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
521
522 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200523 uinfo->count = 1;
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100524 uinfo->value.enumerated.items = alc_pin_mode_n_items(dir);
525
526 if (item_num<alc_pin_mode_min(dir) || item_num>alc_pin_mode_max(dir))
527 item_num = alc_pin_mode_min(dir);
528 strcpy(uinfo->value.enumerated.name, alc_pin_mode_names[item_num]);
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200529 return 0;
530}
531
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200532static int alc_pin_mode_get(struct snd_kcontrol *kcontrol,
533 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200534{
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100535 unsigned int i;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200536 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
537 hda_nid_t nid = kcontrol->private_value & 0xffff;
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100538 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200539 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200540 unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
541 AC_VERB_GET_PIN_WIDGET_CONTROL,
542 0x00);
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200543
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100544 /* Find enumerated value for current pinctl setting */
545 i = alc_pin_mode_min(dir);
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200546 while (alc_pin_mode_values[i] != pinctl && i <= alc_pin_mode_max(dir))
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100547 i++;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200548 *valp = i <= alc_pin_mode_max(dir) ? i: alc_pin_mode_min(dir);
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100549 return 0;
550}
551
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200552static int alc_pin_mode_put(struct snd_kcontrol *kcontrol,
553 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100554{
555 signed int change;
556 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
557 hda_nid_t nid = kcontrol->private_value & 0xffff;
558 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
559 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200560 unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
561 AC_VERB_GET_PIN_WIDGET_CONTROL,
562 0x00);
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100563
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200564 if (val < alc_pin_mode_min(dir) || val > alc_pin_mode_max(dir))
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100565 val = alc_pin_mode_min(dir);
566
567 change = pinctl != alc_pin_mode_values[val];
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100568 if (change) {
569 /* Set pin mode to that requested */
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200570 snd_hda_codec_write_cache(codec, nid, 0,
571 AC_VERB_SET_PIN_WIDGET_CONTROL,
572 alc_pin_mode_values[val]);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100573
Kailang Yangea1fb292008-08-26 12:58:38 +0200574 /* Also enable the retasking pin's input/output as required
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100575 * for the requested pin mode. Enum values of 2 or less are
576 * input modes.
577 *
578 * Dynamically switching the input/output buffers probably
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200579 * reduces noise slightly (particularly on input) so we'll
580 * do it. However, having both input and output buffers
581 * enabled simultaneously doesn't seem to be problematic if
582 * this turns out to be necessary in the future.
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100583 */
584 if (val <= 2) {
Takashi Iwai47fd8302007-08-10 17:11:07 +0200585 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
586 HDA_AMP_MUTE, HDA_AMP_MUTE);
587 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
588 HDA_AMP_MUTE, 0);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100589 } else {
Takashi Iwai47fd8302007-08-10 17:11:07 +0200590 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
591 HDA_AMP_MUTE, HDA_AMP_MUTE);
592 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
593 HDA_AMP_MUTE, 0);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100594 }
595 }
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200596 return change;
597}
598
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100599#define ALC_PIN_MODE(xname, nid, dir) \
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200600 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100601 .info = alc_pin_mode_info, \
602 .get = alc_pin_mode_get, \
603 .put = alc_pin_mode_put, \
604 .private_value = nid | (dir<<16) }
Kailang Yangdf694da2005-12-05 19:42:22 +0100605
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100606/* A switch control for ALC260 GPIO pins. Multiple GPIOs can be ganged
607 * together using a mask with more than one bit set. This control is
608 * currently used only by the ALC260 test model. At this stage they are not
609 * needed for any "production" models.
610 */
611#ifdef CONFIG_SND_DEBUG
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200612#define alc_gpio_data_info snd_ctl_boolean_mono_info
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200613
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200614static int alc_gpio_data_get(struct snd_kcontrol *kcontrol,
615 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100616{
617 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
618 hda_nid_t nid = kcontrol->private_value & 0xffff;
619 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
620 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200621 unsigned int val = snd_hda_codec_read(codec, nid, 0,
622 AC_VERB_GET_GPIO_DATA, 0x00);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100623
624 *valp = (val & mask) != 0;
625 return 0;
626}
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200627static int alc_gpio_data_put(struct snd_kcontrol *kcontrol,
628 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100629{
630 signed int change;
631 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
632 hda_nid_t nid = kcontrol->private_value & 0xffff;
633 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
634 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200635 unsigned int gpio_data = snd_hda_codec_read(codec, nid, 0,
636 AC_VERB_GET_GPIO_DATA,
637 0x00);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100638
639 /* Set/unset the masked GPIO bit(s) as needed */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200640 change = (val == 0 ? 0 : mask) != (gpio_data & mask);
641 if (val == 0)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100642 gpio_data &= ~mask;
643 else
644 gpio_data |= mask;
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200645 snd_hda_codec_write_cache(codec, nid, 0,
646 AC_VERB_SET_GPIO_DATA, gpio_data);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100647
648 return change;
649}
650#define ALC_GPIO_DATA_SWITCH(xname, nid, mask) \
651 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
652 .info = alc_gpio_data_info, \
653 .get = alc_gpio_data_get, \
654 .put = alc_gpio_data_put, \
655 .private_value = nid | (mask<<16) }
656#endif /* CONFIG_SND_DEBUG */
657
Jonathan Woithe92621f12006-02-28 11:47:47 +0100658/* A switch control to allow the enabling of the digital IO pins on the
659 * ALC260. This is incredibly simplistic; the intention of this control is
660 * to provide something in the test model allowing digital outputs to be
661 * identified if present. If models are found which can utilise these
662 * outputs a more complete mixer control can be devised for those models if
663 * necessary.
664 */
665#ifdef CONFIG_SND_DEBUG
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200666#define alc_spdif_ctrl_info snd_ctl_boolean_mono_info
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200667
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200668static int alc_spdif_ctrl_get(struct snd_kcontrol *kcontrol,
669 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe92621f12006-02-28 11:47:47 +0100670{
671 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
672 hda_nid_t nid = kcontrol->private_value & 0xffff;
673 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
674 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200675 unsigned int val = snd_hda_codec_read(codec, nid, 0,
Andrew Paprocki3982d172007-12-19 12:13:44 +0100676 AC_VERB_GET_DIGI_CONVERT_1, 0x00);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100677
678 *valp = (val & mask) != 0;
679 return 0;
680}
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200681static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol,
682 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe92621f12006-02-28 11:47:47 +0100683{
684 signed int change;
685 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
686 hda_nid_t nid = kcontrol->private_value & 0xffff;
687 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
688 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200689 unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
Andrew Paprocki3982d172007-12-19 12:13:44 +0100690 AC_VERB_GET_DIGI_CONVERT_1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200691 0x00);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100692
693 /* Set/unset the masked control bit(s) as needed */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200694 change = (val == 0 ? 0 : mask) != (ctrl_data & mask);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100695 if (val==0)
696 ctrl_data &= ~mask;
697 else
698 ctrl_data |= mask;
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200699 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
700 ctrl_data);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100701
702 return change;
703}
704#define ALC_SPDIF_CTRL_SWITCH(xname, nid, mask) \
705 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
706 .info = alc_spdif_ctrl_info, \
707 .get = alc_spdif_ctrl_get, \
708 .put = alc_spdif_ctrl_put, \
709 .private_value = nid | (mask<<16) }
710#endif /* CONFIG_SND_DEBUG */
711
Jonathan Woithef8225f62008-01-08 12:16:54 +0100712/* A switch control to allow the enabling EAPD digital outputs on the ALC26x.
713 * Again, this is only used in the ALC26x test models to help identify when
714 * the EAPD line must be asserted for features to work.
715 */
716#ifdef CONFIG_SND_DEBUG
717#define alc_eapd_ctrl_info snd_ctl_boolean_mono_info
718
719static int alc_eapd_ctrl_get(struct snd_kcontrol *kcontrol,
720 struct snd_ctl_elem_value *ucontrol)
721{
722 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
723 hda_nid_t nid = kcontrol->private_value & 0xffff;
724 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
725 long *valp = ucontrol->value.integer.value;
726 unsigned int val = snd_hda_codec_read(codec, nid, 0,
727 AC_VERB_GET_EAPD_BTLENABLE, 0x00);
728
729 *valp = (val & mask) != 0;
730 return 0;
731}
732
733static int alc_eapd_ctrl_put(struct snd_kcontrol *kcontrol,
734 struct snd_ctl_elem_value *ucontrol)
735{
736 int change;
737 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
738 hda_nid_t nid = kcontrol->private_value & 0xffff;
739 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
740 long val = *ucontrol->value.integer.value;
741 unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
742 AC_VERB_GET_EAPD_BTLENABLE,
743 0x00);
744
745 /* Set/unset the masked control bit(s) as needed */
746 change = (!val ? 0 : mask) != (ctrl_data & mask);
747 if (!val)
748 ctrl_data &= ~mask;
749 else
750 ctrl_data |= mask;
751 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
752 ctrl_data);
753
754 return change;
755}
756
757#define ALC_EAPD_CTRL_SWITCH(xname, nid, mask) \
758 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
759 .info = alc_eapd_ctrl_info, \
760 .get = alc_eapd_ctrl_get, \
761 .put = alc_eapd_ctrl_put, \
762 .private_value = nid | (mask<<16) }
763#endif /* CONFIG_SND_DEBUG */
764
Kailang Yangdf694da2005-12-05 19:42:22 +0100765/*
Takashi Iwai23f0c042009-02-26 13:03:58 +0100766 * set up the input pin config (depending on the given auto-pin type)
767 */
768static void alc_set_input_pin(struct hda_codec *codec, hda_nid_t nid,
769 int auto_pin_type)
770{
771 unsigned int val = PIN_IN;
772
773 if (auto_pin_type <= AUTO_PIN_FRONT_MIC) {
774 unsigned int pincap;
Takashi Iwai1327a322009-03-23 13:07:47 +0100775 pincap = snd_hda_query_pin_caps(codec, nid);
Takashi Iwai23f0c042009-02-26 13:03:58 +0100776 pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
777 if (pincap & AC_PINCAP_VREF_80)
778 val = PIN_VREF80;
Takashi Iwai461c6c32009-05-25 08:06:02 +0200779 else if (pincap & AC_PINCAP_VREF_50)
780 val = PIN_VREF50;
781 else if (pincap & AC_PINCAP_VREF_100)
782 val = PIN_VREF100;
783 else if (pincap & AC_PINCAP_VREF_GRD)
784 val = PIN_VREFGRD;
Takashi Iwai23f0c042009-02-26 13:03:58 +0100785 }
786 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, val);
787}
788
789/*
Takashi Iwaid88897e2008-10-31 15:01:37 +0100790 */
791static void add_mixer(struct alc_spec *spec, struct snd_kcontrol_new *mix)
792{
793 if (snd_BUG_ON(spec->num_mixers >= ARRAY_SIZE(spec->mixers)))
794 return;
795 spec->mixers[spec->num_mixers++] = mix;
796}
797
798static void add_verb(struct alc_spec *spec, const struct hda_verb *verb)
799{
800 if (snd_BUG_ON(spec->num_init_verbs >= ARRAY_SIZE(spec->init_verbs)))
801 return;
802 spec->init_verbs[spec->num_init_verbs++] = verb;
803}
804
Takashi Iwaidaead532008-11-28 12:55:36 +0100805#ifdef CONFIG_PROC_FS
806/*
807 * hook for proc
808 */
809static void print_realtek_coef(struct snd_info_buffer *buffer,
810 struct hda_codec *codec, hda_nid_t nid)
811{
812 int coeff;
813
814 if (nid != 0x20)
815 return;
816 coeff = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PROC_COEF, 0);
817 snd_iprintf(buffer, " Processing Coefficient: 0x%02x\n", coeff);
818 coeff = snd_hda_codec_read(codec, nid, 0,
819 AC_VERB_GET_COEF_INDEX, 0);
820 snd_iprintf(buffer, " Coefficient Index: 0x%02x\n", coeff);
821}
822#else
823#define print_realtek_coef NULL
824#endif
825
Takashi Iwaid88897e2008-10-31 15:01:37 +0100826/*
Kailang Yangdf694da2005-12-05 19:42:22 +0100827 * set up from the preset table
828 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200829static void setup_preset(struct alc_spec *spec,
830 const struct alc_config_preset *preset)
Kailang Yangdf694da2005-12-05 19:42:22 +0100831{
832 int i;
833
834 for (i = 0; i < ARRAY_SIZE(preset->mixers) && preset->mixers[i]; i++)
Takashi Iwaid88897e2008-10-31 15:01:37 +0100835 add_mixer(spec, preset->mixers[i]);
Takashi Iwaif9e336f2008-10-31 16:37:07 +0100836 spec->cap_mixer = preset->cap_mixer;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200837 for (i = 0; i < ARRAY_SIZE(preset->init_verbs) && preset->init_verbs[i];
838 i++)
Takashi Iwaid88897e2008-10-31 15:01:37 +0100839 add_verb(spec, preset->init_verbs[i]);
Kailang Yangea1fb292008-08-26 12:58:38 +0200840
Kailang Yangdf694da2005-12-05 19:42:22 +0100841 spec->channel_mode = preset->channel_mode;
842 spec->num_channel_mode = preset->num_channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200843 spec->need_dac_fix = preset->need_dac_fix;
Kailang Yangdf694da2005-12-05 19:42:22 +0100844
845 spec->multiout.max_channels = spec->channel_mode[0].channels;
846
847 spec->multiout.num_dacs = preset->num_dacs;
848 spec->multiout.dac_nids = preset->dac_nids;
849 spec->multiout.dig_out_nid = preset->dig_out_nid;
Wu Fengguangb25c9da2009-02-06 15:02:27 +0800850 spec->multiout.slave_dig_outs = preset->slave_dig_outs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100851 spec->multiout.hp_nid = preset->hp_nid;
Kailang Yangea1fb292008-08-26 12:58:38 +0200852
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200853 spec->num_mux_defs = preset->num_mux_defs;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200854 if (!spec->num_mux_defs)
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200855 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +0100856 spec->input_mux = preset->input_mux;
857
858 spec->num_adc_nids = preset->num_adc_nids;
859 spec->adc_nids = preset->adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100860 spec->capsrc_nids = preset->capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +0100861 spec->dig_in_nid = preset->dig_in_nid;
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100862
863 spec->unsol_event = preset->unsol_event;
864 spec->init_hook = preset->init_hook;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200865#ifdef CONFIG_SND_HDA_POWER_SAVE
866 spec->loopback.amplist = preset->loopbacks;
867#endif
Kailang Yangdf694da2005-12-05 19:42:22 +0100868}
869
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200870/* Enable GPIO mask and set output */
871static struct hda_verb alc_gpio1_init_verbs[] = {
872 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
873 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
874 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
875 { }
876};
877
878static struct hda_verb alc_gpio2_init_verbs[] = {
879 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
880 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
881 {0x01, AC_VERB_SET_GPIO_DATA, 0x02},
882 { }
883};
884
Kailang Yangbdd148a2007-05-08 15:19:08 +0200885static struct hda_verb alc_gpio3_init_verbs[] = {
886 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
887 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
888 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
889 { }
890};
891
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +0200892/*
893 * Fix hardware PLL issue
894 * On some codecs, the analog PLL gating control must be off while
895 * the default value is 1.
896 */
897static void alc_fix_pll(struct hda_codec *codec)
898{
899 struct alc_spec *spec = codec->spec;
900 unsigned int val;
901
902 if (!spec->pll_nid)
903 return;
904 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
905 spec->pll_coef_idx);
906 val = snd_hda_codec_read(codec, spec->pll_nid, 0,
907 AC_VERB_GET_PROC_COEF, 0);
908 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
909 spec->pll_coef_idx);
910 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_PROC_COEF,
911 val & ~(1 << spec->pll_coef_bit));
912}
913
914static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
915 unsigned int coef_idx, unsigned int coef_bit)
916{
917 struct alc_spec *spec = codec->spec;
918 spec->pll_nid = nid;
919 spec->pll_coef_idx = coef_idx;
920 spec->pll_coef_bit = coef_bit;
921 alc_fix_pll(codec);
922}
923
Kailang Yangc9b58002007-10-16 14:30:01 +0200924static void alc_sku_automute(struct hda_codec *codec)
925{
926 struct alc_spec *spec = codec->spec;
Kailang Yangc9b58002007-10-16 14:30:01 +0200927 unsigned int present;
928 unsigned int hp_nid = spec->autocfg.hp_pins[0];
929 unsigned int sp_nid = spec->autocfg.speaker_pins[0];
930
931 /* need to execute and sync at first */
932 snd_hda_codec_read(codec, hp_nid, 0, AC_VERB_SET_PIN_SENSE, 0);
933 present = snd_hda_codec_read(codec, hp_nid, 0,
934 AC_VERB_GET_PIN_SENSE, 0);
935 spec->jack_present = (present & 0x80000000) != 0;
Takashi Iwaif6c7e542008-02-12 18:32:23 +0100936 snd_hda_codec_write(codec, sp_nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
937 spec->jack_present ? 0 : PIN_OUT);
Kailang Yangc9b58002007-10-16 14:30:01 +0200938}
939
Takashi Iwai4605b712008-10-31 14:18:24 +0100940#if 0 /* it's broken in some acses -- temporarily disabled */
Kailang Yang7fb0d782008-10-15 11:12:35 +0200941static void alc_mic_automute(struct hda_codec *codec)
942{
943 struct alc_spec *spec = codec->spec;
944 unsigned int present;
945 unsigned int mic_nid = spec->autocfg.input_pins[AUTO_PIN_MIC];
946 unsigned int fmic_nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC];
947 unsigned int mix_nid = spec->capsrc_nids[0];
948 unsigned int capsrc_idx_mic, capsrc_idx_fmic;
949
950 capsrc_idx_mic = mic_nid - 0x18;
951 capsrc_idx_fmic = fmic_nid - 0x18;
952 present = snd_hda_codec_read(codec, mic_nid, 0,
953 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
954 snd_hda_codec_write(codec, mix_nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
955 0x7000 | (capsrc_idx_mic << 8) | (present ? 0 : 0x80));
956 snd_hda_codec_write(codec, mix_nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
957 0x7000 | (capsrc_idx_fmic << 8) | (present ? 0x80 : 0));
958 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, capsrc_idx_fmic,
959 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
960}
Takashi Iwai4605b712008-10-31 14:18:24 +0100961#else
Takashi Iwai45bdd1c2009-02-06 16:11:25 +0100962#define alc_mic_automute(codec) do {} while(0) /* NOP */
Takashi Iwai4605b712008-10-31 14:18:24 +0100963#endif /* disabled */
Kailang Yang7fb0d782008-10-15 11:12:35 +0200964
Kailang Yangc9b58002007-10-16 14:30:01 +0200965/* unsolicited event for HP jack sensing */
966static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res)
967{
968 if (codec->vendor_id == 0x10ec0880)
969 res >>= 28;
970 else
971 res >>= 26;
Kailang Yang7fb0d782008-10-15 11:12:35 +0200972 if (res == ALC880_HP_EVENT)
973 alc_sku_automute(codec);
Kailang Yangc9b58002007-10-16 14:30:01 +0200974
Kailang Yang7fb0d782008-10-15 11:12:35 +0200975 if (res == ALC880_MIC_EVENT)
976 alc_mic_automute(codec);
977}
978
979static void alc_inithook(struct hda_codec *codec)
980{
Kailang Yangc9b58002007-10-16 14:30:01 +0200981 alc_sku_automute(codec);
Kailang Yang7fb0d782008-10-15 11:12:35 +0200982 alc_mic_automute(codec);
Kailang Yangc9b58002007-10-16 14:30:01 +0200983}
984
Kailang Yangf9423e72008-05-27 12:32:25 +0200985/* additional initialization for ALC888 variants */
986static void alc888_coef_init(struct hda_codec *codec)
987{
988 unsigned int tmp;
989
990 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0);
991 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
992 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
Takashi Iwai37db6232009-03-05 09:40:16 +0100993 if ((tmp & 0xf0) == 0x20)
Kailang Yangf9423e72008-05-27 12:32:25 +0200994 /* alc888S-VC */
995 snd_hda_codec_read(codec, 0x20, 0,
996 AC_VERB_SET_PROC_COEF, 0x830);
997 else
998 /* alc888-VB */
999 snd_hda_codec_read(codec, 0x20, 0,
1000 AC_VERB_SET_PROC_COEF, 0x3030);
1001}
1002
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001003/* 32-bit subsystem ID for BIOS loading in HD Audio codec.
1004 * 31 ~ 16 : Manufacture ID
1005 * 15 ~ 8 : SKU ID
1006 * 7 ~ 0 : Assembly ID
1007 * port-A --> pin 39/41, port-E --> pin 14/15, port-D --> pin 35/36
1008 */
1009static void alc_subsystem_id(struct hda_codec *codec,
1010 unsigned int porta, unsigned int porte,
1011 unsigned int portd)
1012{
Kailang Yangc9b58002007-10-16 14:30:01 +02001013 unsigned int ass, tmp, i;
1014 unsigned nid;
1015 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001016
Kailang Yangc9b58002007-10-16 14:30:01 +02001017 ass = codec->subsystem_id & 0xffff;
1018 if ((ass != codec->bus->pci->subsystem_device) && (ass & 1))
1019 goto do_sku;
1020
Kailang Yangea1fb292008-08-26 12:58:38 +02001021 /*
Kailang Yangc9b58002007-10-16 14:30:01 +02001022 * 31~30 : port conetcivity
1023 * 29~21 : reserve
1024 * 20 : PCBEEP input
1025 * 19~16 : Check sum (15:1)
1026 * 15~1 : Custom
1027 * 0 : override
1028 */
1029 nid = 0x1d;
1030 if (codec->vendor_id == 0x10ec0260)
1031 nid = 0x17;
Takashi Iwai0e8a21b2009-02-20 14:13:06 +01001032 ass = snd_hda_codec_get_pincfg(codec, nid);
Kailang Yangc9b58002007-10-16 14:30:01 +02001033 if (!(ass & 1) && !(ass & 0x100000))
1034 return;
1035 if ((ass >> 30) != 1) /* no physical connection */
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001036 return;
1037
Kailang Yangc9b58002007-10-16 14:30:01 +02001038 /* check sum */
1039 tmp = 0;
1040 for (i = 1; i < 16; i++) {
Kailang Yang8c427222008-01-10 13:03:59 +01001041 if ((ass >> i) & 1)
Kailang Yangc9b58002007-10-16 14:30:01 +02001042 tmp++;
1043 }
1044 if (((ass >> 16) & 0xf) != tmp)
1045 return;
1046do_sku:
1047 /*
1048 * 0 : override
1049 * 1 : Swap Jack
1050 * 2 : 0 --> Desktop, 1 --> Laptop
1051 * 3~5 : External Amplifier control
1052 * 7~6 : Reserved
1053 */
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001054 tmp = (ass & 0x38) >> 3; /* external Amp control */
1055 switch (tmp) {
1056 case 1:
1057 snd_hda_sequence_write(codec, alc_gpio1_init_verbs);
1058 break;
1059 case 3:
1060 snd_hda_sequence_write(codec, alc_gpio2_init_verbs);
1061 break;
Kailang Yangbdd148a2007-05-08 15:19:08 +02001062 case 7:
1063 snd_hda_sequence_write(codec, alc_gpio3_init_verbs);
1064 break;
Kailang Yangc9b58002007-10-16 14:30:01 +02001065 case 5: /* set EAPD output high */
Kailang Yangbdd148a2007-05-08 15:19:08 +02001066 switch (codec->vendor_id) {
Kailang Yangc9b58002007-10-16 14:30:01 +02001067 case 0x10ec0260:
1068 snd_hda_codec_write(codec, 0x0f, 0,
1069 AC_VERB_SET_EAPD_BTLENABLE, 2);
1070 snd_hda_codec_write(codec, 0x10, 0,
1071 AC_VERB_SET_EAPD_BTLENABLE, 2);
1072 break;
1073 case 0x10ec0262:
Kailang Yangbdd148a2007-05-08 15:19:08 +02001074 case 0x10ec0267:
1075 case 0x10ec0268:
Kailang Yangc9b58002007-10-16 14:30:01 +02001076 case 0x10ec0269:
Takashi Iwaic6e8f2d2009-02-06 12:45:52 +01001077 case 0x10ec0272:
Kailang Yangf9423e72008-05-27 12:32:25 +02001078 case 0x10ec0660:
1079 case 0x10ec0662:
1080 case 0x10ec0663:
Kailang Yangc9b58002007-10-16 14:30:01 +02001081 case 0x10ec0862:
Takashi Iwai20a3a052008-05-23 17:52:53 +02001082 case 0x10ec0889:
Kailang Yangbdd148a2007-05-08 15:19:08 +02001083 snd_hda_codec_write(codec, 0x14, 0,
1084 AC_VERB_SET_EAPD_BTLENABLE, 2);
1085 snd_hda_codec_write(codec, 0x15, 0,
1086 AC_VERB_SET_EAPD_BTLENABLE, 2);
Kailang Yangc9b58002007-10-16 14:30:01 +02001087 break;
Kailang Yangbdd148a2007-05-08 15:19:08 +02001088 }
Kailang Yangc9b58002007-10-16 14:30:01 +02001089 switch (codec->vendor_id) {
1090 case 0x10ec0260:
1091 snd_hda_codec_write(codec, 0x1a, 0,
1092 AC_VERB_SET_COEF_INDEX, 7);
1093 tmp = snd_hda_codec_read(codec, 0x1a, 0,
1094 AC_VERB_GET_PROC_COEF, 0);
1095 snd_hda_codec_write(codec, 0x1a, 0,
1096 AC_VERB_SET_COEF_INDEX, 7);
1097 snd_hda_codec_write(codec, 0x1a, 0,
1098 AC_VERB_SET_PROC_COEF,
1099 tmp | 0x2010);
1100 break;
1101 case 0x10ec0262:
1102 case 0x10ec0880:
1103 case 0x10ec0882:
1104 case 0x10ec0883:
1105 case 0x10ec0885:
Takashi Iwai4a5a4c52009-02-06 12:46:59 +01001106 case 0x10ec0887:
Takashi Iwai20a3a052008-05-23 17:52:53 +02001107 case 0x10ec0889:
Kailang Yangc9b58002007-10-16 14:30:01 +02001108 snd_hda_codec_write(codec, 0x20, 0,
1109 AC_VERB_SET_COEF_INDEX, 7);
1110 tmp = snd_hda_codec_read(codec, 0x20, 0,
1111 AC_VERB_GET_PROC_COEF, 0);
1112 snd_hda_codec_write(codec, 0x20, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +02001113 AC_VERB_SET_COEF_INDEX, 7);
Kailang Yangc9b58002007-10-16 14:30:01 +02001114 snd_hda_codec_write(codec, 0x20, 0,
1115 AC_VERB_SET_PROC_COEF,
1116 tmp | 0x2010);
1117 break;
Kailang Yangf9423e72008-05-27 12:32:25 +02001118 case 0x10ec0888:
Takashi Iwai1082c742008-08-22 15:24:22 +02001119 /*alc888_coef_init(codec);*/ /* called in alc_init() */
Kailang Yangf9423e72008-05-27 12:32:25 +02001120 break;
Kailang Yangc9b58002007-10-16 14:30:01 +02001121 case 0x10ec0267:
1122 case 0x10ec0268:
1123 snd_hda_codec_write(codec, 0x20, 0,
1124 AC_VERB_SET_COEF_INDEX, 7);
1125 tmp = snd_hda_codec_read(codec, 0x20, 0,
1126 AC_VERB_GET_PROC_COEF, 0);
1127 snd_hda_codec_write(codec, 0x20, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +02001128 AC_VERB_SET_COEF_INDEX, 7);
Kailang Yangc9b58002007-10-16 14:30:01 +02001129 snd_hda_codec_write(codec, 0x20, 0,
1130 AC_VERB_SET_PROC_COEF,
1131 tmp | 0x3000);
1132 break;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001133 }
Kailang Yangc9b58002007-10-16 14:30:01 +02001134 default:
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001135 break;
1136 }
Kailang Yangea1fb292008-08-26 12:58:38 +02001137
Kailang Yang8c427222008-01-10 13:03:59 +01001138 /* is laptop or Desktop and enable the function "Mute internal speaker
Kailang Yangc9b58002007-10-16 14:30:01 +02001139 * when the external headphone out jack is plugged"
1140 */
Kailang Yang8c427222008-01-10 13:03:59 +01001141 if (!(ass & 0x8000))
Kailang Yangc9b58002007-10-16 14:30:01 +02001142 return;
1143 /*
1144 * 10~8 : Jack location
1145 * 12~11: Headphone out -> 00: PortA, 01: PortE, 02: PortD, 03: Resvered
1146 * 14~13: Resvered
1147 * 15 : 1 --> enable the function "Mute internal speaker
1148 * when the external headphone out jack is plugged"
1149 */
1150 if (!spec->autocfg.speaker_pins[0]) {
Kailang Yang8c427222008-01-10 13:03:59 +01001151 if (spec->autocfg.line_out_pins[0])
Kailang Yangc9b58002007-10-16 14:30:01 +02001152 spec->autocfg.speaker_pins[0] =
Kailang Yang8c427222008-01-10 13:03:59 +01001153 spec->autocfg.line_out_pins[0];
Kailang Yangc9b58002007-10-16 14:30:01 +02001154 else
1155 return;
1156 }
1157
1158 if (!spec->autocfg.hp_pins[0]) {
1159 tmp = (ass >> 11) & 0x3; /* HP to chassis */
1160 if (tmp == 0)
1161 spec->autocfg.hp_pins[0] = porta;
1162 else if (tmp == 1)
1163 spec->autocfg.hp_pins[0] = porte;
1164 else if (tmp == 2)
1165 spec->autocfg.hp_pins[0] = portd;
1166 else
1167 return;
1168 }
Kailang Yang7fb0d782008-10-15 11:12:35 +02001169 if (spec->autocfg.hp_pins[0])
1170 snd_hda_codec_write(codec, spec->autocfg.hp_pins[0], 0,
1171 AC_VERB_SET_UNSOLICITED_ENABLE,
1172 AC_USRSP_EN | ALC880_HP_EVENT);
Kailang Yangc9b58002007-10-16 14:30:01 +02001173
Takashi Iwai4605b712008-10-31 14:18:24 +01001174#if 0 /* it's broken in some acses -- temporarily disabled */
Kailang Yang7fb0d782008-10-15 11:12:35 +02001175 if (spec->autocfg.input_pins[AUTO_PIN_MIC] &&
1176 spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC])
1177 snd_hda_codec_write(codec,
1178 spec->autocfg.input_pins[AUTO_PIN_MIC], 0,
1179 AC_VERB_SET_UNSOLICITED_ENABLE,
1180 AC_USRSP_EN | ALC880_MIC_EVENT);
Takashi Iwai4605b712008-10-31 14:18:24 +01001181#endif /* disabled */
Kailang Yangea1fb292008-08-26 12:58:38 +02001182
Kailang Yangc9b58002007-10-16 14:30:01 +02001183 spec->unsol_event = alc_sku_unsol_event;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001184}
1185
Takashi Iwai41e41f12005-06-08 14:48:49 +02001186/*
Takashi Iwaif95474e2007-07-10 00:47:43 +02001187 * Fix-up pin default configurations
1188 */
1189
1190struct alc_pincfg {
1191 hda_nid_t nid;
1192 u32 val;
1193};
1194
1195static void alc_fix_pincfg(struct hda_codec *codec,
1196 const struct snd_pci_quirk *quirk,
1197 const struct alc_pincfg **pinfix)
1198{
1199 const struct alc_pincfg *cfg;
1200
1201 quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk);
1202 if (!quirk)
1203 return;
1204
1205 cfg = pinfix[quirk->value];
Takashi Iwai0e8a21b2009-02-20 14:13:06 +01001206 for (; cfg->nid; cfg++)
1207 snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val);
Takashi Iwaif95474e2007-07-10 00:47:43 +02001208}
1209
1210/*
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001211 * ALC888
1212 */
1213
1214/*
1215 * 2ch mode
1216 */
1217static struct hda_verb alc888_4ST_ch2_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 Line in */
1222 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
1223 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1224/* Line-Out as Front */
1225 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00},
1226 { } /* end */
1227};
1228
1229/*
1230 * 4ch mode
1231 */
1232static struct hda_verb alc888_4ST_ch4_intel_init[] = {
1233/* Mic-in jack as mic in */
1234 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1235 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
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 Front */
1240 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00},
1241 { } /* end */
1242};
1243
1244/*
1245 * 6ch mode
1246 */
1247static struct hda_verb alc888_4ST_ch6_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 CLFE (workaround because Mic-in is not loud enough) */
1255 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
1256 { } /* end */
1257};
1258
1259/*
1260 * 8ch mode
1261 */
1262static struct hda_verb alc888_4ST_ch8_intel_init[] = {
1263/* Mic-in jack as CLFE */
1264 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1265 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1266/* Line-in jack as Surround */
1267 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1268 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1269/* Line-Out as Side */
1270 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
1271 { } /* end */
1272};
1273
1274static struct hda_channel_mode alc888_4ST_8ch_intel_modes[4] = {
1275 { 2, alc888_4ST_ch2_intel_init },
1276 { 4, alc888_4ST_ch4_intel_init },
1277 { 6, alc888_4ST_ch6_intel_init },
1278 { 8, alc888_4ST_ch8_intel_init },
1279};
1280
1281/*
1282 * ALC888 Fujitsu Siemens Amillo xa3530
1283 */
1284
1285static struct hda_verb alc888_fujitsu_xa3530_verbs[] = {
1286/* Front Mic: set to PIN_IN (empty by default) */
1287 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1288/* Connect Internal HP to Front */
1289 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1290 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1291 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
1292/* Connect Bass HP to Front */
1293 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1294 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1295 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
1296/* Connect Line-Out side jack (SPDIF) to Side */
1297 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1298 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1299 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
1300/* Connect Mic jack to CLFE */
1301 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1302 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1303 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02},
1304/* Connect Line-in jack to Surround */
1305 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1306 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1307 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
1308/* Connect HP out jack to Front */
1309 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1310 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1311 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
1312/* Enable unsolicited event for HP jack and Line-out jack */
1313 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
1314 {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
1315 {}
1316};
1317
1318static void alc888_fujitsu_xa3530_automute(struct hda_codec *codec)
1319{
1320 unsigned int present;
1321 unsigned int bits;
1322 /* Line out presence */
1323 present = snd_hda_codec_read(codec, 0x17, 0,
1324 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
1325 /* HP out presence */
1326 present = present || snd_hda_codec_read(codec, 0x1b, 0,
1327 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
1328 bits = present ? HDA_AMP_MUTE : 0;
1329 /* Toggle internal speakers muting */
1330 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
1331 HDA_AMP_MUTE, bits);
1332 /* Toggle internal bass muting */
1333 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
1334 HDA_AMP_MUTE, bits);
1335}
1336
1337static void alc888_fujitsu_xa3530_unsol_event(struct hda_codec *codec,
1338 unsigned int res)
1339{
1340 if (res >> 26 == ALC880_HP_EVENT)
1341 alc888_fujitsu_xa3530_automute(codec);
1342}
1343
1344
1345/*
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001346 * ALC888 Acer Aspire 4930G model
1347 */
1348
1349static struct hda_verb alc888_acer_aspire_4930g_verbs[] = {
1350/* Front Mic: set to PIN_IN (empty by default) */
1351 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1352/* Unselect Front Mic by default in input mixer 3 */
1353 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001354/* Enable unsolicited event for HP jack */
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001355 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
1356/* Connect Internal HP to front */
1357 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1358 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1359 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
1360/* Connect HP out to front */
1361 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1362 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1363 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
1364 { }
1365};
1366
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001367static struct hda_input_mux alc888_2_capture_sources[2] = {
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001368 /* Front mic only available on one ADC */
1369 {
1370 .num_items = 4,
1371 .items = {
1372 { "Mic", 0x0 },
1373 { "Line", 0x2 },
1374 { "CD", 0x4 },
1375 { "Front Mic", 0xb },
1376 },
1377 },
1378 {
1379 .num_items = 3,
1380 .items = {
1381 { "Mic", 0x0 },
1382 { "Line", 0x2 },
1383 { "CD", 0x4 },
1384 },
1385 }
1386};
1387
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001388static struct snd_kcontrol_new alc888_base_mixer[] = {
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001389 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1390 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
1391 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1392 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
1393 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
1394 HDA_OUTPUT),
1395 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
1396 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1397 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
1398 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
1399 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
1400 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1401 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1402 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1403 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1404 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1405 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
1406 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001407 { } /* end */
1408};
1409
1410static void alc888_acer_aspire_4930g_automute(struct hda_codec *codec)
1411{
1412 unsigned int present;
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001413 unsigned int bits;
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001414 present = snd_hda_codec_read(codec, 0x15, 0,
1415 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001416 bits = present ? HDA_AMP_MUTE : 0;
1417 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
1418 HDA_AMP_MUTE, bits);
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001419}
1420
1421static void alc888_acer_aspire_4930g_unsol_event(struct hda_codec *codec,
1422 unsigned int res)
1423{
1424 if (res >> 26 == ALC880_HP_EVENT)
1425 alc888_acer_aspire_4930g_automute(codec);
1426}
1427
1428/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001429 * ALC880 3-stack model
1430 *
1431 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0e)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001432 * Pin assignment: Front = 0x14, Line-In/Surr = 0x1a, Mic/CLFE = 0x18,
1433 * F-Mic = 0x1b, HP = 0x19
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434 */
1435
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001436static hda_nid_t alc880_dac_nids[4] = {
1437 /* front, rear, clfe, rear_surr */
1438 0x02, 0x05, 0x04, 0x03
1439};
1440
1441static hda_nid_t alc880_adc_nids[3] = {
1442 /* ADC0-2 */
1443 0x07, 0x08, 0x09,
1444};
1445
1446/* The datasheet says the node 0x07 is connected from inputs,
1447 * but it shows zero connection in the real implementation on some devices.
Kailang Yangdf694da2005-12-05 19:42:22 +01001448 * Note: this is a 915GAV bug, fixed on 915GLV
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001450static hda_nid_t alc880_adc_nids_alt[2] = {
1451 /* ADC1-2 */
1452 0x08, 0x09,
1453};
1454
1455#define ALC880_DIGOUT_NID 0x06
1456#define ALC880_DIGIN_NID 0x0a
1457
1458static struct hda_input_mux alc880_capture_source = {
1459 .num_items = 4,
1460 .items = {
1461 { "Mic", 0x0 },
1462 { "Front Mic", 0x3 },
1463 { "Line", 0x2 },
1464 { "CD", 0x4 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465 },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001466};
1467
1468/* channel source setting (2/6 channel selection for 3-stack) */
1469/* 2ch mode */
1470static struct hda_verb alc880_threestack_ch2_init[] = {
1471 /* set line-in to input, mute it */
1472 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
1473 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1474 /* set mic-in to input vref 80%, mute it */
1475 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1476 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 { } /* end */
1478};
1479
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001480/* 6ch mode */
1481static struct hda_verb alc880_threestack_ch6_init[] = {
1482 /* set line-in to output, unmute it */
1483 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1484 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1485 /* set mic-in to output, unmute it */
1486 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1487 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1488 { } /* end */
1489};
1490
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001491static struct hda_channel_mode alc880_threestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001492 { 2, alc880_threestack_ch2_init },
1493 { 6, alc880_threestack_ch6_init },
1494};
1495
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001496static struct snd_kcontrol_new alc880_three_stack_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02001497 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001498 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02001499 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001500 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02001501 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1502 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001503 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1504 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1506 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1507 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1508 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1509 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1510 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1511 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
1512 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513 HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001514 {
1515 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1516 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01001517 .info = alc_ch_mode_info,
1518 .get = alc_ch_mode_get,
1519 .put = alc_ch_mode_put,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001520 },
1521 { } /* end */
1522};
1523
1524/* capture mixer elements */
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001525static int alc_cap_vol_info(struct snd_kcontrol *kcontrol,
1526 struct snd_ctl_elem_info *uinfo)
1527{
1528 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1529 struct alc_spec *spec = codec->spec;
1530 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001531
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001532 mutex_lock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001533 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0,
1534 HDA_INPUT);
1535 err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001536 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001537 return err;
1538}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001540static int alc_cap_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
1541 unsigned int size, unsigned int __user *tlv)
1542{
1543 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1544 struct alc_spec *spec = codec->spec;
1545 int err;
1546
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001547 mutex_lock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001548 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0,
1549 HDA_INPUT);
1550 err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001551 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001552 return err;
1553}
1554
1555typedef int (*getput_call_t)(struct snd_kcontrol *kcontrol,
1556 struct snd_ctl_elem_value *ucontrol);
1557
1558static int alc_cap_getput_caller(struct snd_kcontrol *kcontrol,
1559 struct snd_ctl_elem_value *ucontrol,
1560 getput_call_t func)
1561{
1562 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1563 struct alc_spec *spec = codec->spec;
1564 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1565 int err;
1566
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001567 mutex_lock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001568 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[adc_idx],
1569 3, 0, HDA_INPUT);
1570 err = func(kcontrol, ucontrol);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001571 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001572 return err;
1573}
1574
1575static int alc_cap_vol_get(struct snd_kcontrol *kcontrol,
1576 struct snd_ctl_elem_value *ucontrol)
1577{
1578 return alc_cap_getput_caller(kcontrol, ucontrol,
1579 snd_hda_mixer_amp_volume_get);
1580}
1581
1582static int alc_cap_vol_put(struct snd_kcontrol *kcontrol,
1583 struct snd_ctl_elem_value *ucontrol)
1584{
1585 return alc_cap_getput_caller(kcontrol, ucontrol,
1586 snd_hda_mixer_amp_volume_put);
1587}
1588
1589/* capture mixer elements */
1590#define alc_cap_sw_info snd_ctl_boolean_stereo_info
1591
1592static int alc_cap_sw_get(struct snd_kcontrol *kcontrol,
1593 struct snd_ctl_elem_value *ucontrol)
1594{
1595 return alc_cap_getput_caller(kcontrol, ucontrol,
1596 snd_hda_mixer_amp_switch_get);
1597}
1598
1599static int alc_cap_sw_put(struct snd_kcontrol *kcontrol,
1600 struct snd_ctl_elem_value *ucontrol)
1601{
1602 return alc_cap_getput_caller(kcontrol, ucontrol,
1603 snd_hda_mixer_amp_switch_put);
1604}
1605
Takashi Iwaia23b6882009-03-23 15:21:36 +01001606#define _DEFINE_CAPMIX(num) \
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001607 { \
1608 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
1609 .name = "Capture Switch", \
1610 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
1611 .count = num, \
1612 .info = alc_cap_sw_info, \
1613 .get = alc_cap_sw_get, \
1614 .put = alc_cap_sw_put, \
1615 }, \
1616 { \
1617 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
1618 .name = "Capture Volume", \
1619 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | \
1620 SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
1621 SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK), \
1622 .count = num, \
1623 .info = alc_cap_vol_info, \
1624 .get = alc_cap_vol_get, \
1625 .put = alc_cap_vol_put, \
1626 .tlv = { .c = alc_cap_vol_tlv }, \
Takashi Iwaia23b6882009-03-23 15:21:36 +01001627 }
1628
1629#define _DEFINE_CAPSRC(num) \
Takashi Iwai3c3e9892008-10-31 17:48:56 +01001630 { \
1631 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
1632 /* .name = "Capture Source", */ \
1633 .name = "Input Source", \
1634 .count = num, \
1635 .info = alc_mux_enum_info, \
1636 .get = alc_mux_enum_get, \
1637 .put = alc_mux_enum_put, \
Takashi Iwaia23b6882009-03-23 15:21:36 +01001638 }
1639
1640#define DEFINE_CAPMIX(num) \
1641static struct snd_kcontrol_new alc_capture_mixer ## num[] = { \
1642 _DEFINE_CAPMIX(num), \
1643 _DEFINE_CAPSRC(num), \
1644 { } /* end */ \
1645}
1646
1647#define DEFINE_CAPMIX_NOSRC(num) \
1648static struct snd_kcontrol_new alc_capture_mixer_nosrc ## num[] = { \
1649 _DEFINE_CAPMIX(num), \
1650 { } /* end */ \
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001651}
1652
1653/* up to three ADCs */
1654DEFINE_CAPMIX(1);
1655DEFINE_CAPMIX(2);
1656DEFINE_CAPMIX(3);
Takashi Iwaia23b6882009-03-23 15:21:36 +01001657DEFINE_CAPMIX_NOSRC(1);
1658DEFINE_CAPMIX_NOSRC(2);
1659DEFINE_CAPMIX_NOSRC(3);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001660
1661/*
1662 * ALC880 5-stack model
1663 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001664 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0d),
1665 * Side = 0x02 (0xd)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001666 * Pin assignment: Front = 0x14, Surr = 0x17, CLFE = 0x16
1667 * Line-In/Side = 0x1a, Mic = 0x18, F-Mic = 0x1b, HP = 0x19
1668 */
1669
1670/* additional mixers to alc880_three_stack_mixer */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001671static struct snd_kcontrol_new alc880_five_stack_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001672 HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001673 HDA_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674 { } /* end */
1675};
1676
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001677/* channel source setting (6/8 channel selection for 5-stack) */
1678/* 6ch mode */
1679static struct hda_verb alc880_fivestack_ch6_init[] = {
1680 /* set line-in to input, mute it */
1681 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
1682 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02001683 { } /* end */
1684};
1685
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001686/* 8ch mode */
1687static struct hda_verb alc880_fivestack_ch8_init[] = {
1688 /* set line-in to output, unmute it */
1689 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1690 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1691 { } /* end */
1692};
1693
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001694static struct hda_channel_mode alc880_fivestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001695 { 6, alc880_fivestack_ch6_init },
1696 { 8, alc880_fivestack_ch8_init },
1697};
1698
1699
1700/*
1701 * ALC880 6-stack model
1702 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001703 * DAC: Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e),
1704 * Side = 0x05 (0x0f)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001705 * Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, Side = 0x17,
1706 * Mic = 0x18, F-Mic = 0x19, Line = 0x1a, HP = 0x1b
1707 */
1708
1709static hda_nid_t alc880_6st_dac_nids[4] = {
1710 /* front, rear, clfe, rear_surr */
1711 0x02, 0x03, 0x04, 0x05
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02001712};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001713
1714static struct hda_input_mux alc880_6stack_capture_source = {
1715 .num_items = 4,
1716 .items = {
1717 { "Mic", 0x0 },
1718 { "Front Mic", 0x1 },
1719 { "Line", 0x2 },
1720 { "CD", 0x4 },
1721 },
1722};
1723
1724/* fixed 8-channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001725static struct hda_channel_mode alc880_sixstack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001726 { 8, NULL },
1727};
1728
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001729static struct snd_kcontrol_new alc880_six_stack_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001730 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001731 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001732 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001733 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001734 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1735 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001736 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1737 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001738 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001739 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001740 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1741 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1742 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1743 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1744 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1745 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1746 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1747 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001748 {
1749 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1750 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01001751 .info = alc_ch_mode_info,
1752 .get = alc_ch_mode_get,
1753 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02001754 },
1755 { } /* end */
1756};
1757
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001758
1759/*
1760 * ALC880 W810 model
1761 *
1762 * W810 has rear IO for:
1763 * Front (DAC 02)
1764 * Surround (DAC 03)
1765 * Center/LFE (DAC 04)
1766 * Digital out (06)
1767 *
1768 * The system also has a pair of internal speakers, and a headphone jack.
1769 * These are both connected to Line2 on the codec, hence to DAC 02.
Kailang Yangea1fb292008-08-26 12:58:38 +02001770 *
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001771 * There is a variable resistor to control the speaker or headphone
1772 * volume. This is a hardware-only device without a software API.
1773 *
1774 * Plugging headphones in will disable the internal speakers. This is
1775 * implemented in hardware, not via the driver using jack sense. In
1776 * a similar fashion, plugging into the rear socket marked "front" will
1777 * disable both the speakers and headphones.
1778 *
1779 * For input, there's a microphone jack, and an "audio in" jack.
1780 * These may not do anything useful with this driver yet, because I
1781 * haven't setup any initialization verbs for these yet...
1782 */
1783
1784static hda_nid_t alc880_w810_dac_nids[3] = {
1785 /* front, rear/surround, clfe */
1786 0x02, 0x03, 0x04
1787};
1788
1789/* fixed 6 channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001790static struct hda_channel_mode alc880_w810_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001791 { 6, NULL }
1792};
1793
1794/* Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, HP = 0x1b */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001795static struct snd_kcontrol_new alc880_w810_base_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001796 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001797 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001798 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001799 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001800 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1801 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001802 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1803 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001804 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
1805 { } /* end */
1806};
1807
1808
1809/*
1810 * Z710V model
1811 *
1812 * DAC: Front = 0x02 (0x0c), HP = 0x03 (0x0d)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001813 * Pin assignment: Front = 0x14, HP = 0x15, Mic = 0x18, Mic2 = 0x19(?),
1814 * Line = 0x1a
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001815 */
1816
1817static hda_nid_t alc880_z71v_dac_nids[1] = {
1818 0x02
1819};
1820#define ALC880_Z71V_HP_DAC 0x03
1821
1822/* fixed 2 channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001823static struct hda_channel_mode alc880_2_jack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001824 { 2, NULL }
1825};
1826
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001827static struct snd_kcontrol_new alc880_z71v_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001828 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001829 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001830 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001831 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001832 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1833 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1834 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1835 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1836 { } /* end */
1837};
1838
1839
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001840/*
1841 * ALC880 F1734 model
1842 *
1843 * DAC: HP = 0x02 (0x0c), Front = 0x03 (0x0d)
1844 * Pin assignment: HP = 0x14, Front = 0x15, Mic = 0x18
1845 */
1846
1847static hda_nid_t alc880_f1734_dac_nids[1] = {
1848 0x03
1849};
1850#define ALC880_F1734_HP_DAC 0x02
1851
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001852static struct snd_kcontrol_new alc880_f1734_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001853 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001854 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01001855 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1856 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001857 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1858 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Takashi Iwai937b4162008-02-11 14:52:36 +01001859 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1860 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001861 { } /* end */
1862};
1863
Takashi Iwai937b4162008-02-11 14:52:36 +01001864static struct hda_input_mux alc880_f1734_capture_source = {
1865 .num_items = 2,
1866 .items = {
1867 { "Mic", 0x1 },
1868 { "CD", 0x4 },
1869 },
1870};
1871
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001872
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001873/*
1874 * ALC880 ASUS model
1875 *
1876 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
1877 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
1878 * Mic = 0x18, Line = 0x1a
1879 */
1880
1881#define alc880_asus_dac_nids alc880_w810_dac_nids /* identical with w810 */
1882#define alc880_asus_modes alc880_threestack_modes /* 2/6 channel mode */
1883
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001884static struct snd_kcontrol_new alc880_asus_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001885 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001886 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001887 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001888 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001889 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1890 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001891 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1892 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001893 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1894 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1895 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1896 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1897 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1898 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001899 {
1900 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1901 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01001902 .info = alc_ch_mode_info,
1903 .get = alc_ch_mode_get,
1904 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02001905 },
1906 { } /* end */
1907};
1908
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001909/*
1910 * ALC880 ASUS W1V model
1911 *
1912 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
1913 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
1914 * Mic = 0x18, Line = 0x1a, Line2 = 0x1b
1915 */
1916
1917/* additional mixers to alc880_asus_mixer */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001918static struct snd_kcontrol_new alc880_asus_w1v_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001919 HDA_CODEC_VOLUME("Line2 Playback Volume", 0x0b, 0x03, HDA_INPUT),
1920 HDA_CODEC_MUTE("Line2 Playback Switch", 0x0b, 0x03, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001921 { } /* end */
1922};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001923
Kailang Yangdf694da2005-12-05 19:42:22 +01001924/* TCL S700 */
1925static struct snd_kcontrol_new alc880_tcl_s700_mixer[] = {
1926 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1927 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
1928 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
1929 HDA_CODEC_VOLUME("CD Playback Volume", 0x0B, 0x04, HDA_INPUT),
1930 HDA_CODEC_MUTE("CD Playback Switch", 0x0B, 0x04, HDA_INPUT),
1931 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0B, 0x0, HDA_INPUT),
1932 HDA_CODEC_MUTE("Mic Playback Switch", 0x0B, 0x0, HDA_INPUT),
1933 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
1934 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01001935 { } /* end */
1936};
1937
Kailang Yangccc656c2006-10-17 12:32:26 +02001938/* Uniwill */
1939static struct snd_kcontrol_new alc880_uniwill_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01001940 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1941 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
1942 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1943 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02001944 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1945 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
1946 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1947 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
1948 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1949 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1950 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1951 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1952 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1953 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1954 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1955 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02001956 {
1957 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1958 .name = "Channel Mode",
1959 .info = alc_ch_mode_info,
1960 .get = alc_ch_mode_get,
1961 .put = alc_ch_mode_put,
1962 },
1963 { } /* end */
1964};
1965
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01001966static struct snd_kcontrol_new alc880_fujitsu_mixer[] = {
1967 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),
1971 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1972 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1973 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1974 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1975 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1976 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
1977 { } /* end */
1978};
1979
Kailang Yangccc656c2006-10-17 12:32:26 +02001980static struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01001981 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1982 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
1983 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1984 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02001985 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1986 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1987 { } /* end */
1988};
1989
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990/*
Takashi Iwai2134ea42008-01-10 16:53:55 +01001991 * virtual master controls
1992 */
1993
1994/*
1995 * slave controls for virtual master
1996 */
1997static const char *alc_slave_vols[] = {
1998 "Front Playback Volume",
1999 "Surround Playback Volume",
2000 "Center Playback Volume",
2001 "LFE Playback Volume",
2002 "Side Playback Volume",
2003 "Headphone Playback Volume",
2004 "Speaker Playback Volume",
2005 "Mono Playback Volume",
Takashi Iwai2134ea42008-01-10 16:53:55 +01002006 "Line-Out Playback Volume",
Takashi Iwai26f5df22008-11-03 17:39:46 +01002007 "PCM Playback Volume",
Takashi Iwai2134ea42008-01-10 16:53:55 +01002008 NULL,
2009};
2010
2011static const char *alc_slave_sws[] = {
2012 "Front Playback Switch",
2013 "Surround Playback Switch",
2014 "Center Playback Switch",
2015 "LFE Playback Switch",
2016 "Side Playback Switch",
2017 "Headphone Playback Switch",
2018 "Speaker Playback Switch",
2019 "Mono Playback Switch",
Takashi Iwaiedb54a52008-01-29 12:47:02 +01002020 "IEC958 Playback Switch",
Takashi Iwai2134ea42008-01-10 16:53:55 +01002021 NULL,
2022};
2023
2024/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002025 * build control elements
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026 */
Takashi Iwai603c4012008-07-30 15:01:44 +02002027
2028static void alc_free_kctls(struct hda_codec *codec);
2029
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002030/* additional beep mixers; the actual parameters are overwritten at build */
2031static struct snd_kcontrol_new alc_beep_mixer[] = {
2032 HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_INPUT),
2033 HDA_CODEC_MUTE("Beep Playback Switch", 0, 0, HDA_INPUT),
2034 { } /* end */
2035};
2036
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037static int alc_build_controls(struct hda_codec *codec)
2038{
2039 struct alc_spec *spec = codec->spec;
2040 int err;
2041 int i;
2042
2043 for (i = 0; i < spec->num_mixers; i++) {
2044 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
2045 if (err < 0)
2046 return err;
2047 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002048 if (spec->cap_mixer) {
2049 err = snd_hda_add_new_ctls(codec, spec->cap_mixer);
2050 if (err < 0)
2051 return err;
2052 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002053 if (spec->multiout.dig_out_nid) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002054 err = snd_hda_create_spdif_out_ctls(codec,
2055 spec->multiout.dig_out_nid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002056 if (err < 0)
2057 return err;
Takashi Iwaie64f14f2009-01-20 18:32:55 +01002058 if (!spec->no_analog) {
2059 err = snd_hda_create_spdif_share_sw(codec,
2060 &spec->multiout);
2061 if (err < 0)
2062 return err;
2063 spec->multiout.share_spdif = 1;
2064 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002065 }
2066 if (spec->dig_in_nid) {
2067 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
2068 if (err < 0)
2069 return err;
2070 }
Takashi Iwai2134ea42008-01-10 16:53:55 +01002071
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002072 /* create beep controls if needed */
2073 if (spec->beep_amp) {
2074 struct snd_kcontrol_new *knew;
2075 for (knew = alc_beep_mixer; knew->name; knew++) {
2076 struct snd_kcontrol *kctl;
2077 kctl = snd_ctl_new1(knew, codec);
2078 if (!kctl)
2079 return -ENOMEM;
2080 kctl->private_value = spec->beep_amp;
2081 err = snd_hda_ctl_add(codec, kctl);
2082 if (err < 0)
2083 return err;
2084 }
2085 }
2086
Takashi Iwai2134ea42008-01-10 16:53:55 +01002087 /* if we have no master control, let's create it */
Takashi Iwaie64f14f2009-01-20 18:32:55 +01002088 if (!spec->no_analog &&
2089 !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
Takashi Iwai1c82ed12008-02-18 13:05:50 +01002090 unsigned int vmaster_tlv[4];
Takashi Iwai2134ea42008-01-10 16:53:55 +01002091 snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
Takashi Iwai1c82ed12008-02-18 13:05:50 +01002092 HDA_OUTPUT, vmaster_tlv);
Takashi Iwai2134ea42008-01-10 16:53:55 +01002093 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
Takashi Iwai1c82ed12008-02-18 13:05:50 +01002094 vmaster_tlv, alc_slave_vols);
Takashi Iwai2134ea42008-01-10 16:53:55 +01002095 if (err < 0)
2096 return err;
2097 }
Takashi Iwaie64f14f2009-01-20 18:32:55 +01002098 if (!spec->no_analog &&
2099 !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
Takashi Iwai2134ea42008-01-10 16:53:55 +01002100 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
2101 NULL, alc_slave_sws);
2102 if (err < 0)
2103 return err;
2104 }
2105
Takashi Iwai603c4012008-07-30 15:01:44 +02002106 alc_free_kctls(codec); /* no longer needed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002107 return 0;
2108}
2109
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002110
Linus Torvalds1da177e2005-04-16 15:20:36 -07002111/*
2112 * initialize the codec volumes, etc
2113 */
2114
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002115/*
2116 * generic initialization of ADC, input mixers and output mixers
2117 */
2118static struct hda_verb alc880_volume_init_verbs[] = {
2119 /*
2120 * Unmute ADC0-2 and set the default input to mic-in
2121 */
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002122 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002123 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002124 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002125 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002126 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002127 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002128
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002129 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
2130 * mixer widget
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002131 * Note: PASD motherboards uses the Line In 2 as the input for front
2132 * panel mic (mic 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002133 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002134 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02002135 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2136 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2137 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
2138 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2139 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
2140 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
2141 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002142
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002143 /*
2144 * Set up output mixers (0x0c - 0x0f)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002145 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002146 /* set vol=0 to output mixers */
2147 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2148 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2149 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2150 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2151 /* set up input amps for analog loopback */
2152 /* Amp Indices: DAC = 0, mixer = 1 */
Takashi Iwai05acb862005-06-10 19:50:25 +02002153 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2154 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02002155 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2156 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02002157 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2158 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02002159 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2160 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002161
2162 { }
2163};
2164
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002165/*
2166 * 3-stack pin configuration:
2167 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
2168 */
2169static struct hda_verb alc880_pin_3stack_init_verbs[] = {
2170 /*
2171 * preset connection lists of input pins
2172 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
2173 */
2174 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
2175 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2176 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
2177
2178 /*
2179 * Set pin mode and muting
2180 */
2181 /* set front pin widgets 0x14 for output */
2182 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2183 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2184 /* Mic1 (rear panel) pin widget for input and vref at 80% */
2185 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2186 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2187 /* Mic2 (as headphone out) for HP output */
2188 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2189 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2190 /* Line In pin widget for input */
2191 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2192 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2193 /* Line2 (as front mic) pin widget for input and vref at 80% */
2194 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2195 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2196 /* CD pin widget for input */
2197 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2198
2199 { }
2200};
2201
2202/*
2203 * 5-stack pin configuration:
2204 * front = 0x14, surround = 0x17, clfe = 0x16, mic = 0x18, HP = 0x19,
2205 * line-in/side = 0x1a, f-mic = 0x1b
2206 */
2207static struct hda_verb alc880_pin_5stack_init_verbs[] = {
2208 /*
2209 * preset connection lists of input pins
2210 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
2211 */
2212 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2213 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/side */
2214
2215 /*
2216 * Set pin mode and muting
2217 */
2218 /* set pin widgets 0x14-0x17 for output */
Takashi Iwai05acb862005-06-10 19:50:25 +02002219 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2220 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2221 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2222 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002223 /* unmute pins for output (no gain on this amp) */
2224 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2225 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2226 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2227 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2228
Linus Torvalds1da177e2005-04-16 15:20:36 -07002229 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02002230 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002231 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2232 /* Mic2 (as headphone out) for HP output */
2233 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02002234 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002235 /* Line In pin widget for input */
2236 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2237 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2238 /* Line2 (as front mic) pin widget for input and vref at 80% */
2239 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2240 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2241 /* CD pin widget for input */
2242 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243
2244 { }
2245};
2246
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002247/*
2248 * W810 pin configuration:
2249 * front = 0x14, surround = 0x15, clfe = 0x16, HP = 0x1b
2250 */
2251static struct hda_verb alc880_pin_w810_init_verbs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252 /* hphone/speaker input selector: front DAC */
2253 {0x13, AC_VERB_SET_CONNECT_SEL, 0x0},
2254
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002255 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2256 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2257 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2258 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2259 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2260 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2261
2262 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02002263 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002264
Linus Torvalds1da177e2005-04-16 15:20:36 -07002265 { }
2266};
2267
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002268/*
2269 * Z71V pin configuration:
2270 * Speaker-out = 0x14, HP = 0x15, Mic = 0x18, Line-in = 0x1a, Mic2 = 0x1b (?)
2271 */
2272static struct hda_verb alc880_pin_z71v_init_verbs[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02002273 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002274 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai05acb862005-06-10 19:50:25 +02002275 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002276 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02002277
Takashi Iwai16ded522005-06-10 19:58:24 +02002278 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002279 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02002280 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002281 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02002282
2283 { }
2284};
2285
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002286/*
2287 * 6-stack pin configuration:
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002288 * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18,
2289 * f-mic = 0x19, line = 0x1a, HP = 0x1b
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002290 */
2291static struct hda_verb alc880_pin_6stack_init_verbs[] = {
2292 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2293
Takashi Iwai16ded522005-06-10 19:58:24 +02002294 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002295 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002296 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002297 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002298 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002299 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002300 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002301 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2302
Takashi Iwai16ded522005-06-10 19:58:24 +02002303 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002304 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002305 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002306 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002307 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002308 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002309 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai16ded522005-06-10 19:58:24 +02002310 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002311 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangea1fb292008-08-26 12:58:38 +02002312
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002313 { }
2314};
Takashi Iwai16ded522005-06-10 19:58:24 +02002315
Kailang Yangccc656c2006-10-17 12:32:26 +02002316/*
2317 * Uniwill pin configuration:
2318 * HP = 0x14, InternalSpeaker = 0x15, mic = 0x18, internal mic = 0x19,
2319 * line = 0x1a
2320 */
2321static struct hda_verb alc880_uniwill_init_verbs[] = {
2322 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2323
2324 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2325 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2326 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2327 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2328 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2329 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2330 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2331 {0x17, 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 /* {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, */
2346 /* {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
2347 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2348
2349 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
2350 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
2351
2352 { }
2353};
2354
2355/*
2356* Uniwill P53
Kailang Yangea1fb292008-08-26 12:58:38 +02002357* HP = 0x14, InternalSpeaker = 0x15, mic = 0x19,
Kailang Yangccc656c2006-10-17 12:32:26 +02002358 */
2359static struct hda_verb alc880_uniwill_p53_init_verbs[] = {
2360 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2361
2362 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2363 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2364 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2365 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2366 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2367 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2368 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2369 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2370 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2371 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2372 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2373 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2374
2375 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2376 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2377 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2378 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2379 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2380 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2381
2382 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
2383 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_DCVOL_EVENT},
2384
2385 { }
2386};
2387
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01002388static struct hda_verb alc880_beep_init_verbs[] = {
2389 { 0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) },
2390 { }
2391};
2392
Kailang Yangccc656c2006-10-17 12:32:26 +02002393/* toggle speaker-output according to the hp-jack state */
Takashi Iwai458a4fa2007-05-05 12:18:40 +02002394static void alc880_uniwill_hp_automute(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02002395{
2396 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002397 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02002398
2399 present = snd_hda_codec_read(codec, 0x14, 0,
2400 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02002401 bits = present ? HDA_AMP_MUTE : 0;
2402 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
2403 HDA_AMP_MUTE, bits);
2404 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
2405 HDA_AMP_MUTE, bits);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02002406}
2407
2408/* auto-toggle front mic */
2409static void alc880_uniwill_mic_automute(struct hda_codec *codec)
2410{
2411 unsigned int present;
2412 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02002413
2414 present = snd_hda_codec_read(codec, 0x18, 0,
2415 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02002416 bits = present ? HDA_AMP_MUTE : 0;
2417 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02002418}
2419
2420static void alc880_uniwill_automute(struct hda_codec *codec)
2421{
2422 alc880_uniwill_hp_automute(codec);
2423 alc880_uniwill_mic_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02002424}
2425
2426static void alc880_uniwill_unsol_event(struct hda_codec *codec,
2427 unsigned int res)
2428{
2429 /* Looks like the unsol event is incompatible with the standard
2430 * definition. 4bit tag is placed at 28 bit!
2431 */
Takashi Iwai458a4fa2007-05-05 12:18:40 +02002432 switch (res >> 28) {
2433 case ALC880_HP_EVENT:
2434 alc880_uniwill_hp_automute(codec);
2435 break;
2436 case ALC880_MIC_EVENT:
2437 alc880_uniwill_mic_automute(codec);
2438 break;
2439 }
Kailang Yangccc656c2006-10-17 12:32:26 +02002440}
2441
2442static void alc880_uniwill_p53_hp_automute(struct hda_codec *codec)
2443{
2444 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002445 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02002446
2447 present = snd_hda_codec_read(codec, 0x14, 0,
2448 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02002449 bits = present ? HDA_AMP_MUTE : 0;
Jiang zhe64654c22008-04-14 13:26:21 +02002450 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, HDA_AMP_MUTE, bits);
Kailang Yangccc656c2006-10-17 12:32:26 +02002451}
2452
2453static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec)
2454{
2455 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02002456
Kailang Yangccc656c2006-10-17 12:32:26 +02002457 present = snd_hda_codec_read(codec, 0x21, 0,
Takashi Iwai47fd8302007-08-10 17:11:07 +02002458 AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
2459 present &= HDA_AMP_VOLMASK;
2460 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0,
2461 HDA_AMP_VOLMASK, present);
2462 snd_hda_codec_amp_stereo(codec, 0x0d, HDA_OUTPUT, 0,
2463 HDA_AMP_VOLMASK, present);
Kailang Yangccc656c2006-10-17 12:32:26 +02002464}
Takashi Iwai47fd8302007-08-10 17:11:07 +02002465
Kailang Yangccc656c2006-10-17 12:32:26 +02002466static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec,
2467 unsigned int res)
2468{
2469 /* Looks like the unsol event is incompatible with the standard
2470 * definition. 4bit tag is placed at 28 bit!
2471 */
2472 if ((res >> 28) == ALC880_HP_EVENT)
2473 alc880_uniwill_p53_hp_automute(codec);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002474 if ((res >> 28) == ALC880_DCVOL_EVENT)
Kailang Yangccc656c2006-10-17 12:32:26 +02002475 alc880_uniwill_p53_dcvol_automute(codec);
2476}
2477
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002478/*
2479 * F1734 pin configuration:
2480 * HP = 0x14, speaker-out = 0x15, mic = 0x18
2481 */
2482static struct hda_verb alc880_pin_f1734_init_verbs[] = {
Michael Gruberee7a9c72008-03-10 11:30:59 +01002483 {0x07, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002484 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
2485 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
2486 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
2487 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
2488
2489 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2490 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2491 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2492 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2493
2494 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2495 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Michael Gruberee7a9c72008-03-10 11:30:59 +01002496 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002497 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2498 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2499 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2500 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2501 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2502 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02002503
Takashi Iwai937b4162008-02-11 14:52:36 +01002504 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
2505 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_DCVOL_EVENT},
2506
Takashi Iwai16ded522005-06-10 19:58:24 +02002507 { }
2508};
2509
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002510/*
2511 * ASUS pin configuration:
2512 * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a
2513 */
2514static struct hda_verb alc880_pin_asus_init_verbs[] = {
2515 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
2516 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
2517 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
2518 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
2519
2520 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2521 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2522 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2523 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2524 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2525 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2526 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2527 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2528
2529 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2530 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2531 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2532 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2533 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2534 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2535 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2536 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2537 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangea1fb292008-08-26 12:58:38 +02002538
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002539 { }
2540};
2541
2542/* Enable GPIO mask and set output */
Kailang Yangbc9f98a2007-04-12 13:06:07 +02002543#define alc880_gpio1_init_verbs alc_gpio1_init_verbs
2544#define alc880_gpio2_init_verbs alc_gpio2_init_verbs
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002545
Kailang Yangdf694da2005-12-05 19:42:22 +01002546/* Clevo m520g init */
2547static struct hda_verb alc880_pin_clevo_init_verbs[] = {
2548 /* headphone output */
2549 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
2550 /* line-out */
2551 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2552 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2553 /* Line-in */
2554 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2555 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2556 /* CD */
2557 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2558 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2559 /* Mic1 (rear panel) */
2560 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2561 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2562 /* Mic2 (front panel) */
2563 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2564 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2565 /* headphone */
2566 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2567 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2568 /* change to EAPD mode */
2569 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
2570 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
2571
2572 { }
2573};
2574
2575static struct hda_verb alc880_pin_tcl_S700_init_verbs[] = {
Takashi Iwai4b146cb2006-07-28 14:42:36 +02002576 /* change to EAPD mode */
2577 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
2578 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
2579
Kailang Yangdf694da2005-12-05 19:42:22 +01002580 /* Headphone output */
2581 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2582 /* Front output*/
2583 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2584 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
2585
2586 /* Line In pin widget for input */
2587 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2588 /* CD pin widget for input */
2589 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2590 /* Mic1 (rear panel) pin widget for input and vref at 80% */
2591 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2592
2593 /* change to EAPD mode */
2594 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
2595 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
2596
2597 { }
2598};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002599
2600/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002601 * LG m1 express dual
2602 *
2603 * Pin assignment:
2604 * Rear Line-In/Out (blue): 0x14
2605 * Build-in Mic-In: 0x15
2606 * Speaker-out: 0x17
2607 * HP-Out (green): 0x1b
2608 * Mic-In/Out (red): 0x19
2609 * SPDIF-Out: 0x1e
2610 */
2611
2612/* To make 5.1 output working (green=Front, blue=Surr, red=CLFE) */
2613static hda_nid_t alc880_lg_dac_nids[3] = {
2614 0x05, 0x02, 0x03
2615};
2616
2617/* seems analog CD is not working */
2618static struct hda_input_mux alc880_lg_capture_source = {
2619 .num_items = 3,
2620 .items = {
2621 { "Mic", 0x1 },
2622 { "Line", 0x5 },
2623 { "Internal Mic", 0x6 },
2624 },
2625};
2626
2627/* 2,4,6 channel modes */
2628static struct hda_verb alc880_lg_ch2_init[] = {
2629 /* set line-in and mic-in to input */
2630 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2631 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2632 { }
2633};
2634
2635static struct hda_verb alc880_lg_ch4_init[] = {
2636 /* set line-in to out and mic-in to input */
2637 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
2638 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2639 { }
2640};
2641
2642static struct hda_verb alc880_lg_ch6_init[] = {
2643 /* set line-in and mic-in to output */
2644 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
2645 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
2646 { }
2647};
2648
2649static struct hda_channel_mode alc880_lg_ch_modes[3] = {
2650 { 2, alc880_lg_ch2_init },
2651 { 4, alc880_lg_ch4_init },
2652 { 6, alc880_lg_ch6_init },
2653};
2654
2655static struct snd_kcontrol_new alc880_lg_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01002656 HDA_CODEC_VOLUME("Front Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
2657 HDA_BIND_MUTE("Front Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002658 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2659 HDA_BIND_MUTE("Surround Playback Switch", 0x0c, 2, HDA_INPUT),
2660 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
2661 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
2662 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
2663 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
2664 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2665 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
2666 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x06, HDA_INPUT),
2667 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x06, HDA_INPUT),
2668 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x07, HDA_INPUT),
2669 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x07, HDA_INPUT),
2670 {
2671 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2672 .name = "Channel Mode",
2673 .info = alc_ch_mode_info,
2674 .get = alc_ch_mode_get,
2675 .put = alc_ch_mode_put,
2676 },
2677 { } /* end */
2678};
2679
2680static struct hda_verb alc880_lg_init_verbs[] = {
2681 /* set capture source to mic-in */
2682 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2683 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2684 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2685 /* mute all amp mixer inputs */
2686 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02002687 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
2688 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002689 /* line-in to input */
2690 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2691 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2692 /* built-in mic */
2693 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2694 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2695 /* speaker-out */
2696 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2697 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2698 /* mic-in to input */
2699 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
2700 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2701 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2702 /* HP-out */
2703 {0x13, AC_VERB_SET_CONNECT_SEL, 0x03},
2704 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2705 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2706 /* jack sense */
2707 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | 0x1},
2708 { }
2709};
2710
2711/* toggle speaker-output according to the hp-jack state */
2712static void alc880_lg_automute(struct hda_codec *codec)
2713{
2714 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002715 unsigned char bits;
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002716
2717 present = snd_hda_codec_read(codec, 0x1b, 0,
2718 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02002719 bits = present ? HDA_AMP_MUTE : 0;
2720 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
2721 HDA_AMP_MUTE, bits);
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002722}
2723
2724static void alc880_lg_unsol_event(struct hda_codec *codec, unsigned int res)
2725{
2726 /* Looks like the unsol event is incompatible with the standard
2727 * definition. 4bit tag is placed at 28 bit!
2728 */
2729 if ((res >> 28) == 0x01)
2730 alc880_lg_automute(codec);
2731}
2732
2733/*
Takashi Iwaid6815182006-03-23 16:06:23 +01002734 * LG LW20
2735 *
2736 * Pin assignment:
2737 * Speaker-out: 0x14
2738 * Mic-In: 0x18
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02002739 * Built-in Mic-In: 0x19
2740 * Line-In: 0x1b
2741 * HP-Out: 0x1a
Takashi Iwaid6815182006-03-23 16:06:23 +01002742 * SPDIF-Out: 0x1e
2743 */
2744
Takashi Iwaid6815182006-03-23 16:06:23 +01002745static struct hda_input_mux alc880_lg_lw_capture_source = {
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02002746 .num_items = 3,
Takashi Iwaid6815182006-03-23 16:06:23 +01002747 .items = {
2748 { "Mic", 0x0 },
2749 { "Internal Mic", 0x1 },
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02002750 { "Line In", 0x2 },
Takashi Iwaid6815182006-03-23 16:06:23 +01002751 },
2752};
2753
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002754#define alc880_lg_lw_modes alc880_threestack_modes
2755
Takashi Iwaid6815182006-03-23 16:06:23 +01002756static struct snd_kcontrol_new alc880_lg_lw_mixer[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002757 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2758 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
2759 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
2760 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
2761 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2762 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
2763 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2764 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
2765 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2766 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaid6815182006-03-23 16:06:23 +01002767 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2768 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2769 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
2770 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002771 {
2772 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2773 .name = "Channel Mode",
2774 .info = alc_ch_mode_info,
2775 .get = alc_ch_mode_get,
2776 .put = alc_ch_mode_put,
2777 },
Takashi Iwaid6815182006-03-23 16:06:23 +01002778 { } /* end */
2779};
2780
2781static struct hda_verb alc880_lg_lw_init_verbs[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002782 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2783 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
2784 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
2785
Takashi Iwaid6815182006-03-23 16:06:23 +01002786 /* set capture source to mic-in */
2787 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2788 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2789 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02002790 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaid6815182006-03-23 16:06:23 +01002791 /* speaker-out */
2792 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2793 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2794 /* HP-out */
Takashi Iwaid6815182006-03-23 16:06:23 +01002795 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2796 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2797 /* mic-in to input */
2798 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2799 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2800 /* built-in mic */
2801 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2802 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2803 /* jack sense */
2804 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | 0x1},
2805 { }
2806};
2807
2808/* toggle speaker-output according to the hp-jack state */
2809static void alc880_lg_lw_automute(struct hda_codec *codec)
2810{
2811 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002812 unsigned char bits;
Takashi Iwaid6815182006-03-23 16:06:23 +01002813
2814 present = snd_hda_codec_read(codec, 0x1b, 0,
2815 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02002816 bits = present ? HDA_AMP_MUTE : 0;
2817 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
2818 HDA_AMP_MUTE, bits);
Takashi Iwaid6815182006-03-23 16:06:23 +01002819}
2820
2821static void alc880_lg_lw_unsol_event(struct hda_codec *codec, unsigned int res)
2822{
2823 /* Looks like the unsol event is incompatible with the standard
2824 * definition. 4bit tag is placed at 28 bit!
2825 */
2826 if ((res >> 28) == 0x01)
2827 alc880_lg_lw_automute(codec);
2828}
2829
Takashi Iwaidf99cd32008-04-25 15:25:04 +02002830static struct snd_kcontrol_new alc880_medion_rim_mixer[] = {
2831 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2832 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
2833 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2834 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2835 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2836 HDA_CODEC_MUTE("Internal Playback Switch", 0x0b, 0x1, HDA_INPUT),
2837 { } /* end */
2838};
2839
2840static struct hda_input_mux alc880_medion_rim_capture_source = {
2841 .num_items = 2,
2842 .items = {
2843 { "Mic", 0x0 },
2844 { "Internal Mic", 0x1 },
2845 },
2846};
2847
2848static struct hda_verb alc880_medion_rim_init_verbs[] = {
2849 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2850
2851 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2852 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2853
2854 /* Mic1 (rear panel) pin widget for input and vref at 80% */
2855 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2856 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2857 /* Mic2 (as headphone out) for HP output */
2858 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2859 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2860 /* Internal Speaker */
2861 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2862 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2863
2864 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
2865 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
2866
2867 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
2868 { }
2869};
2870
2871/* toggle speaker-output according to the hp-jack state */
2872static void alc880_medion_rim_automute(struct hda_codec *codec)
2873{
2874 unsigned int present;
2875 unsigned char bits;
2876
2877 present = snd_hda_codec_read(codec, 0x14, 0,
2878 AC_VERB_GET_PIN_SENSE, 0)
2879 & AC_PINSENSE_PRESENCE;
2880 bits = present ? HDA_AMP_MUTE : 0;
2881 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
2882 HDA_AMP_MUTE, bits);
2883 if (present)
2884 snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0);
2885 else
2886 snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 2);
2887}
2888
2889static void alc880_medion_rim_unsol_event(struct hda_codec *codec,
2890 unsigned int res)
2891{
2892 /* Looks like the unsol event is incompatible with the standard
2893 * definition. 4bit tag is placed at 28 bit!
2894 */
2895 if ((res >> 28) == ALC880_HP_EVENT)
2896 alc880_medion_rim_automute(codec);
2897}
2898
Takashi Iwaicb53c622007-08-10 17:21:45 +02002899#ifdef CONFIG_SND_HDA_POWER_SAVE
2900static struct hda_amp_list alc880_loopbacks[] = {
2901 { 0x0b, HDA_INPUT, 0 },
2902 { 0x0b, HDA_INPUT, 1 },
2903 { 0x0b, HDA_INPUT, 2 },
2904 { 0x0b, HDA_INPUT, 3 },
2905 { 0x0b, HDA_INPUT, 4 },
2906 { } /* end */
2907};
2908
2909static struct hda_amp_list alc880_lg_loopbacks[] = {
2910 { 0x0b, HDA_INPUT, 1 },
2911 { 0x0b, HDA_INPUT, 6 },
2912 { 0x0b, HDA_INPUT, 7 },
2913 { } /* end */
2914};
2915#endif
2916
Takashi Iwaid6815182006-03-23 16:06:23 +01002917/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002918 * Common callbacks
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002919 */
Takashi Iwai16ded522005-06-10 19:58:24 +02002920
Linus Torvalds1da177e2005-04-16 15:20:36 -07002921static int alc_init(struct hda_codec *codec)
2922{
2923 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002924 unsigned int i;
2925
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02002926 alc_fix_pll(codec);
Takashi Iwai1082c742008-08-22 15:24:22 +02002927 if (codec->vendor_id == 0x10ec0888)
2928 alc888_coef_init(codec);
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02002929
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002930 for (i = 0; i < spec->num_init_verbs; i++)
2931 snd_hda_sequence_write(codec, spec->init_verbs[i]);
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002932
2933 if (spec->init_hook)
2934 spec->init_hook(codec);
2935
Linus Torvalds1da177e2005-04-16 15:20:36 -07002936 return 0;
2937}
2938
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002939static void alc_unsol_event(struct hda_codec *codec, unsigned int res)
2940{
2941 struct alc_spec *spec = codec->spec;
2942
2943 if (spec->unsol_event)
2944 spec->unsol_event(codec, res);
2945}
2946
Takashi Iwaicb53c622007-08-10 17:21:45 +02002947#ifdef CONFIG_SND_HDA_POWER_SAVE
2948static int alc_check_power_status(struct hda_codec *codec, hda_nid_t nid)
2949{
2950 struct alc_spec *spec = codec->spec;
2951 return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
2952}
2953#endif
2954
Linus Torvalds1da177e2005-04-16 15:20:36 -07002955/*
2956 * Analog playback callbacks
2957 */
2958static int alc880_playback_pcm_open(struct hda_pcm_stream *hinfo,
2959 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002960 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002961{
2962 struct alc_spec *spec = codec->spec;
Takashi Iwai9a081602008-02-12 18:37:26 +01002963 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
2964 hinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002965}
2966
2967static int alc880_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
2968 struct hda_codec *codec,
2969 unsigned int stream_tag,
2970 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002971 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002972{
2973 struct alc_spec *spec = codec->spec;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002974 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
2975 stream_tag, format, substream);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002976}
2977
2978static int alc880_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
2979 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002980 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002981{
2982 struct alc_spec *spec = codec->spec;
2983 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
2984}
2985
2986/*
2987 * Digital out
2988 */
2989static int alc880_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
2990 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002991 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002992{
2993 struct alc_spec *spec = codec->spec;
2994 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
2995}
2996
Takashi Iwai6b97eb42007-04-05 14:51:48 +02002997static int alc880_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
2998 struct hda_codec *codec,
2999 unsigned int stream_tag,
3000 unsigned int format,
3001 struct snd_pcm_substream *substream)
3002{
3003 struct alc_spec *spec = codec->spec;
3004 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
3005 stream_tag, format, substream);
3006}
3007
Takashi Iwai9b5f12e2009-02-13 11:47:37 +01003008static int alc880_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
3009 struct hda_codec *codec,
3010 struct snd_pcm_substream *substream)
3011{
3012 struct alc_spec *spec = codec->spec;
3013 return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
3014}
3015
Linus Torvalds1da177e2005-04-16 15:20:36 -07003016static int alc880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
3017 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003018 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003019{
3020 struct alc_spec *spec = codec->spec;
3021 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
3022}
3023
3024/*
3025 * Analog capture
3026 */
Takashi Iwai63300792008-01-24 15:31:36 +01003027static int alc880_alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003028 struct hda_codec *codec,
3029 unsigned int stream_tag,
3030 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003031 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003032{
3033 struct alc_spec *spec = codec->spec;
3034
Takashi Iwai63300792008-01-24 15:31:36 +01003035 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1],
Linus Torvalds1da177e2005-04-16 15:20:36 -07003036 stream_tag, 0, format);
3037 return 0;
3038}
3039
Takashi Iwai63300792008-01-24 15:31:36 +01003040static int alc880_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003041 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003042 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003043{
3044 struct alc_spec *spec = codec->spec;
3045
Takashi Iwai888afa12008-03-18 09:57:50 +01003046 snd_hda_codec_cleanup_stream(codec,
3047 spec->adc_nids[substream->number + 1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003048 return 0;
3049}
3050
3051
3052/*
3053 */
3054static struct hda_pcm_stream alc880_pcm_analog_playback = {
3055 .substreams = 1,
3056 .channels_min = 2,
3057 .channels_max = 8,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003058 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003059 .ops = {
3060 .open = alc880_playback_pcm_open,
3061 .prepare = alc880_playback_pcm_prepare,
3062 .cleanup = alc880_playback_pcm_cleanup
3063 },
3064};
3065
3066static struct hda_pcm_stream alc880_pcm_analog_capture = {
Takashi Iwai63300792008-01-24 15:31:36 +01003067 .substreams = 1,
3068 .channels_min = 2,
3069 .channels_max = 2,
3070 /* NID is set in alc_build_pcms */
3071};
3072
3073static struct hda_pcm_stream alc880_pcm_analog_alt_playback = {
3074 .substreams = 1,
3075 .channels_min = 2,
3076 .channels_max = 2,
3077 /* NID is set in alc_build_pcms */
3078};
3079
3080static struct hda_pcm_stream alc880_pcm_analog_alt_capture = {
3081 .substreams = 2, /* can be overridden */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003082 .channels_min = 2,
3083 .channels_max = 2,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003084 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003085 .ops = {
Takashi Iwai63300792008-01-24 15:31:36 +01003086 .prepare = alc880_alt_capture_pcm_prepare,
3087 .cleanup = alc880_alt_capture_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07003088 },
3089};
3090
3091static struct hda_pcm_stream alc880_pcm_digital_playback = {
3092 .substreams = 1,
3093 .channels_min = 2,
3094 .channels_max = 2,
3095 /* NID is set in alc_build_pcms */
3096 .ops = {
3097 .open = alc880_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02003098 .close = alc880_dig_playback_pcm_close,
Takashi Iwai9b5f12e2009-02-13 11:47:37 +01003099 .prepare = alc880_dig_playback_pcm_prepare,
3100 .cleanup = alc880_dig_playback_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07003101 },
3102};
3103
3104static struct hda_pcm_stream alc880_pcm_digital_capture = {
3105 .substreams = 1,
3106 .channels_min = 2,
3107 .channels_max = 2,
3108 /* NID is set in alc_build_pcms */
3109};
3110
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01003111/* Used by alc_build_pcms to flag that a PCM has no playback stream */
Takashi Iwai63300792008-01-24 15:31:36 +01003112static struct hda_pcm_stream alc_pcm_null_stream = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01003113 .substreams = 0,
3114 .channels_min = 0,
3115 .channels_max = 0,
3116};
3117
Linus Torvalds1da177e2005-04-16 15:20:36 -07003118static int alc_build_pcms(struct hda_codec *codec)
3119{
3120 struct alc_spec *spec = codec->spec;
3121 struct hda_pcm *info = spec->pcm_rec;
3122 int i;
3123
3124 codec->num_pcms = 1;
3125 codec->pcm_info = info;
3126
Takashi Iwaie64f14f2009-01-20 18:32:55 +01003127 if (spec->no_analog)
3128 goto skip_analog;
3129
Linus Torvalds1da177e2005-04-16 15:20:36 -07003130 info->name = spec->stream_name_analog;
Takashi Iwai4a471b72005-12-07 13:56:29 +01003131 if (spec->stream_analog_playback) {
Takashi Iwaida3cec32008-08-08 17:12:14 +02003132 if (snd_BUG_ON(!spec->multiout.dac_nids))
3133 return -EINVAL;
Takashi Iwai4a471b72005-12-07 13:56:29 +01003134 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
3135 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
3136 }
3137 if (spec->stream_analog_capture) {
Takashi Iwaida3cec32008-08-08 17:12:14 +02003138 if (snd_BUG_ON(!spec->adc_nids))
3139 return -EINVAL;
Takashi Iwai4a471b72005-12-07 13:56:29 +01003140 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
3141 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
3142 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003143
Takashi Iwai4a471b72005-12-07 13:56:29 +01003144 if (spec->channel_mode) {
3145 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0;
3146 for (i = 0; i < spec->num_channel_mode; i++) {
3147 if (spec->channel_mode[i].channels > info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max) {
3148 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->channel_mode[i].channels;
3149 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003150 }
3151 }
3152
Takashi Iwaie64f14f2009-01-20 18:32:55 +01003153 skip_analog:
Takashi Iwaie08a0072006-09-07 17:52:14 +02003154 /* SPDIF for stream index #1 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003155 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
Takashi Iwaie08a0072006-09-07 17:52:14 +02003156 codec->num_pcms = 2;
Wu Fengguangb25c9da2009-02-06 15:02:27 +08003157 codec->slave_dig_outs = spec->multiout.slave_dig_outs;
Takashi Iwaic06134d2006-10-11 18:49:13 +02003158 info = spec->pcm_rec + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003159 info->name = spec->stream_name_digital;
Takashi Iwai8c441982009-01-20 18:30:20 +01003160 if (spec->dig_out_type)
3161 info->pcm_type = spec->dig_out_type;
3162 else
3163 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Takashi Iwai4a471b72005-12-07 13:56:29 +01003164 if (spec->multiout.dig_out_nid &&
3165 spec->stream_digital_playback) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003166 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_digital_playback);
3167 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
3168 }
Takashi Iwai4a471b72005-12-07 13:56:29 +01003169 if (spec->dig_in_nid &&
3170 spec->stream_digital_capture) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003171 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_digital_capture);
3172 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
3173 }
Takashi Iwai963f8032008-08-11 10:04:40 +02003174 /* FIXME: do we need this for all Realtek codec models? */
3175 codec->spdif_status_reset = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003176 }
3177
Takashi Iwaie64f14f2009-01-20 18:32:55 +01003178 if (spec->no_analog)
3179 return 0;
3180
Takashi Iwaie08a0072006-09-07 17:52:14 +02003181 /* If the use of more than one ADC is requested for the current
3182 * model, configure a second analog capture-only PCM.
3183 */
3184 /* Additional Analaog capture for index #2 */
Takashi Iwai63300792008-01-24 15:31:36 +01003185 if ((spec->alt_dac_nid && spec->stream_analog_alt_playback) ||
3186 (spec->num_adc_nids > 1 && spec->stream_analog_alt_capture)) {
Takashi Iwaie08a0072006-09-07 17:52:14 +02003187 codec->num_pcms = 3;
Takashi Iwaic06134d2006-10-11 18:49:13 +02003188 info = spec->pcm_rec + 2;
Takashi Iwaie08a0072006-09-07 17:52:14 +02003189 info->name = spec->stream_name_analog;
Takashi Iwai63300792008-01-24 15:31:36 +01003190 if (spec->alt_dac_nid) {
3191 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
3192 *spec->stream_analog_alt_playback;
3193 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
3194 spec->alt_dac_nid;
3195 } else {
3196 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
3197 alc_pcm_null_stream;
3198 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
3199 }
3200 if (spec->num_adc_nids > 1) {
3201 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
3202 *spec->stream_analog_alt_capture;
3203 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
3204 spec->adc_nids[1];
3205 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams =
3206 spec->num_adc_nids - 1;
3207 } else {
3208 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
3209 alc_pcm_null_stream;
3210 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0;
Takashi Iwaie08a0072006-09-07 17:52:14 +02003211 }
3212 }
3213
Linus Torvalds1da177e2005-04-16 15:20:36 -07003214 return 0;
3215}
3216
Takashi Iwai603c4012008-07-30 15:01:44 +02003217static void alc_free_kctls(struct hda_codec *codec)
3218{
3219 struct alc_spec *spec = codec->spec;
3220
3221 if (spec->kctls.list) {
3222 struct snd_kcontrol_new *kctl = spec->kctls.list;
3223 int i;
3224 for (i = 0; i < spec->kctls.used; i++)
3225 kfree(kctl[i].name);
3226 }
3227 snd_array_free(&spec->kctls);
3228}
3229
Linus Torvalds1da177e2005-04-16 15:20:36 -07003230static void alc_free(struct hda_codec *codec)
3231{
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003232 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003233
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003234 if (!spec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003235 return;
3236
Takashi Iwai603c4012008-07-30 15:01:44 +02003237 alc_free_kctls(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003238 kfree(spec);
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09003239 snd_hda_detach_beep_device(codec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003240}
3241
Takashi Iwaie044c392008-10-27 16:56:24 +01003242#ifdef SND_HDA_NEEDS_RESUME
Takashi Iwaie044c392008-10-27 16:56:24 +01003243static int alc_resume(struct hda_codec *codec)
3244{
Takashi Iwaie044c392008-10-27 16:56:24 +01003245 codec->patch_ops.init(codec);
3246 snd_hda_codec_resume_amp(codec);
3247 snd_hda_codec_resume_cache(codec);
3248 return 0;
3249}
Takashi Iwaie044c392008-10-27 16:56:24 +01003250#endif
3251
Linus Torvalds1da177e2005-04-16 15:20:36 -07003252/*
3253 */
3254static struct hda_codec_ops alc_patch_ops = {
3255 .build_controls = alc_build_controls,
3256 .build_pcms = alc_build_pcms,
3257 .init = alc_init,
3258 .free = alc_free,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003259 .unsol_event = alc_unsol_event,
Takashi Iwaie044c392008-10-27 16:56:24 +01003260#ifdef SND_HDA_NEEDS_RESUME
3261 .resume = alc_resume,
3262#endif
Takashi Iwaicb53c622007-08-10 17:21:45 +02003263#ifdef CONFIG_SND_HDA_POWER_SAVE
3264 .check_power_status = alc_check_power_status,
3265#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07003266};
3267
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003268
3269/*
3270 * Test configuration for debugging
3271 *
3272 * Almost all inputs/outputs are enabled. I/O pins can be configured via
3273 * enum controls.
3274 */
3275#ifdef CONFIG_SND_DEBUG
3276static hda_nid_t alc880_test_dac_nids[4] = {
3277 0x02, 0x03, 0x04, 0x05
3278};
3279
3280static struct hda_input_mux alc880_test_capture_source = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003281 .num_items = 7,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003282 .items = {
3283 { "In-1", 0x0 },
3284 { "In-2", 0x1 },
3285 { "In-3", 0x2 },
3286 { "In-4", 0x3 },
3287 { "CD", 0x4 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003288 { "Front", 0x5 },
3289 { "Surround", 0x6 },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003290 },
3291};
3292
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01003293static struct hda_channel_mode alc880_test_modes[4] = {
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003294 { 2, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02003295 { 4, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003296 { 6, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02003297 { 8, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003298};
3299
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003300static int alc_test_pin_ctl_info(struct snd_kcontrol *kcontrol,
3301 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003302{
3303 static char *texts[] = {
3304 "N/A", "Line Out", "HP Out",
3305 "In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%"
3306 };
3307 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
3308 uinfo->count = 1;
3309 uinfo->value.enumerated.items = 8;
3310 if (uinfo->value.enumerated.item >= 8)
3311 uinfo->value.enumerated.item = 7;
3312 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
3313 return 0;
3314}
3315
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003316static int alc_test_pin_ctl_get(struct snd_kcontrol *kcontrol,
3317 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003318{
3319 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3320 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
3321 unsigned int pin_ctl, item = 0;
3322
3323 pin_ctl = snd_hda_codec_read(codec, nid, 0,
3324 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
3325 if (pin_ctl & AC_PINCTL_OUT_EN) {
3326 if (pin_ctl & AC_PINCTL_HP_EN)
3327 item = 2;
3328 else
3329 item = 1;
3330 } else if (pin_ctl & AC_PINCTL_IN_EN) {
3331 switch (pin_ctl & AC_PINCTL_VREFEN) {
3332 case AC_PINCTL_VREF_HIZ: item = 3; break;
3333 case AC_PINCTL_VREF_50: item = 4; break;
3334 case AC_PINCTL_VREF_GRD: item = 5; break;
3335 case AC_PINCTL_VREF_80: item = 6; break;
3336 case AC_PINCTL_VREF_100: item = 7; break;
3337 }
3338 }
3339 ucontrol->value.enumerated.item[0] = item;
3340 return 0;
3341}
3342
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003343static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol,
3344 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003345{
3346 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3347 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
3348 static unsigned int ctls[] = {
3349 0, AC_PINCTL_OUT_EN, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN,
3350 AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ,
3351 AC_PINCTL_IN_EN | AC_PINCTL_VREF_50,
3352 AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD,
3353 AC_PINCTL_IN_EN | AC_PINCTL_VREF_80,
3354 AC_PINCTL_IN_EN | AC_PINCTL_VREF_100,
3355 };
3356 unsigned int old_ctl, new_ctl;
3357
3358 old_ctl = snd_hda_codec_read(codec, nid, 0,
3359 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
3360 new_ctl = ctls[ucontrol->value.enumerated.item[0]];
3361 if (old_ctl != new_ctl) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003362 int val;
3363 snd_hda_codec_write_cache(codec, nid, 0,
3364 AC_VERB_SET_PIN_WIDGET_CONTROL,
3365 new_ctl);
Takashi Iwai47fd8302007-08-10 17:11:07 +02003366 val = ucontrol->value.enumerated.item[0] >= 3 ?
3367 HDA_AMP_MUTE : 0;
3368 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
3369 HDA_AMP_MUTE, val);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003370 return 1;
3371 }
3372 return 0;
3373}
3374
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003375static int alc_test_pin_src_info(struct snd_kcontrol *kcontrol,
3376 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003377{
3378 static char *texts[] = {
3379 "Front", "Surround", "CLFE", "Side"
3380 };
3381 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
3382 uinfo->count = 1;
3383 uinfo->value.enumerated.items = 4;
3384 if (uinfo->value.enumerated.item >= 4)
3385 uinfo->value.enumerated.item = 3;
3386 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
3387 return 0;
3388}
3389
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003390static int alc_test_pin_src_get(struct snd_kcontrol *kcontrol,
3391 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003392{
3393 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3394 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
3395 unsigned int sel;
3396
3397 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0);
3398 ucontrol->value.enumerated.item[0] = sel & 3;
3399 return 0;
3400}
3401
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003402static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol,
3403 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003404{
3405 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3406 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
3407 unsigned int sel;
3408
3409 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3;
3410 if (ucontrol->value.enumerated.item[0] != sel) {
3411 sel = ucontrol->value.enumerated.item[0] & 3;
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003412 snd_hda_codec_write_cache(codec, nid, 0,
3413 AC_VERB_SET_CONNECT_SEL, sel);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003414 return 1;
3415 }
3416 return 0;
3417}
3418
3419#define PIN_CTL_TEST(xname,nid) { \
3420 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
3421 .name = xname, \
3422 .info = alc_test_pin_ctl_info, \
3423 .get = alc_test_pin_ctl_get, \
3424 .put = alc_test_pin_ctl_put, \
3425 .private_value = nid \
3426 }
3427
3428#define PIN_SRC_TEST(xname,nid) { \
3429 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
3430 .name = xname, \
3431 .info = alc_test_pin_src_info, \
3432 .get = alc_test_pin_src_get, \
3433 .put = alc_test_pin_src_put, \
3434 .private_value = nid \
3435 }
3436
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003437static struct snd_kcontrol_new alc880_test_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02003438 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3439 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
3440 HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
3441 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003442 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
3443 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
3444 HDA_BIND_MUTE("CLFE Playback Switch", 0x0e, 2, HDA_INPUT),
3445 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003446 PIN_CTL_TEST("Front Pin Mode", 0x14),
3447 PIN_CTL_TEST("Surround Pin Mode", 0x15),
3448 PIN_CTL_TEST("CLFE Pin Mode", 0x16),
3449 PIN_CTL_TEST("Side Pin Mode", 0x17),
3450 PIN_CTL_TEST("In-1 Pin Mode", 0x18),
3451 PIN_CTL_TEST("In-2 Pin Mode", 0x19),
3452 PIN_CTL_TEST("In-3 Pin Mode", 0x1a),
3453 PIN_CTL_TEST("In-4 Pin Mode", 0x1b),
3454 PIN_SRC_TEST("In-1 Pin Source", 0x18),
3455 PIN_SRC_TEST("In-2 Pin Source", 0x19),
3456 PIN_SRC_TEST("In-3 Pin Source", 0x1a),
3457 PIN_SRC_TEST("In-4 Pin Source", 0x1b),
3458 HDA_CODEC_VOLUME("In-1 Playback Volume", 0x0b, 0x0, HDA_INPUT),
3459 HDA_CODEC_MUTE("In-1 Playback Switch", 0x0b, 0x0, HDA_INPUT),
3460 HDA_CODEC_VOLUME("In-2 Playback Volume", 0x0b, 0x1, HDA_INPUT),
3461 HDA_CODEC_MUTE("In-2 Playback Switch", 0x0b, 0x1, HDA_INPUT),
3462 HDA_CODEC_VOLUME("In-3 Playback Volume", 0x0b, 0x2, HDA_INPUT),
3463 HDA_CODEC_MUTE("In-3 Playback Switch", 0x0b, 0x2, HDA_INPUT),
3464 HDA_CODEC_VOLUME("In-4 Playback Volume", 0x0b, 0x3, HDA_INPUT),
3465 HDA_CODEC_MUTE("In-4 Playback Switch", 0x0b, 0x3, HDA_INPUT),
3466 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x4, HDA_INPUT),
3467 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x4, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003468 {
3469 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3470 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01003471 .info = alc_ch_mode_info,
3472 .get = alc_ch_mode_get,
3473 .put = alc_ch_mode_put,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003474 },
3475 { } /* end */
3476};
3477
3478static struct hda_verb alc880_test_init_verbs[] = {
3479 /* Unmute inputs of 0x0c - 0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02003480 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3481 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3482 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3483 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3484 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3485 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3486 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3487 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003488 /* Vol output for 0x0c-0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02003489 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3490 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3491 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3492 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003493 /* Set output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02003494 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3495 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3496 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3497 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003498 /* Unmute output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02003499 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3500 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3501 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3502 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003503 /* Set input pins 0x18-0x1c */
Takashi Iwai16ded522005-06-10 19:58:24 +02003504 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3505 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwai05acb862005-06-10 19:50:25 +02003506 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3507 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3508 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003509 /* Mute input pins 0x18-0x1b */
Takashi Iwai05acb862005-06-10 19:50:25 +02003510 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3511 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3512 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3513 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003514 /* ADC set up */
Takashi Iwai05acb862005-06-10 19:50:25 +02003515 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003516 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02003517 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003518 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02003519 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003520 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02003521 /* Analog input/passthru */
3522 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3523 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
3524 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
3525 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
3526 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003527 { }
3528};
3529#endif
3530
Linus Torvalds1da177e2005-04-16 15:20:36 -07003531/*
3532 */
3533
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003534static const char *alc880_models[ALC880_MODEL_LAST] = {
3535 [ALC880_3ST] = "3stack",
3536 [ALC880_TCL_S700] = "tcl",
3537 [ALC880_3ST_DIG] = "3stack-digout",
3538 [ALC880_CLEVO] = "clevo",
3539 [ALC880_5ST] = "5stack",
3540 [ALC880_5ST_DIG] = "5stack-digout",
3541 [ALC880_W810] = "w810",
3542 [ALC880_Z71V] = "z71v",
3543 [ALC880_6ST] = "6stack",
3544 [ALC880_6ST_DIG] = "6stack-digout",
3545 [ALC880_ASUS] = "asus",
3546 [ALC880_ASUS_W1V] = "asus-w1v",
3547 [ALC880_ASUS_DIG] = "asus-dig",
3548 [ALC880_ASUS_DIG2] = "asus-dig2",
3549 [ALC880_UNIWILL_DIG] = "uniwill",
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003550 [ALC880_UNIWILL_P53] = "uniwill-p53",
3551 [ALC880_FUJITSU] = "fujitsu",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003552 [ALC880_F1734] = "F1734",
3553 [ALC880_LG] = "lg",
3554 [ALC880_LG_LW] = "lg-lw",
Takashi Iwaidf99cd32008-04-25 15:25:04 +02003555 [ALC880_MEDION_RIM] = "medion",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003556#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003557 [ALC880_TEST] = "test",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003558#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003559 [ALC880_AUTO] = "auto",
3560};
3561
3562static struct snd_pci_quirk alc880_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003563 SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003564 SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG),
3565 SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST),
3566 SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_3ST_DIG),
3567 SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_6ST_DIG),
3568 SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_6ST_DIG),
3569 SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_6ST_DIG),
3570 SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_3ST_DIG),
3571 SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003572 SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_6ST_DIG),
3573 SND_PCI_QUIRK(0x103c, 0x2a09, "HP", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003574 SND_PCI_QUIRK(0x1043, 0x10b3, "ASUS W1V", ALC880_ASUS_W1V),
3575 SND_PCI_QUIRK(0x1043, 0x10c2, "ASUS W6A", ALC880_ASUS_DIG),
3576 SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS Wxx", ALC880_ASUS_DIG),
3577 SND_PCI_QUIRK(0x1043, 0x1113, "ASUS", ALC880_ASUS_DIG),
3578 SND_PCI_QUIRK(0x1043, 0x1123, "ASUS", ALC880_ASUS_DIG),
3579 SND_PCI_QUIRK(0x1043, 0x1173, "ASUS", ALC880_ASUS_DIG),
3580 SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_Z71V),
3581 /* SND_PCI_QUIRK(0x1043, 0x1964, "ASUS", ALC880_ASUS_DIG), */
3582 SND_PCI_QUIRK(0x1043, 0x1973, "ASUS", ALC880_ASUS_DIG),
3583 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS", ALC880_ASUS_DIG),
Travis Place186c3112008-05-20 11:54:41 +02003584 SND_PCI_QUIRK(0x1043, 0x814e, "ASUS P5GD1 w/SPDIF", ALC880_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003585 SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG),
3586 SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST),
3587 SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST),
Takashi Iwaidea0a502009-02-09 17:14:52 +01003588 SND_PCI_QUIRK_VENDOR(0x1043, "ASUS", ALC880_ASUS), /* default ASUS */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003589 SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003590 SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST),
3591 SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003592 SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_5ST),
3593 SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003594 SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_6ST_DIG),
3595 SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_6ST_DIG),
3596 SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_6ST_DIG),
3597 SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003598 SND_PCI_QUIRK(0x1558, 0x0520, "Clevo m520G", ALC880_CLEVO),
3599 SND_PCI_QUIRK(0x1558, 0x0660, "Clevo m655n", ALC880_CLEVO),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003600 SND_PCI_QUIRK(0x1558, 0x5401, "ASUS", ALC880_ASUS_DIG2),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003601 SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003602 SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_UNIWILL_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003603 SND_PCI_QUIRK(0x1584, 0x9054, "Uniwlll", ALC880_F1734),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003604 SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL),
3605 SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003606 SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810),
Takashi Iwaidf99cd32008-04-25 15:25:04 +02003607 SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_MEDION_RIM),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003608 SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003609 SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003610 SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734),
Travis Place1d116042008-06-23 11:42:30 +02003611 SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FUJITSU),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003612 SND_PCI_QUIRK(0x1734, 0x10ac, "FSC", ALC880_UNIWILL),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003613 SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003614 SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003615 SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG),
3616 SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003617 SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003618 SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700),
3619 SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG), /* broken BIOS */
3620 SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG),
3621 SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003622 SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_5ST_DIG),
3623 SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003624 SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003625 SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003626 SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_3ST_DIG),
3627 SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003628 SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_5ST_DIG),
3629 SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_5ST_DIG),
3630 SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +01003631 /* default Intel */
3632 SND_PCI_QUIRK_VENDOR(0x8086, "Intel mobo", ALC880_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003633 SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG),
3634 SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003635 {}
3636};
3637
Takashi Iwai16ded522005-06-10 19:58:24 +02003638/*
Kailang Yangdf694da2005-12-05 19:42:22 +01003639 * ALC880 codec presets
Takashi Iwai16ded522005-06-10 19:58:24 +02003640 */
Takashi Iwai16ded522005-06-10 19:58:24 +02003641static struct alc_config_preset alc880_presets[] = {
3642 [ALC880_3ST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003643 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003644 .init_verbs = { alc880_volume_init_verbs,
3645 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003646 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02003647 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003648 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
3649 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003650 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003651 .input_mux = &alc880_capture_source,
3652 },
3653 [ALC880_3ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003654 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003655 .init_verbs = { alc880_volume_init_verbs,
3656 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003657 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02003658 .dac_nids = alc880_dac_nids,
3659 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003660 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
3661 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003662 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003663 .input_mux = &alc880_capture_source,
3664 },
Kailang Yangdf694da2005-12-05 19:42:22 +01003665 [ALC880_TCL_S700] = {
3666 .mixers = { alc880_tcl_s700_mixer },
3667 .init_verbs = { alc880_volume_init_verbs,
3668 alc880_pin_tcl_S700_init_verbs,
3669 alc880_gpio2_init_verbs },
3670 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3671 .dac_nids = alc880_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01003672 .adc_nids = alc880_adc_nids_alt, /* FIXME: correct? */
3673 .num_adc_nids = 1, /* single ADC */
Kailang Yangdf694da2005-12-05 19:42:22 +01003674 .hp_nid = 0x03,
3675 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3676 .channel_mode = alc880_2_jack_modes,
3677 .input_mux = &alc880_capture_source,
3678 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003679 [ALC880_5ST] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003680 .mixers = { alc880_three_stack_mixer,
3681 alc880_five_stack_mixer},
3682 .init_verbs = { alc880_volume_init_verbs,
3683 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003684 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3685 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003686 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
3687 .channel_mode = alc880_fivestack_modes,
3688 .input_mux = &alc880_capture_source,
3689 },
3690 [ALC880_5ST_DIG] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003691 .mixers = { alc880_three_stack_mixer,
3692 alc880_five_stack_mixer },
3693 .init_verbs = { alc880_volume_init_verbs,
3694 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003695 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3696 .dac_nids = alc880_dac_nids,
3697 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003698 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
3699 .channel_mode = alc880_fivestack_modes,
3700 .input_mux = &alc880_capture_source,
3701 },
Takashi Iwaib6482d42005-06-27 15:32:43 +02003702 [ALC880_6ST] = {
3703 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003704 .init_verbs = { alc880_volume_init_verbs,
3705 alc880_pin_6stack_init_verbs },
Takashi Iwaib6482d42005-06-27 15:32:43 +02003706 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
3707 .dac_nids = alc880_6st_dac_nids,
3708 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
3709 .channel_mode = alc880_sixstack_modes,
3710 .input_mux = &alc880_6stack_capture_source,
3711 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003712 [ALC880_6ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003713 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003714 .init_verbs = { alc880_volume_init_verbs,
3715 alc880_pin_6stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003716 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
3717 .dac_nids = alc880_6st_dac_nids,
3718 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003719 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
3720 .channel_mode = alc880_sixstack_modes,
3721 .input_mux = &alc880_6stack_capture_source,
3722 },
3723 [ALC880_W810] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003724 .mixers = { alc880_w810_base_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003725 .init_verbs = { alc880_volume_init_verbs,
3726 alc880_pin_w810_init_verbs,
Takashi Iwaib0af0de2005-06-21 14:49:19 +02003727 alc880_gpio2_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003728 .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids),
3729 .dac_nids = alc880_w810_dac_nids,
3730 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003731 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
3732 .channel_mode = alc880_w810_modes,
3733 .input_mux = &alc880_capture_source,
3734 },
3735 [ALC880_Z71V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003736 .mixers = { alc880_z71v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003737 .init_verbs = { alc880_volume_init_verbs,
3738 alc880_pin_z71v_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003739 .num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids),
3740 .dac_nids = alc880_z71v_dac_nids,
3741 .dig_out_nid = ALC880_DIGOUT_NID,
3742 .hp_nid = 0x03,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003743 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3744 .channel_mode = alc880_2_jack_modes,
Takashi Iwai16ded522005-06-10 19:58:24 +02003745 .input_mux = &alc880_capture_source,
3746 },
3747 [ALC880_F1734] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003748 .mixers = { alc880_f1734_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003749 .init_verbs = { alc880_volume_init_verbs,
3750 alc880_pin_f1734_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003751 .num_dacs = ARRAY_SIZE(alc880_f1734_dac_nids),
3752 .dac_nids = alc880_f1734_dac_nids,
3753 .hp_nid = 0x02,
3754 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3755 .channel_mode = alc880_2_jack_modes,
Takashi Iwai937b4162008-02-11 14:52:36 +01003756 .input_mux = &alc880_f1734_capture_source,
3757 .unsol_event = alc880_uniwill_p53_unsol_event,
3758 .init_hook = alc880_uniwill_p53_hp_automute,
Takashi Iwai16ded522005-06-10 19:58:24 +02003759 },
3760 [ALC880_ASUS] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003761 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003762 .init_verbs = { alc880_volume_init_verbs,
3763 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003764 alc880_gpio1_init_verbs },
3765 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3766 .dac_nids = alc880_asus_dac_nids,
3767 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3768 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003769 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003770 .input_mux = &alc880_capture_source,
3771 },
3772 [ALC880_ASUS_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003773 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003774 .init_verbs = { alc880_volume_init_verbs,
3775 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003776 alc880_gpio1_init_verbs },
3777 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3778 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003779 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003780 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3781 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003782 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003783 .input_mux = &alc880_capture_source,
3784 },
Kailang Yangdf694da2005-12-05 19:42:22 +01003785 [ALC880_ASUS_DIG2] = {
3786 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003787 .init_verbs = { alc880_volume_init_verbs,
3788 alc880_pin_asus_init_verbs,
Kailang Yangdf694da2005-12-05 19:42:22 +01003789 alc880_gpio2_init_verbs }, /* use GPIO2 */
3790 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3791 .dac_nids = alc880_asus_dac_nids,
3792 .dig_out_nid = ALC880_DIGOUT_NID,
3793 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3794 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003795 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01003796 .input_mux = &alc880_capture_source,
3797 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003798 [ALC880_ASUS_W1V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003799 .mixers = { alc880_asus_mixer, alc880_asus_w1v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003800 .init_verbs = { alc880_volume_init_verbs,
3801 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003802 alc880_gpio1_init_verbs },
3803 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3804 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003805 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003806 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3807 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003808 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003809 .input_mux = &alc880_capture_source,
3810 },
3811 [ALC880_UNIWILL_DIG] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01003812 .mixers = { alc880_asus_mixer },
Kailang Yangccc656c2006-10-17 12:32:26 +02003813 .init_verbs = { alc880_volume_init_verbs,
3814 alc880_pin_asus_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003815 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3816 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003817 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003818 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3819 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003820 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003821 .input_mux = &alc880_capture_source,
3822 },
Kailang Yangccc656c2006-10-17 12:32:26 +02003823 [ALC880_UNIWILL] = {
3824 .mixers = { alc880_uniwill_mixer },
3825 .init_verbs = { alc880_volume_init_verbs,
3826 alc880_uniwill_init_verbs },
3827 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3828 .dac_nids = alc880_asus_dac_nids,
3829 .dig_out_nid = ALC880_DIGOUT_NID,
3830 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
3831 .channel_mode = alc880_threestack_modes,
3832 .need_dac_fix = 1,
3833 .input_mux = &alc880_capture_source,
3834 .unsol_event = alc880_uniwill_unsol_event,
3835 .init_hook = alc880_uniwill_automute,
3836 },
3837 [ALC880_UNIWILL_P53] = {
3838 .mixers = { alc880_uniwill_p53_mixer },
3839 .init_verbs = { alc880_volume_init_verbs,
3840 alc880_uniwill_p53_init_verbs },
3841 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3842 .dac_nids = alc880_asus_dac_nids,
3843 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003844 .channel_mode = alc880_threestack_modes,
3845 .input_mux = &alc880_capture_source,
3846 .unsol_event = alc880_uniwill_p53_unsol_event,
3847 .init_hook = alc880_uniwill_p53_hp_automute,
3848 },
3849 [ALC880_FUJITSU] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01003850 .mixers = { alc880_fujitsu_mixer },
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003851 .init_verbs = { alc880_volume_init_verbs,
3852 alc880_uniwill_p53_init_verbs,
3853 alc880_beep_init_verbs },
3854 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3855 .dac_nids = alc880_dac_nids,
Takashi Iwaid53d7d92007-08-20 15:20:02 +02003856 .dig_out_nid = ALC880_DIGOUT_NID,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003857 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3858 .channel_mode = alc880_2_jack_modes,
Kailang Yangccc656c2006-10-17 12:32:26 +02003859 .input_mux = &alc880_capture_source,
3860 .unsol_event = alc880_uniwill_p53_unsol_event,
3861 .init_hook = alc880_uniwill_p53_hp_automute,
3862 },
Kailang Yangdf694da2005-12-05 19:42:22 +01003863 [ALC880_CLEVO] = {
3864 .mixers = { alc880_three_stack_mixer },
3865 .init_verbs = { alc880_volume_init_verbs,
3866 alc880_pin_clevo_init_verbs },
3867 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3868 .dac_nids = alc880_dac_nids,
3869 .hp_nid = 0x03,
3870 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
3871 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003872 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01003873 .input_mux = &alc880_capture_source,
3874 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003875 [ALC880_LG] = {
3876 .mixers = { alc880_lg_mixer },
3877 .init_verbs = { alc880_volume_init_verbs,
3878 alc880_lg_init_verbs },
3879 .num_dacs = ARRAY_SIZE(alc880_lg_dac_nids),
3880 .dac_nids = alc880_lg_dac_nids,
3881 .dig_out_nid = ALC880_DIGOUT_NID,
3882 .num_channel_mode = ARRAY_SIZE(alc880_lg_ch_modes),
3883 .channel_mode = alc880_lg_ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003884 .need_dac_fix = 1,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003885 .input_mux = &alc880_lg_capture_source,
3886 .unsol_event = alc880_lg_unsol_event,
3887 .init_hook = alc880_lg_automute,
Takashi Iwaicb53c622007-08-10 17:21:45 +02003888#ifdef CONFIG_SND_HDA_POWER_SAVE
3889 .loopbacks = alc880_lg_loopbacks,
3890#endif
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003891 },
Takashi Iwaid6815182006-03-23 16:06:23 +01003892 [ALC880_LG_LW] = {
3893 .mixers = { alc880_lg_lw_mixer },
3894 .init_verbs = { alc880_volume_init_verbs,
3895 alc880_lg_lw_init_verbs },
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003896 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwaid6815182006-03-23 16:06:23 +01003897 .dac_nids = alc880_dac_nids,
3898 .dig_out_nid = ALC880_DIGOUT_NID,
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003899 .num_channel_mode = ARRAY_SIZE(alc880_lg_lw_modes),
3900 .channel_mode = alc880_lg_lw_modes,
Takashi Iwaid6815182006-03-23 16:06:23 +01003901 .input_mux = &alc880_lg_lw_capture_source,
3902 .unsol_event = alc880_lg_lw_unsol_event,
3903 .init_hook = alc880_lg_lw_automute,
3904 },
Takashi Iwaidf99cd32008-04-25 15:25:04 +02003905 [ALC880_MEDION_RIM] = {
3906 .mixers = { alc880_medion_rim_mixer },
3907 .init_verbs = { alc880_volume_init_verbs,
3908 alc880_medion_rim_init_verbs,
3909 alc_gpio2_init_verbs },
3910 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3911 .dac_nids = alc880_dac_nids,
3912 .dig_out_nid = ALC880_DIGOUT_NID,
3913 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3914 .channel_mode = alc880_2_jack_modes,
3915 .input_mux = &alc880_medion_rim_capture_source,
3916 .unsol_event = alc880_medion_rim_unsol_event,
3917 .init_hook = alc880_medion_rim_automute,
3918 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003919#ifdef CONFIG_SND_DEBUG
3920 [ALC880_TEST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003921 .mixers = { alc880_test_mixer },
3922 .init_verbs = { alc880_test_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003923 .num_dacs = ARRAY_SIZE(alc880_test_dac_nids),
3924 .dac_nids = alc880_test_dac_nids,
3925 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003926 .num_channel_mode = ARRAY_SIZE(alc880_test_modes),
3927 .channel_mode = alc880_test_modes,
3928 .input_mux = &alc880_test_capture_source,
3929 },
3930#endif
3931};
3932
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003933/*
3934 * Automatic parse of I/O pins from the BIOS configuration
3935 */
3936
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003937enum {
3938 ALC_CTL_WIDGET_VOL,
3939 ALC_CTL_WIDGET_MUTE,
3940 ALC_CTL_BIND_MUTE,
3941};
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003942static struct snd_kcontrol_new alc880_control_templates[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003943 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
3944 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Takashi Iwai985be542005-11-02 18:26:49 +01003945 HDA_BIND_MUTE(NULL, 0, 0, 0),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003946};
3947
3948/* add dynamic controls */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003949static int add_control(struct alc_spec *spec, int type, const char *name,
3950 unsigned long val)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003951{
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003952 struct snd_kcontrol_new *knew;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003953
Takashi Iwai603c4012008-07-30 15:01:44 +02003954 snd_array_init(&spec->kctls, sizeof(*knew), 32);
3955 knew = snd_array_new(&spec->kctls);
3956 if (!knew)
3957 return -ENOMEM;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003958 *knew = alc880_control_templates[type];
Paulo Marques543537b2005-06-23 00:09:02 -07003959 knew->name = kstrdup(name, GFP_KERNEL);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003960 if (!knew->name)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003961 return -ENOMEM;
3962 knew->private_value = val;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003963 return 0;
3964}
3965
3966#define alc880_is_fixed_pin(nid) ((nid) >= 0x14 && (nid) <= 0x17)
3967#define alc880_fixed_pin_idx(nid) ((nid) - 0x14)
3968#define alc880_is_multi_pin(nid) ((nid) >= 0x18)
3969#define alc880_multi_pin_idx(nid) ((nid) - 0x18)
3970#define alc880_is_input_pin(nid) ((nid) >= 0x18)
3971#define alc880_input_pin_idx(nid) ((nid) - 0x18)
3972#define alc880_idx_to_dac(nid) ((nid) + 0x02)
3973#define alc880_dac_to_idx(nid) ((nid) - 0x02)
3974#define alc880_idx_to_mixer(nid) ((nid) + 0x0c)
3975#define alc880_idx_to_selector(nid) ((nid) + 0x10)
3976#define ALC880_PIN_CD_NID 0x1c
3977
3978/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003979static int alc880_auto_fill_dac_nids(struct alc_spec *spec,
3980 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003981{
3982 hda_nid_t nid;
3983 int assigned[4];
3984 int i, j;
3985
3986 memset(assigned, 0, sizeof(assigned));
Takashi Iwaib0af0de2005-06-21 14:49:19 +02003987 spec->multiout.dac_nids = spec->private_dac_nids;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003988
3989 /* check the pins hardwired to audio widget */
3990 for (i = 0; i < cfg->line_outs; i++) {
3991 nid = cfg->line_out_pins[i];
3992 if (alc880_is_fixed_pin(nid)) {
3993 int idx = alc880_fixed_pin_idx(nid);
Libin Yang5014f192005-11-23 15:48:36 +01003994 spec->multiout.dac_nids[i] = alc880_idx_to_dac(idx);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003995 assigned[idx] = 1;
3996 }
3997 }
3998 /* left pins can be connect to any audio widget */
3999 for (i = 0; i < cfg->line_outs; i++) {
4000 nid = cfg->line_out_pins[i];
4001 if (alc880_is_fixed_pin(nid))
4002 continue;
4003 /* search for an empty channel */
4004 for (j = 0; j < cfg->line_outs; j++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004005 if (!assigned[j]) {
4006 spec->multiout.dac_nids[i] =
4007 alc880_idx_to_dac(j);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004008 assigned[j] = 1;
4009 break;
4010 }
4011 }
4012 }
4013 spec->multiout.num_dacs = cfg->line_outs;
4014 return 0;
4015}
4016
4017/* add playback controls from the parsed DAC table */
Kailang Yangdf694da2005-12-05 19:42:22 +01004018static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
4019 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004020{
4021 char name[32];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004022 static const char *chname[4] = {
4023 "Front", "Surround", NULL /*CLFE*/, "Side"
4024 };
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004025 hda_nid_t nid;
4026 int i, err;
4027
4028 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004029 if (!spec->multiout.dac_nids[i])
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004030 continue;
4031 nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i]));
4032 if (i == 2) {
4033 /* Center/LFE */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004034 err = add_control(spec, ALC_CTL_WIDGET_VOL,
4035 "Center Playback Volume",
4036 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
4037 HDA_OUTPUT));
4038 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004039 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004040 err = add_control(spec, ALC_CTL_WIDGET_VOL,
4041 "LFE Playback Volume",
4042 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
4043 HDA_OUTPUT));
4044 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004045 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004046 err = add_control(spec, ALC_CTL_BIND_MUTE,
4047 "Center Playback Switch",
4048 HDA_COMPOSE_AMP_VAL(nid, 1, 2,
4049 HDA_INPUT));
4050 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004051 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004052 err = add_control(spec, ALC_CTL_BIND_MUTE,
4053 "LFE Playback Switch",
4054 HDA_COMPOSE_AMP_VAL(nid, 2, 2,
4055 HDA_INPUT));
4056 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004057 return err;
4058 } else {
4059 sprintf(name, "%s Playback Volume", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004060 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
4061 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
4062 HDA_OUTPUT));
4063 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004064 return err;
4065 sprintf(name, "%s Playback Switch", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004066 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
4067 HDA_COMPOSE_AMP_VAL(nid, 3, 2,
4068 HDA_INPUT));
4069 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004070 return err;
4071 }
4072 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004073 return 0;
4074}
4075
Takashi Iwai8d88bc32005-11-17 11:09:23 +01004076/* add playback controls for speaker and HP outputs */
4077static int alc880_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
4078 const char *pfx)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004079{
4080 hda_nid_t nid;
4081 int err;
Takashi Iwai8d88bc32005-11-17 11:09:23 +01004082 char name[32];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004083
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004084 if (!pin)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004085 return 0;
4086
4087 if (alc880_is_fixed_pin(pin)) {
4088 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
Takashi Iwai82bc9552006-03-21 11:24:42 +01004089 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004090 if (!spec->multiout.hp_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004091 spec->multiout.hp_nid = nid;
Takashi Iwai82bc9552006-03-21 11:24:42 +01004092 else
4093 spec->multiout.extra_out_nid[0] = nid;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004094 /* control HP volume/switch on the output mixer amp */
4095 nid = alc880_idx_to_mixer(alc880_fixed_pin_idx(pin));
Takashi Iwai8d88bc32005-11-17 11:09:23 +01004096 sprintf(name, "%s Playback Volume", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004097 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
4098 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
4099 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004100 return err;
Takashi Iwai8d88bc32005-11-17 11:09:23 +01004101 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004102 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
4103 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
4104 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004105 return err;
4106 } else if (alc880_is_multi_pin(pin)) {
4107 /* set manual connection */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004108 /* we have only a switch on HP-out PIN */
Takashi Iwai8d88bc32005-11-17 11:09:23 +01004109 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004110 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
4111 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
4112 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004113 return err;
4114 }
4115 return 0;
4116}
4117
4118/* create input playback/capture controls for the given pin */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004119static int new_analog_input(struct alc_spec *spec, hda_nid_t pin,
4120 const char *ctlname,
Kailang Yangdf694da2005-12-05 19:42:22 +01004121 int idx, hda_nid_t mix_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004122{
4123 char name[32];
Kailang Yangdf694da2005-12-05 19:42:22 +01004124 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004125
4126 sprintf(name, "%s Playback Volume", ctlname);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004127 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
4128 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
4129 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004130 return err;
4131 sprintf(name, "%s Playback Switch", ctlname);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004132 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
4133 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
4134 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004135 return err;
4136 return 0;
4137}
4138
4139/* create playback/capture controls for input pins */
Kailang Yangdf694da2005-12-05 19:42:22 +01004140static int alc880_auto_create_analog_input_ctls(struct alc_spec *spec,
4141 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004142{
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02004143 struct hda_input_mux *imux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01004144 int i, err, idx;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004145
4146 for (i = 0; i < AUTO_PIN_LAST; i++) {
4147 if (alc880_is_input_pin(cfg->input_pins[i])) {
Kailang Yangdf694da2005-12-05 19:42:22 +01004148 idx = alc880_input_pin_idx(cfg->input_pins[i]);
Takashi Iwai4a471b72005-12-07 13:56:29 +01004149 err = new_analog_input(spec, cfg->input_pins[i],
4150 auto_pin_cfg_labels[i],
Kailang Yangdf694da2005-12-05 19:42:22 +01004151 idx, 0x0b);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004152 if (err < 0)
4153 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004154 imux->items[imux->num_items].label =
4155 auto_pin_cfg_labels[i];
4156 imux->items[imux->num_items].index =
4157 alc880_input_pin_idx(cfg->input_pins[i]);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004158 imux->num_items++;
4159 }
4160 }
4161 return 0;
4162}
4163
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004164static void alc_set_pin_output(struct hda_codec *codec, hda_nid_t nid,
4165 unsigned int pin_type)
4166{
4167 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
4168 pin_type);
4169 /* unmute pin */
Takashi Iwaid260cdf2008-02-13 17:19:35 +01004170 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
4171 AMP_OUT_UNMUTE);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004172}
4173
Kailang Yangdf694da2005-12-05 19:42:22 +01004174static void alc880_auto_set_output_and_unmute(struct hda_codec *codec,
4175 hda_nid_t nid, int pin_type,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004176 int dac_idx)
4177{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004178 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004179 /* need the manual connection? */
4180 if (alc880_is_multi_pin(nid)) {
4181 struct alc_spec *spec = codec->spec;
4182 int idx = alc880_multi_pin_idx(nid);
4183 snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
4184 AC_VERB_SET_CONNECT_SEL,
4185 alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
4186 }
4187}
4188
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02004189static int get_pin_type(int line_out_type)
4190{
4191 if (line_out_type == AUTO_PIN_HP_OUT)
4192 return PIN_HP;
4193 else
4194 return PIN_OUT;
4195}
4196
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004197static void alc880_auto_init_multi_out(struct hda_codec *codec)
4198{
4199 struct alc_spec *spec = codec->spec;
4200 int i;
Kailang Yangea1fb292008-08-26 12:58:38 +02004201
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004202 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004203 for (i = 0; i < spec->autocfg.line_outs; i++) {
4204 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02004205 int pin_type = get_pin_type(spec->autocfg.line_out_type);
4206 alc880_auto_set_output_and_unmute(codec, nid, pin_type, i);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004207 }
4208}
4209
Takashi Iwai8d88bc32005-11-17 11:09:23 +01004210static void alc880_auto_init_extra_out(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004211{
4212 struct alc_spec *spec = codec->spec;
4213 hda_nid_t pin;
4214
Takashi Iwai82bc9552006-03-21 11:24:42 +01004215 pin = spec->autocfg.speaker_pins[0];
Takashi Iwai8d88bc32005-11-17 11:09:23 +01004216 if (pin) /* connect to front */
4217 alc880_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02004218 pin = spec->autocfg.hp_pins[0];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004219 if (pin) /* connect to front */
4220 alc880_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
4221}
4222
4223static void alc880_auto_init_analog_input(struct hda_codec *codec)
4224{
4225 struct alc_spec *spec = codec->spec;
4226 int i;
4227
4228 for (i = 0; i < AUTO_PIN_LAST; i++) {
4229 hda_nid_t nid = spec->autocfg.input_pins[i];
4230 if (alc880_is_input_pin(nid)) {
Takashi Iwai23f0c042009-02-26 13:03:58 +01004231 alc_set_input_pin(codec, nid, i);
Takashi Iwaie82c0252009-03-23 15:17:38 +01004232 if (nid != ALC880_PIN_CD_NID &&
4233 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004234 snd_hda_codec_write(codec, nid, 0,
4235 AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004236 AMP_OUT_MUTE);
4237 }
4238 }
4239}
4240
4241/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004242/* return 1 if successful, 0 if the proper config is not found,
4243 * or a negative error code
4244 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004245static int alc880_parse_auto_config(struct hda_codec *codec)
4246{
4247 struct alc_spec *spec = codec->spec;
Takashi Iwai6a05ac42009-02-13 11:19:09 +01004248 int i, err;
Kailang Yangdf694da2005-12-05 19:42:22 +01004249 static hda_nid_t alc880_ignore[] = { 0x1d, 0 };
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004250
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004251 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
4252 alc880_ignore);
4253 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004254 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004255 if (!spec->autocfg.line_outs)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004256 return 0; /* can't find valid BIOS pin config */
Kailang Yangdf694da2005-12-05 19:42:22 +01004257
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004258 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
4259 if (err < 0)
4260 return err;
4261 err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
4262 if (err < 0)
4263 return err;
4264 err = alc880_auto_create_extra_out(spec,
4265 spec->autocfg.speaker_pins[0],
4266 "Speaker");
4267 if (err < 0)
4268 return err;
4269 err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
4270 "Headphone");
4271 if (err < 0)
4272 return err;
4273 err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg);
4274 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004275 return err;
4276
4277 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
4278
Takashi Iwai6a05ac42009-02-13 11:19:09 +01004279 /* check multiple SPDIF-out (for recent codecs) */
4280 for (i = 0; i < spec->autocfg.dig_outs; i++) {
4281 hda_nid_t dig_nid;
4282 err = snd_hda_get_connections(codec,
4283 spec->autocfg.dig_out_pins[i],
4284 &dig_nid, 1);
4285 if (err < 0)
4286 continue;
4287 if (!i)
4288 spec->multiout.dig_out_nid = dig_nid;
4289 else {
4290 spec->multiout.slave_dig_outs = spec->slave_dig_outs;
4291 spec->slave_dig_outs[i - 1] = dig_nid;
4292 if (i == ARRAY_SIZE(spec->slave_dig_outs) - 1)
4293 break;
4294 }
4295 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004296 if (spec->autocfg.dig_in_pin)
4297 spec->dig_in_nid = ALC880_DIGIN_NID;
4298
Takashi Iwai603c4012008-07-30 15:01:44 +02004299 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +01004300 add_mixer(spec, spec->kctls.list);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004301
Takashi Iwaid88897e2008-10-31 15:01:37 +01004302 add_verb(spec, alc880_volume_init_verbs);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004303
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004304 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02004305 spec->input_mux = &spec->private_imux[0];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004306
4307 return 1;
4308}
4309
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004310/* additional initialization for auto-configuration model */
4311static void alc880_auto_init(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004312{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004313 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004314 alc880_auto_init_multi_out(codec);
Takashi Iwai8d88bc32005-11-17 11:09:23 +01004315 alc880_auto_init_extra_out(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004316 alc880_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004317 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02004318 alc_inithook(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004319}
4320
Takashi Iwaif9e336f2008-10-31 16:37:07 +01004321static void set_capture_mixer(struct alc_spec *spec)
4322{
Takashi Iwaia23b6882009-03-23 15:21:36 +01004323 static struct snd_kcontrol_new *caps[2][3] = {
4324 { alc_capture_mixer_nosrc1,
4325 alc_capture_mixer_nosrc2,
4326 alc_capture_mixer_nosrc3 },
4327 { alc_capture_mixer1,
4328 alc_capture_mixer2,
4329 alc_capture_mixer3 },
Takashi Iwaif9e336f2008-10-31 16:37:07 +01004330 };
Takashi Iwaia23b6882009-03-23 15:21:36 +01004331 if (spec->num_adc_nids > 0 && spec->num_adc_nids <= 3) {
4332 int mux;
4333 if (spec->input_mux && spec->input_mux->num_items > 1)
4334 mux = 1;
4335 else
4336 mux = 0;
4337 spec->cap_mixer = caps[mux][spec->num_adc_nids - 1];
4338 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01004339}
4340
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01004341#define set_beep_amp(spec, nid, idx, dir) \
4342 ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir))
4343
4344/*
4345 * OK, here we have finally the patch for ALC880
4346 */
4347
Linus Torvalds1da177e2005-04-16 15:20:36 -07004348static int patch_alc880(struct hda_codec *codec)
4349{
4350 struct alc_spec *spec;
4351 int board_config;
Kailang Yangdf694da2005-12-05 19:42:22 +01004352 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004353
Takashi Iwaie560d8d2005-09-09 14:21:46 +02004354 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004355 if (spec == NULL)
4356 return -ENOMEM;
4357
4358 codec->spec = spec;
4359
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004360 board_config = snd_hda_check_board_config(codec, ALC880_MODEL_LAST,
4361 alc880_models,
4362 alc880_cfg_tbl);
4363 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004364 printk(KERN_INFO "hda_codec: Unknown model for ALC880, "
4365 "trying auto-probe from BIOS...\n");
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004366 board_config = ALC880_AUTO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004367 }
4368
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004369 if (board_config == ALC880_AUTO) {
4370 /* automatic parse from the BIOS config */
4371 err = alc880_parse_auto_config(codec);
4372 if (err < 0) {
4373 alc_free(codec);
4374 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004375 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004376 printk(KERN_INFO
4377 "hda_codec: Cannot set up configuration "
4378 "from BIOS. Using 3-stack mode...\n");
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004379 board_config = ALC880_3ST;
4380 }
4381 }
4382
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09004383 err = snd_hda_attach_beep_device(codec, 0x1);
4384 if (err < 0) {
4385 alc_free(codec);
4386 return err;
4387 }
4388
Kailang Yangdf694da2005-12-05 19:42:22 +01004389 if (board_config != ALC880_AUTO)
4390 setup_preset(spec, &alc880_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004391
4392 spec->stream_name_analog = "ALC880 Analog";
4393 spec->stream_analog_playback = &alc880_pcm_analog_playback;
4394 spec->stream_analog_capture = &alc880_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01004395 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004396
4397 spec->stream_name_digital = "ALC880 Digital";
4398 spec->stream_digital_playback = &alc880_pcm_digital_playback;
4399 spec->stream_digital_capture = &alc880_pcm_digital_capture;
4400
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004401 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004402 /* check whether NID 0x07 is valid */
Takashi Iwai54d17402005-11-21 16:33:22 +01004403 unsigned int wcap = get_wcaps(codec, alc880_adc_nids[0]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004404 /* get type */
4405 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004406 if (wcap != AC_WID_AUD_IN) {
4407 spec->adc_nids = alc880_adc_nids_alt;
4408 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids_alt);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004409 } else {
4410 spec->adc_nids = alc880_adc_nids;
4411 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004412 }
4413 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01004414 set_capture_mixer(spec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01004415 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004416
Takashi Iwai2134ea42008-01-10 16:53:55 +01004417 spec->vmaster_nid = 0x0c;
4418
Linus Torvalds1da177e2005-04-16 15:20:36 -07004419 codec->patch_ops = alc_patch_ops;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004420 if (board_config == ALC880_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004421 spec->init_hook = alc880_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02004422#ifdef CONFIG_SND_HDA_POWER_SAVE
4423 if (!spec->loopback.amplist)
4424 spec->loopback.amplist = alc880_loopbacks;
4425#endif
Takashi Iwaidaead532008-11-28 12:55:36 +01004426 codec->proc_widget_hook = print_realtek_coef;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004427
4428 return 0;
4429}
4430
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004431
Linus Torvalds1da177e2005-04-16 15:20:36 -07004432/*
4433 * ALC260 support
4434 */
4435
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004436static hda_nid_t alc260_dac_nids[1] = {
4437 /* front */
4438 0x02,
4439};
4440
4441static hda_nid_t alc260_adc_nids[1] = {
4442 /* ADC0 */
4443 0x04,
4444};
4445
Kailang Yangdf694da2005-12-05 19:42:22 +01004446static hda_nid_t alc260_adc_nids_alt[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004447 /* ADC1 */
4448 0x05,
4449};
4450
Jonathan Woithed57fdac2006-02-28 11:38:35 +01004451/* NIDs used when simultaneous access to both ADCs makes sense. Note that
4452 * alc260_capture_mixer assumes ADC0 (nid 0x04) is the first ADC.
4453 */
4454static hda_nid_t alc260_dual_adc_nids[2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004455 /* ADC0, ADC1 */
4456 0x04, 0x05
4457};
4458
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004459#define ALC260_DIGOUT_NID 0x03
4460#define ALC260_DIGIN_NID 0x06
4461
4462static struct hda_input_mux alc260_capture_source = {
4463 .num_items = 4,
4464 .items = {
4465 { "Mic", 0x0 },
4466 { "Front Mic", 0x1 },
4467 { "Line", 0x2 },
4468 { "CD", 0x4 },
4469 },
4470};
4471
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01004472/* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004473 * headphone jack and the internal CD lines since these are the only pins at
4474 * which audio can appear. For flexibility, also allow the option of
4475 * recording the mixer output on the second ADC (ADC0 doesn't have a
4476 * connection to the mixer output).
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004477 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004478static struct hda_input_mux alc260_fujitsu_capture_sources[2] = {
4479 {
4480 .num_items = 3,
4481 .items = {
4482 { "Mic/Line", 0x0 },
4483 { "CD", 0x4 },
4484 { "Headphone", 0x2 },
4485 },
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004486 },
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004487 {
4488 .num_items = 4,
4489 .items = {
4490 { "Mic/Line", 0x0 },
4491 { "CD", 0x4 },
4492 { "Headphone", 0x2 },
4493 { "Mixer", 0x5 },
4494 },
4495 },
4496
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004497};
4498
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004499/* Acer TravelMate(/Extensa/Aspire) notebooks have similar configuration to
4500 * the Fujitsu S702x, but jacks are marked differently.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004501 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004502static struct hda_input_mux alc260_acer_capture_sources[2] = {
4503 {
4504 .num_items = 4,
4505 .items = {
4506 { "Mic", 0x0 },
4507 { "Line", 0x2 },
4508 { "CD", 0x4 },
4509 { "Headphone", 0x5 },
4510 },
4511 },
4512 {
4513 .num_items = 5,
4514 .items = {
4515 { "Mic", 0x0 },
4516 { "Line", 0x2 },
4517 { "CD", 0x4 },
4518 { "Headphone", 0x6 },
4519 { "Mixer", 0x5 },
4520 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004521 },
4522};
Michael Schwingencc959482009-02-22 18:58:45 +01004523
4524/* Maxdata Favorit 100XS */
4525static struct hda_input_mux alc260_favorit100_capture_sources[2] = {
4526 {
4527 .num_items = 2,
4528 .items = {
4529 { "Line/Mic", 0x0 },
4530 { "CD", 0x4 },
4531 },
4532 },
4533 {
4534 .num_items = 3,
4535 .items = {
4536 { "Line/Mic", 0x0 },
4537 { "CD", 0x4 },
4538 { "Mixer", 0x5 },
4539 },
4540 },
4541};
4542
Linus Torvalds1da177e2005-04-16 15:20:36 -07004543/*
4544 * This is just place-holder, so there's something for alc_build_pcms to look
4545 * at when it calculates the maximum number of channels. ALC260 has no mixer
4546 * element which allows changing the channel mode, so the verb list is
4547 * never used.
4548 */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01004549static struct hda_channel_mode alc260_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004550 { 2, NULL },
4551};
4552
Kailang Yangdf694da2005-12-05 19:42:22 +01004553
4554/* Mixer combinations
4555 *
4556 * basic: base_output + input + pc_beep + capture
4557 * HP: base_output + input + capture_alt
4558 * HP_3013: hp_3013 + input + capture
4559 * fujitsu: fujitsu + capture
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004560 * acer: acer + capture
Kailang Yangdf694da2005-12-05 19:42:22 +01004561 */
4562
4563static struct snd_kcontrol_new alc260_base_output_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02004564 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01004565 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01004566 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
4567 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
4568 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
4569 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
4570 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004571};
Kailang Yangdf694da2005-12-05 19:42:22 +01004572
4573static struct snd_kcontrol_new alc260_input_mixer[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004574 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4575 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
4576 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
4577 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
4578 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
4579 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
4580 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT),
4581 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004582 { } /* end */
4583};
4584
Takashi Iwaibec15c32008-01-28 18:16:30 +01004585/* update HP, line and mono out pins according to the master switch */
4586static void alc260_hp_master_update(struct hda_codec *codec,
4587 hda_nid_t hp, hda_nid_t line,
4588 hda_nid_t mono)
4589{
4590 struct alc_spec *spec = codec->spec;
4591 unsigned int val = spec->master_sw ? PIN_HP : 0;
4592 /* change HP and line-out pins */
Takashi Iwai30cde0a2008-11-07 14:49:28 +01004593 snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwaibec15c32008-01-28 18:16:30 +01004594 val);
Takashi Iwai30cde0a2008-11-07 14:49:28 +01004595 snd_hda_codec_write(codec, line, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwaibec15c32008-01-28 18:16:30 +01004596 val);
4597 /* mono (speaker) depending on the HP jack sense */
4598 val = (val && !spec->jack_present) ? PIN_OUT : 0;
Takashi Iwai30cde0a2008-11-07 14:49:28 +01004599 snd_hda_codec_write(codec, mono, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwaibec15c32008-01-28 18:16:30 +01004600 val);
4601}
4602
4603static int alc260_hp_master_sw_get(struct snd_kcontrol *kcontrol,
4604 struct snd_ctl_elem_value *ucontrol)
4605{
4606 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4607 struct alc_spec *spec = codec->spec;
4608 *ucontrol->value.integer.value = spec->master_sw;
4609 return 0;
4610}
4611
4612static int alc260_hp_master_sw_put(struct snd_kcontrol *kcontrol,
4613 struct snd_ctl_elem_value *ucontrol)
4614{
4615 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4616 struct alc_spec *spec = codec->spec;
4617 int val = !!*ucontrol->value.integer.value;
4618 hda_nid_t hp, line, mono;
4619
4620 if (val == spec->master_sw)
4621 return 0;
4622 spec->master_sw = val;
4623 hp = (kcontrol->private_value >> 16) & 0xff;
4624 line = (kcontrol->private_value >> 8) & 0xff;
4625 mono = kcontrol->private_value & 0xff;
4626 alc260_hp_master_update(codec, hp, line, mono);
4627 return 1;
4628}
4629
4630static struct snd_kcontrol_new alc260_hp_output_mixer[] = {
4631 {
4632 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4633 .name = "Master Playback Switch",
4634 .info = snd_ctl_boolean_mono_info,
4635 .get = alc260_hp_master_sw_get,
4636 .put = alc260_hp_master_sw_put,
4637 .private_value = (0x0f << 16) | (0x10 << 8) | 0x11
4638 },
4639 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4640 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
4641 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
4642 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
4643 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
4644 HDA_OUTPUT),
4645 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2, HDA_INPUT),
4646 { } /* end */
4647};
4648
4649static struct hda_verb alc260_hp_unsol_verbs[] = {
4650 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
4651 {},
4652};
4653
4654static void alc260_hp_automute(struct hda_codec *codec)
4655{
4656 struct alc_spec *spec = codec->spec;
4657 unsigned int present;
4658
4659 present = snd_hda_codec_read(codec, 0x10, 0,
4660 AC_VERB_GET_PIN_SENSE, 0);
4661 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
4662 alc260_hp_master_update(codec, 0x0f, 0x10, 0x11);
4663}
4664
4665static void alc260_hp_unsol_event(struct hda_codec *codec, unsigned int res)
4666{
4667 if ((res >> 26) == ALC880_HP_EVENT)
4668 alc260_hp_automute(codec);
4669}
4670
Kailang Yangdf694da2005-12-05 19:42:22 +01004671static struct snd_kcontrol_new alc260_hp_3013_mixer[] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01004672 {
4673 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4674 .name = "Master Playback Switch",
4675 .info = snd_ctl_boolean_mono_info,
4676 .get = alc260_hp_master_sw_get,
4677 .put = alc260_hp_master_sw_put,
Takashi Iwai30cde0a2008-11-07 14:49:28 +01004678 .private_value = (0x15 << 16) | (0x10 << 8) | 0x11
Takashi Iwaibec15c32008-01-28 18:16:30 +01004679 },
Kailang Yangdf694da2005-12-05 19:42:22 +01004680 HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT),
4681 HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT),
4682 HDA_CODEC_VOLUME("Aux-In Playback Volume", 0x07, 0x06, HDA_INPUT),
4683 HDA_CODEC_MUTE("Aux-In Playback Switch", 0x07, 0x06, HDA_INPUT),
4684 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4685 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01004686 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
4687 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02004688 { } /* end */
4689};
4690
Kailang Yang3f878302008-08-26 13:02:23 +02004691static struct hda_bind_ctls alc260_dc7600_bind_master_vol = {
4692 .ops = &snd_hda_bind_vol,
4693 .values = {
4694 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_OUTPUT),
4695 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_OUTPUT),
4696 HDA_COMPOSE_AMP_VAL(0x0a, 3, 0, HDA_OUTPUT),
4697 0
4698 },
4699};
4700
4701static struct hda_bind_ctls alc260_dc7600_bind_switch = {
4702 .ops = &snd_hda_bind_sw,
4703 .values = {
4704 HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT),
4705 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
4706 0
4707 },
4708};
4709
4710static struct snd_kcontrol_new alc260_hp_dc7600_mixer[] = {
4711 HDA_BIND_VOL("Master Playback Volume", &alc260_dc7600_bind_master_vol),
4712 HDA_BIND_SW("LineOut Playback Switch", &alc260_dc7600_bind_switch),
4713 HDA_CODEC_MUTE("Speaker Playback Switch", 0x0f, 0x0, HDA_OUTPUT),
4714 HDA_CODEC_MUTE("Headphone Playback Switch", 0x10, 0x0, HDA_OUTPUT),
4715 { } /* end */
4716};
4717
Takashi Iwaibec15c32008-01-28 18:16:30 +01004718static struct hda_verb alc260_hp_3013_unsol_verbs[] = {
4719 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
4720 {},
4721};
4722
4723static void alc260_hp_3013_automute(struct hda_codec *codec)
4724{
4725 struct alc_spec *spec = codec->spec;
4726 unsigned int present;
4727
4728 present = snd_hda_codec_read(codec, 0x15, 0,
4729 AC_VERB_GET_PIN_SENSE, 0);
4730 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
Takashi Iwai30cde0a2008-11-07 14:49:28 +01004731 alc260_hp_master_update(codec, 0x15, 0x10, 0x11);
Takashi Iwaibec15c32008-01-28 18:16:30 +01004732}
4733
4734static void alc260_hp_3013_unsol_event(struct hda_codec *codec,
4735 unsigned int res)
4736{
4737 if ((res >> 26) == ALC880_HP_EVENT)
4738 alc260_hp_3013_automute(codec);
4739}
4740
Kailang Yang3f878302008-08-26 13:02:23 +02004741static void alc260_hp_3012_automute(struct hda_codec *codec)
4742{
4743 unsigned int present, bits;
4744
4745 present = snd_hda_codec_read(codec, 0x10, 0,
4746 AC_VERB_GET_PIN_SENSE, 0) & AC_PINSENSE_PRESENCE;
4747
4748 bits = present ? 0 : PIN_OUT;
4749 snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
4750 bits);
4751 snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
4752 bits);
4753 snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
4754 bits);
4755}
4756
4757static void alc260_hp_3012_unsol_event(struct hda_codec *codec,
4758 unsigned int res)
4759{
4760 if ((res >> 26) == ALC880_HP_EVENT)
4761 alc260_hp_3012_automute(codec);
4762}
4763
4764/* Fujitsu S702x series laptops. ALC260 pin usage: Mic/Line jack = 0x12,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004765 * HP jack = 0x14, CD audio = 0x16, internal speaker = 0x10.
4766 */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01004767static struct snd_kcontrol_new alc260_fujitsu_mixer[] = {
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004768 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01004769 HDA_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004770 ALC_PIN_MODE("Headphone Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004771 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4772 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
4773 HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT),
4774 HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004775 ALC_PIN_MODE("Mic/Line Jack Mode", 0x12, ALC_PIN_DIR_IN),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01004776 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT),
4777 HDA_BIND_MUTE("Speaker Playback Switch", 0x09, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01004778 { } /* end */
4779};
4780
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004781/* Mixer for Acer TravelMate(/Extensa/Aspire) notebooks. Note that current
4782 * versions of the ALC260 don't act on requests to enable mic bias from NID
4783 * 0x0f (used to drive the headphone jack in these laptops). The ALC260
4784 * datasheet doesn't mention this restriction. At this stage it's not clear
4785 * whether this behaviour is intentional or is a hardware bug in chip
4786 * revisions available in early 2006. Therefore for now allow the
4787 * "Headphone Jack Mode" control to span all choices, but if it turns out
4788 * that the lack of mic bias for this NID is intentional we could change the
4789 * mode from ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
4790 *
4791 * In addition, Acer TravelMate(/Extensa/Aspire) notebooks in early 2006
4792 * don't appear to make the mic bias available from the "line" jack, even
4793 * though the NID used for this jack (0x14) can supply it. The theory is
4794 * that perhaps Acer have included blocking capacitors between the ALC260
4795 * and the output jack. If this turns out to be the case for all such
4796 * models the "Line Jack Mode" mode could be changed from ALC_PIN_DIR_INOUT
4797 * to ALC_PIN_DIR_INOUT_NOMICBIAS.
Jonathan Woithebd869482006-11-28 11:35:52 +01004798 *
4799 * The C20x Tablet series have a mono internal speaker which is controlled
4800 * via the chip's Mono sum widget and pin complex, so include the necessary
4801 * controls for such models. On models without a "mono speaker" the control
4802 * won't do anything.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004803 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004804static struct snd_kcontrol_new alc260_acer_mixer[] = {
4805 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4806 HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004807 ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01004808 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
Jonathan Woithebd869482006-11-28 11:35:52 +01004809 HDA_OUTPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01004810 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2,
Jonathan Woithebd869482006-11-28 11:35:52 +01004811 HDA_INPUT),
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004812 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4813 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
4814 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
4815 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
4816 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
4817 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
4818 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
4819 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004820 { } /* end */
4821};
4822
Michael Schwingencc959482009-02-22 18:58:45 +01004823/* Maxdata Favorit 100XS: one output and one input (0x12) jack
4824 */
4825static struct snd_kcontrol_new alc260_favorit100_mixer[] = {
4826 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4827 HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
4828 ALC_PIN_MODE("Output Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
4829 HDA_CODEC_VOLUME("Line/Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
4830 HDA_CODEC_MUTE("Line/Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
4831 ALC_PIN_MODE("Line/Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
4832 { } /* end */
4833};
4834
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004835/* Packard bell V7900 ALC260 pin usage: HP = 0x0f, Mic jack = 0x12,
4836 * Line In jack = 0x14, CD audio = 0x16, pc beep = 0x17.
4837 */
4838static struct snd_kcontrol_new alc260_will_mixer[] = {
4839 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4840 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
4841 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
4842 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
4843 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
4844 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
4845 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
4846 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
4847 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4848 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004849 { } /* end */
4850};
4851
4852/* Replacer 672V ALC260 pin usage: Mic jack = 0x12,
4853 * Line In jack = 0x14, ATAPI Mic = 0x13, speaker = 0x0f.
4854 */
4855static struct snd_kcontrol_new alc260_replacer_672v_mixer[] = {
4856 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4857 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
4858 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
4859 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
4860 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
4861 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x07, 0x1, HDA_INPUT),
4862 HDA_CODEC_MUTE("ATATI Mic Playback Switch", 0x07, 0x1, HDA_INPUT),
4863 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
4864 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
4865 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
4866 { } /* end */
4867};
4868
Kailang Yangdf694da2005-12-05 19:42:22 +01004869/*
4870 * initialization verbs
4871 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004872static struct hda_verb alc260_init_verbs[] = {
4873 /* Line In pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02004874 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004875 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02004876 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004877 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02004878 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004879 /* Mic2 (front panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02004880 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004881 /* LINE-2 is used for line-out in rear */
Takashi Iwai05acb862005-06-10 19:50:25 +02004882 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004883 /* select line-out */
Jonathan Woithefd56f2d2006-01-24 10:35:46 +01004884 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004885 /* LINE-OUT pin */
Takashi Iwai05acb862005-06-10 19:50:25 +02004886 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004887 /* enable HP */
Takashi Iwai05acb862005-06-10 19:50:25 +02004888 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004889 /* enable Mono */
Takashi Iwai05acb862005-06-10 19:50:25 +02004890 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4891 /* mute capture amp left and right */
Takashi Iwai16ded522005-06-10 19:58:24 +02004892 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004893 /* set connection select to line in (default select for this ADC) */
4894 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai16ded522005-06-10 19:58:24 +02004895 /* mute capture amp left and right */
4896 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4897 /* set connection select to line in (default select for this ADC) */
4898 {0x05, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai05acb862005-06-10 19:50:25 +02004899 /* set vol=0 Line-Out mixer amp left and right */
4900 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4901 /* unmute pin widget amp left and right (no gain on this amp) */
4902 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4903 /* set vol=0 HP mixer amp left and right */
4904 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4905 /* unmute pin widget amp left and right (no gain on this amp) */
4906 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4907 /* set vol=0 Mono mixer amp left and right */
4908 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4909 /* unmute pin widget amp left and right (no gain on this amp) */
4910 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4911 /* unmute LINE-2 out pin */
4912 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004913 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
4914 * Line In 2 = 0x03
4915 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02004916 /* mute analog inputs */
4917 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4918 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4919 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4920 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4921 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004922 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
Takashi Iwai05acb862005-06-10 19:50:25 +02004923 /* mute Front out path */
4924 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4925 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4926 /* mute Headphone out path */
4927 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4928 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4929 /* mute Mono out path */
4930 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4931 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004932 { }
4933};
4934
Takashi Iwai474167d2006-05-17 17:17:43 +02004935#if 0 /* should be identical with alc260_init_verbs? */
Kailang Yangdf694da2005-12-05 19:42:22 +01004936static struct hda_verb alc260_hp_init_verbs[] = {
4937 /* Headphone and output */
4938 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
4939 /* mono output */
4940 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4941 /* Mic1 (rear panel) pin widget for input and vref at 80% */
4942 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4943 /* Mic2 (front panel) pin widget for input and vref at 80% */
4944 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4945 /* Line In pin widget for input */
4946 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4947 /* Line-2 pin widget for output */
4948 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4949 /* CD pin widget for input */
4950 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4951 /* unmute amp left and right */
4952 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
4953 /* set connection select to line in (default select for this ADC) */
4954 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
4955 /* unmute Line-Out mixer amp left and right (volume = 0) */
4956 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
4957 /* mute pin widget amp left and right (no gain on this amp) */
4958 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
4959 /* unmute HP mixer amp left and right (volume = 0) */
4960 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
4961 /* mute pin widget amp left and right (no gain on this amp) */
4962 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004963 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
4964 * Line In 2 = 0x03
4965 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02004966 /* mute analog inputs */
4967 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4968 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4969 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4970 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4971 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01004972 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
4973 /* Unmute Front out path */
4974 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4975 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4976 /* Unmute Headphone out path */
4977 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4978 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4979 /* Unmute Mono out path */
4980 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4981 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4982 { }
4983};
Takashi Iwai474167d2006-05-17 17:17:43 +02004984#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01004985
4986static struct hda_verb alc260_hp_3013_init_verbs[] = {
4987 /* Line out and output */
4988 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4989 /* mono output */
4990 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4991 /* Mic1 (rear panel) pin widget for input and vref at 80% */
4992 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4993 /* Mic2 (front panel) pin widget for input and vref at 80% */
4994 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4995 /* Line In pin widget for input */
4996 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4997 /* Headphone pin widget for output */
4998 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
4999 /* CD pin widget for input */
5000 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
5001 /* unmute amp left and right */
5002 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
5003 /* set connection select to line in (default select for this ADC) */
5004 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
5005 /* unmute Line-Out mixer amp left and right (volume = 0) */
5006 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
5007 /* mute pin widget amp left and right (no gain on this amp) */
5008 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
5009 /* unmute HP mixer amp left and right (volume = 0) */
5010 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
5011 /* mute pin widget amp left and right (no gain on this amp) */
5012 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005013 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
5014 * Line In 2 = 0x03
5015 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02005016 /* mute analog inputs */
5017 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5018 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5019 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5020 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5021 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01005022 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
5023 /* Unmute Front out path */
5024 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5025 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
5026 /* Unmute Headphone out path */
5027 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5028 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
5029 /* Unmute Mono out path */
5030 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5031 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
5032 { }
5033};
5034
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005035/* Initialisation sequence for ALC260 as configured in Fujitsu S702x
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005036 * laptops. ALC260 pin usage: Mic/Line jack = 0x12, HP jack = 0x14, CD
5037 * audio = 0x16, internal speaker = 0x10.
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005038 */
5039static struct hda_verb alc260_fujitsu_init_verbs[] = {
5040 /* Disable all GPIOs */
5041 {0x01, AC_VERB_SET_GPIO_MASK, 0},
5042 /* Internal speaker is connected to headphone pin */
5043 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5044 /* Headphone/Line-out jack connects to Line1 pin; make it an output */
5045 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Jonathan Woithef7ace402006-02-28 11:46:14 +01005046 /* Mic/Line-in jack is connected to mic1 pin, so make it an input */
5047 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
5048 /* Ensure all other unused pins are disabled and muted. */
5049 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5050 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005051 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01005052 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005053 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01005054 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5055 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5056 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005057
Jonathan Woithef7ace402006-02-28 11:46:14 +01005058 /* Disable digital (SPDIF) pins */
5059 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
5060 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01005061
Kailang Yangea1fb292008-08-26 12:58:38 +02005062 /* Ensure Line1 pin widget takes its input from the OUT1 sum bus
Jonathan Woithef7ace402006-02-28 11:46:14 +01005063 * when acting as an output.
5064 */
5065 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
5066
5067 /* Start with output sum widgets muted and their output gains at min */
Takashi Iwai8b33a5a2006-02-09 11:57:01 +01005068 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5069 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5070 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5071 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5072 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5073 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5074 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5075 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5076 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005077
Jonathan Woithef7ace402006-02-28 11:46:14 +01005078 /* Unmute HP pin widget amp left and right (no equiv mixer ctrl) */
5079 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5080 /* Unmute Line1 pin widget output buffer since it starts as an output.
5081 * If the pin mode is changed by the user the pin mode control will
5082 * take care of enabling the pin's input/output buffers as needed.
5083 * Therefore there's no need to enable the input buffer at this
5084 * stage.
Jonathan Woithecdcd9262006-02-28 11:36:42 +01005085 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01005086 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +02005087 /* Unmute input buffer of pin widget used for Line-in (no equiv
Jonathan Woithecdcd9262006-02-28 11:36:42 +01005088 * mixer ctrl)
5089 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01005090 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005091
Jonathan Woithef7ace402006-02-28 11:46:14 +01005092 /* Mute capture amp left and right */
5093 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +02005094 /* Set ADC connection select to match default mixer setting - line
Jonathan Woithef7ace402006-02-28 11:46:14 +01005095 * in (on mic1 pin)
5096 */
5097 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005098
Jonathan Woithef7ace402006-02-28 11:46:14 +01005099 /* Do the same for the second ADC: mute capture input amp and
5100 * set ADC connection to line in (on mic1 pin)
5101 */
5102 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5103 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01005104
Jonathan Woithef7ace402006-02-28 11:46:14 +01005105 /* Mute all inputs to mixer widget (even unconnected ones) */
5106 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
5107 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
5108 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
5109 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
5110 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
5111 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
5112 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
5113 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
Takashi Iwai4a471b72005-12-07 13:56:29 +01005114
5115 { }
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005116};
5117
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005118/* Initialisation sequence for ALC260 as configured in Acer TravelMate and
5119 * similar laptops (adapted from Fujitsu init verbs).
5120 */
5121static struct hda_verb alc260_acer_init_verbs[] = {
5122 /* On TravelMate laptops, GPIO 0 enables the internal speaker and
5123 * the headphone jack. Turn this on and rely on the standard mute
5124 * methods whenever the user wants to turn these outputs off.
5125 */
5126 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
5127 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
5128 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
5129 /* Internal speaker/Headphone jack is connected to Line-out pin */
5130 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5131 /* Internal microphone/Mic jack is connected to Mic1 pin */
5132 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
5133 /* Line In jack is connected to Line1 pin */
5134 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Jonathan Woithebd869482006-11-28 11:35:52 +01005135 /* Some Acers (eg: C20x Tablets) use Mono pin for internal speaker */
5136 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005137 /* Ensure all other unused pins are disabled and muted. */
5138 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5139 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005140 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5141 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5142 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5143 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5144 /* Disable digital (SPDIF) pins */
5145 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
5146 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
5147
Kailang Yangea1fb292008-08-26 12:58:38 +02005148 /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005149 * bus when acting as outputs.
5150 */
5151 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
5152 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
5153
5154 /* Start with output sum widgets muted and their output gains at min */
5155 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5156 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5157 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5158 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5159 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5160 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5161 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5162 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5163 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5164
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005165 /* Unmute Line-out pin widget amp left and right
5166 * (no equiv mixer ctrl)
5167 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005168 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithebd869482006-11-28 11:35:52 +01005169 /* Unmute mono pin widget amp output (no equiv mixer ctrl) */
5170 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005171 /* Unmute Mic1 and Line1 pin widget input buffers since they start as
5172 * inputs. If the pin mode is changed by the user the pin mode control
5173 * will take care of enabling the pin's input/output buffers as needed.
5174 * Therefore there's no need to enable the input buffer at this
5175 * stage.
5176 */
5177 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5178 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5179
5180 /* Mute capture amp left and right */
5181 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5182 /* Set ADC connection select to match default mixer setting - mic
5183 * (on mic1 pin)
5184 */
5185 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
5186
5187 /* Do similar with the second ADC: mute capture input amp and
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005188 * set ADC connection to mic to match ALSA's default state.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005189 */
5190 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005191 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005192
5193 /* Mute all inputs to mixer widget (even unconnected ones) */
5194 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
5195 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
5196 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
5197 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
5198 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
5199 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
5200 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
5201 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
5202
5203 { }
5204};
5205
Michael Schwingencc959482009-02-22 18:58:45 +01005206/* Initialisation sequence for Maxdata Favorit 100XS
5207 * (adapted from Acer init verbs).
5208 */
5209static struct hda_verb alc260_favorit100_init_verbs[] = {
5210 /* GPIO 0 enables the output jack.
5211 * Turn this on and rely on the standard mute
5212 * methods whenever the user wants to turn these outputs off.
5213 */
5214 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
5215 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
5216 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
5217 /* Line/Mic input jack is connected to Mic1 pin */
5218 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
5219 /* Ensure all other unused pins are disabled and muted. */
5220 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5221 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5222 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5223 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5224 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5225 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5226 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5227 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5228 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5229 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5230 /* Disable digital (SPDIF) pins */
5231 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
5232 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
5233
5234 /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
5235 * bus when acting as outputs.
5236 */
5237 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
5238 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
5239
5240 /* Start with output sum widgets muted and their output gains at min */
5241 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5242 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5243 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5244 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5245 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5246 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5247 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5248 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5249 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5250
5251 /* Unmute Line-out pin widget amp left and right
5252 * (no equiv mixer ctrl)
5253 */
5254 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5255 /* Unmute Mic1 and Line1 pin widget input buffers since they start as
5256 * inputs. If the pin mode is changed by the user the pin mode control
5257 * will take care of enabling the pin's input/output buffers as needed.
5258 * Therefore there's no need to enable the input buffer at this
5259 * stage.
5260 */
5261 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5262
5263 /* Mute capture amp left and right */
5264 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5265 /* Set ADC connection select to match default mixer setting - mic
5266 * (on mic1 pin)
5267 */
5268 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
5269
5270 /* Do similar with the second ADC: mute capture input amp and
5271 * set ADC connection to mic to match ALSA's default state.
5272 */
5273 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5274 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
5275
5276 /* Mute all inputs to mixer widget (even unconnected ones) */
5277 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
5278 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
5279 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
5280 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
5281 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
5282 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
5283 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
5284 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
5285
5286 { }
5287};
5288
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005289static struct hda_verb alc260_will_verbs[] = {
5290 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5291 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x00},
5292 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
5293 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
5294 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
5295 {0x1a, AC_VERB_SET_PROC_COEF, 0x3040},
5296 {}
5297};
5298
5299static struct hda_verb alc260_replacer_672v_verbs[] = {
5300 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
5301 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
5302 {0x1a, AC_VERB_SET_PROC_COEF, 0x3050},
5303
5304 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
5305 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
5306 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
5307
5308 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
5309 {}
5310};
5311
5312/* toggle speaker-output according to the hp-jack state */
5313static void alc260_replacer_672v_automute(struct hda_codec *codec)
5314{
5315 unsigned int present;
5316
5317 /* speaker --> GPIO Data 0, hp or spdif --> GPIO data 1 */
5318 present = snd_hda_codec_read(codec, 0x0f, 0,
5319 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
5320 if (present) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02005321 snd_hda_codec_write_cache(codec, 0x01, 0,
5322 AC_VERB_SET_GPIO_DATA, 1);
5323 snd_hda_codec_write_cache(codec, 0x0f, 0,
5324 AC_VERB_SET_PIN_WIDGET_CONTROL,
5325 PIN_HP);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005326 } else {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02005327 snd_hda_codec_write_cache(codec, 0x01, 0,
5328 AC_VERB_SET_GPIO_DATA, 0);
5329 snd_hda_codec_write_cache(codec, 0x0f, 0,
5330 AC_VERB_SET_PIN_WIDGET_CONTROL,
5331 PIN_OUT);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005332 }
5333}
5334
5335static void alc260_replacer_672v_unsol_event(struct hda_codec *codec,
5336 unsigned int res)
5337{
5338 if ((res >> 26) == ALC880_HP_EVENT)
5339 alc260_replacer_672v_automute(codec);
5340}
5341
Kailang Yang3f878302008-08-26 13:02:23 +02005342static struct hda_verb alc260_hp_dc7600_verbs[] = {
5343 {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
5344 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
5345 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5346 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5347 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5348 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5349 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
5350 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
5351 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
5352 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
5353 {}
5354};
5355
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005356/* Test configuration for debugging, modelled after the ALC880 test
5357 * configuration.
5358 */
5359#ifdef CONFIG_SND_DEBUG
5360static hda_nid_t alc260_test_dac_nids[1] = {
5361 0x02,
5362};
5363static hda_nid_t alc260_test_adc_nids[2] = {
5364 0x04, 0x05,
5365};
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005366/* For testing the ALC260, each input MUX needs its own definition since
Kailang Yangea1fb292008-08-26 12:58:38 +02005367 * the signal assignments are different. This assumes that the first ADC
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005368 * is NID 0x04.
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01005369 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005370static struct hda_input_mux alc260_test_capture_sources[2] = {
5371 {
5372 .num_items = 7,
5373 .items = {
5374 { "MIC1 pin", 0x0 },
5375 { "MIC2 pin", 0x1 },
5376 { "LINE1 pin", 0x2 },
5377 { "LINE2 pin", 0x3 },
5378 { "CD pin", 0x4 },
5379 { "LINE-OUT pin", 0x5 },
5380 { "HP-OUT pin", 0x6 },
5381 },
5382 },
5383 {
5384 .num_items = 8,
5385 .items = {
5386 { "MIC1 pin", 0x0 },
5387 { "MIC2 pin", 0x1 },
5388 { "LINE1 pin", 0x2 },
5389 { "LINE2 pin", 0x3 },
5390 { "CD pin", 0x4 },
5391 { "Mixer", 0x5 },
5392 { "LINE-OUT pin", 0x6 },
5393 { "HP-OUT pin", 0x7 },
5394 },
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005395 },
5396};
5397static struct snd_kcontrol_new alc260_test_mixer[] = {
5398 /* Output driver widgets */
5399 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
5400 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
5401 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x09, 0x0, HDA_OUTPUT),
5402 HDA_BIND_MUTE("LOUT2 Playback Switch", 0x09, 2, HDA_INPUT),
5403 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5404 HDA_BIND_MUTE("LOUT1 Playback Switch", 0x08, 2, HDA_INPUT),
5405
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005406 /* Modes for retasking pin widgets
5407 * Note: the ALC260 doesn't seem to act on requests to enable mic
5408 * bias from NIDs 0x0f and 0x10. The ALC260 datasheet doesn't
5409 * mention this restriction. At this stage it's not clear whether
5410 * this behaviour is intentional or is a hardware bug in chip
5411 * revisions available at least up until early 2006. Therefore for
5412 * now allow the "HP-OUT" and "LINE-OUT" Mode controls to span all
5413 * choices, but if it turns out that the lack of mic bias for these
5414 * NIDs is intentional we could change their modes from
5415 * ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
5416 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005417 ALC_PIN_MODE("HP-OUT pin mode", 0x10, ALC_PIN_DIR_INOUT),
5418 ALC_PIN_MODE("LINE-OUT pin mode", 0x0f, ALC_PIN_DIR_INOUT),
5419 ALC_PIN_MODE("LINE2 pin mode", 0x15, ALC_PIN_DIR_INOUT),
5420 ALC_PIN_MODE("LINE1 pin mode", 0x14, ALC_PIN_DIR_INOUT),
5421 ALC_PIN_MODE("MIC2 pin mode", 0x13, ALC_PIN_DIR_INOUT),
5422 ALC_PIN_MODE("MIC1 pin mode", 0x12, ALC_PIN_DIR_INOUT),
5423
5424 /* Loopback mixer controls */
5425 HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x07, 0x00, HDA_INPUT),
5426 HDA_CODEC_MUTE("MIC1 Playback Switch", 0x07, 0x00, HDA_INPUT),
5427 HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x07, 0x01, HDA_INPUT),
5428 HDA_CODEC_MUTE("MIC2 Playback Switch", 0x07, 0x01, HDA_INPUT),
5429 HDA_CODEC_VOLUME("LINE1 Playback Volume", 0x07, 0x02, HDA_INPUT),
5430 HDA_CODEC_MUTE("LINE1 Playback Switch", 0x07, 0x02, HDA_INPUT),
5431 HDA_CODEC_VOLUME("LINE2 Playback Volume", 0x07, 0x03, HDA_INPUT),
5432 HDA_CODEC_MUTE("LINE2 Playback Switch", 0x07, 0x03, HDA_INPUT),
5433 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
5434 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005435 HDA_CODEC_VOLUME("LINE-OUT loopback Playback Volume", 0x07, 0x06, HDA_INPUT),
5436 HDA_CODEC_MUTE("LINE-OUT loopback Playback Switch", 0x07, 0x06, HDA_INPUT),
5437 HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x07, 0x7, HDA_INPUT),
5438 HDA_CODEC_MUTE("HP-OUT loopback Playback Switch", 0x07, 0x7, HDA_INPUT),
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01005439
5440 /* Controls for GPIO pins, assuming they are configured as outputs */
5441 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
5442 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
5443 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
5444 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
5445
Jonathan Woithe92621f12006-02-28 11:47:47 +01005446 /* Switches to allow the digital IO pins to be enabled. The datasheet
5447 * is ambigious as to which NID is which; testing on laptops which
Kailang Yangea1fb292008-08-26 12:58:38 +02005448 * make this output available should provide clarification.
Jonathan Woithe92621f12006-02-28 11:47:47 +01005449 */
5450 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x03, 0x01),
5451 ALC_SPDIF_CTRL_SWITCH("SPDIF Capture Switch", 0x06, 0x01),
5452
Jonathan Woithef8225f62008-01-08 12:16:54 +01005453 /* A switch allowing EAPD to be enabled. Some laptops seem to use
5454 * this output to turn on an external amplifier.
5455 */
5456 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
5457 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
5458
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005459 { } /* end */
5460};
5461static struct hda_verb alc260_test_init_verbs[] = {
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01005462 /* Enable all GPIOs as outputs with an initial value of 0 */
5463 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f},
5464 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
5465 {0x01, AC_VERB_SET_GPIO_MASK, 0x0f},
5466
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005467 /* Enable retasking pins as output, initially without power amp */
5468 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5469 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5470 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5471 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5472 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5473 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5474
Jonathan Woithe92621f12006-02-28 11:47:47 +01005475 /* Disable digital (SPDIF) pins initially, but users can enable
5476 * them via a mixer switch. In the case of SPDIF-out, this initverb
5477 * payload also sets the generation to 0, output to be in "consumer"
5478 * PCM format, copyright asserted, no pre-emphasis and no validity
5479 * control.
5480 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005481 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
5482 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
5483
Kailang Yangea1fb292008-08-26 12:58:38 +02005484 /* Ensure mic1, mic2, line1 and line2 pin widgets take input from the
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005485 * OUT1 sum bus when acting as an output.
5486 */
5487 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
5488 {0x0c, AC_VERB_SET_CONNECT_SEL, 0},
5489 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
5490 {0x0e, AC_VERB_SET_CONNECT_SEL, 0},
5491
5492 /* Start with output sum widgets muted and their output gains at min */
5493 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5494 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5495 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5496 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5497 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5498 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5499 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5500 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5501 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5502
Jonathan Woithecdcd9262006-02-28 11:36:42 +01005503 /* Unmute retasking pin widget output buffers since the default
5504 * state appears to be output. As the pin mode is changed by the
5505 * user the pin mode control will take care of enabling the pin's
5506 * input/output buffers as needed.
5507 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005508 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5509 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5510 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5511 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5512 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5513 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5514 /* Also unmute the mono-out pin widget */
5515 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5516
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005517 /* Mute capture amp left and right */
5518 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithef7ace402006-02-28 11:46:14 +01005519 /* Set ADC connection select to match default mixer setting (mic1
5520 * pin)
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005521 */
5522 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
5523
5524 /* Do the same for the second ADC: mute capture input amp and
Jonathan Woithef7ace402006-02-28 11:46:14 +01005525 * set ADC connection to mic1 pin
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005526 */
5527 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5528 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
5529
5530 /* Mute all inputs to mixer widget (even unconnected ones) */
5531 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
5532 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
5533 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
5534 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
5535 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
5536 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
5537 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
5538 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
5539
5540 { }
5541};
5542#endif
5543
Takashi Iwai63300792008-01-24 15:31:36 +01005544#define alc260_pcm_analog_playback alc880_pcm_analog_alt_playback
5545#define alc260_pcm_analog_capture alc880_pcm_analog_capture
Linus Torvalds1da177e2005-04-16 15:20:36 -07005546
Takashi Iwaia3bcba32005-12-06 19:05:29 +01005547#define alc260_pcm_digital_playback alc880_pcm_digital_playback
5548#define alc260_pcm_digital_capture alc880_pcm_digital_capture
5549
Kailang Yangdf694da2005-12-05 19:42:22 +01005550/*
5551 * for BIOS auto-configuration
5552 */
5553
5554static int alc260_add_playback_controls(struct alc_spec *spec, hda_nid_t nid,
Takashi Iwai863b4512008-10-21 17:01:47 +02005555 const char *pfx, int *vol_bits)
Kailang Yangdf694da2005-12-05 19:42:22 +01005556{
5557 hda_nid_t nid_vol;
5558 unsigned long vol_val, sw_val;
5559 char name[32];
5560 int err;
5561
5562 if (nid >= 0x0f && nid < 0x11) {
5563 nid_vol = nid - 0x7;
5564 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
5565 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
5566 } else if (nid == 0x11) {
5567 nid_vol = nid - 0x7;
5568 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT);
5569 sw_val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
5570 } else if (nid >= 0x12 && nid <= 0x15) {
5571 nid_vol = 0x08;
5572 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
5573 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
5574 } else
5575 return 0; /* N/A */
Kailang Yangea1fb292008-08-26 12:58:38 +02005576
Takashi Iwai863b4512008-10-21 17:01:47 +02005577 if (!(*vol_bits & (1 << nid_vol))) {
5578 /* first control for the volume widget */
5579 snprintf(name, sizeof(name), "%s Playback Volume", pfx);
5580 err = add_control(spec, ALC_CTL_WIDGET_VOL, name, vol_val);
5581 if (err < 0)
5582 return err;
5583 *vol_bits |= (1 << nid_vol);
5584 }
Kailang Yangdf694da2005-12-05 19:42:22 +01005585 snprintf(name, sizeof(name), "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005586 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, sw_val);
5587 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01005588 return err;
5589 return 1;
5590}
5591
5592/* add playback controls from the parsed DAC table */
5593static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec,
5594 const struct auto_pin_cfg *cfg)
5595{
5596 hda_nid_t nid;
5597 int err;
Takashi Iwai863b4512008-10-21 17:01:47 +02005598 int vols = 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01005599
5600 spec->multiout.num_dacs = 1;
5601 spec->multiout.dac_nids = spec->private_dac_nids;
5602 spec->multiout.dac_nids[0] = 0x02;
5603
5604 nid = cfg->line_out_pins[0];
5605 if (nid) {
Takashi Iwai863b4512008-10-21 17:01:47 +02005606 err = alc260_add_playback_controls(spec, nid, "Front", &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01005607 if (err < 0)
5608 return err;
5609 }
5610
Takashi Iwai82bc9552006-03-21 11:24:42 +01005611 nid = cfg->speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01005612 if (nid) {
Takashi Iwai863b4512008-10-21 17:01:47 +02005613 err = alc260_add_playback_controls(spec, nid, "Speaker", &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01005614 if (err < 0)
5615 return err;
5616 }
5617
Takashi Iwaieb06ed82006-09-20 17:10:27 +02005618 nid = cfg->hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01005619 if (nid) {
Takashi Iwai863b4512008-10-21 17:01:47 +02005620 err = alc260_add_playback_controls(spec, nid, "Headphone",
5621 &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01005622 if (err < 0)
5623 return err;
5624 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005625 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01005626}
5627
5628/* create playback/capture controls for input pins */
5629static int alc260_auto_create_analog_input_ctls(struct alc_spec *spec,
5630 const struct auto_pin_cfg *cfg)
5631{
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02005632 struct hda_input_mux *imux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01005633 int i, err, idx;
5634
5635 for (i = 0; i < AUTO_PIN_LAST; i++) {
5636 if (cfg->input_pins[i] >= 0x12) {
5637 idx = cfg->input_pins[i] - 0x12;
Takashi Iwai4a471b72005-12-07 13:56:29 +01005638 err = new_analog_input(spec, cfg->input_pins[i],
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005639 auto_pin_cfg_labels[i], idx,
5640 0x07);
Kailang Yangdf694da2005-12-05 19:42:22 +01005641 if (err < 0)
5642 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005643 imux->items[imux->num_items].label =
5644 auto_pin_cfg_labels[i];
Kailang Yangdf694da2005-12-05 19:42:22 +01005645 imux->items[imux->num_items].index = idx;
5646 imux->num_items++;
5647 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005648 if (cfg->input_pins[i] >= 0x0f && cfg->input_pins[i] <= 0x10){
Kailang Yangdf694da2005-12-05 19:42:22 +01005649 idx = cfg->input_pins[i] - 0x09;
Takashi Iwai4a471b72005-12-07 13:56:29 +01005650 err = new_analog_input(spec, cfg->input_pins[i],
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005651 auto_pin_cfg_labels[i], idx,
5652 0x07);
Kailang Yangdf694da2005-12-05 19:42:22 +01005653 if (err < 0)
5654 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005655 imux->items[imux->num_items].label =
5656 auto_pin_cfg_labels[i];
Kailang Yangdf694da2005-12-05 19:42:22 +01005657 imux->items[imux->num_items].index = idx;
5658 imux->num_items++;
5659 }
5660 }
5661 return 0;
5662}
5663
5664static void alc260_auto_set_output_and_unmute(struct hda_codec *codec,
5665 hda_nid_t nid, int pin_type,
5666 int sel_idx)
5667{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005668 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01005669 /* need the manual connection? */
5670 if (nid >= 0x12) {
5671 int idx = nid - 0x12;
5672 snd_hda_codec_write(codec, idx + 0x0b, 0,
5673 AC_VERB_SET_CONNECT_SEL, sel_idx);
Kailang Yangdf694da2005-12-05 19:42:22 +01005674 }
5675}
5676
5677static void alc260_auto_init_multi_out(struct hda_codec *codec)
5678{
5679 struct alc_spec *spec = codec->spec;
5680 hda_nid_t nid;
5681
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005682 alc_subsystem_id(codec, 0x10, 0x15, 0x0f);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005683 nid = spec->autocfg.line_out_pins[0];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02005684 if (nid) {
5685 int pin_type = get_pin_type(spec->autocfg.line_out_type);
5686 alc260_auto_set_output_and_unmute(codec, nid, pin_type, 0);
5687 }
Kailang Yangea1fb292008-08-26 12:58:38 +02005688
Takashi Iwai82bc9552006-03-21 11:24:42 +01005689 nid = spec->autocfg.speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01005690 if (nid)
5691 alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
5692
Takashi Iwaieb06ed82006-09-20 17:10:27 +02005693 nid = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01005694 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02005695 alc260_auto_set_output_and_unmute(codec, nid, PIN_HP, 0);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005696}
Kailang Yangdf694da2005-12-05 19:42:22 +01005697
5698#define ALC260_PIN_CD_NID 0x16
5699static void alc260_auto_init_analog_input(struct hda_codec *codec)
5700{
5701 struct alc_spec *spec = codec->spec;
5702 int i;
5703
5704 for (i = 0; i < AUTO_PIN_LAST; i++) {
5705 hda_nid_t nid = spec->autocfg.input_pins[i];
5706 if (nid >= 0x12) {
Takashi Iwai23f0c042009-02-26 13:03:58 +01005707 alc_set_input_pin(codec, nid, i);
Takashi Iwaie82c0252009-03-23 15:17:38 +01005708 if (nid != ALC260_PIN_CD_NID &&
5709 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005710 snd_hda_codec_write(codec, nid, 0,
5711 AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangdf694da2005-12-05 19:42:22 +01005712 AMP_OUT_MUTE);
5713 }
5714 }
5715}
5716
5717/*
5718 * generic initialization of ADC, input mixers and output mixers
5719 */
5720static struct hda_verb alc260_volume_init_verbs[] = {
5721 /*
5722 * Unmute ADC0-1 and set the default input to mic-in
5723 */
5724 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
5725 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5726 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
5727 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +02005728
Kailang Yangdf694da2005-12-05 19:42:22 +01005729 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
5730 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005731 * Note: PASD motherboards uses the Line In 2 as the input for
5732 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01005733 */
5734 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02005735 /* mute analog inputs */
5736 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5737 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5738 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5739 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5740 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01005741
5742 /*
5743 * Set up output mixers (0x08 - 0x0a)
5744 */
5745 /* set vol=0 to output mixers */
5746 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5747 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5748 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5749 /* set up input amps for analog loopback */
5750 /* Amp Indices: DAC = 0, mixer = 1 */
5751 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5752 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5753 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5754 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5755 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5756 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +02005757
Kailang Yangdf694da2005-12-05 19:42:22 +01005758 { }
5759};
5760
5761static int alc260_parse_auto_config(struct hda_codec *codec)
5762{
5763 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01005764 int err;
5765 static hda_nid_t alc260_ignore[] = { 0x17, 0 };
5766
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005767 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
5768 alc260_ignore);
5769 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01005770 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005771 err = alc260_auto_create_multi_out_ctls(spec, &spec->autocfg);
5772 if (err < 0)
Takashi Iwai4a471b72005-12-07 13:56:29 +01005773 return err;
Takashi Iwai603c4012008-07-30 15:01:44 +02005774 if (!spec->kctls.list)
Kailang Yangdf694da2005-12-05 19:42:22 +01005775 return 0; /* can't find valid BIOS pin config */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005776 err = alc260_auto_create_analog_input_ctls(spec, &spec->autocfg);
5777 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01005778 return err;
5779
5780 spec->multiout.max_channels = 2;
5781
Takashi Iwai0852d7a2009-02-11 11:35:15 +01005782 if (spec->autocfg.dig_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +01005783 spec->multiout.dig_out_nid = ALC260_DIGOUT_NID;
Takashi Iwai603c4012008-07-30 15:01:44 +02005784 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +01005785 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +01005786
Takashi Iwaid88897e2008-10-31 15:01:37 +01005787 add_verb(spec, alc260_volume_init_verbs);
Kailang Yangdf694da2005-12-05 19:42:22 +01005788
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005789 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02005790 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01005791
Kailang Yangdf694da2005-12-05 19:42:22 +01005792 return 1;
5793}
5794
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005795/* additional initialization for auto-configuration model */
5796static void alc260_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01005797{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005798 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01005799 alc260_auto_init_multi_out(codec);
5800 alc260_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005801 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02005802 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01005803}
5804
Takashi Iwaicb53c622007-08-10 17:21:45 +02005805#ifdef CONFIG_SND_HDA_POWER_SAVE
5806static struct hda_amp_list alc260_loopbacks[] = {
5807 { 0x07, HDA_INPUT, 0 },
5808 { 0x07, HDA_INPUT, 1 },
5809 { 0x07, HDA_INPUT, 2 },
5810 { 0x07, HDA_INPUT, 3 },
5811 { 0x07, HDA_INPUT, 4 },
5812 { } /* end */
5813};
5814#endif
5815
Kailang Yangdf694da2005-12-05 19:42:22 +01005816/*
5817 * ALC260 configurations
5818 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005819static const char *alc260_models[ALC260_MODEL_LAST] = {
5820 [ALC260_BASIC] = "basic",
5821 [ALC260_HP] = "hp",
5822 [ALC260_HP_3013] = "hp-3013",
Takashi Iwai2922c9a2008-08-27 18:12:42 +02005823 [ALC260_HP_DC7600] = "hp-dc7600",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005824 [ALC260_FUJITSU_S702X] = "fujitsu",
5825 [ALC260_ACER] = "acer",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005826 [ALC260_WILL] = "will",
5827 [ALC260_REPLACER_672V] = "replacer",
Michael Schwingencc959482009-02-22 18:58:45 +01005828 [ALC260_FAVORIT100] = "favorit100",
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005829#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005830 [ALC260_TEST] = "test",
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005831#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005832 [ALC260_AUTO] = "auto",
5833};
5834
5835static struct snd_pci_quirk alc260_cfg_tbl[] = {
Jonathan Woithebd869482006-11-28 11:35:52 +01005836 SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005837 SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER),
Michael Schwingencc959482009-02-22 18:58:45 +01005838 SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FAVORIT100),
Takashi Iwai9720b712007-03-13 21:46:23 +01005839 SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013),
Takashi Iwaia8a5d062007-03-15 15:10:28 +01005840 SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_HP_3013),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005841 SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013),
Jaroslav Kysela34ec8a02008-07-10 14:49:19 +02005842 SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP_3013),
Kailang Yang3f878302008-08-26 13:02:23 +02005843 SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_DC7600),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005844 SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013),
5845 SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP),
5846 SND_PCI_QUIRK(0x103c, 0x3015, "HP", ALC260_HP),
5847 SND_PCI_QUIRK(0x103c, 0x3016, "HP", ALC260_HP),
5848 SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_BASIC),
5849 SND_PCI_QUIRK(0x104d, 0x81cc, "Sony VAIO", ALC260_BASIC),
5850 SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC),
5851 SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X),
5852 SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005853 SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_REPLACER_672V),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01005854 SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_WILL),
Takashi Iwai16ded522005-06-10 19:58:24 +02005855 {}
5856};
5857
Kailang Yangdf694da2005-12-05 19:42:22 +01005858static struct alc_config_preset alc260_presets[] = {
5859 [ALC260_BASIC] = {
5860 .mixers = { alc260_base_output_mixer,
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01005861 alc260_input_mixer },
Kailang Yangdf694da2005-12-05 19:42:22 +01005862 .init_verbs = { alc260_init_verbs },
5863 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5864 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005865 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
Kailang Yangdf694da2005-12-05 19:42:22 +01005866 .adc_nids = alc260_adc_nids,
5867 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5868 .channel_mode = alc260_modes,
5869 .input_mux = &alc260_capture_source,
5870 },
5871 [ALC260_HP] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01005872 .mixers = { alc260_hp_output_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005873 alc260_input_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01005874 .init_verbs = { alc260_init_verbs,
5875 alc260_hp_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01005876 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5877 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005878 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
5879 .adc_nids = alc260_adc_nids_alt,
Kailang Yangdf694da2005-12-05 19:42:22 +01005880 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5881 .channel_mode = alc260_modes,
5882 .input_mux = &alc260_capture_source,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005883 .unsol_event = alc260_hp_unsol_event,
5884 .init_hook = alc260_hp_automute,
Kailang Yangdf694da2005-12-05 19:42:22 +01005885 },
Kailang Yang3f878302008-08-26 13:02:23 +02005886 [ALC260_HP_DC7600] = {
5887 .mixers = { alc260_hp_dc7600_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005888 alc260_input_mixer },
Kailang Yang3f878302008-08-26 13:02:23 +02005889 .init_verbs = { alc260_init_verbs,
5890 alc260_hp_dc7600_verbs },
5891 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5892 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005893 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
5894 .adc_nids = alc260_adc_nids_alt,
Kailang Yang3f878302008-08-26 13:02:23 +02005895 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5896 .channel_mode = alc260_modes,
5897 .input_mux = &alc260_capture_source,
5898 .unsol_event = alc260_hp_3012_unsol_event,
5899 .init_hook = alc260_hp_3012_automute,
5900 },
Kailang Yangdf694da2005-12-05 19:42:22 +01005901 [ALC260_HP_3013] = {
5902 .mixers = { alc260_hp_3013_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005903 alc260_input_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01005904 .init_verbs = { alc260_hp_3013_init_verbs,
5905 alc260_hp_3013_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01005906 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5907 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005908 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
5909 .adc_nids = alc260_adc_nids_alt,
Kailang Yangdf694da2005-12-05 19:42:22 +01005910 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5911 .channel_mode = alc260_modes,
5912 .input_mux = &alc260_capture_source,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005913 .unsol_event = alc260_hp_3013_unsol_event,
5914 .init_hook = alc260_hp_3013_automute,
Kailang Yangdf694da2005-12-05 19:42:22 +01005915 },
5916 [ALC260_FUJITSU_S702X] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005917 .mixers = { alc260_fujitsu_mixer },
Kailang Yangdf694da2005-12-05 19:42:22 +01005918 .init_verbs = { alc260_fujitsu_init_verbs },
5919 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5920 .dac_nids = alc260_dac_nids,
Jonathan Woithed57fdac2006-02-28 11:38:35 +01005921 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
5922 .adc_nids = alc260_dual_adc_nids,
Kailang Yangdf694da2005-12-05 19:42:22 +01005923 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5924 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005925 .num_mux_defs = ARRAY_SIZE(alc260_fujitsu_capture_sources),
5926 .input_mux = alc260_fujitsu_capture_sources,
Kailang Yangdf694da2005-12-05 19:42:22 +01005927 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005928 [ALC260_ACER] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005929 .mixers = { alc260_acer_mixer },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005930 .init_verbs = { alc260_acer_init_verbs },
5931 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5932 .dac_nids = alc260_dac_nids,
5933 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
5934 .adc_nids = alc260_dual_adc_nids,
5935 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5936 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005937 .num_mux_defs = ARRAY_SIZE(alc260_acer_capture_sources),
5938 .input_mux = alc260_acer_capture_sources,
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005939 },
Michael Schwingencc959482009-02-22 18:58:45 +01005940 [ALC260_FAVORIT100] = {
5941 .mixers = { alc260_favorit100_mixer },
5942 .init_verbs = { alc260_favorit100_init_verbs },
5943 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5944 .dac_nids = alc260_dac_nids,
5945 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
5946 .adc_nids = alc260_dual_adc_nids,
5947 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5948 .channel_mode = alc260_modes,
5949 .num_mux_defs = ARRAY_SIZE(alc260_favorit100_capture_sources),
5950 .input_mux = alc260_favorit100_capture_sources,
5951 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005952 [ALC260_WILL] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005953 .mixers = { alc260_will_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005954 .init_verbs = { alc260_init_verbs, alc260_will_verbs },
5955 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5956 .dac_nids = alc260_dac_nids,
5957 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
5958 .adc_nids = alc260_adc_nids,
5959 .dig_out_nid = ALC260_DIGOUT_NID,
5960 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5961 .channel_mode = alc260_modes,
5962 .input_mux = &alc260_capture_source,
5963 },
5964 [ALC260_REPLACER_672V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005965 .mixers = { alc260_replacer_672v_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005966 .init_verbs = { alc260_init_verbs, alc260_replacer_672v_verbs },
5967 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5968 .dac_nids = alc260_dac_nids,
5969 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
5970 .adc_nids = alc260_adc_nids,
5971 .dig_out_nid = ALC260_DIGOUT_NID,
5972 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5973 .channel_mode = alc260_modes,
5974 .input_mux = &alc260_capture_source,
5975 .unsol_event = alc260_replacer_672v_unsol_event,
5976 .init_hook = alc260_replacer_672v_automute,
5977 },
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005978#ifdef CONFIG_SND_DEBUG
5979 [ALC260_TEST] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005980 .mixers = { alc260_test_mixer },
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005981 .init_verbs = { alc260_test_init_verbs },
5982 .num_dacs = ARRAY_SIZE(alc260_test_dac_nids),
5983 .dac_nids = alc260_test_dac_nids,
5984 .num_adc_nids = ARRAY_SIZE(alc260_test_adc_nids),
5985 .adc_nids = alc260_test_adc_nids,
5986 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5987 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005988 .num_mux_defs = ARRAY_SIZE(alc260_test_capture_sources),
5989 .input_mux = alc260_test_capture_sources,
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005990 },
5991#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01005992};
5993
Linus Torvalds1da177e2005-04-16 15:20:36 -07005994static int patch_alc260(struct hda_codec *codec)
5995{
5996 struct alc_spec *spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01005997 int err, board_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005998
Takashi Iwaie560d8d2005-09-09 14:21:46 +02005999 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006000 if (spec == NULL)
6001 return -ENOMEM;
6002
6003 codec->spec = spec;
6004
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006005 board_config = snd_hda_check_board_config(codec, ALC260_MODEL_LAST,
6006 alc260_models,
6007 alc260_cfg_tbl);
6008 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006009 snd_printd(KERN_INFO "hda_codec: Unknown model for ALC260, "
6010 "trying auto-probe from BIOS...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01006011 board_config = ALC260_AUTO;
Takashi Iwai16ded522005-06-10 19:58:24 +02006012 }
6013
Kailang Yangdf694da2005-12-05 19:42:22 +01006014 if (board_config == ALC260_AUTO) {
6015 /* automatic parse from the BIOS config */
6016 err = alc260_parse_auto_config(codec);
6017 if (err < 0) {
6018 alc_free(codec);
6019 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006020 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006021 printk(KERN_INFO
6022 "hda_codec: Cannot set up configuration "
6023 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01006024 board_config = ALC260_BASIC;
6025 }
Takashi Iwai16ded522005-06-10 19:58:24 +02006026 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006027
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09006028 err = snd_hda_attach_beep_device(codec, 0x1);
6029 if (err < 0) {
6030 alc_free(codec);
6031 return err;
6032 }
6033
Kailang Yangdf694da2005-12-05 19:42:22 +01006034 if (board_config != ALC260_AUTO)
6035 setup_preset(spec, &alc260_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006036
6037 spec->stream_name_analog = "ALC260 Analog";
6038 spec->stream_analog_playback = &alc260_pcm_analog_playback;
6039 spec->stream_analog_capture = &alc260_pcm_analog_capture;
6040
Takashi Iwaia3bcba32005-12-06 19:05:29 +01006041 spec->stream_name_digital = "ALC260 Digital";
6042 spec->stream_digital_playback = &alc260_pcm_digital_playback;
6043 spec->stream_digital_capture = &alc260_pcm_digital_capture;
6044
Takashi Iwai4ef0ef12008-11-03 17:47:49 +01006045 if (!spec->adc_nids && spec->input_mux) {
6046 /* check whether NID 0x04 is valid */
6047 unsigned int wcap = get_wcaps(codec, 0x04);
6048 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
6049 /* get type */
6050 if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
6051 spec->adc_nids = alc260_adc_nids_alt;
6052 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt);
6053 } else {
6054 spec->adc_nids = alc260_adc_nids;
6055 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids);
6056 }
6057 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006058 set_capture_mixer(spec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01006059 set_beep_amp(spec, 0x07, 0x05, HDA_INPUT);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006060
Takashi Iwai2134ea42008-01-10 16:53:55 +01006061 spec->vmaster_nid = 0x08;
6062
Linus Torvalds1da177e2005-04-16 15:20:36 -07006063 codec->patch_ops = alc_patch_ops;
Kailang Yangdf694da2005-12-05 19:42:22 +01006064 if (board_config == ALC260_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01006065 spec->init_hook = alc260_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02006066#ifdef CONFIG_SND_HDA_POWER_SAVE
6067 if (!spec->loopback.amplist)
6068 spec->loopback.amplist = alc260_loopbacks;
6069#endif
Takashi Iwaidaead532008-11-28 12:55:36 +01006070 codec->proc_widget_hook = print_realtek_coef;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006071
6072 return 0;
6073}
6074
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006075
Linus Torvalds1da177e2005-04-16 15:20:36 -07006076/*
6077 * ALC882 support
6078 *
6079 * ALC882 is almost identical with ALC880 but has cleaner and more flexible
6080 * configuration. Each pin widget can choose any input DACs and a mixer.
6081 * Each ADC is connected from a mixer of all inputs. This makes possible
6082 * 6-channel independent captures.
6083 *
6084 * In addition, an independent DAC for the multi-playback (not used in this
6085 * driver yet).
6086 */
Kailang Yangdf694da2005-12-05 19:42:22 +01006087#define ALC882_DIGOUT_NID 0x06
6088#define ALC882_DIGIN_NID 0x0a
Linus Torvalds1da177e2005-04-16 15:20:36 -07006089
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01006090static struct hda_channel_mode alc882_ch_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006091 { 8, NULL }
6092};
6093
6094static hda_nid_t alc882_dac_nids[4] = {
6095 /* front, rear, clfe, rear_surr */
6096 0x02, 0x03, 0x04, 0x05
6097};
6098
Kailang Yangdf694da2005-12-05 19:42:22 +01006099/* identical with ALC880 */
6100#define alc882_adc_nids alc880_adc_nids
6101#define alc882_adc_nids_alt alc880_adc_nids_alt
Linus Torvalds1da177e2005-04-16 15:20:36 -07006102
Takashi Iwaie1406342008-02-11 18:32:32 +01006103static hda_nid_t alc882_capsrc_nids[3] = { 0x24, 0x23, 0x22 };
6104static hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 };
6105
Linus Torvalds1da177e2005-04-16 15:20:36 -07006106/* input MUX */
6107/* FIXME: should be a matrix-type input source selection */
6108
6109static struct hda_input_mux alc882_capture_source = {
6110 .num_items = 4,
6111 .items = {
6112 { "Mic", 0x0 },
6113 { "Front Mic", 0x1 },
6114 { "Line", 0x2 },
6115 { "CD", 0x4 },
6116 },
6117};
Kailang Yangdf694da2005-12-05 19:42:22 +01006118/*
Kailang Yang272a5272007-05-14 11:00:38 +02006119 * 2ch mode
6120 */
6121static struct hda_verb alc882_3ST_ch2_init[] = {
6122 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
6123 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6124 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
6125 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6126 { } /* end */
6127};
6128
6129/*
6130 * 6ch mode
6131 */
6132static struct hda_verb alc882_3ST_ch6_init[] = {
6133 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6134 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6135 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
6136 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6137 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6138 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6139 { } /* end */
6140};
6141
6142static struct hda_channel_mode alc882_3ST_6ch_modes[2] = {
6143 { 2, alc882_3ST_ch2_init },
6144 { 6, alc882_3ST_ch6_init },
6145};
6146
6147/*
Kailang Yangdf694da2005-12-05 19:42:22 +01006148 * 6ch mode
6149 */
6150static struct hda_verb alc882_sixstack_ch6_init[] = {
6151 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
6152 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6153 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6154 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6155 { } /* end */
6156};
6157
6158/*
6159 * 8ch mode
6160 */
6161static struct hda_verb alc882_sixstack_ch8_init[] = {
6162 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6163 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6164 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6165 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6166 { } /* end */
6167};
6168
6169static struct hda_channel_mode alc882_sixstack_modes[2] = {
6170 { 6, alc882_sixstack_ch6_init },
6171 { 8, alc882_sixstack_ch8_init },
6172};
6173
Takashi Iwai87350ad2007-08-16 18:19:38 +02006174/*
6175 * macbook pro ALC885 can switch LineIn to LineOut without loosing Mic
6176 */
6177
6178/*
6179 * 2ch mode
6180 */
6181static struct hda_verb alc885_mbp_ch2_init[] = {
6182 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
6183 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6184 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6185 { } /* end */
6186};
6187
6188/*
6189 * 6ch mode
6190 */
6191static struct hda_verb alc885_mbp_ch6_init[] = {
6192 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6193 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6194 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6195 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6196 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6197 { } /* end */
6198};
6199
6200static struct hda_channel_mode alc885_mbp_6ch_modes[2] = {
6201 { 2, alc885_mbp_ch2_init },
6202 { 6, alc885_mbp_ch6_init },
6203};
6204
6205
Linus Torvalds1da177e2005-04-16 15:20:36 -07006206/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
6207 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
6208 */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01006209static struct snd_kcontrol_new alc882_base_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02006210 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01006211 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02006212 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01006213 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02006214 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
6215 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01006216 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
6217 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02006218 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01006219 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07006220 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6221 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6222 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6223 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6224 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6225 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006226 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07006227 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6228 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006229 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07006230 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07006231 { } /* end */
6232};
6233
Takashi Iwai87350ad2007-08-16 18:19:38 +02006234static struct snd_kcontrol_new alc885_mbp3_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01006235 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
6236 HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
6237 HDA_CODEC_MUTE ("Speaker Playback Switch", 0x14, 0x00, HDA_OUTPUT),
6238 HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
6239 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6240 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02006241 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
6242 HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01006243 HDA_CODEC_VOLUME("Line Boost", 0x1a, 0x00, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02006244 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT),
6245 { } /* end */
6246};
Kailang Yangbdd148a2007-05-08 15:19:08 +02006247static struct snd_kcontrol_new alc882_w2jc_mixer[] = {
6248 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6249 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6250 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6251 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6252 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6253 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6254 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6255 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
6256 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangbdd148a2007-05-08 15:19:08 +02006257 { } /* end */
6258};
6259
Kailang Yang272a5272007-05-14 11:00:38 +02006260static struct snd_kcontrol_new alc882_targa_mixer[] = {
6261 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6262 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6263 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6264 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6265 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6266 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6267 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6268 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6269 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai96fe7cc82007-09-07 10:57:44 +02006270 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02006271 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
6272 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai96fe7cc82007-09-07 10:57:44 +02006273 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02006274 { } /* end */
6275};
6276
6277/* Pin assignment: Front=0x14, HP = 0x15, Front = 0x16, ???
6278 * Front Mic=0x18, Line In = 0x1a, Line In = 0x1b, CD = 0x1c
6279 */
6280static struct snd_kcontrol_new alc882_asus_a7j_mixer[] = {
6281 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6282 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
6283 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
6284 HDA_CODEC_MUTE("Mobile Front Playback Switch", 0x16, 0x0, HDA_OUTPUT),
6285 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6286 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6287 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6288 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6289 HDA_CODEC_VOLUME("Mobile Line Playback Volume", 0x0b, 0x03, HDA_INPUT),
6290 HDA_CODEC_MUTE("Mobile Line Playback Switch", 0x0b, 0x03, HDA_INPUT),
6291 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6292 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai96fe7cc82007-09-07 10:57:44 +02006293 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02006294 { } /* end */
6295};
6296
Takashi Iwai914759b2007-09-06 14:52:04 +02006297static struct snd_kcontrol_new alc882_asus_a7m_mixer[] = {
6298 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6299 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6300 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
6301 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6302 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6303 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6304 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6305 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6306 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
6307 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai914759b2007-09-06 14:52:04 +02006308 { } /* end */
6309};
6310
Kailang Yangdf694da2005-12-05 19:42:22 +01006311static struct snd_kcontrol_new alc882_chmode_mixer[] = {
6312 {
6313 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6314 .name = "Channel Mode",
6315 .info = alc_ch_mode_info,
6316 .get = alc_ch_mode_get,
6317 .put = alc_ch_mode_put,
6318 },
6319 { } /* end */
6320};
6321
Linus Torvalds1da177e2005-04-16 15:20:36 -07006322static struct hda_verb alc882_init_verbs[] = {
6323 /* Front mixer: unmute input/output amp left and right (volume = 0) */
Takashi Iwai05acb862005-06-10 19:50:25 +02006324 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6325 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6326 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006327 /* Rear mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02006328 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6329 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6330 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006331 /* CLFE mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02006332 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6333 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6334 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006335 /* Side mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02006336 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6337 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6338 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006339
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006340 /* Front Pin: output 0 (0x0c) */
Takashi Iwai05acb862005-06-10 19:50:25 +02006341 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02006342 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006343 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006344 /* Rear Pin: output 1 (0x0d) */
Takashi Iwai05acb862005-06-10 19:50:25 +02006345 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02006346 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006347 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006348 /* CLFE Pin: output 2 (0x0e) */
Takashi Iwai05acb862005-06-10 19:50:25 +02006349 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02006350 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006351 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006352 /* Side Pin: output 3 (0x0f) */
Takashi Iwai05acb862005-06-10 19:50:25 +02006353 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02006354 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006355 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006356 /* Mic (rear) pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02006357 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006358 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6359 /* Front Mic pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02006360 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006361 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6362 /* Line In pin: input */
Takashi Iwai05acb862005-06-10 19:50:25 +02006363 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006364 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6365 /* Line-2 In: Headphone output (output 0 - 0x0c) */
6366 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6367 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6368 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006369 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02006370 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006371
6372 /* FIXME: use matrix-type input source selection */
6373 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
6374 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
Takashi Iwai05acb862005-06-10 19:50:25 +02006375 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6376 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6377 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6378 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006379 /* Input mixer2 */
Takashi Iwai05acb862005-06-10 19:50:25 +02006380 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6381 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6382 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6383 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006384 /* Input mixer3 */
Takashi Iwai05acb862005-06-10 19:50:25 +02006385 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6386 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6387 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6388 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6389 /* ADC1: mute amp left and right */
6390 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02006391 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02006392 /* ADC2: mute amp left and right */
6393 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02006394 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02006395 /* ADC3: mute amp left and right */
6396 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02006397 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006398
6399 { }
6400};
6401
Takashi Iwai4b146cb2006-07-28 14:42:36 +02006402static struct hda_verb alc882_eapd_verbs[] = {
6403 /* change to EAPD mode */
6404 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01006405 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006406 { }
Takashi Iwai4b146cb2006-07-28 14:42:36 +02006407};
6408
Tobin Davis9102cd12006-12-15 10:02:12 +01006409/* Mac Pro test */
6410static struct snd_kcontrol_new alc882_macpro_mixer[] = {
6411 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6412 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6413 HDA_CODEC_MUTE("Headphone Playback Switch", 0x18, 0x0, HDA_OUTPUT),
6414 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
6415 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01006416 /* FIXME: this looks suspicious...
Tobin Davis9102cd12006-12-15 10:02:12 +01006417 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x02, HDA_INPUT),
6418 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01006419 */
Tobin Davis9102cd12006-12-15 10:02:12 +01006420 { } /* end */
6421};
6422
6423static struct hda_verb alc882_macpro_init_verbs[] = {
6424 /* Front mixer: unmute input/output amp left and right (volume = 0) */
6425 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6426 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6427 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6428 /* Front Pin: output 0 (0x0c) */
6429 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6430 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6431 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
6432 /* Front Mic pin: input vref at 80% */
6433 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
6434 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6435 /* Speaker: output */
6436 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6437 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6438 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x04},
6439 /* Headphone output (output 0 - 0x0c) */
6440 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6441 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6442 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
6443
6444 /* FIXME: use matrix-type input source selection */
6445 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
6446 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
6447 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6448 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6449 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6450 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6451 /* Input mixer2 */
6452 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6453 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6454 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6455 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6456 /* Input mixer3 */
6457 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6458 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6459 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6460 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6461 /* ADC1: mute amp left and right */
6462 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6463 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
6464 /* ADC2: mute amp left and right */
6465 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6466 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
6467 /* ADC3: mute amp left and right */
6468 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6469 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
6470
6471 { }
6472};
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006473
Takashi Iwai87350ad2007-08-16 18:19:38 +02006474/* Macbook Pro rev3 */
6475static struct hda_verb alc885_mbp3_init_verbs[] = {
6476 /* Front mixer: unmute input/output amp left and right (volume = 0) */
6477 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6478 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6479 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6480 /* Rear mixer */
6481 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6482 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6483 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6484 /* Front Pin: output 0 (0x0c) */
6485 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6486 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6487 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
6488 /* HP Pin: output 0 (0x0d) */
6489 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
6490 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6491 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
6492 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
6493 /* Mic (rear) pin: input vref at 80% */
6494 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
6495 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6496 /* Front Mic pin: input vref at 80% */
6497 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
6498 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6499 /* Line In pin: use output 1 when in LineOut mode */
6500 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
6501 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6502 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
6503
6504 /* FIXME: use matrix-type input source selection */
6505 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
6506 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
6507 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6508 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6509 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6510 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6511 /* Input mixer2 */
6512 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6513 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6514 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6515 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6516 /* Input mixer3 */
6517 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6518 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6519 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6520 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6521 /* ADC1: mute amp left and right */
6522 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6523 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
6524 /* ADC2: mute amp left and right */
6525 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6526 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
6527 /* ADC3: mute amp left and right */
6528 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6529 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
6530
6531 { }
6532};
6533
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006534/* iMac 24 mixer. */
6535static struct snd_kcontrol_new alc885_imac24_mixer[] = {
6536 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
6537 HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x00, HDA_INPUT),
6538 { } /* end */
6539};
6540
6541/* iMac 24 init verbs. */
6542static struct hda_verb alc885_imac24_init_verbs[] = {
6543 /* Internal speakers: output 0 (0x0c) */
6544 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6545 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6546 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
6547 /* Internal speakers: output 0 (0x0c) */
6548 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6549 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6550 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
6551 /* Headphone: output 0 (0x0c) */
6552 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6553 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6554 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
6555 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
6556 /* Front Mic: input vref at 80% */
6557 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
6558 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6559 { }
6560};
6561
6562/* Toggle speaker-output according to the hp-jack state */
6563static void alc885_imac24_automute(struct hda_codec *codec)
6564{
6565 unsigned int present;
6566
6567 present = snd_hda_codec_read(codec, 0x14, 0,
6568 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02006569 snd_hda_codec_amp_stereo(codec, 0x18, HDA_OUTPUT, 0,
6570 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
6571 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0,
6572 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006573}
6574
6575/* Processes unsolicited events. */
6576static void alc885_imac24_unsol_event(struct hda_codec *codec,
6577 unsigned int res)
6578{
6579 /* Headphone insertion or removal. */
6580 if ((res >> 26) == ALC880_HP_EVENT)
6581 alc885_imac24_automute(codec);
6582}
6583
Takashi Iwai87350ad2007-08-16 18:19:38 +02006584static void alc885_mbp3_automute(struct hda_codec *codec)
6585{
6586 unsigned int present;
6587
6588 present = snd_hda_codec_read(codec, 0x15, 0,
6589 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
6590 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
6591 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
6592 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
6593 HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE);
6594
6595}
6596static void alc885_mbp3_unsol_event(struct hda_codec *codec,
6597 unsigned int res)
6598{
6599 /* Headphone insertion or removal. */
6600 if ((res >> 26) == ALC880_HP_EVENT)
6601 alc885_mbp3_automute(codec);
6602}
6603
6604
Kailang Yang272a5272007-05-14 11:00:38 +02006605static struct hda_verb alc882_targa_verbs[] = {
6606 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6607 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6608
6609 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6610 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02006611
Kailang Yang272a5272007-05-14 11:00:38 +02006612 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
6613 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
6614 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
6615
6616 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
6617 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
6618 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
6619 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
6620 { } /* end */
6621};
6622
6623/* toggle speaker-output according to the hp-jack state */
6624static void alc882_targa_automute(struct hda_codec *codec)
6625{
6626 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02006627
Kailang Yang272a5272007-05-14 11:00:38 +02006628 present = snd_hda_codec_read(codec, 0x14, 0,
6629 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02006630 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
6631 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02006632 snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
6633 present ? 1 : 3);
Kailang Yang272a5272007-05-14 11:00:38 +02006634}
6635
6636static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res)
6637{
6638 /* Looks like the unsol event is incompatible with the standard
6639 * definition. 4bit tag is placed at 26 bit!
6640 */
6641 if (((res >> 26) == ALC880_HP_EVENT)) {
6642 alc882_targa_automute(codec);
6643 }
6644}
6645
6646static struct hda_verb alc882_asus_a7j_verbs[] = {
6647 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6648 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6649
6650 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6651 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6652 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02006653
Kailang Yang272a5272007-05-14 11:00:38 +02006654 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
6655 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
6656 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
6657
6658 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
6659 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
6660 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
6661 { } /* end */
6662};
6663
Takashi Iwai914759b2007-09-06 14:52:04 +02006664static struct hda_verb alc882_asus_a7m_verbs[] = {
6665 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6666 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6667
6668 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6669 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6670 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02006671
Takashi Iwai914759b2007-09-06 14:52:04 +02006672 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
6673 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
6674 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
6675
6676 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
6677 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
6678 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
6679 { } /* end */
6680};
6681
Tobin Davis9102cd12006-12-15 10:02:12 +01006682static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted)
6683{
6684 unsigned int gpiostate, gpiomask, gpiodir;
6685
6686 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
6687 AC_VERB_GET_GPIO_DATA, 0);
6688
6689 if (!muted)
6690 gpiostate |= (1 << pin);
6691 else
6692 gpiostate &= ~(1 << pin);
6693
6694 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
6695 AC_VERB_GET_GPIO_MASK, 0);
6696 gpiomask |= (1 << pin);
6697
6698 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
6699 AC_VERB_GET_GPIO_DIRECTION, 0);
6700 gpiodir |= (1 << pin);
6701
6702
6703 snd_hda_codec_write(codec, codec->afg, 0,
6704 AC_VERB_SET_GPIO_MASK, gpiomask);
6705 snd_hda_codec_write(codec, codec->afg, 0,
6706 AC_VERB_SET_GPIO_DIRECTION, gpiodir);
6707
6708 msleep(1);
6709
6710 snd_hda_codec_write(codec, codec->afg, 0,
6711 AC_VERB_SET_GPIO_DATA, gpiostate);
6712}
6713
Takashi Iwai7debbe52007-08-16 15:01:03 +02006714/* set up GPIO at initialization */
6715static void alc885_macpro_init_hook(struct hda_codec *codec)
6716{
6717 alc882_gpio_mute(codec, 0, 0);
6718 alc882_gpio_mute(codec, 1, 0);
6719}
6720
6721/* set up GPIO and update auto-muting at initialization */
6722static void alc885_imac24_init_hook(struct hda_codec *codec)
6723{
6724 alc885_macpro_init_hook(codec);
6725 alc885_imac24_automute(codec);
6726}
6727
Kailang Yangdf694da2005-12-05 19:42:22 +01006728/*
6729 * generic initialization of ADC, input mixers and output mixers
6730 */
6731static struct hda_verb alc882_auto_init_verbs[] = {
6732 /*
6733 * Unmute ADC0-2 and set the default input to mic-in
6734 */
6735 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
6736 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6737 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
6738 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6739 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
6740 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6741
Takashi Iwaicb53c622007-08-10 17:21:45 +02006742 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +01006743 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006744 * Note: PASD motherboards uses the Line In 2 as the input for
6745 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01006746 */
6747 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02006748 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6749 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6750 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6751 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6752 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01006753
6754 /*
6755 * Set up output mixers (0x0c - 0x0f)
6756 */
6757 /* set vol=0 to output mixers */
6758 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6759 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6760 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6761 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6762 /* set up input amps for analog loopback */
6763 /* Amp Indices: DAC = 0, mixer = 1 */
6764 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6765 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6766 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6767 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6768 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6769 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6770 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6771 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6772 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6773 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6774
6775 /* FIXME: use matrix-type input source selection */
6776 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
6777 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
6778 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6779 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
6780 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
6781 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
6782 /* Input mixer2 */
6783 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6784 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
6785 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
6786 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
6787 /* Input mixer3 */
6788 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6789 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
6790 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
6791 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
6792
6793 { }
6794};
6795
Takashi Iwaicb53c622007-08-10 17:21:45 +02006796#ifdef CONFIG_SND_HDA_POWER_SAVE
6797#define alc882_loopbacks alc880_loopbacks
6798#endif
6799
Kailang Yangdf694da2005-12-05 19:42:22 +01006800/* pcm configuration: identiacal with ALC880 */
6801#define alc882_pcm_analog_playback alc880_pcm_analog_playback
6802#define alc882_pcm_analog_capture alc880_pcm_analog_capture
6803#define alc882_pcm_digital_playback alc880_pcm_digital_playback
6804#define alc882_pcm_digital_capture alc880_pcm_digital_capture
6805
6806/*
6807 * configuration and preset
6808 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006809static const char *alc882_models[ALC882_MODEL_LAST] = {
6810 [ALC882_3ST_DIG] = "3stack-dig",
6811 [ALC882_6ST_DIG] = "6stack-dig",
6812 [ALC882_ARIMA] = "arima",
Kailang Yangbdd148a2007-05-08 15:19:08 +02006813 [ALC882_W2JC] = "w2jc",
Takashi Iwai0438a002007-09-06 14:54:11 +02006814 [ALC882_TARGA] = "targa",
6815 [ALC882_ASUS_A7J] = "asus-a7j",
6816 [ALC882_ASUS_A7M] = "asus-a7m",
Tobin Davis9102cd12006-12-15 10:02:12 +01006817 [ALC885_MACPRO] = "macpro",
Takashi Iwai87350ad2007-08-16 18:19:38 +02006818 [ALC885_MBP3] = "mbp3",
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006819 [ALC885_IMAC24] = "imac24",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006820 [ALC882_AUTO] = "auto",
6821};
6822
6823static struct snd_pci_quirk alc882_cfg_tbl[] = {
6824 SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG),
Kailang Yang272a5272007-05-14 11:00:38 +02006825 SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J),
Kailang Yangac8842a2007-09-20 12:51:39 +02006826 SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J),
Takashi Iwai914759b2007-09-06 14:52:04 +02006827 SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01006828 SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC),
Claudio Matsuokac5d9f1c2007-07-19 23:18:32 +02006829 SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG),
Tobin Davis7b9470d2006-12-28 13:56:48 +01006830 SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01006831 SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG),
Jiang zhe44447042008-01-28 12:28:24 +01006832 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01006833 SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */
6834 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG),
6835 SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA),
Kailang Yangdf694da2005-12-05 19:42:22 +01006836 {}
6837};
6838
6839static struct alc_config_preset alc882_presets[] = {
6840 [ALC882_3ST_DIG] = {
6841 .mixers = { alc882_base_mixer },
6842 .init_verbs = { alc882_init_verbs },
6843 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6844 .dac_nids = alc882_dac_nids,
6845 .dig_out_nid = ALC882_DIGOUT_NID,
Kailang Yangdf694da2005-12-05 19:42:22 +01006846 .dig_in_nid = ALC882_DIGIN_NID,
6847 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
6848 .channel_mode = alc882_ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02006849 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01006850 .input_mux = &alc882_capture_source,
6851 },
6852 [ALC882_6ST_DIG] = {
6853 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
6854 .init_verbs = { alc882_init_verbs },
6855 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6856 .dac_nids = alc882_dac_nids,
6857 .dig_out_nid = ALC882_DIGOUT_NID,
Kailang Yangdf694da2005-12-05 19:42:22 +01006858 .dig_in_nid = ALC882_DIGIN_NID,
6859 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
6860 .channel_mode = alc882_sixstack_modes,
6861 .input_mux = &alc882_capture_source,
6862 },
Takashi Iwai4b146cb2006-07-28 14:42:36 +02006863 [ALC882_ARIMA] = {
6864 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
6865 .init_verbs = { alc882_init_verbs, alc882_eapd_verbs },
6866 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6867 .dac_nids = alc882_dac_nids,
6868 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
6869 .channel_mode = alc882_sixstack_modes,
6870 .input_mux = &alc882_capture_source,
6871 },
Kailang Yangbdd148a2007-05-08 15:19:08 +02006872 [ALC882_W2JC] = {
6873 .mixers = { alc882_w2jc_mixer, alc882_chmode_mixer },
6874 .init_verbs = { alc882_init_verbs, alc882_eapd_verbs,
6875 alc880_gpio1_init_verbs },
6876 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6877 .dac_nids = alc882_dac_nids,
6878 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
6879 .channel_mode = alc880_threestack_modes,
6880 .need_dac_fix = 1,
6881 .input_mux = &alc882_capture_source,
6882 .dig_out_nid = ALC882_DIGOUT_NID,
6883 },
Takashi Iwai87350ad2007-08-16 18:19:38 +02006884 [ALC885_MBP3] = {
6885 .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer },
6886 .init_verbs = { alc885_mbp3_init_verbs,
6887 alc880_gpio1_init_verbs },
6888 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6889 .dac_nids = alc882_dac_nids,
6890 .channel_mode = alc885_mbp_6ch_modes,
6891 .num_channel_mode = ARRAY_SIZE(alc885_mbp_6ch_modes),
6892 .input_mux = &alc882_capture_source,
6893 .dig_out_nid = ALC882_DIGOUT_NID,
6894 .dig_in_nid = ALC882_DIGIN_NID,
6895 .unsol_event = alc885_mbp3_unsol_event,
6896 .init_hook = alc885_mbp3_automute,
6897 },
Tobin Davis9102cd12006-12-15 10:02:12 +01006898 [ALC885_MACPRO] = {
6899 .mixers = { alc882_macpro_mixer },
6900 .init_verbs = { alc882_macpro_init_verbs },
6901 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6902 .dac_nids = alc882_dac_nids,
6903 .dig_out_nid = ALC882_DIGOUT_NID,
6904 .dig_in_nid = ALC882_DIGIN_NID,
6905 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
6906 .channel_mode = alc882_ch_modes,
6907 .input_mux = &alc882_capture_source,
Takashi Iwai7debbe52007-08-16 15:01:03 +02006908 .init_hook = alc885_macpro_init_hook,
Tobin Davis9102cd12006-12-15 10:02:12 +01006909 },
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006910 [ALC885_IMAC24] = {
6911 .mixers = { alc885_imac24_mixer },
6912 .init_verbs = { alc885_imac24_init_verbs },
6913 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6914 .dac_nids = alc882_dac_nids,
6915 .dig_out_nid = ALC882_DIGOUT_NID,
6916 .dig_in_nid = ALC882_DIGIN_NID,
6917 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
6918 .channel_mode = alc882_ch_modes,
6919 .input_mux = &alc882_capture_source,
6920 .unsol_event = alc885_imac24_unsol_event,
Takashi Iwai7debbe52007-08-16 15:01:03 +02006921 .init_hook = alc885_imac24_init_hook,
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006922 },
Kailang Yang272a5272007-05-14 11:00:38 +02006923 [ALC882_TARGA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006924 .mixers = { alc882_targa_mixer, alc882_chmode_mixer },
Kailang Yang272a5272007-05-14 11:00:38 +02006925 .init_verbs = { alc882_init_verbs, alc882_targa_verbs},
6926 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6927 .dac_nids = alc882_dac_nids,
6928 .dig_out_nid = ALC882_DIGOUT_NID,
6929 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
6930 .adc_nids = alc882_adc_nids,
Takashi Iwaie1406342008-02-11 18:32:32 +01006931 .capsrc_nids = alc882_capsrc_nids,
Kailang Yang272a5272007-05-14 11:00:38 +02006932 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
6933 .channel_mode = alc882_3ST_6ch_modes,
6934 .need_dac_fix = 1,
6935 .input_mux = &alc882_capture_source,
6936 .unsol_event = alc882_targa_unsol_event,
6937 .init_hook = alc882_targa_automute,
6938 },
6939 [ALC882_ASUS_A7J] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006940 .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer },
Kailang Yang272a5272007-05-14 11:00:38 +02006941 .init_verbs = { alc882_init_verbs, alc882_asus_a7j_verbs},
6942 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6943 .dac_nids = alc882_dac_nids,
6944 .dig_out_nid = ALC882_DIGOUT_NID,
6945 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
6946 .adc_nids = alc882_adc_nids,
Takashi Iwaie1406342008-02-11 18:32:32 +01006947 .capsrc_nids = alc882_capsrc_nids,
Kailang Yang272a5272007-05-14 11:00:38 +02006948 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
6949 .channel_mode = alc882_3ST_6ch_modes,
6950 .need_dac_fix = 1,
6951 .input_mux = &alc882_capture_source,
Kailang Yangea1fb292008-08-26 12:58:38 +02006952 },
Takashi Iwai914759b2007-09-06 14:52:04 +02006953 [ALC882_ASUS_A7M] = {
6954 .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer },
6955 .init_verbs = { alc882_init_verbs, alc882_eapd_verbs,
6956 alc880_gpio1_init_verbs,
6957 alc882_asus_a7m_verbs },
6958 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6959 .dac_nids = alc882_dac_nids,
6960 .dig_out_nid = ALC882_DIGOUT_NID,
6961 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
6962 .channel_mode = alc880_threestack_modes,
6963 .need_dac_fix = 1,
6964 .input_mux = &alc882_capture_source,
Kailang Yangea1fb292008-08-26 12:58:38 +02006965 },
Kailang Yangdf694da2005-12-05 19:42:22 +01006966};
6967
6968
6969/*
Takashi Iwaif95474e2007-07-10 00:47:43 +02006970 * Pin config fixes
6971 */
Kailang Yangea1fb292008-08-26 12:58:38 +02006972enum {
Takashi Iwaif95474e2007-07-10 00:47:43 +02006973 PINFIX_ABIT_AW9D_MAX
6974};
6975
6976static struct alc_pincfg alc882_abit_aw9d_pinfix[] = {
6977 { 0x15, 0x01080104 }, /* side */
6978 { 0x16, 0x01011012 }, /* rear */
6979 { 0x17, 0x01016011 }, /* clfe */
6980 { }
6981};
6982
6983static const struct alc_pincfg *alc882_pin_fixes[] = {
6984 [PINFIX_ABIT_AW9D_MAX] = alc882_abit_aw9d_pinfix,
6985};
6986
6987static struct snd_pci_quirk alc882_pinfix_tbl[] = {
6988 SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
6989 {}
6990};
6991
6992/*
Kailang Yangdf694da2005-12-05 19:42:22 +01006993 * BIOS auto configuration
6994 */
6995static void alc882_auto_set_output_and_unmute(struct hda_codec *codec,
6996 hda_nid_t nid, int pin_type,
6997 int dac_idx)
6998{
6999 /* set as output */
7000 struct alc_spec *spec = codec->spec;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007001 int idx;
7002
Takashi Iwaif6c7e542008-02-12 18:32:23 +01007003 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01007004 if (spec->multiout.dac_nids[dac_idx] == 0x25)
7005 idx = 4;
7006 else
7007 idx = spec->multiout.dac_nids[dac_idx] - 2;
Kailang Yangdf694da2005-12-05 19:42:22 +01007008 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
7009
7010}
7011
7012static void alc882_auto_init_multi_out(struct hda_codec *codec)
7013{
7014 struct alc_spec *spec = codec->spec;
7015 int i;
7016
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007017 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Kailang Yangdf694da2005-12-05 19:42:22 +01007018 for (i = 0; i <= HDA_SIDE; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007019 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02007020 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01007021 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02007022 alc882_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007023 i);
Kailang Yangdf694da2005-12-05 19:42:22 +01007024 }
7025}
7026
7027static void alc882_auto_init_hp_out(struct hda_codec *codec)
7028{
7029 struct alc_spec *spec = codec->spec;
7030 hda_nid_t pin;
7031
Takashi Iwaieb06ed82006-09-20 17:10:27 +02007032 pin = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01007033 if (pin) /* connect to front */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007034 /* use dac 0 */
7035 alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01007036 pin = spec->autocfg.speaker_pins[0];
7037 if (pin)
7038 alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Kailang Yangdf694da2005-12-05 19:42:22 +01007039}
7040
7041#define alc882_is_input_pin(nid) alc880_is_input_pin(nid)
7042#define ALC882_PIN_CD_NID ALC880_PIN_CD_NID
7043
7044static void alc882_auto_init_analog_input(struct hda_codec *codec)
7045{
7046 struct alc_spec *spec = codec->spec;
7047 int i;
7048
7049 for (i = 0; i < AUTO_PIN_LAST; i++) {
7050 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwai7194cae2008-03-06 16:58:17 +01007051 if (!nid)
7052 continue;
Takashi Iwai23f0c042009-02-26 13:03:58 +01007053 alc_set_input_pin(codec, nid, AUTO_PIN_FRONT_MIC /*i*/);
Takashi Iwai7194cae2008-03-06 16:58:17 +01007054 if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
7055 snd_hda_codec_write(codec, nid, 0,
7056 AC_VERB_SET_AMP_GAIN_MUTE,
7057 AMP_OUT_MUTE);
Kailang Yangdf694da2005-12-05 19:42:22 +01007058 }
7059}
7060
Takashi Iwaif511b012008-08-15 16:46:42 +02007061static void alc882_auto_init_input_src(struct hda_codec *codec)
7062{
7063 struct alc_spec *spec = codec->spec;
Takashi Iwaif511b012008-08-15 16:46:42 +02007064 int c;
7065
7066 for (c = 0; c < spec->num_adc_nids; c++) {
7067 hda_nid_t conn_list[HDA_MAX_NUM_INPUTS];
7068 hda_nid_t nid = spec->capsrc_nids[c];
Herton Ronaldo Krzesinskib98b7b32009-01-29 13:18:31 -02007069 unsigned int mux_idx;
7070 const struct hda_input_mux *imux;
Takashi Iwaif511b012008-08-15 16:46:42 +02007071 int conns, mute, idx, item;
7072
7073 conns = snd_hda_get_connections(codec, nid, conn_list,
7074 ARRAY_SIZE(conn_list));
7075 if (conns < 0)
7076 continue;
Herton Ronaldo Krzesinskib98b7b32009-01-29 13:18:31 -02007077 mux_idx = c >= spec->num_mux_defs ? 0 : c;
7078 imux = &spec->input_mux[mux_idx];
Takashi Iwaif511b012008-08-15 16:46:42 +02007079 for (idx = 0; idx < conns; idx++) {
7080 /* if the current connection is the selected one,
7081 * unmute it as default - otherwise mute it
7082 */
7083 mute = AMP_IN_MUTE(idx);
7084 for (item = 0; item < imux->num_items; item++) {
7085 if (imux->items[item].index == idx) {
7086 if (spec->cur_mux[c] == item)
7087 mute = AMP_IN_UNMUTE(idx);
7088 break;
7089 }
7090 }
Herton Ronaldo Krzesinskib98b7b32009-01-29 13:18:31 -02007091 /* check if we have a selector or mixer
7092 * we could check for the widget type instead, but
7093 * just check for Amp-In presence (in case of mixer
7094 * without amp-in there is something wrong, this
7095 * function shouldn't be used or capsrc nid is wrong)
7096 */
7097 if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)
7098 snd_hda_codec_write(codec, nid, 0,
7099 AC_VERB_SET_AMP_GAIN_MUTE,
7100 mute);
7101 else if (mute != AMP_IN_MUTE(idx))
7102 snd_hda_codec_write(codec, nid, 0,
7103 AC_VERB_SET_CONNECT_SEL,
7104 idx);
Takashi Iwaif511b012008-08-15 16:46:42 +02007105 }
7106 }
7107}
7108
Takashi Iwai776e1842007-08-29 15:07:11 +02007109/* add mic boosts if needed */
7110static int alc_auto_add_mic_boost(struct hda_codec *codec)
7111{
7112 struct alc_spec *spec = codec->spec;
7113 int err;
7114 hda_nid_t nid;
7115
7116 nid = spec->autocfg.input_pins[AUTO_PIN_MIC];
Takashi Iwaice22e032008-01-11 17:38:35 +01007117 if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
Takashi Iwai776e1842007-08-29 15:07:11 +02007118 err = add_control(spec, ALC_CTL_WIDGET_VOL,
7119 "Mic Boost",
7120 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
7121 if (err < 0)
7122 return err;
7123 }
7124 nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC];
Takashi Iwaice22e032008-01-11 17:38:35 +01007125 if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
Takashi Iwai776e1842007-08-29 15:07:11 +02007126 err = add_control(spec, ALC_CTL_WIDGET_VOL,
7127 "Front Mic Boost",
7128 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
7129 if (err < 0)
7130 return err;
7131 }
7132 return 0;
7133}
7134
Kailang Yangdf694da2005-12-05 19:42:22 +01007135/* almost identical with ALC880 parser... */
7136static int alc882_parse_auto_config(struct hda_codec *codec)
7137{
7138 struct alc_spec *spec = codec->spec;
7139 int err = alc880_parse_auto_config(codec);
7140
7141 if (err < 0)
7142 return err;
Takashi Iwai776e1842007-08-29 15:07:11 +02007143 else if (!err)
7144 return 0; /* no config found */
7145
7146 err = alc_auto_add_mic_boost(codec);
7147 if (err < 0)
7148 return err;
7149
7150 /* hack - override the init verbs */
7151 spec->init_verbs[0] = alc882_auto_init_verbs;
7152
7153 return 1; /* config found */
Kailang Yangdf694da2005-12-05 19:42:22 +01007154}
7155
Takashi Iwaiae6b8132006-03-03 16:47:17 +01007156/* additional initialization for auto-configuration model */
7157static void alc882_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01007158{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01007159 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01007160 alc882_auto_init_multi_out(codec);
7161 alc882_auto_init_hp_out(codec);
7162 alc882_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +02007163 alc882_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01007164 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02007165 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01007166}
7167
Takashi Iwai7943a8a2008-04-16 17:29:09 +02007168static int patch_alc883(struct hda_codec *codec); /* called in patch_alc882() */
7169
Linus Torvalds1da177e2005-04-16 15:20:36 -07007170static int patch_alc882(struct hda_codec *codec)
7171{
7172 struct alc_spec *spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01007173 int err, board_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007174
Takashi Iwaie560d8d2005-09-09 14:21:46 +02007175 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007176 if (spec == NULL)
7177 return -ENOMEM;
7178
Linus Torvalds1da177e2005-04-16 15:20:36 -07007179 codec->spec = spec;
7180
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007181 board_config = snd_hda_check_board_config(codec, ALC882_MODEL_LAST,
7182 alc882_models,
7183 alc882_cfg_tbl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007184
Kailang Yangdf694da2005-12-05 19:42:22 +01007185 if (board_config < 0 || board_config >= ALC882_MODEL_LAST) {
Tobin Davis081d17c2007-02-15 17:46:18 +01007186 /* Pick up systems that don't supply PCI SSID */
7187 switch (codec->subsystem_id) {
7188 case 0x106b0c00: /* Mac Pro */
7189 board_config = ALC885_MACPRO;
7190 break;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02007191 case 0x106b1000: /* iMac 24 */
Peter Korsgaardf3911c52008-09-27 09:13:45 +02007192 case 0x106b2800: /* AppleTV */
Mark Eggleston3077e442009-01-31 17:57:54 +01007193 case 0x106b3e00: /* iMac 24 Aluminium */
Nicola Fagnanic54728d2007-07-19 23:28:52 +02007194 board_config = ALC885_IMAC24;
7195 break;
Luke Yelavich2d466382009-02-23 13:00:33 +11007196 case 0x106b00a0: /* MacBookPro3,1 - Another revision */
Takashi Iwaic7e07572008-06-26 14:42:51 +02007197 case 0x106b00a1: /* Macbook (might be wrong - PCI SSID?) */
David Woodhouse9c95c432008-09-18 13:37:13 -07007198 case 0x106b00a4: /* MacbookPro4,1 */
Takashi Iwai87350ad2007-08-16 18:19:38 +02007199 case 0x106b2c00: /* Macbook Pro rev3 */
Takashi Iwaic7e07572008-06-26 14:42:51 +02007200 case 0x106b3600: /* Macbook 3.1 */
Luke Yelavich2a884642009-01-28 15:58:38 +11007201 case 0x106b3800: /* MacbookPro4,1 - latter revision */
Takashi Iwai87350ad2007-08-16 18:19:38 +02007202 board_config = ALC885_MBP3;
7203 break;
Tobin Davis081d17c2007-02-15 17:46:18 +01007204 default:
Takashi Iwai7943a8a2008-04-16 17:29:09 +02007205 /* ALC889A is handled better as ALC888-compatible */
Clive Messer669faba2008-09-30 15:49:13 +02007206 if (codec->revision_id == 0x100101 ||
7207 codec->revision_id == 0x100103) {
Takashi Iwai7943a8a2008-04-16 17:29:09 +02007208 alc_free(codec);
7209 return patch_alc883(codec);
7210 }
Tobin Davis081d17c2007-02-15 17:46:18 +01007211 printk(KERN_INFO "hda_codec: Unknown model for ALC882, "
7212 "trying auto-probe from BIOS...\n");
7213 board_config = ALC882_AUTO;
7214 }
Kailang Yangdf694da2005-12-05 19:42:22 +01007215 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007216
Takashi Iwaif95474e2007-07-10 00:47:43 +02007217 alc_fix_pincfg(codec, alc882_pinfix_tbl, alc882_pin_fixes);
7218
Kailang Yangdf694da2005-12-05 19:42:22 +01007219 if (board_config == ALC882_AUTO) {
7220 /* automatic parse from the BIOS config */
7221 err = alc882_parse_auto_config(codec);
7222 if (err < 0) {
7223 alc_free(codec);
7224 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007225 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007226 printk(KERN_INFO
7227 "hda_codec: Cannot set up configuration "
7228 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01007229 board_config = ALC882_3ST_DIG;
7230 }
7231 }
7232
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09007233 err = snd_hda_attach_beep_device(codec, 0x1);
7234 if (err < 0) {
7235 alc_free(codec);
7236 return err;
7237 }
7238
Kailang Yangdf694da2005-12-05 19:42:22 +01007239 if (board_config != ALC882_AUTO)
7240 setup_preset(spec, &alc882_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007241
Kailang Yang2f893282008-05-27 12:14:47 +02007242 if (codec->vendor_id == 0x10ec0885) {
7243 spec->stream_name_analog = "ALC885 Analog";
7244 spec->stream_name_digital = "ALC885 Digital";
7245 } else {
7246 spec->stream_name_analog = "ALC882 Analog";
7247 spec->stream_name_digital = "ALC882 Digital";
7248 }
7249
Kailang Yangdf694da2005-12-05 19:42:22 +01007250 spec->stream_analog_playback = &alc882_pcm_analog_playback;
7251 spec->stream_analog_capture = &alc882_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01007252 /* FIXME: setup DAC5 */
7253 /*spec->stream_analog_alt_playback = &alc880_pcm_analog_alt_playback;*/
7254 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007255
Kailang Yangdf694da2005-12-05 19:42:22 +01007256 spec->stream_digital_playback = &alc882_pcm_digital_playback;
7257 spec->stream_digital_capture = &alc882_pcm_digital_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007258
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02007259 spec->capture_style = CAPT_MIX; /* matrix-style capture */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007260 if (!spec->adc_nids && spec->input_mux) {
Kailang Yangdf694da2005-12-05 19:42:22 +01007261 /* check whether NID 0x07 is valid */
Takashi Iwai4a471b72005-12-07 13:56:29 +01007262 unsigned int wcap = get_wcaps(codec, 0x07);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007263 /* get type */
7264 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Kailang Yangdf694da2005-12-05 19:42:22 +01007265 if (wcap != AC_WID_AUD_IN) {
7266 spec->adc_nids = alc882_adc_nids_alt;
7267 spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids_alt);
Takashi Iwaie1406342008-02-11 18:32:32 +01007268 spec->capsrc_nids = alc882_capsrc_nids_alt;
Kailang Yangdf694da2005-12-05 19:42:22 +01007269 } else {
7270 spec->adc_nids = alc882_adc_nids;
7271 spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids);
Takashi Iwaie1406342008-02-11 18:32:32 +01007272 spec->capsrc_nids = alc882_capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +01007273 }
7274 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007275 set_capture_mixer(spec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01007276 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007277
Takashi Iwai2134ea42008-01-10 16:53:55 +01007278 spec->vmaster_nid = 0x0c;
7279
Linus Torvalds1da177e2005-04-16 15:20:36 -07007280 codec->patch_ops = alc_patch_ops;
Kailang Yangdf694da2005-12-05 19:42:22 +01007281 if (board_config == ALC882_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01007282 spec->init_hook = alc882_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02007283#ifdef CONFIG_SND_HDA_POWER_SAVE
7284 if (!spec->loopback.amplist)
7285 spec->loopback.amplist = alc882_loopbacks;
7286#endif
Takashi Iwaidaead532008-11-28 12:55:36 +01007287 codec->proc_widget_hook = print_realtek_coef;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007288
7289 return 0;
7290}
7291
7292/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007293 * ALC883 support
7294 *
7295 * ALC883 is almost identical with ALC880 but has cleaner and more flexible
7296 * configuration. Each pin widget can choose any input DACs and a mixer.
7297 * Each ADC is connected from a mixer of all inputs. This makes possible
7298 * 6-channel independent captures.
7299 *
7300 * In addition, an independent DAC for the multi-playback (not used in this
7301 * driver yet).
7302 */
7303#define ALC883_DIGOUT_NID 0x06
7304#define ALC883_DIGIN_NID 0x0a
7305
Wu Fengguang3ab90932008-11-17 09:51:09 +01007306#define ALC1200_DIGOUT_NID 0x10
7307
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007308static hda_nid_t alc883_dac_nids[4] = {
7309 /* front, rear, clfe, rear_surr */
Herton Ronaldo Krzesinskif32a19e2008-03-18 09:27:08 +01007310 0x02, 0x03, 0x04, 0x05
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007311};
7312
7313static hda_nid_t alc883_adc_nids[2] = {
7314 /* ADC1-2 */
7315 0x08, 0x09,
7316};
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007317
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007318static hda_nid_t alc883_adc_nids_alt[1] = {
7319 /* ADC1 */
7320 0x08,
7321};
7322
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08007323static hda_nid_t alc883_adc_nids_rev[2] = {
7324 /* ADC2-1 */
7325 0x09, 0x08
7326};
7327
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02007328#define alc889_adc_nids alc880_adc_nids
7329
Takashi Iwaie1406342008-02-11 18:32:32 +01007330static hda_nid_t alc883_capsrc_nids[2] = { 0x23, 0x22 };
7331
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08007332static hda_nid_t alc883_capsrc_nids_rev[2] = { 0x22, 0x23 };
7333
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02007334#define alc889_capsrc_nids alc882_capsrc_nids
7335
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007336/* input MUX */
7337/* FIXME: should be a matrix-type input source selection */
7338
7339static struct hda_input_mux alc883_capture_source = {
7340 .num_items = 4,
7341 .items = {
7342 { "Mic", 0x0 },
7343 { "Front Mic", 0x1 },
7344 { "Line", 0x2 },
7345 { "CD", 0x4 },
7346 },
7347};
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007348
Jiang zhe17bba1b2008-06-04 12:11:07 +02007349static struct hda_input_mux alc883_3stack_6ch_intel = {
7350 .num_items = 4,
7351 .items = {
7352 { "Mic", 0x1 },
7353 { "Front Mic", 0x0 },
7354 { "Line", 0x2 },
7355 { "CD", 0x4 },
7356 },
7357};
7358
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007359static struct hda_input_mux alc883_lenovo_101e_capture_source = {
7360 .num_items = 2,
7361 .items = {
7362 { "Mic", 0x1 },
7363 { "Line", 0x2 },
7364 },
7365};
7366
Kailang Yang272a5272007-05-14 11:00:38 +02007367static struct hda_input_mux alc883_lenovo_nb0763_capture_source = {
7368 .num_items = 4,
7369 .items = {
7370 { "Mic", 0x0 },
7371 { "iMic", 0x1 },
7372 { "Line", 0x2 },
7373 { "CD", 0x4 },
7374 },
7375};
7376
Jiang zhefb97dc62008-03-06 11:07:11 +01007377static struct hda_input_mux alc883_fujitsu_pi2515_capture_source = {
7378 .num_items = 2,
7379 .items = {
7380 { "Mic", 0x0 },
7381 { "Int Mic", 0x1 },
7382 },
7383};
7384
Kailang Yange2757d52008-08-26 13:17:46 +02007385static struct hda_input_mux alc883_lenovo_sky_capture_source = {
7386 .num_items = 3,
7387 .items = {
7388 { "Mic", 0x0 },
7389 { "Front Mic", 0x1 },
7390 { "Line", 0x4 },
7391 },
7392};
7393
7394static struct hda_input_mux alc883_asus_eee1601_capture_source = {
7395 .num_items = 2,
7396 .items = {
7397 { "Mic", 0x0 },
7398 { "Line", 0x2 },
7399 },
7400};
7401
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007402/*
7403 * 2ch mode
7404 */
7405static struct hda_channel_mode alc883_3ST_2ch_modes[1] = {
7406 { 2, NULL }
7407};
7408
7409/*
7410 * 2ch mode
7411 */
7412static struct hda_verb alc883_3ST_ch2_init[] = {
7413 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7414 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7415 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7416 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7417 { } /* end */
7418};
7419
7420/*
Tobin Davisb2011312007-09-17 12:45:11 +02007421 * 4ch mode
7422 */
7423static struct hda_verb alc883_3ST_ch4_init[] = {
7424 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7425 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7426 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7427 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7428 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7429 { } /* end */
7430};
7431
7432/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007433 * 6ch mode
7434 */
7435static struct hda_verb alc883_3ST_ch6_init[] = {
7436 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7437 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7438 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7439 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7440 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7441 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7442 { } /* end */
7443};
7444
Tobin Davisb2011312007-09-17 12:45:11 +02007445static struct hda_channel_mode alc883_3ST_6ch_modes[3] = {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007446 { 2, alc883_3ST_ch2_init },
Tobin Davisb2011312007-09-17 12:45:11 +02007447 { 4, alc883_3ST_ch4_init },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007448 { 6, alc883_3ST_ch6_init },
7449};
7450
7451/*
Jiang zhe17bba1b2008-06-04 12:11:07 +02007452 * 2ch mode
7453 */
7454static struct hda_verb alc883_3ST_ch2_intel_init[] = {
7455 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7456 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7457 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7458 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7459 { } /* end */
7460};
7461
7462/*
7463 * 4ch mode
7464 */
7465static struct hda_verb alc883_3ST_ch4_intel_init[] = {
7466 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7467 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7468 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7469 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7470 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7471 { } /* end */
7472};
7473
7474/*
7475 * 6ch mode
7476 */
7477static struct hda_verb alc883_3ST_ch6_intel_init[] = {
7478 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7479 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7480 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x02 },
7481 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7482 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7483 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7484 { } /* end */
7485};
7486
7487static struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = {
7488 { 2, alc883_3ST_ch2_intel_init },
7489 { 4, alc883_3ST_ch4_intel_init },
7490 { 6, alc883_3ST_ch6_intel_init },
7491};
7492
7493/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007494 * 6ch mode
7495 */
7496static struct hda_verb alc883_sixstack_ch6_init[] = {
7497 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
7498 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7499 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7500 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7501 { } /* end */
7502};
7503
7504/*
7505 * 8ch mode
7506 */
7507static struct hda_verb alc883_sixstack_ch8_init[] = {
7508 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7509 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7510 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7511 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7512 { } /* end */
7513};
7514
7515static struct hda_channel_mode alc883_sixstack_modes[2] = {
7516 { 6, alc883_sixstack_ch6_init },
7517 { 8, alc883_sixstack_ch8_init },
7518};
7519
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01007520static struct hda_verb alc883_medion_eapd_verbs[] = {
7521 /* eanable EAPD on medion laptop */
7522 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
7523 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
7524 { }
7525};
7526
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007527/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
7528 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
7529 */
7530
7531static struct snd_kcontrol_new alc883_base_mixer[] = {
7532 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7533 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7534 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7535 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
7536 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7537 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
7538 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7539 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
7540 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
7541 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
7542 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7543 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7544 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7545 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7546 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7547 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007548 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007549 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7550 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007551 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007552 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007553 { } /* end */
7554};
7555
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01007556static struct snd_kcontrol_new alc883_mitac_mixer[] = {
7557 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7558 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7559 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7560 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
7561 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7562 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
7563 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
7564 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7565 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7566 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7567 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7568 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
7569 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01007570 { } /* end */
7571};
7572
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007573static struct snd_kcontrol_new alc883_clevo_m720_mixer[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01007574 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7575 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
7576 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7577 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
7578 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7579 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7580 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7581 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7582 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
7583 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Jiang zhe368c7a92008-03-04 11:20:33 +01007584 { } /* end */
7585};
7586
Jiang zhefb97dc62008-03-06 11:07:11 +01007587static struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = {
7588 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7589 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
7590 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7591 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
7592 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7593 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7594 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7595 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7596 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
7597 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Jiang zhefb97dc62008-03-06 11:07:11 +01007598 { } /* end */
7599};
7600
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007601static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = {
7602 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7603 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7604 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7605 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7606 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7607 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7608 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7609 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007610 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007611 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7612 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007613 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007614 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007615 { } /* end */
7616};
7617
7618static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
7619 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7620 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7621 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7622 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
7623 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7624 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
7625 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7626 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
7627 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 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("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7631 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7632 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007633 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007634 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7635 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007636 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007637 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007638 { } /* end */
7639};
7640
Jiang zhe17bba1b2008-06-04 12:11:07 +02007641static struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = {
7642 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7643 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7644 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7645 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
7646 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
7647 HDA_OUTPUT),
7648 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
7649 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7650 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
7651 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
7652 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7653 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7654 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7655 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7656 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7657 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
7658 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
7659 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7660 HDA_CODEC_VOLUME("Front Mic Boost", 0x18, 0, HDA_INPUT),
7661 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Jiang zhe17bba1b2008-06-04 12:11:07 +02007662 { } /* end */
7663};
7664
Takashi Iwaid1d985f2006-11-23 19:27:12 +01007665static struct snd_kcontrol_new alc883_fivestack_mixer[] = {
Tobin Davisc07584c2006-10-13 12:32:16 +02007666 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02007667 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007668 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02007669 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007670 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7671 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02007672 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7673 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007674 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7675 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7676 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7677 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7678 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7679 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007680 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007681 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7682 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007683 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007684 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007685 { } /* end */
7686};
7687
Kailang Yangccc656c2006-10-17 12:32:26 +02007688static struct snd_kcontrol_new alc883_tagra_mixer[] = {
7689 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7690 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7691 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7692 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7693 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
7694 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7695 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
7696 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7697 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
7698 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7699 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7700 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7701 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7702 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007703 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02007704 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02007705 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007706};
Kailang Yangccc656c2006-10-17 12:32:26 +02007707
7708static struct snd_kcontrol_new alc883_tagra_2ch_mixer[] = {
7709 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7710 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7711 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7712 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7713 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7714 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007715 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02007716 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Jiang zhe4383fae2008-04-14 12:58:57 +02007717 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7718 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
7719 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02007720 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007721};
Kailang Yangccc656c2006-10-17 12:32:26 +02007722
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007723static struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = {
7724 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7725 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01007726 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7727 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007728 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7729 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7730 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7731 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007732 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007733};
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007734
Kailang Yang272a5272007-05-14 11:00:38 +02007735static struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = {
7736 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7737 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
7738 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7739 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7740 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7741 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7742 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7743 HDA_CODEC_VOLUME("iMic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7744 HDA_CODEC_MUTE("iMic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02007745 { } /* end */
7746};
7747
7748static struct snd_kcontrol_new alc883_medion_md2_mixer[] = {
7749 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7750 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7751 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
7752 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7753 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7754 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7755 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7756 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7757 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02007758 { } /* end */
Kailang Yangea1fb292008-08-26 12:58:38 +02007759};
Kailang Yang272a5272007-05-14 11:00:38 +02007760
Tobin Davis2880a862007-08-07 11:50:26 +02007761static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = {
Kailang Yangd1a991a2007-08-15 16:21:59 +02007762 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7763 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02007764 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02007765 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7766 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Kailang Yangd1a991a2007-08-15 16:21:59 +02007767 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7768 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7769 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02007770 { } /* end */
Kailang Yangd1a991a2007-08-15 16:21:59 +02007771};
Tobin Davis2880a862007-08-07 11:50:26 +02007772
Kailang Yange2757d52008-08-26 13:17:46 +02007773static struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = {
7774 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7775 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7776 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
7777 HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
7778 HDA_CODEC_VOLUME_MONO("Center Playback Volume",
7779 0x0d, 1, 0x0, HDA_OUTPUT),
7780 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
7781 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
7782 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
7783 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
7784 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
7785 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7786 HDA_CODEC_MUTE("iSpeaker Playback Switch", 0x1a, 0x0, HDA_OUTPUT),
7787 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7788 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7789 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7790 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7791 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7792 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7793 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7794 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7795 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
7796 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02007797 { } /* end */
7798};
7799
7800static struct hda_bind_ctls alc883_bind_cap_vol = {
7801 .ops = &snd_hda_bind_vol,
7802 .values = {
7803 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
7804 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
7805 0
7806 },
7807};
7808
7809static struct hda_bind_ctls alc883_bind_cap_switch = {
7810 .ops = &snd_hda_bind_sw,
7811 .values = {
7812 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
7813 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
7814 0
7815 },
7816};
7817
7818static struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = {
7819 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7820 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7821 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7822 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7823 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7824 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7825 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7826 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007827 { } /* end */
7828};
7829
7830static struct snd_kcontrol_new alc883_asus_eee1601_cap_mixer[] = {
Kailang Yange2757d52008-08-26 13:17:46 +02007831 HDA_BIND_VOL("Capture Volume", &alc883_bind_cap_vol),
7832 HDA_BIND_SW("Capture Switch", &alc883_bind_cap_switch),
7833 {
7834 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7835 /* .name = "Capture Source", */
7836 .name = "Input Source",
7837 .count = 1,
Takashi Iwai54cbc9a2008-10-31 15:24:04 +01007838 .info = alc_mux_enum_info,
7839 .get = alc_mux_enum_get,
7840 .put = alc_mux_enum_put,
Kailang Yange2757d52008-08-26 13:17:46 +02007841 },
7842 { } /* end */
7843};
7844
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007845static struct snd_kcontrol_new alc883_chmode_mixer[] = {
7846 {
7847 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7848 .name = "Channel Mode",
7849 .info = alc_ch_mode_info,
7850 .get = alc_ch_mode_get,
7851 .put = alc_ch_mode_put,
7852 },
7853 { } /* end */
7854};
7855
7856static struct hda_verb alc883_init_verbs[] = {
7857 /* ADC1: mute amp left and right */
Kailang Yange2757d52008-08-26 13:17:46 +02007858 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007859 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
7860 /* ADC2: mute amp left and right */
7861 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7862 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
7863 /* Front mixer: unmute input/output amp left and right (volume = 0) */
7864 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7865 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7866 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7867 /* Rear mixer */
7868 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7869 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7870 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7871 /* CLFE mixer */
7872 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7873 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7874 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7875 /* Side mixer */
7876 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7877 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7878 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7879
Takashi Iwaicb53c622007-08-10 17:21:45 +02007880 /* mute analog input loopbacks */
7881 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7882 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7883 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7884 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7885 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007886
7887 /* Front Pin: output 0 (0x0c) */
7888 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7889 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7890 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
7891 /* Rear Pin: output 1 (0x0d) */
7892 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7893 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7894 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
7895 /* CLFE Pin: output 2 (0x0e) */
7896 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7897 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7898 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
7899 /* Side Pin: output 3 (0x0f) */
7900 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7901 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7902 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
7903 /* Mic (rear) pin: input vref at 80% */
7904 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7905 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7906 /* Front Mic pin: input vref at 80% */
7907 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7908 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7909 /* Line In pin: input */
7910 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
7911 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7912 /* Line-2 In: Headphone output (output 0 - 0x0c) */
7913 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7914 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7915 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
7916 /* CD pin widget for input */
7917 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
7918
7919 /* FIXME: use matrix-type input source selection */
7920 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
7921 /* Input mixer2 */
7922 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yange2757d52008-08-26 13:17:46 +02007923 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7924 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7925 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007926 /* Input mixer3 */
7927 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yange2757d52008-08-26 13:17:46 +02007928 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7929 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7930 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007931 { }
7932};
7933
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01007934/* toggle speaker-output according to the hp-jack state */
7935static void alc883_mitac_hp_automute(struct hda_codec *codec)
7936{
7937 unsigned int present;
7938
7939 present = snd_hda_codec_read(codec, 0x15, 0,
7940 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7941 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7942 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7943 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
7944 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7945}
7946
7947/* auto-toggle front mic */
7948/*
7949static void alc883_mitac_mic_automute(struct hda_codec *codec)
7950{
7951 unsigned int present;
7952 unsigned char bits;
7953
7954 present = snd_hda_codec_read(codec, 0x18, 0,
7955 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7956 bits = present ? HDA_AMP_MUTE : 0;
7957 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
7958}
7959*/
7960
7961static void alc883_mitac_automute(struct hda_codec *codec)
7962{
7963 alc883_mitac_hp_automute(codec);
7964 /* alc883_mitac_mic_automute(codec); */
7965}
7966
7967static void alc883_mitac_unsol_event(struct hda_codec *codec,
7968 unsigned int res)
7969{
7970 switch (res >> 26) {
7971 case ALC880_HP_EVENT:
7972 alc883_mitac_hp_automute(codec);
7973 break;
7974 case ALC880_MIC_EVENT:
7975 /* alc883_mitac_mic_automute(codec); */
7976 break;
7977 }
7978}
7979
7980static struct hda_verb alc883_mitac_verbs[] = {
7981 /* HP */
7982 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7983 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7984 /* Subwoofer */
7985 {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
7986 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7987
7988 /* enable unsolicited event */
7989 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7990 /* {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, */
7991
7992 { } /* end */
7993};
7994
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007995static struct hda_verb alc883_clevo_m720_verbs[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01007996 /* HP */
7997 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7998 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7999 /* Int speaker */
8000 {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
8001 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8002
8003 /* enable unsolicited event */
8004 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008005 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Jiang zhe368c7a92008-03-04 11:20:33 +01008006
8007 { } /* end */
8008};
8009
Jiang zhefb97dc62008-03-06 11:07:11 +01008010static struct hda_verb alc883_2ch_fujitsu_pi2515_verbs[] = {
8011 /* HP */
8012 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8013 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8014 /* Subwoofer */
8015 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
8016 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8017
8018 /* enable unsolicited event */
8019 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8020
8021 { } /* end */
8022};
8023
Kailang Yangccc656c2006-10-17 12:32:26 +02008024static struct hda_verb alc883_tagra_verbs[] = {
8025 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8026 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8027
8028 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8029 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02008030
Kailang Yangccc656c2006-10-17 12:32:26 +02008031 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
8032 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
8033 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8034
8035 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008036 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
8037 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
8038 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
Kailang Yangccc656c2006-10-17 12:32:26 +02008039
8040 { } /* end */
8041};
8042
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008043static struct hda_verb alc883_lenovo_101e_verbs[] = {
8044 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8045 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT|AC_USRSP_EN},
8046 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT|AC_USRSP_EN},
8047 { } /* end */
8048};
8049
Kailang Yang272a5272007-05-14 11:00:38 +02008050static struct hda_verb alc883_lenovo_nb0763_verbs[] = {
8051 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8052 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8053 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8054 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8055 { } /* end */
8056};
8057
8058static struct hda_verb alc888_lenovo_ms7195_verbs[] = {
8059 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8060 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8061 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8062 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT | AC_USRSP_EN},
8063 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8064 { } /* end */
8065};
8066
Kailang Yang189609a2007-08-20 11:31:23 +02008067static struct hda_verb alc883_haier_w66_verbs[] = {
8068 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8069 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8070
8071 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8072
8073 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
8074 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8075 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8076 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8077 { } /* end */
8078};
8079
Kailang Yange2757d52008-08-26 13:17:46 +02008080static struct hda_verb alc888_lenovo_sky_verbs[] = {
8081 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8082 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8083 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8084 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8085 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8086 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8087 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
8088 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8089 { } /* end */
8090};
8091
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03008092static struct hda_verb alc888_6st_dell_verbs[] = {
8093 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8094 { }
8095};
8096
8097static void alc888_3st_hp_front_automute(struct hda_codec *codec)
8098{
8099 unsigned int present, bits;
8100
8101 present = snd_hda_codec_read(codec, 0x1b, 0,
8102 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
8103 bits = present ? HDA_AMP_MUTE : 0;
8104 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8105 HDA_AMP_MUTE, bits);
8106 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
8107 HDA_AMP_MUTE, bits);
8108 snd_hda_codec_amp_stereo(codec, 0x18, HDA_OUTPUT, 0,
8109 HDA_AMP_MUTE, bits);
8110}
8111
8112static void alc888_3st_hp_unsol_event(struct hda_codec *codec,
8113 unsigned int res)
8114{
8115 switch (res >> 26) {
8116 case ALC880_HP_EVENT:
8117 alc888_3st_hp_front_automute(codec);
8118 break;
8119 }
8120}
8121
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008122static struct hda_verb alc888_3st_hp_verbs[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008123 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */
Herton Ronaldo Krzesinskif32a19e2008-03-18 09:27:08 +01008124 {0x16, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Rear : output 1 (0x0d) */
8125 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* CLFE : output 2 (0x0e) */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008126 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03008127 { } /* end */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008128};
8129
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03008130/*
8131 * 2ch mode
8132 */
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008133static struct hda_verb alc888_3st_hp_2ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008134 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
8135 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
8136 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
8137 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03008138 { } /* end */
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008139};
8140
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03008141/*
8142 * 4ch mode
8143 */
8144static struct hda_verb alc888_3st_hp_4ch_init[] = {
8145 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
8146 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
8147 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8148 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
8149 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 },
8150 { } /* end */
8151};
8152
8153/*
8154 * 6ch mode
8155 */
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008156static struct hda_verb alc888_3st_hp_6ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008157 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8158 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03008159 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008160 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8161 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03008162 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 },
8163 { } /* end */
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008164};
8165
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03008166static struct hda_channel_mode alc888_3st_hp_modes[3] = {
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008167 { 2, alc888_3st_hp_2ch_init },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03008168 { 4, alc888_3st_hp_4ch_init },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008169 { 6, alc888_3st_hp_6ch_init },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008170};
8171
Kailang Yang272a5272007-05-14 11:00:38 +02008172/* toggle front-jack and RCA according to the hp-jack state */
8173static void alc888_lenovo_ms7195_front_automute(struct hda_codec *codec)
8174{
8175 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02008176
Kailang Yang272a5272007-05-14 11:00:38 +02008177 present = snd_hda_codec_read(codec, 0x1b, 0,
8178 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02008179 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8180 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
8181 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8182 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02008183}
8184
8185/* toggle RCA according to the front-jack state */
8186static void alc888_lenovo_ms7195_rca_automute(struct hda_codec *codec)
8187{
8188 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02008189
Kailang Yang272a5272007-05-14 11:00:38 +02008190 present = snd_hda_codec_read(codec, 0x14, 0,
8191 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02008192 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8193 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02008194}
Takashi Iwai47fd8302007-08-10 17:11:07 +02008195
Kailang Yang272a5272007-05-14 11:00:38 +02008196static void alc883_lenovo_ms7195_unsol_event(struct hda_codec *codec,
8197 unsigned int res)
8198{
8199 if ((res >> 26) == ALC880_HP_EVENT)
8200 alc888_lenovo_ms7195_front_automute(codec);
8201 if ((res >> 26) == ALC880_FRONT_EVENT)
8202 alc888_lenovo_ms7195_rca_automute(codec);
8203}
8204
8205static struct hda_verb alc883_medion_md2_verbs[] = {
8206 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8207 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8208
8209 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8210
8211 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8212 { } /* end */
8213};
8214
8215/* toggle speaker-output according to the hp-jack state */
8216static void alc883_medion_md2_automute(struct hda_codec *codec)
8217{
8218 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02008219
Kailang Yang272a5272007-05-14 11:00:38 +02008220 present = snd_hda_codec_read(codec, 0x14, 0,
8221 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02008222 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8223 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02008224}
8225
8226static void alc883_medion_md2_unsol_event(struct hda_codec *codec,
8227 unsigned int res)
8228{
8229 if ((res >> 26) == ALC880_HP_EVENT)
8230 alc883_medion_md2_automute(codec);
8231}
8232
Kailang Yangccc656c2006-10-17 12:32:26 +02008233/* toggle speaker-output according to the hp-jack state */
8234static void alc883_tagra_automute(struct hda_codec *codec)
8235{
8236 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008237 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02008238
8239 present = snd_hda_codec_read(codec, 0x14, 0,
8240 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02008241 bits = present ? HDA_AMP_MUTE : 0;
8242 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
8243 HDA_AMP_MUTE, bits);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02008244 snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
8245 present ? 1 : 3);
Kailang Yangccc656c2006-10-17 12:32:26 +02008246}
8247
8248static void alc883_tagra_unsol_event(struct hda_codec *codec, unsigned int res)
8249{
8250 if ((res >> 26) == ALC880_HP_EVENT)
8251 alc883_tagra_automute(codec);
8252}
8253
Jiang zhe368c7a92008-03-04 11:20:33 +01008254/* toggle speaker-output according to the hp-jack state */
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008255static void alc883_clevo_m720_hp_automute(struct hda_codec *codec)
Jiang zhe368c7a92008-03-04 11:20:33 +01008256{
8257 unsigned int present;
8258 unsigned char bits;
8259
8260 present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0)
8261 & AC_PINSENSE_PRESENCE;
8262 bits = present ? HDA_AMP_MUTE : 0;
8263 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8264 HDA_AMP_MUTE, bits);
8265}
8266
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008267static void alc883_clevo_m720_mic_automute(struct hda_codec *codec)
8268{
8269 unsigned int present;
8270
8271 present = snd_hda_codec_read(codec, 0x18, 0,
8272 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
8273 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
8274 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
8275}
8276
8277static void alc883_clevo_m720_automute(struct hda_codec *codec)
8278{
8279 alc883_clevo_m720_hp_automute(codec);
8280 alc883_clevo_m720_mic_automute(codec);
8281}
8282
8283static void alc883_clevo_m720_unsol_event(struct hda_codec *codec,
Jiang zhe368c7a92008-03-04 11:20:33 +01008284 unsigned int res)
8285{
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008286 switch (res >> 26) {
8287 case ALC880_HP_EVENT:
8288 alc883_clevo_m720_hp_automute(codec);
8289 break;
8290 case ALC880_MIC_EVENT:
8291 alc883_clevo_m720_mic_automute(codec);
8292 break;
8293 }
Jiang zhe368c7a92008-03-04 11:20:33 +01008294}
8295
Jiang zhefb97dc62008-03-06 11:07:11 +01008296/* toggle speaker-output according to the hp-jack state */
8297static void alc883_2ch_fujitsu_pi2515_automute(struct hda_codec *codec)
8298{
8299 unsigned int present;
8300 unsigned char bits;
8301
8302 present = snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0)
8303 & AC_PINSENSE_PRESENCE;
8304 bits = present ? HDA_AMP_MUTE : 0;
8305 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8306 HDA_AMP_MUTE, bits);
8307}
8308
8309static void alc883_2ch_fujitsu_pi2515_unsol_event(struct hda_codec *codec,
8310 unsigned int res)
8311{
8312 if ((res >> 26) == ALC880_HP_EVENT)
8313 alc883_2ch_fujitsu_pi2515_automute(codec);
8314}
8315
Kailang Yang189609a2007-08-20 11:31:23 +02008316static void alc883_haier_w66_automute(struct hda_codec *codec)
8317{
8318 unsigned int present;
8319 unsigned char bits;
8320
8321 present = snd_hda_codec_read(codec, 0x1b, 0,
8322 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
8323 bits = present ? 0x80 : 0;
8324 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8325 0x80, bits);
8326}
8327
8328static void alc883_haier_w66_unsol_event(struct hda_codec *codec,
8329 unsigned int res)
8330{
8331 if ((res >> 26) == ALC880_HP_EVENT)
8332 alc883_haier_w66_automute(codec);
8333}
8334
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008335static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
8336{
8337 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008338 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008339
8340 present = snd_hda_codec_read(codec, 0x14, 0,
8341 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02008342 bits = present ? HDA_AMP_MUTE : 0;
8343 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8344 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008345}
8346
8347static void alc883_lenovo_101e_all_automute(struct hda_codec *codec)
8348{
8349 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008350 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008351
8352 present = snd_hda_codec_read(codec, 0x1b, 0,
8353 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02008354 bits = present ? HDA_AMP_MUTE : 0;
8355 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8356 HDA_AMP_MUTE, bits);
8357 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8358 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008359}
8360
8361static void alc883_lenovo_101e_unsol_event(struct hda_codec *codec,
8362 unsigned int res)
8363{
8364 if ((res >> 26) == ALC880_HP_EVENT)
8365 alc883_lenovo_101e_all_automute(codec);
8366 if ((res >> 26) == ALC880_FRONT_EVENT)
8367 alc883_lenovo_101e_ispeaker_automute(codec);
8368}
8369
Takashi Iwai676a9b52007-08-16 15:23:35 +02008370/* toggle speaker-output according to the hp-jack state */
8371static void alc883_acer_aspire_automute(struct hda_codec *codec)
8372{
8373 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02008374
Takashi Iwai676a9b52007-08-16 15:23:35 +02008375 present = snd_hda_codec_read(codec, 0x14, 0,
8376 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
8377 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8378 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
8379 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
8380 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
8381}
8382
8383static void alc883_acer_aspire_unsol_event(struct hda_codec *codec,
8384 unsigned int res)
8385{
8386 if ((res >> 26) == ALC880_HP_EVENT)
8387 alc883_acer_aspire_automute(codec);
8388}
8389
Kailang Yangd1a991a2007-08-15 16:21:59 +02008390static struct hda_verb alc883_acer_eapd_verbs[] = {
8391 /* HP Pin: output 0 (0x0c) */
8392 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8393 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8394 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8395 /* Front Pin: output 0 (0x0c) */
Takashi Iwai676a9b52007-08-16 15:23:35 +02008396 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8397 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangd1a991a2007-08-15 16:21:59 +02008398 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangd1a991a2007-08-15 16:21:59 +02008399 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
8400 /* eanable EAPD on medion laptop */
8401 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
8402 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
Takashi Iwai676a9b52007-08-16 15:23:35 +02008403 /* enable unsolicited event */
8404 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yangd1a991a2007-08-15 16:21:59 +02008405 { }
8406};
8407
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008408static void alc888_6st_dell_front_automute(struct hda_codec *codec)
8409{
8410 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02008411
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008412 present = snd_hda_codec_read(codec, 0x1b, 0,
8413 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
8414 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8415 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
8416 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8417 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
8418 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
8419 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
8420 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
8421 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
8422}
8423
8424static void alc888_6st_dell_unsol_event(struct hda_codec *codec,
8425 unsigned int res)
8426{
8427 switch (res >> 26) {
8428 case ALC880_HP_EVENT:
Takashi Iwai939778a2009-02-05 15:57:55 +01008429 /* printk(KERN_DEBUG "hp_event\n"); */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008430 alc888_6st_dell_front_automute(codec);
8431 break;
8432 }
8433}
8434
Kailang Yange2757d52008-08-26 13:17:46 +02008435static void alc888_lenovo_sky_front_automute(struct hda_codec *codec)
8436{
8437 unsigned int mute;
8438 unsigned int present;
8439
8440 snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
8441 present = snd_hda_codec_read(codec, 0x1b, 0,
8442 AC_VERB_GET_PIN_SENSE, 0);
8443 present = (present & 0x80000000) != 0;
8444 if (present) {
8445 /* mute internal speaker */
8446 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8447 HDA_AMP_MUTE, HDA_AMP_MUTE);
8448 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8449 HDA_AMP_MUTE, HDA_AMP_MUTE);
8450 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
8451 HDA_AMP_MUTE, HDA_AMP_MUTE);
8452 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
8453 HDA_AMP_MUTE, HDA_AMP_MUTE);
8454 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0,
8455 HDA_AMP_MUTE, HDA_AMP_MUTE);
8456 } else {
8457 /* unmute internal speaker if necessary */
8458 mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
8459 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8460 HDA_AMP_MUTE, mute);
8461 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8462 HDA_AMP_MUTE, mute);
8463 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
8464 HDA_AMP_MUTE, mute);
8465 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
8466 HDA_AMP_MUTE, mute);
8467 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0,
8468 HDA_AMP_MUTE, mute);
8469 }
8470}
8471
8472static void alc883_lenovo_sky_unsol_event(struct hda_codec *codec,
8473 unsigned int res)
8474{
8475 if ((res >> 26) == ALC880_HP_EVENT)
8476 alc888_lenovo_sky_front_automute(codec);
8477}
8478
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008479/*
8480 * generic initialization of ADC, input mixers and output mixers
8481 */
8482static struct hda_verb alc883_auto_init_verbs[] = {
8483 /*
8484 * Unmute ADC0-2 and set the default input to mic-in
8485 */
8486 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8487 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8488 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8489 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8490
Takashi Iwaicb53c622007-08-10 17:21:45 +02008491 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008492 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008493 * Note: PASD motherboards uses the Line In 2 as the input for
8494 * front panel mic (mic 2)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008495 */
8496 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02008497 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8498 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8499 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8500 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8501 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008502
8503 /*
8504 * Set up output mixers (0x0c - 0x0f)
8505 */
8506 /* set vol=0 to output mixers */
8507 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8508 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8509 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8510 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8511 /* set up input amps for analog loopback */
8512 /* Amp Indices: DAC = 0, mixer = 1 */
8513 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8514 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8515 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8516 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8517 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8518 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8519 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8520 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8521 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8522 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8523
8524 /* FIXME: use matrix-type input source selection */
8525 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
8526 /* Input mixer1 */
8527 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8528 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8529 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008530 /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, */
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008531 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
8532 /* Input mixer2 */
8533 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8534 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8535 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008536 /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, */
Andy Shevchenkoe3cde642007-12-03 16:50:58 +01008537 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008538
8539 { }
8540};
8541
Kailang Yange2757d52008-08-26 13:17:46 +02008542static struct hda_verb alc888_asus_m90v_verbs[] = {
8543 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8544 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8545 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8546 /* enable unsolicited event */
8547 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8548 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
8549 { } /* end */
8550};
8551
8552static void alc883_nb_mic_automute(struct hda_codec *codec)
8553{
8554 unsigned int present;
8555
8556 present = snd_hda_codec_read(codec, 0x18, 0,
8557 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
8558 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
8559 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
8560 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
8561 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
8562}
8563
8564static void alc883_M90V_speaker_automute(struct hda_codec *codec)
8565{
8566 unsigned int present;
8567 unsigned char bits;
8568
8569 present = snd_hda_codec_read(codec, 0x1b, 0,
8570 AC_VERB_GET_PIN_SENSE, 0)
8571 & AC_PINSENSE_PRESENCE;
8572 bits = present ? 0 : PIN_OUT;
8573 snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
8574 bits);
8575 snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
8576 bits);
8577 snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
8578 bits);
8579}
8580
8581static void alc883_mode2_unsol_event(struct hda_codec *codec,
8582 unsigned int res)
8583{
8584 switch (res >> 26) {
8585 case ALC880_HP_EVENT:
8586 alc883_M90V_speaker_automute(codec);
8587 break;
8588 case ALC880_MIC_EVENT:
8589 alc883_nb_mic_automute(codec);
8590 break;
8591 }
8592}
8593
8594static void alc883_mode2_inithook(struct hda_codec *codec)
8595{
8596 alc883_M90V_speaker_automute(codec);
8597 alc883_nb_mic_automute(codec);
8598}
8599
8600static struct hda_verb alc888_asus_eee1601_verbs[] = {
8601 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8602 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8603 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8604 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8605 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8606 {0x20, AC_VERB_SET_COEF_INDEX, 0x0b},
8607 {0x20, AC_VERB_SET_PROC_COEF, 0x0838},
8608 /* enable unsolicited event */
8609 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8610 { } /* end */
8611};
8612
8613static void alc883_eee1601_speaker_automute(struct hda_codec *codec)
8614{
8615 unsigned int present;
8616 unsigned char bits;
8617
8618 present = snd_hda_codec_read(codec, 0x14, 0,
8619 AC_VERB_GET_PIN_SENSE, 0)
8620 & AC_PINSENSE_PRESENCE;
8621 bits = present ? 0 : PIN_OUT;
8622 snd_hda_codec_write(codec, 0x1b, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
8623 bits);
8624}
8625
8626static void alc883_eee1601_unsol_event(struct hda_codec *codec,
8627 unsigned int res)
8628{
8629 switch (res >> 26) {
8630 case ALC880_HP_EVENT:
8631 alc883_eee1601_speaker_automute(codec);
8632 break;
8633 }
8634}
8635
8636static void alc883_eee1601_inithook(struct hda_codec *codec)
8637{
8638 alc883_eee1601_speaker_automute(codec);
8639}
8640
Takashi Iwaicb53c622007-08-10 17:21:45 +02008641#ifdef CONFIG_SND_HDA_POWER_SAVE
8642#define alc883_loopbacks alc880_loopbacks
8643#endif
8644
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008645/* pcm configuration: identiacal with ALC880 */
8646#define alc883_pcm_analog_playback alc880_pcm_analog_playback
8647#define alc883_pcm_analog_capture alc880_pcm_analog_capture
Takashi Iwai63300792008-01-24 15:31:36 +01008648#define alc883_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008649#define alc883_pcm_digital_playback alc880_pcm_digital_playback
8650#define alc883_pcm_digital_capture alc880_pcm_digital_capture
8651
8652/*
8653 * configuration and preset
8654 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008655static const char *alc883_models[ALC883_MODEL_LAST] = {
8656 [ALC883_3ST_2ch_DIG] = "3stack-dig",
8657 [ALC883_3ST_6ch_DIG] = "3stack-6ch-dig",
8658 [ALC883_3ST_6ch] = "3stack-6ch",
8659 [ALC883_6ST_DIG] = "6stack-dig",
8660 [ALC883_TARGA_DIG] = "targa-dig",
8661 [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008662 [ALC883_ACER] = "acer",
Tobin Davis2880a862007-08-07 11:50:26 +02008663 [ALC883_ACER_ASPIRE] = "acer-aspire",
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08008664 [ALC888_ACER_ASPIRE_4930G] = "acer-aspire-4930g",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008665 [ALC883_MEDION] = "medion",
Kailang Yang272a5272007-05-14 11:00:38 +02008666 [ALC883_MEDION_MD2] = "medion-md2",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008667 [ALC883_LAPTOP_EAPD] = "laptop-eapd",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008668 [ALC883_LENOVO_101E_2ch] = "lenovo-101e",
Kailang Yang272a5272007-05-14 11:00:38 +02008669 [ALC883_LENOVO_NB0763] = "lenovo-nb0763",
8670 [ALC888_LENOVO_MS7195_DIG] = "lenovo-ms7195-dig",
Kailang Yange2757d52008-08-26 13:17:46 +02008671 [ALC888_LENOVO_SKY] = "lenovo-sky",
Kailang Yang189609a2007-08-20 11:31:23 +02008672 [ALC883_HAIER_W66] = "haier-w66",
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008673 [ALC888_3ST_HP] = "3stack-hp",
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008674 [ALC888_6ST_DELL] = "6stack-dell",
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008675 [ALC883_MITAC] = "mitac",
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008676 [ALC883_CLEVO_M720] = "clevo-m720",
Jiang zhefb97dc62008-03-06 11:07:11 +01008677 [ALC883_FUJITSU_PI2515] = "fujitsu-pi2515",
Vincent Petryef8ef5f2008-11-23 11:31:41 +08008678 [ALC888_FUJITSU_XA3530] = "fujitsu-xa3530",
Jiang zhe17bba1b2008-06-04 12:11:07 +02008679 [ALC883_3ST_6ch_INTEL] = "3stack-6ch-intel",
Wu Fengguang3ab90932008-11-17 09:51:09 +01008680 [ALC1200_ASUS_P5Q] = "asus-p5q",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008681 [ALC883_AUTO] = "auto",
8682};
8683
8684static struct snd_pci_quirk alc883_cfg_tbl[] = {
8685 SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC883_3ST_6ch_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008686 SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE),
Takashi Iwai69e50282008-11-03 10:07:43 +01008687 SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_ACER_ASPIRE),
Takashi Iwai9b6682f2009-03-23 22:50:52 +01008688 SND_PCI_QUIRK(0x1025, 0x010a, "Acer Ferrari 5000", ALC883_ACER_ASPIRE),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008689 SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE),
8690 SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE),
Jaroslav Kysela0b18cb12008-07-28 17:07:07 +02008691 SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_ACER_ASPIRE),
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08008692 SND_PCI_QUIRK(0x1025, 0x013e, "Acer Aspire 4930G",
8693 ALC888_ACER_ASPIRE_4930G),
Lukasz Wojnilowicza8e4f9d2009-01-08 12:00:49 +01008694 SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G",
8695 ALC888_ACER_ASPIRE_4930G),
Takashi Iwaib3bdb302009-02-18 13:16:26 +01008696 SND_PCI_QUIRK(0x1025, 0x0157, "Acer X3200", ALC883_AUTO),
Takashi Iwai94683502009-02-13 09:31:20 +01008697 SND_PCI_QUIRK(0x1025, 0x0158, "Acer AX1700-U3700A", ALC883_AUTO),
Lukasz Wojnilowicza8e4f9d2009-01-08 12:00:49 +01008698 SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G",
8699 ALC888_ACER_ASPIRE_4930G),
Juan Jesus Garcia de Soriacc374c42009-02-23 08:11:59 +01008700 SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G",
8701 ALC888_ACER_ASPIRE_4930G),
Takashi Iwaidea0a502009-02-09 17:14:52 +01008702 /* default Acer */
8703 SND_PCI_QUIRK_VENDOR(0x1025, "Acer laptop", ALC883_ACER),
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008704 SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL),
Tobin Davisfebe3372007-06-12 11:27:46 +02008705 SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008706 SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP),
8707 SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP),
Herton Ronaldo Krzesinski5d85f8d2008-03-20 12:13:46 +01008708 SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG),
Chris Bagwell06bf3e12009-01-01 10:32:08 +01008709 SND_PCI_QUIRK(0x103c, 0x2a66, "HP Acacia", ALC888_3ST_HP),
Herton Ronaldo Krzesinski7ec30f02009-03-04 14:22:52 -03008710 SND_PCI_QUIRK(0x103c, 0x2a72, "HP Educ.ar", ALC888_3ST_HP),
Kailang Yanga01c30c2008-10-15 11:14:58 +02008711 SND_PCI_QUIRK(0x1043, 0x1873, "Asus M90V", ALC888_ASUS_M90V),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008712 SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG),
Mackenzie Morgan44a678d2009-02-10 17:13:43 +01008713 SND_PCI_QUIRK(0x1043, 0x8284, "Asus Z37E", ALC883_6ST_DIG),
Wu Fengguang3ab90932008-11-17 09:51:09 +01008714 SND_PCI_QUIRK(0x1043, 0x82fe, "Asus P5Q-EM HDMI", ALC1200_ASUS_P5Q),
Kailang Yange2757d52008-08-26 13:17:46 +02008715 SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_ASUS_EEE1601),
Travis Place97ec7102008-05-23 18:31:46 +02008716 SND_PCI_QUIRK(0x105b, 0x0ce8, "Foxconn P35AX-S", ALC883_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008717 SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC883_6ST_DIG),
Luke Yelavich2de686d2009-01-16 15:08:02 +11008718 SND_PCI_QUIRK(0x1071, 0x8227, "Mitac 82801H", ALC883_MITAC),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008719 SND_PCI_QUIRK(0x1071, 0x8253, "Mitac 8252d", ALC883_MITAC),
8720 SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD),
Kailang Yange2757d52008-08-26 13:17:46 +02008721 SND_PCI_QUIRK(0x10f1, 0x2350, "TYAN-S2350", ALC888_6ST_DELL),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008722 SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch),
Tobin Davis57b14f22007-04-18 23:05:36 +02008723 SND_PCI_QUIRK(0x1458, 0xa002, "MSI", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008724 SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG),
8725 SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG),
8726 SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG),
Jiang zhe4383fae2008-04-14 12:58:57 +02008727 SND_PCI_QUIRK(0x1462, 0x2fb3, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008728 SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG),
Pascal Terjan82808232008-03-04 11:33:28 +01008729 SND_PCI_QUIRK(0x1462, 0x3783, "NEC S970", ALC883_TARGA_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008730 SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG),
8731 SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG),
8732 SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG),
8733 SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG),
8734 SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG),
8735 SND_PCI_QUIRK(0x1462, 0x3fdf, "MSI", ALC883_TARGA_DIG),
8736 SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG),
8737 SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG),
8738 SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008739 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG),
8740 SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG),
Tobin Davis799f88a2007-05-29 14:29:08 +02008741 SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG),
Takashi Iwaiee095432008-11-25 15:03:38 +01008742 SND_PCI_QUIRK(0x1462, 0x7260, "MSI 7260", ALC883_TARGA_DIG),
Herton Ronaldo Krzesinski86d34b72008-03-18 09:27:59 +01008743 SND_PCI_QUIRK(0x1462, 0x7267, "MSI", ALC883_3ST_6ch_DIG),
Leonard Norrgard2a296cb2007-01-08 11:28:22 +01008744 SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG),
Tobin Davis2dcd5222007-07-10 17:04:57 +02008745 SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008746 SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008747 SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG),
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008748 SND_PCI_QUIRK(0x1558, 0x0721, "Clevo laptop M720R", ALC883_CLEVO_M720),
8749 SND_PCI_QUIRK(0x1558, 0x0722, "Clevo laptop M720SR", ALC883_CLEVO_M720),
Takashi Iwaidea0a502009-02-09 17:14:52 +01008750 SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC883_LAPTOP_EAPD),
Daniel T Chene60623b2007-05-29 03:41:55 -04008751 SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008752 SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION),
Takashi Iwaibfb53032009-04-14 14:51:04 +02008753 SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1100, "FSC AMILO Xi/Pi25xx",
Takashi Iwaif67d8172009-02-04 23:30:19 +01008754 ALC883_FUJITSU_PI2515),
Takashi Iwaibfb53032009-04-14 14:51:04 +02008755 SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1130, "Fujitsu AMILO Xa35xx",
Vincent Petryef8ef5f2008-11-23 11:31:41 +08008756 ALC888_FUJITSU_XA3530),
Kailang Yang272a5272007-05-14 11:00:38 +02008757 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch),
Kailang Yang272a5272007-05-14 11:00:38 +02008758 SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008759 SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763),
8760 SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Kailang Yange2757d52008-08-26 13:17:46 +02008761 SND_PCI_QUIRK(0x17aa, 0x101d, "Lenovo Sky", ALC888_LENOVO_SKY),
Kailang Yang272a5272007-05-14 11:00:38 +02008762 SND_PCI_QUIRK(0x17c0, 0x4071, "MEDION MD2", ALC883_MEDION_MD2),
Takashi Iwai959973b2008-11-05 11:30:56 +01008763 SND_PCI_QUIRK(0x17c0, 0x4085, "MEDION MD96630", ALC888_LENOVO_MS7195_DIG),
Andrew Paprocki0b167bf2008-02-03 10:15:44 +01008764 SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG),
Kailang Yang189609a2007-08-20 11:31:23 +02008765 SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66),
Jiang zhe17bba1b2008-06-04 12:11:07 +02008766 SND_PCI_QUIRK(0x8086, 0x0001, "DG33BUC", ALC883_3ST_6ch_INTEL),
8767 SND_PCI_QUIRK(0x8086, 0x0002, "DG33FBC", ALC883_3ST_6ch_INTEL),
Luke Yelavich2de686d2009-01-16 15:08:02 +11008768 SND_PCI_QUIRK(0x8086, 0x2503, "82801H", ALC883_MITAC),
Wu Fengguang4b558992009-01-12 09:18:58 +08008769 SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC883_3ST_6ch_INTEL),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008770 SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008771 {}
8772};
8773
Wu Fengguangf3cd3f52009-04-02 19:44:18 +08008774static hda_nid_t alc883_slave_dig_outs[] = {
8775 ALC1200_DIGOUT_NID, 0,
8776};
8777
Wu Fengguangb25c9da2009-02-06 15:02:27 +08008778static hda_nid_t alc1200_slave_dig_outs[] = {
8779 ALC883_DIGOUT_NID, 0,
8780};
8781
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008782static struct alc_config_preset alc883_presets[] = {
8783 [ALC883_3ST_2ch_DIG] = {
8784 .mixers = { alc883_3ST_2ch_mixer },
8785 .init_verbs = { alc883_init_verbs },
8786 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8787 .dac_nids = alc883_dac_nids,
8788 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008789 .dig_in_nid = ALC883_DIGIN_NID,
8790 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8791 .channel_mode = alc883_3ST_2ch_modes,
8792 .input_mux = &alc883_capture_source,
8793 },
8794 [ALC883_3ST_6ch_DIG] = {
8795 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
8796 .init_verbs = { alc883_init_verbs },
8797 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8798 .dac_nids = alc883_dac_nids,
8799 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008800 .dig_in_nid = ALC883_DIGIN_NID,
8801 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
8802 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02008803 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008804 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008805 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008806 [ALC883_3ST_6ch] = {
8807 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
8808 .init_verbs = { alc883_init_verbs },
8809 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8810 .dac_nids = alc883_dac_nids,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008811 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
8812 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02008813 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008814 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008815 },
Jiang zhe17bba1b2008-06-04 12:11:07 +02008816 [ALC883_3ST_6ch_INTEL] = {
8817 .mixers = { alc883_3ST_6ch_intel_mixer, alc883_chmode_mixer },
8818 .init_verbs = { alc883_init_verbs },
8819 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8820 .dac_nids = alc883_dac_nids,
8821 .dig_out_nid = ALC883_DIGOUT_NID,
8822 .dig_in_nid = ALC883_DIGIN_NID,
Wu Fengguangf3cd3f52009-04-02 19:44:18 +08008823 .slave_dig_outs = alc883_slave_dig_outs,
Jiang zhe17bba1b2008-06-04 12:11:07 +02008824 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_intel_modes),
8825 .channel_mode = alc883_3ST_6ch_intel_modes,
8826 .need_dac_fix = 1,
8827 .input_mux = &alc883_3stack_6ch_intel,
8828 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008829 [ALC883_6ST_DIG] = {
8830 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
8831 .init_verbs = { alc883_init_verbs },
8832 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8833 .dac_nids = alc883_dac_nids,
8834 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008835 .dig_in_nid = ALC883_DIGIN_NID,
8836 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
8837 .channel_mode = alc883_sixstack_modes,
8838 .input_mux = &alc883_capture_source,
8839 },
Kailang Yangccc656c2006-10-17 12:32:26 +02008840 [ALC883_TARGA_DIG] = {
8841 .mixers = { alc883_tagra_mixer, alc883_chmode_mixer },
8842 .init_verbs = { alc883_init_verbs, alc883_tagra_verbs},
8843 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8844 .dac_nids = alc883_dac_nids,
8845 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +02008846 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
8847 .channel_mode = alc883_3ST_6ch_modes,
8848 .need_dac_fix = 1,
8849 .input_mux = &alc883_capture_source,
8850 .unsol_event = alc883_tagra_unsol_event,
8851 .init_hook = alc883_tagra_automute,
8852 },
8853 [ALC883_TARGA_2ch_DIG] = {
8854 .mixers = { alc883_tagra_2ch_mixer},
8855 .init_verbs = { alc883_init_verbs, alc883_tagra_verbs},
8856 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8857 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01008858 .adc_nids = alc883_adc_nids_alt,
8859 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Kailang Yangccc656c2006-10-17 12:32:26 +02008860 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +02008861 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8862 .channel_mode = alc883_3ST_2ch_modes,
8863 .input_mux = &alc883_capture_source,
8864 .unsol_event = alc883_tagra_unsol_event,
8865 .init_hook = alc883_tagra_automute,
8866 },
Vladimir Avdoninbab282b2006-08-22 13:31:58 +02008867 [ALC883_ACER] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02008868 .mixers = { alc883_base_mixer },
Vladimir Avdoninbab282b2006-08-22 13:31:58 +02008869 /* On TravelMate laptops, GPIO 0 enables the internal speaker
8870 * and the headphone jack. Turn this on and rely on the
8871 * standard mute methods whenever the user wants to turn
8872 * these outputs off.
8873 */
8874 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs },
8875 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8876 .dac_nids = alc883_dac_nids,
Vladimir Avdoninbab282b2006-08-22 13:31:58 +02008877 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8878 .channel_mode = alc883_3ST_2ch_modes,
8879 .input_mux = &alc883_capture_source,
8880 },
Tobin Davis2880a862007-08-07 11:50:26 +02008881 [ALC883_ACER_ASPIRE] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02008882 .mixers = { alc883_acer_aspire_mixer },
Kailang Yangd1a991a2007-08-15 16:21:59 +02008883 .init_verbs = { alc883_init_verbs, alc883_acer_eapd_verbs },
Tobin Davis2880a862007-08-07 11:50:26 +02008884 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8885 .dac_nids = alc883_dac_nids,
8886 .dig_out_nid = ALC883_DIGOUT_NID,
Tobin Davis2880a862007-08-07 11:50:26 +02008887 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8888 .channel_mode = alc883_3ST_2ch_modes,
8889 .input_mux = &alc883_capture_source,
Takashi Iwai676a9b52007-08-16 15:23:35 +02008890 .unsol_event = alc883_acer_aspire_unsol_event,
8891 .init_hook = alc883_acer_aspire_automute,
Kailang Yangd1a991a2007-08-15 16:21:59 +02008892 },
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08008893 [ALC888_ACER_ASPIRE_4930G] = {
Vincent Petryef8ef5f2008-11-23 11:31:41 +08008894 .mixers = { alc888_base_mixer,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08008895 alc883_chmode_mixer },
8896 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
8897 alc888_acer_aspire_4930g_verbs },
8898 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8899 .dac_nids = alc883_dac_nids,
8900 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
8901 .adc_nids = alc883_adc_nids_rev,
8902 .capsrc_nids = alc883_capsrc_nids_rev,
8903 .dig_out_nid = ALC883_DIGOUT_NID,
8904 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
8905 .channel_mode = alc883_3ST_6ch_modes,
8906 .need_dac_fix = 1,
8907 .num_mux_defs =
Vincent Petryef8ef5f2008-11-23 11:31:41 +08008908 ARRAY_SIZE(alc888_2_capture_sources),
8909 .input_mux = alc888_2_capture_sources,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08008910 .unsol_event = alc888_acer_aspire_4930g_unsol_event,
8911 .init_hook = alc888_acer_aspire_4930g_automute,
8912 },
Tobin Davisc07584c2006-10-13 12:32:16 +02008913 [ALC883_MEDION] = {
8914 .mixers = { alc883_fivestack_mixer,
8915 alc883_chmode_mixer },
8916 .init_verbs = { alc883_init_verbs,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008917 alc883_medion_eapd_verbs },
Tobin Davisc07584c2006-10-13 12:32:16 +02008918 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8919 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01008920 .adc_nids = alc883_adc_nids_alt,
8921 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Tobin Davisc07584c2006-10-13 12:32:16 +02008922 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
8923 .channel_mode = alc883_sixstack_modes,
8924 .input_mux = &alc883_capture_source,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008925 },
Kailang Yang272a5272007-05-14 11:00:38 +02008926 [ALC883_MEDION_MD2] = {
8927 .mixers = { alc883_medion_md2_mixer},
8928 .init_verbs = { alc883_init_verbs, alc883_medion_md2_verbs},
8929 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8930 .dac_nids = alc883_dac_nids,
8931 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang272a5272007-05-14 11:00:38 +02008932 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8933 .channel_mode = alc883_3ST_2ch_modes,
8934 .input_mux = &alc883_capture_source,
8935 .unsol_event = alc883_medion_md2_unsol_event,
8936 .init_hook = alc883_medion_md2_automute,
Kailang Yangea1fb292008-08-26 12:58:38 +02008937 },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008938 [ALC883_LAPTOP_EAPD] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02008939 .mixers = { alc883_base_mixer },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008940 .init_verbs = { alc883_init_verbs, alc882_eapd_verbs },
8941 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8942 .dac_nids = alc883_dac_nids,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008943 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8944 .channel_mode = alc883_3ST_2ch_modes,
8945 .input_mux = &alc883_capture_source,
8946 },
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008947 [ALC883_CLEVO_M720] = {
8948 .mixers = { alc883_clevo_m720_mixer },
8949 .init_verbs = { alc883_init_verbs, alc883_clevo_m720_verbs },
Jiang zhe368c7a92008-03-04 11:20:33 +01008950 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8951 .dac_nids = alc883_dac_nids,
8952 .dig_out_nid = ALC883_DIGOUT_NID,
8953 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8954 .channel_mode = alc883_3ST_2ch_modes,
8955 .input_mux = &alc883_capture_source,
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008956 .unsol_event = alc883_clevo_m720_unsol_event,
8957 .init_hook = alc883_clevo_m720_automute,
Jiang zhe368c7a92008-03-04 11:20:33 +01008958 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008959 [ALC883_LENOVO_101E_2ch] = {
8960 .mixers = { alc883_lenovo_101e_2ch_mixer},
8961 .init_verbs = { alc883_init_verbs, alc883_lenovo_101e_verbs},
8962 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8963 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01008964 .adc_nids = alc883_adc_nids_alt,
8965 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008966 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8967 .channel_mode = alc883_3ST_2ch_modes,
8968 .input_mux = &alc883_lenovo_101e_capture_source,
8969 .unsol_event = alc883_lenovo_101e_unsol_event,
8970 .init_hook = alc883_lenovo_101e_all_automute,
8971 },
Kailang Yang272a5272007-05-14 11:00:38 +02008972 [ALC883_LENOVO_NB0763] = {
8973 .mixers = { alc883_lenovo_nb0763_mixer },
8974 .init_verbs = { alc883_init_verbs, alc883_lenovo_nb0763_verbs},
8975 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8976 .dac_nids = alc883_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +02008977 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8978 .channel_mode = alc883_3ST_2ch_modes,
8979 .need_dac_fix = 1,
8980 .input_mux = &alc883_lenovo_nb0763_capture_source,
8981 .unsol_event = alc883_medion_md2_unsol_event,
8982 .init_hook = alc883_medion_md2_automute,
8983 },
8984 [ALC888_LENOVO_MS7195_DIG] = {
8985 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
8986 .init_verbs = { alc883_init_verbs, alc888_lenovo_ms7195_verbs},
8987 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8988 .dac_nids = alc883_dac_nids,
8989 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang272a5272007-05-14 11:00:38 +02008990 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
8991 .channel_mode = alc883_3ST_6ch_modes,
8992 .need_dac_fix = 1,
8993 .input_mux = &alc883_capture_source,
8994 .unsol_event = alc883_lenovo_ms7195_unsol_event,
8995 .init_hook = alc888_lenovo_ms7195_front_automute,
Kailang Yang189609a2007-08-20 11:31:23 +02008996 },
8997 [ALC883_HAIER_W66] = {
8998 .mixers = { alc883_tagra_2ch_mixer},
8999 .init_verbs = { alc883_init_verbs, alc883_haier_w66_verbs},
9000 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9001 .dac_nids = alc883_dac_nids,
9002 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang189609a2007-08-20 11:31:23 +02009003 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9004 .channel_mode = alc883_3ST_2ch_modes,
9005 .input_mux = &alc883_capture_source,
9006 .unsol_event = alc883_haier_w66_unsol_event,
9007 .init_hook = alc883_haier_w66_automute,
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +01009008 },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009009 [ALC888_3ST_HP] = {
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +01009010 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009011 .init_verbs = { alc883_init_verbs, alc888_3st_hp_verbs },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009012 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9013 .dac_nids = alc883_dac_nids,
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009014 .num_channel_mode = ARRAY_SIZE(alc888_3st_hp_modes),
9015 .channel_mode = alc888_3st_hp_modes,
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009016 .need_dac_fix = 1,
9017 .input_mux = &alc883_capture_source,
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009018 .unsol_event = alc888_3st_hp_unsol_event,
9019 .init_hook = alc888_3st_hp_front_automute,
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009020 },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009021 [ALC888_6ST_DELL] = {
Herton Ronaldo Krzesinskif24dbdc2008-03-20 12:14:28 +01009022 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009023 .init_verbs = { alc883_init_verbs, alc888_6st_dell_verbs },
9024 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9025 .dac_nids = alc883_dac_nids,
9026 .dig_out_nid = ALC883_DIGOUT_NID,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009027 .dig_in_nid = ALC883_DIGIN_NID,
9028 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
9029 .channel_mode = alc883_sixstack_modes,
9030 .input_mux = &alc883_capture_source,
9031 .unsol_event = alc888_6st_dell_unsol_event,
9032 .init_hook = alc888_6st_dell_front_automute,
9033 },
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009034 [ALC883_MITAC] = {
9035 .mixers = { alc883_mitac_mixer },
9036 .init_verbs = { alc883_init_verbs, alc883_mitac_verbs },
9037 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9038 .dac_nids = alc883_dac_nids,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009039 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9040 .channel_mode = alc883_3ST_2ch_modes,
9041 .input_mux = &alc883_capture_source,
9042 .unsol_event = alc883_mitac_unsol_event,
9043 .init_hook = alc883_mitac_automute,
9044 },
Jiang zhefb97dc62008-03-06 11:07:11 +01009045 [ALC883_FUJITSU_PI2515] = {
9046 .mixers = { alc883_2ch_fujitsu_pi2515_mixer },
9047 .init_verbs = { alc883_init_verbs,
9048 alc883_2ch_fujitsu_pi2515_verbs},
9049 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9050 .dac_nids = alc883_dac_nids,
9051 .dig_out_nid = ALC883_DIGOUT_NID,
9052 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9053 .channel_mode = alc883_3ST_2ch_modes,
9054 .input_mux = &alc883_fujitsu_pi2515_capture_source,
9055 .unsol_event = alc883_2ch_fujitsu_pi2515_unsol_event,
9056 .init_hook = alc883_2ch_fujitsu_pi2515_automute,
9057 },
Vincent Petryef8ef5f2008-11-23 11:31:41 +08009058 [ALC888_FUJITSU_XA3530] = {
9059 .mixers = { alc888_base_mixer, alc883_chmode_mixer },
9060 .init_verbs = { alc883_init_verbs,
9061 alc888_fujitsu_xa3530_verbs },
9062 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9063 .dac_nids = alc883_dac_nids,
9064 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
9065 .adc_nids = alc883_adc_nids_rev,
9066 .capsrc_nids = alc883_capsrc_nids_rev,
9067 .dig_out_nid = ALC883_DIGOUT_NID,
9068 .num_channel_mode = ARRAY_SIZE(alc888_4ST_8ch_intel_modes),
9069 .channel_mode = alc888_4ST_8ch_intel_modes,
9070 .num_mux_defs =
9071 ARRAY_SIZE(alc888_2_capture_sources),
9072 .input_mux = alc888_2_capture_sources,
9073 .unsol_event = alc888_fujitsu_xa3530_unsol_event,
9074 .init_hook = alc888_fujitsu_xa3530_automute,
9075 },
Kailang Yange2757d52008-08-26 13:17:46 +02009076 [ALC888_LENOVO_SKY] = {
9077 .mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer },
9078 .init_verbs = { alc883_init_verbs, alc888_lenovo_sky_verbs},
9079 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9080 .dac_nids = alc883_dac_nids,
9081 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yange2757d52008-08-26 13:17:46 +02009082 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
9083 .channel_mode = alc883_sixstack_modes,
9084 .need_dac_fix = 1,
9085 .input_mux = &alc883_lenovo_sky_capture_source,
9086 .unsol_event = alc883_lenovo_sky_unsol_event,
9087 .init_hook = alc888_lenovo_sky_front_automute,
9088 },
9089 [ALC888_ASUS_M90V] = {
9090 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
9091 .init_verbs = { alc883_init_verbs, alc888_asus_m90v_verbs },
9092 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9093 .dac_nids = alc883_dac_nids,
9094 .dig_out_nid = ALC883_DIGOUT_NID,
9095 .dig_in_nid = ALC883_DIGIN_NID,
9096 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
9097 .channel_mode = alc883_3ST_6ch_modes,
9098 .need_dac_fix = 1,
9099 .input_mux = &alc883_fujitsu_pi2515_capture_source,
9100 .unsol_event = alc883_mode2_unsol_event,
9101 .init_hook = alc883_mode2_inithook,
9102 },
9103 [ALC888_ASUS_EEE1601] = {
9104 .mixers = { alc883_asus_eee1601_mixer },
Takashi Iwaif9e336f2008-10-31 16:37:07 +01009105 .cap_mixer = alc883_asus_eee1601_cap_mixer,
Kailang Yange2757d52008-08-26 13:17:46 +02009106 .init_verbs = { alc883_init_verbs, alc888_asus_eee1601_verbs },
9107 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9108 .dac_nids = alc883_dac_nids,
9109 .dig_out_nid = ALC883_DIGOUT_NID,
9110 .dig_in_nid = ALC883_DIGIN_NID,
9111 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9112 .channel_mode = alc883_3ST_2ch_modes,
9113 .need_dac_fix = 1,
9114 .input_mux = &alc883_asus_eee1601_capture_source,
9115 .unsol_event = alc883_eee1601_unsol_event,
9116 .init_hook = alc883_eee1601_inithook,
9117 },
Wu Fengguang3ab90932008-11-17 09:51:09 +01009118 [ALC1200_ASUS_P5Q] = {
9119 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
9120 .init_verbs = { alc883_init_verbs },
9121 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9122 .dac_nids = alc883_dac_nids,
9123 .dig_out_nid = ALC1200_DIGOUT_NID,
9124 .dig_in_nid = ALC883_DIGIN_NID,
Wu Fengguangb25c9da2009-02-06 15:02:27 +08009125 .slave_dig_outs = alc1200_slave_dig_outs,
Wu Fengguang3ab90932008-11-17 09:51:09 +01009126 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
9127 .channel_mode = alc883_sixstack_modes,
9128 .input_mux = &alc883_capture_source,
9129 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009130};
9131
9132
9133/*
9134 * BIOS auto configuration
9135 */
9136static void alc883_auto_set_output_and_unmute(struct hda_codec *codec,
9137 hda_nid_t nid, int pin_type,
9138 int dac_idx)
9139{
9140 /* set as output */
9141 struct alc_spec *spec = codec->spec;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009142 int idx;
9143
Takashi Iwaif6c7e542008-02-12 18:32:23 +01009144 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009145 if (spec->multiout.dac_nids[dac_idx] == 0x25)
9146 idx = 4;
9147 else
9148 idx = spec->multiout.dac_nids[dac_idx] - 2;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009149 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
9150
9151}
9152
9153static void alc883_auto_init_multi_out(struct hda_codec *codec)
9154{
9155 struct alc_spec *spec = codec->spec;
9156 int i;
9157
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009158 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009159 for (i = 0; i <= HDA_SIDE; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009160 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02009161 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009162 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02009163 alc883_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009164 i);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009165 }
9166}
9167
9168static void alc883_auto_init_hp_out(struct hda_codec *codec)
9169{
9170 struct alc_spec *spec = codec->spec;
9171 hda_nid_t pin;
9172
Takashi Iwaieb06ed82006-09-20 17:10:27 +02009173 pin = spec->autocfg.hp_pins[0];
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009174 if (pin) /* connect to front */
9175 /* use dac 0 */
9176 alc883_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01009177 pin = spec->autocfg.speaker_pins[0];
9178 if (pin)
9179 alc883_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009180}
9181
9182#define alc883_is_input_pin(nid) alc880_is_input_pin(nid)
9183#define ALC883_PIN_CD_NID ALC880_PIN_CD_NID
9184
9185static void alc883_auto_init_analog_input(struct hda_codec *codec)
9186{
9187 struct alc_spec *spec = codec->spec;
9188 int i;
9189
9190 for (i = 0; i < AUTO_PIN_LAST; i++) {
9191 hda_nid_t nid = spec->autocfg.input_pins[i];
9192 if (alc883_is_input_pin(nid)) {
Takashi Iwai23f0c042009-02-26 13:03:58 +01009193 alc_set_input_pin(codec, nid, i);
Takashi Iwaie82c0252009-03-23 15:17:38 +01009194 if (nid != ALC883_PIN_CD_NID &&
9195 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009196 snd_hda_codec_write(codec, nid, 0,
9197 AC_VERB_SET_AMP_GAIN_MUTE,
9198 AMP_OUT_MUTE);
9199 }
9200 }
9201}
9202
Takashi Iwaif511b012008-08-15 16:46:42 +02009203#define alc883_auto_init_input_src alc882_auto_init_input_src
9204
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009205/* almost identical with ALC880 parser... */
9206static int alc883_parse_auto_config(struct hda_codec *codec)
9207{
9208 struct alc_spec *spec = codec->spec;
9209 int err = alc880_parse_auto_config(codec);
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02009210 struct auto_pin_cfg *cfg = &spec->autocfg;
9211 int i;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009212
9213 if (err < 0)
9214 return err;
Takashi Iwai776e1842007-08-29 15:07:11 +02009215 else if (!err)
9216 return 0; /* no config found */
9217
9218 err = alc_auto_add_mic_boost(codec);
9219 if (err < 0)
9220 return err;
9221
9222 /* hack - override the init verbs */
9223 spec->init_verbs[0] = alc883_auto_init_verbs;
Takashi Iwai776e1842007-08-29 15:07:11 +02009224
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02009225 /* setup input_mux for ALC889 */
9226 if (codec->vendor_id == 0x10ec0889) {
9227 /* digital-mic input pin is excluded in alc880_auto_create..()
9228 * because it's under 0x18
9229 */
9230 if (cfg->input_pins[AUTO_PIN_MIC] == 0x12 ||
9231 cfg->input_pins[AUTO_PIN_FRONT_MIC] == 0x12) {
9232 struct hda_input_mux *imux = &spec->private_imux[0];
9233 for (i = 1; i < 3; i++)
9234 memcpy(&spec->private_imux[i],
9235 &spec->private_imux[0],
9236 sizeof(spec->private_imux[0]));
9237 imux->items[imux->num_items].label = "Int DMic";
9238 imux->items[imux->num_items].index = 0x0b;
9239 imux->num_items++;
9240 spec->num_mux_defs = 3;
9241 spec->input_mux = spec->private_imux;
9242 }
9243 }
9244
Takashi Iwai776e1842007-08-29 15:07:11 +02009245 return 1; /* config found */
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009246}
9247
9248/* additional initialization for auto-configuration model */
9249static void alc883_auto_init(struct hda_codec *codec)
9250{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01009251 struct alc_spec *spec = codec->spec;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009252 alc883_auto_init_multi_out(codec);
9253 alc883_auto_init_hp_out(codec);
9254 alc883_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +02009255 alc883_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01009256 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02009257 alc_inithook(codec);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009258}
9259
9260static int patch_alc883(struct hda_codec *codec)
9261{
9262 struct alc_spec *spec;
9263 int err, board_config;
9264
9265 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
9266 if (spec == NULL)
9267 return -ENOMEM;
9268
9269 codec->spec = spec;
9270
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02009271 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
9272
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009273 board_config = snd_hda_check_board_config(codec, ALC883_MODEL_LAST,
9274 alc883_models,
9275 alc883_cfg_tbl);
9276 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009277 printk(KERN_INFO "hda_codec: Unknown model for ALC883, "
9278 "trying auto-probe from BIOS...\n");
9279 board_config = ALC883_AUTO;
9280 }
9281
9282 if (board_config == ALC883_AUTO) {
9283 /* automatic parse from the BIOS config */
9284 err = alc883_parse_auto_config(codec);
9285 if (err < 0) {
9286 alc_free(codec);
9287 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009288 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009289 printk(KERN_INFO
9290 "hda_codec: Cannot set up configuration "
9291 "from BIOS. Using base mode...\n");
9292 board_config = ALC883_3ST_2ch_DIG;
9293 }
9294 }
9295
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09009296 err = snd_hda_attach_beep_device(codec, 0x1);
9297 if (err < 0) {
9298 alc_free(codec);
9299 return err;
9300 }
9301
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009302 if (board_config != ALC883_AUTO)
9303 setup_preset(spec, &alc883_presets[board_config]);
9304
Kailang Yang2f893282008-05-27 12:14:47 +02009305 switch (codec->vendor_id) {
9306 case 0x10ec0888:
Kailang Yang44426082008-10-15 11:18:05 +02009307 if (codec->revision_id == 0x100101) {
9308 spec->stream_name_analog = "ALC1200 Analog";
9309 spec->stream_name_digital = "ALC1200 Digital";
9310 } else {
9311 spec->stream_name_analog = "ALC888 Analog";
9312 spec->stream_name_digital = "ALC888 Digital";
9313 }
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02009314 if (!spec->num_adc_nids) {
9315 spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids);
9316 spec->adc_nids = alc883_adc_nids;
9317 }
9318 if (!spec->capsrc_nids)
9319 spec->capsrc_nids = alc883_capsrc_nids;
9320 spec->capture_style = CAPT_MIX; /* matrix-style capture */
Kailang Yang2f893282008-05-27 12:14:47 +02009321 break;
9322 case 0x10ec0889:
9323 spec->stream_name_analog = "ALC889 Analog";
9324 spec->stream_name_digital = "ALC889 Digital";
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02009325 if (!spec->num_adc_nids) {
9326 spec->num_adc_nids = ARRAY_SIZE(alc889_adc_nids);
9327 spec->adc_nids = alc889_adc_nids;
9328 }
9329 if (!spec->capsrc_nids)
9330 spec->capsrc_nids = alc889_capsrc_nids;
9331 spec->capture_style = CAPT_1MUX_MIX; /* 1mux/Nmix-style
9332 capture */
Kailang Yang2f893282008-05-27 12:14:47 +02009333 break;
9334 default:
9335 spec->stream_name_analog = "ALC883 Analog";
9336 spec->stream_name_digital = "ALC883 Digital";
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02009337 if (!spec->num_adc_nids) {
9338 spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids);
9339 spec->adc_nids = alc883_adc_nids;
9340 }
9341 if (!spec->capsrc_nids)
9342 spec->capsrc_nids = alc883_capsrc_nids;
9343 spec->capture_style = CAPT_MIX; /* matrix-style capture */
Kailang Yang2f893282008-05-27 12:14:47 +02009344 break;
9345 }
9346
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009347 spec->stream_analog_playback = &alc883_pcm_analog_playback;
9348 spec->stream_analog_capture = &alc883_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01009349 spec->stream_analog_alt_capture = &alc883_pcm_analog_alt_capture;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009350
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009351 spec->stream_digital_playback = &alc883_pcm_digital_playback;
9352 spec->stream_digital_capture = &alc883_pcm_digital_capture;
9353
Takashi Iwaif9e336f2008-10-31 16:37:07 +01009354 if (!spec->cap_mixer)
9355 set_capture_mixer(spec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01009356 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009357
Takashi Iwai2134ea42008-01-10 16:53:55 +01009358 spec->vmaster_nid = 0x0c;
9359
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009360 codec->patch_ops = alc_patch_ops;
9361 if (board_config == ALC883_AUTO)
9362 spec->init_hook = alc883_auto_init;
Kailang Yangf9423e72008-05-27 12:32:25 +02009363
Takashi Iwaicb53c622007-08-10 17:21:45 +02009364#ifdef CONFIG_SND_HDA_POWER_SAVE
9365 if (!spec->loopback.amplist)
9366 spec->loopback.amplist = alc883_loopbacks;
9367#endif
Takashi Iwaidaead532008-11-28 12:55:36 +01009368 codec->proc_widget_hook = print_realtek_coef;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009369
9370 return 0;
9371}
9372
9373/*
Kailang Yangdf694da2005-12-05 19:42:22 +01009374 * ALC262 support
9375 */
9376
9377#define ALC262_DIGOUT_NID ALC880_DIGOUT_NID
9378#define ALC262_DIGIN_NID ALC880_DIGIN_NID
9379
9380#define alc262_dac_nids alc260_dac_nids
9381#define alc262_adc_nids alc882_adc_nids
9382#define alc262_adc_nids_alt alc882_adc_nids_alt
Takashi Iwai88c71a92008-02-14 17:27:17 +01009383#define alc262_capsrc_nids alc882_capsrc_nids
9384#define alc262_capsrc_nids_alt alc882_capsrc_nids_alt
Kailang Yangdf694da2005-12-05 19:42:22 +01009385
9386#define alc262_modes alc260_modes
Takashi Iwaic5f2ea02005-12-06 18:54:31 +01009387#define alc262_capture_source alc882_capture_source
Kailang Yangdf694da2005-12-05 19:42:22 +01009388
Kailang Yang4e555fe2008-08-26 13:05:55 +02009389static hda_nid_t alc262_dmic_adc_nids[1] = {
9390 /* ADC0 */
9391 0x09
9392};
9393
9394static hda_nid_t alc262_dmic_capsrc_nids[1] = { 0x22 };
9395
Kailang Yangdf694da2005-12-05 19:42:22 +01009396static struct snd_kcontrol_new alc262_base_mixer[] = {
9397 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9398 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9399 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9400 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9401 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9402 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9403 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9404 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01009405 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01009406 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
9407 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01009408 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01009409 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),
9410 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9411 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
9412 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01009413 { } /* end */
Takashi Iwai834be882006-03-01 14:16:17 +01009414};
9415
Kailang Yangccc656c2006-10-17 12:32:26 +02009416static struct snd_kcontrol_new alc262_hippo1_mixer[] = {
9417 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9418 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9419 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9420 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9421 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9422 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9423 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9424 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01009425 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009426 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
9427 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01009428 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009429 /*HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),*/
9430 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
9431 { } /* end */
9432};
9433
Takashi Iwaice875f02008-01-28 18:17:43 +01009434/* update HP, line and mono-out pins according to the master switch */
9435static void alc262_hp_master_update(struct hda_codec *codec)
9436{
9437 struct alc_spec *spec = codec->spec;
9438 int val = spec->master_sw;
9439
9440 /* HP & line-out */
9441 snd_hda_codec_write_cache(codec, 0x1b, 0,
9442 AC_VERB_SET_PIN_WIDGET_CONTROL,
9443 val ? PIN_HP : 0);
9444 snd_hda_codec_write_cache(codec, 0x15, 0,
9445 AC_VERB_SET_PIN_WIDGET_CONTROL,
9446 val ? PIN_HP : 0);
9447 /* mono (speaker) depending on the HP jack sense */
9448 val = val && !spec->jack_present;
9449 snd_hda_codec_write_cache(codec, 0x16, 0,
9450 AC_VERB_SET_PIN_WIDGET_CONTROL,
9451 val ? PIN_OUT : 0);
9452}
9453
9454static void alc262_hp_bpc_automute(struct hda_codec *codec)
9455{
9456 struct alc_spec *spec = codec->spec;
9457 unsigned int presence;
9458 presence = snd_hda_codec_read(codec, 0x1b, 0,
9459 AC_VERB_GET_PIN_SENSE, 0);
9460 spec->jack_present = !!(presence & AC_PINSENSE_PRESENCE);
9461 alc262_hp_master_update(codec);
9462}
9463
9464static void alc262_hp_bpc_unsol_event(struct hda_codec *codec, unsigned int res)
9465{
9466 if ((res >> 26) != ALC880_HP_EVENT)
9467 return;
9468 alc262_hp_bpc_automute(codec);
9469}
9470
9471static void alc262_hp_wildwest_automute(struct hda_codec *codec)
9472{
9473 struct alc_spec *spec = codec->spec;
9474 unsigned int presence;
9475 presence = snd_hda_codec_read(codec, 0x15, 0,
9476 AC_VERB_GET_PIN_SENSE, 0);
9477 spec->jack_present = !!(presence & AC_PINSENSE_PRESENCE);
9478 alc262_hp_master_update(codec);
9479}
9480
9481static void alc262_hp_wildwest_unsol_event(struct hda_codec *codec,
9482 unsigned int res)
9483{
9484 if ((res >> 26) != ALC880_HP_EVENT)
9485 return;
9486 alc262_hp_wildwest_automute(codec);
9487}
9488
9489static int alc262_hp_master_sw_get(struct snd_kcontrol *kcontrol,
9490 struct snd_ctl_elem_value *ucontrol)
9491{
9492 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
9493 struct alc_spec *spec = codec->spec;
9494 *ucontrol->value.integer.value = spec->master_sw;
9495 return 0;
9496}
9497
9498static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol,
9499 struct snd_ctl_elem_value *ucontrol)
9500{
9501 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
9502 struct alc_spec *spec = codec->spec;
9503 int val = !!*ucontrol->value.integer.value;
9504
9505 if (val == spec->master_sw)
9506 return 0;
9507 spec->master_sw = val;
9508 alc262_hp_master_update(codec);
9509 return 1;
9510}
9511
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009512static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
Takashi Iwaice875f02008-01-28 18:17:43 +01009513 {
9514 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9515 .name = "Master Playback Switch",
9516 .info = snd_ctl_boolean_mono_info,
9517 .get = alc262_hp_master_sw_get,
9518 .put = alc262_hp_master_sw_put,
9519 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009520 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9521 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9522 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +01009523 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
9524 HDA_OUTPUT),
9525 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
9526 HDA_OUTPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009527 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9528 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01009529 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009530 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
9531 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01009532 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009533 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9534 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9535 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9536 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009537 HDA_CODEC_VOLUME("AUX IN Playback Volume", 0x0b, 0x06, HDA_INPUT),
9538 HDA_CODEC_MUTE("AUX IN Playback Switch", 0x0b, 0x06, HDA_INPUT),
9539 { } /* end */
9540};
9541
Kailang Yangcd7509a2007-01-26 18:33:17 +01009542static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = {
Takashi Iwaice875f02008-01-28 18:17:43 +01009543 {
9544 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9545 .name = "Master Playback Switch",
9546 .info = snd_ctl_boolean_mono_info,
9547 .get = alc262_hp_master_sw_get,
9548 .put = alc262_hp_master_sw_put,
9549 },
Kailang Yangcd7509a2007-01-26 18:33:17 +01009550 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9551 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
9552 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
9553 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +01009554 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
9555 HDA_OUTPUT),
9556 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
9557 HDA_OUTPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +01009558 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT),
9559 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01009560 HDA_CODEC_VOLUME("Front Mic Boost", 0x1a, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +01009561 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
9562 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
9563 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9564 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +01009565 { } /* end */
9566};
9567
9568static struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = {
9569 HDA_CODEC_VOLUME("Rear Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9570 HDA_CODEC_MUTE("Rear Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01009571 HDA_CODEC_VOLUME("Rear Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +01009572 { } /* end */
9573};
9574
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009575/* mute/unmute internal speaker according to the hp jack and mute state */
9576static void alc262_hp_t5735_automute(struct hda_codec *codec, int force)
9577{
9578 struct alc_spec *spec = codec->spec;
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009579
9580 if (force || !spec->sense_updated) {
9581 unsigned int present;
9582 present = snd_hda_codec_read(codec, 0x15, 0,
9583 AC_VERB_GET_PIN_SENSE, 0);
Takashi Iwai4bb26132008-01-28 18:12:42 +01009584 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009585 spec->sense_updated = 1;
9586 }
Takashi Iwai4bb26132008-01-28 18:12:42 +01009587 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0, HDA_AMP_MUTE,
9588 spec->jack_present ? HDA_AMP_MUTE : 0);
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009589}
9590
9591static void alc262_hp_t5735_unsol_event(struct hda_codec *codec,
9592 unsigned int res)
9593{
9594 if ((res >> 26) != ALC880_HP_EVENT)
9595 return;
9596 alc262_hp_t5735_automute(codec, 1);
9597}
9598
9599static void alc262_hp_t5735_init_hook(struct hda_codec *codec)
9600{
9601 alc262_hp_t5735_automute(codec, 1);
9602}
9603
9604static struct snd_kcontrol_new alc262_hp_t5735_mixer[] = {
Takashi Iwai86cd9292008-01-28 18:09:56 +01009605 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9606 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009607 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
9608 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9609 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9610 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9611 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9612 { } /* end */
9613};
9614
9615static struct hda_verb alc262_hp_t5735_verbs[] = {
9616 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9617 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9618
9619 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9620 { }
9621};
9622
Kailang Yang8c427222008-01-10 13:03:59 +01009623static struct snd_kcontrol_new alc262_hp_rp5700_mixer[] = {
Takashi Iwaif2f48e12008-01-28 18:14:43 +01009624 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9625 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01009626 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
9627 HDA_CODEC_MUTE("Speaker Playback Switch", 0x16, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +01009628 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
9629 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
9630 { } /* end */
9631};
9632
9633static struct hda_verb alc262_hp_rp5700_verbs[] = {
9634 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9635 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9636 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9637 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9638 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
9639 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
9640 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
9641 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
9642 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
9643 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
9644 {}
9645};
9646
9647static struct hda_input_mux alc262_hp_rp5700_capture_source = {
9648 .num_items = 1,
9649 .items = {
9650 { "Line", 0x1 },
9651 },
9652};
9653
Takashi Iwai0724ea22007-08-23 00:31:43 +02009654/* bind hp and internal speaker mute (with plug check) */
9655static int alc262_sony_master_sw_put(struct snd_kcontrol *kcontrol,
9656 struct snd_ctl_elem_value *ucontrol)
9657{
9658 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
9659 long *valp = ucontrol->value.integer.value;
9660 int change;
9661
9662 /* change hp mute */
9663 change = snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0,
9664 HDA_AMP_MUTE,
9665 valp[0] ? 0 : HDA_AMP_MUTE);
9666 change |= snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0,
9667 HDA_AMP_MUTE,
9668 valp[1] ? 0 : HDA_AMP_MUTE);
9669 if (change) {
9670 /* change speaker according to HP jack state */
9671 struct alc_spec *spec = codec->spec;
9672 unsigned int mute;
9673 if (spec->jack_present)
9674 mute = HDA_AMP_MUTE;
9675 else
9676 mute = snd_hda_codec_amp_read(codec, 0x15, 0,
9677 HDA_OUTPUT, 0);
9678 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9679 HDA_AMP_MUTE, mute);
9680 }
9681 return change;
9682}
Takashi Iwai5b319542007-07-26 11:49:22 +02009683
Kailang Yang272a5272007-05-14 11:00:38 +02009684static struct snd_kcontrol_new alc262_sony_mixer[] = {
Takashi Iwai0724ea22007-08-23 00:31:43 +02009685 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9686 {
9687 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9688 .name = "Master Playback Switch",
9689 .info = snd_hda_mixer_amp_switch_info,
9690 .get = snd_hda_mixer_amp_switch_get,
9691 .put = alc262_sony_master_sw_put,
9692 .private_value = HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
9693 },
Kailang Yang272a5272007-05-14 11:00:38 +02009694 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9695 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9696 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
9697 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
9698 { } /* end */
9699};
9700
Kailang Yang83c34212007-07-05 11:43:05 +02009701static struct snd_kcontrol_new alc262_benq_t31_mixer[] = {
9702 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9703 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9704 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9705 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9706 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9707 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
9708 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
9709 { } /* end */
9710};
Kailang Yang272a5272007-05-14 11:00:38 +02009711
Tony Vroonba340e82009-02-02 19:01:30 +00009712static struct snd_kcontrol_new alc262_tyan_mixer[] = {
9713 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9714 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
9715 HDA_CODEC_VOLUME("Aux Playback Volume", 0x0b, 0x06, HDA_INPUT),
9716 HDA_CODEC_MUTE("Aux Playback Switch", 0x0b, 0x06, HDA_INPUT),
9717 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9718 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9719 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9720 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9721 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9722 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
9723 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
9724 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
9725 { } /* end */
9726};
9727
9728static struct hda_verb alc262_tyan_verbs[] = {
9729 /* Headphone automute */
9730 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
9731 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9732 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9733
9734 /* P11 AUX_IN, white 4-pin connector */
9735 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
9736 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_1, 0xe1},
9737 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_2, 0x93},
9738 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0x19},
9739
9740 {}
9741};
9742
9743/* unsolicited event for HP jack sensing */
9744static void alc262_tyan_automute(struct hda_codec *codec)
9745{
9746 unsigned int mute;
9747 unsigned int present;
9748
9749 snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
9750 present = snd_hda_codec_read(codec, 0x1b, 0,
9751 AC_VERB_GET_PIN_SENSE, 0);
9752 present = (present & 0x80000000) != 0;
9753 if (present) {
9754 /* mute line output on ATX panel */
9755 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9756 HDA_AMP_MUTE, HDA_AMP_MUTE);
9757 } else {
9758 /* unmute line output if necessary */
9759 mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
9760 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9761 HDA_AMP_MUTE, mute);
9762 }
9763}
9764
9765static void alc262_tyan_unsol_event(struct hda_codec *codec,
9766 unsigned int res)
9767{
9768 if ((res >> 26) != ALC880_HP_EVENT)
9769 return;
9770 alc262_tyan_automute(codec);
9771}
9772
Kailang Yangdf694da2005-12-05 19:42:22 +01009773#define alc262_capture_mixer alc882_capture_mixer
9774#define alc262_capture_alt_mixer alc882_capture_alt_mixer
9775
9776/*
9777 * generic initialization of ADC, input mixers and output mixers
9778 */
9779static struct hda_verb alc262_init_verbs[] = {
9780 /*
9781 * Unmute ADC0-2 and set the default input to mic-in
9782 */
9783 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
9784 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9785 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
9786 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9787 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
9788 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9789
Takashi Iwaicb53c622007-08-10 17:21:45 +02009790 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +01009791 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009792 * Note: PASD motherboards uses the Line In 2 as the input for
9793 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01009794 */
9795 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02009796 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9797 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
9798 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
9799 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
9800 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01009801
9802 /*
9803 * Set up output mixers (0x0c - 0x0e)
9804 */
9805 /* set vol=0 to output mixers */
9806 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9807 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9808 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9809 /* set up input amps for analog loopback */
9810 /* Amp Indices: DAC = 0, mixer = 1 */
9811 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9812 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9813 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9814 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9815 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9816 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9817
9818 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
9819 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
9820 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
9821 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9822 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9823 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9824
9825 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
9826 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
9827 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
9828 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
9829 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Kailang Yangea1fb292008-08-26 12:58:38 +02009830
Kailang Yangdf694da2005-12-05 19:42:22 +01009831 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
9832 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Kailang Yangea1fb292008-08-26 12:58:38 +02009833
Kailang Yangdf694da2005-12-05 19:42:22 +01009834 /* FIXME: use matrix-type input source selection */
9835 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
9836 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
9837 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9838 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
9839 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
9840 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
9841 /* Input mixer2 */
9842 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9843 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
9844 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
9845 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
9846 /* Input mixer3 */
9847 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9848 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
9849 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009850 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
Kailang Yangdf694da2005-12-05 19:42:22 +01009851
9852 { }
9853};
9854
Kailang Yang4e555fe2008-08-26 13:05:55 +02009855static struct hda_verb alc262_eapd_verbs[] = {
9856 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
9857 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
9858 { }
9859};
9860
Kailang Yangccc656c2006-10-17 12:32:26 +02009861static struct hda_verb alc262_hippo_unsol_verbs[] = {
9862 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
9863 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9864 {}
9865};
9866
9867static struct hda_verb alc262_hippo1_unsol_verbs[] = {
9868 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
9869 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
9870 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
9871
9872 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
9873 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9874 {}
9875};
9876
Kailang Yang272a5272007-05-14 11:00:38 +02009877static struct hda_verb alc262_sony_unsol_verbs[] = {
9878 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
9879 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9880 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, // Front Mic
9881
9882 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
9883 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Akio Idehara7b1e8792008-06-09 22:46:07 +09009884 {}
Kailang Yang272a5272007-05-14 11:00:38 +02009885};
9886
Kailang Yang4e555fe2008-08-26 13:05:55 +02009887static struct hda_input_mux alc262_dmic_capture_source = {
9888 .num_items = 2,
9889 .items = {
9890 { "Int DMic", 0x9 },
9891 { "Mic", 0x0 },
9892 },
9893};
9894
9895static struct snd_kcontrol_new alc262_toshiba_s06_mixer[] = {
9896 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9897 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9898 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9899 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9900 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang4e555fe2008-08-26 13:05:55 +02009901 { } /* end */
9902};
9903
9904static struct hda_verb alc262_toshiba_s06_verbs[] = {
9905 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
9906 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9907 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9908 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9909 {0x22, AC_VERB_SET_CONNECT_SEL, 0x09},
9910 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9911 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
9912 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
9913 {}
9914};
9915
9916static void alc262_dmic_automute(struct hda_codec *codec)
9917{
9918 unsigned int present;
9919
9920 present = snd_hda_codec_read(codec, 0x18, 0,
9921 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
9922 snd_hda_codec_write(codec, 0x22, 0,
9923 AC_VERB_SET_CONNECT_SEL, present ? 0x0 : 0x09);
9924}
9925
9926/* toggle speaker-output according to the hp-jack state */
9927static void alc262_toshiba_s06_speaker_automute(struct hda_codec *codec)
9928{
9929 unsigned int present;
9930 unsigned char bits;
9931
9932 present = snd_hda_codec_read(codec, 0x15, 0,
9933 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
9934 bits = present ? 0 : PIN_OUT;
9935 snd_hda_codec_write(codec, 0x14, 0,
9936 AC_VERB_SET_PIN_WIDGET_CONTROL, bits);
9937}
9938
9939
9940
9941/* unsolicited event for HP jack sensing */
9942static void alc262_toshiba_s06_unsol_event(struct hda_codec *codec,
9943 unsigned int res)
9944{
9945 if ((res >> 26) == ALC880_HP_EVENT)
9946 alc262_toshiba_s06_speaker_automute(codec);
9947 if ((res >> 26) == ALC880_MIC_EVENT)
9948 alc262_dmic_automute(codec);
9949
9950}
9951
9952static void alc262_toshiba_s06_init_hook(struct hda_codec *codec)
9953{
9954 alc262_toshiba_s06_speaker_automute(codec);
9955 alc262_dmic_automute(codec);
9956}
9957
Kailang Yangccc656c2006-10-17 12:32:26 +02009958/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwai5b319542007-07-26 11:49:22 +02009959static void alc262_hippo_automute(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02009960{
9961 struct alc_spec *spec = codec->spec;
9962 unsigned int mute;
Takashi Iwai5b319542007-07-26 11:49:22 +02009963 unsigned int present;
Kailang Yangccc656c2006-10-17 12:32:26 +02009964
Takashi Iwai5b319542007-07-26 11:49:22 +02009965 /* need to execute and sync at first */
9966 snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0);
9967 present = snd_hda_codec_read(codec, 0x15, 0,
9968 AC_VERB_GET_PIN_SENSE, 0);
9969 spec->jack_present = (present & 0x80000000) != 0;
Kailang Yangccc656c2006-10-17 12:32:26 +02009970 if (spec->jack_present) {
9971 /* mute internal speaker */
Takashi Iwai47fd8302007-08-10 17:11:07 +02009972 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9973 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yangccc656c2006-10-17 12:32:26 +02009974 } else {
9975 /* unmute internal speaker if necessary */
9976 mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0);
Takashi Iwai47fd8302007-08-10 17:11:07 +02009977 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9978 HDA_AMP_MUTE, mute);
Kailang Yangccc656c2006-10-17 12:32:26 +02009979 }
9980}
9981
9982/* unsolicited event for HP jack sensing */
9983static void alc262_hippo_unsol_event(struct hda_codec *codec,
9984 unsigned int res)
9985{
9986 if ((res >> 26) != ALC880_HP_EVENT)
9987 return;
Takashi Iwai5b319542007-07-26 11:49:22 +02009988 alc262_hippo_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02009989}
9990
Takashi Iwai5b319542007-07-26 11:49:22 +02009991static void alc262_hippo1_automute(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02009992{
Kailang Yangccc656c2006-10-17 12:32:26 +02009993 unsigned int mute;
Takashi Iwai5b319542007-07-26 11:49:22 +02009994 unsigned int present;
Kailang Yangccc656c2006-10-17 12:32:26 +02009995
Takashi Iwai5b319542007-07-26 11:49:22 +02009996 snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
9997 present = snd_hda_codec_read(codec, 0x1b, 0,
9998 AC_VERB_GET_PIN_SENSE, 0);
9999 present = (present & 0x80000000) != 0;
10000 if (present) {
Kailang Yangccc656c2006-10-17 12:32:26 +020010001 /* mute internal speaker */
Takashi Iwai47fd8302007-08-10 17:11:07 +020010002 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
10003 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yangccc656c2006-10-17 12:32:26 +020010004 } else {
10005 /* unmute internal speaker if necessary */
10006 mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
Takashi Iwai47fd8302007-08-10 17:11:07 +020010007 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
10008 HDA_AMP_MUTE, mute);
Kailang Yangccc656c2006-10-17 12:32:26 +020010009 }
10010}
10011
10012/* unsolicited event for HP jack sensing */
10013static void alc262_hippo1_unsol_event(struct hda_codec *codec,
10014 unsigned int res)
10015{
10016 if ((res >> 26) != ALC880_HP_EVENT)
10017 return;
Takashi Iwai5b319542007-07-26 11:49:22 +020010018 alc262_hippo1_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +020010019}
10020
Takashi Iwai834be882006-03-01 14:16:17 +010010021/*
Pascal Terjane8f9ae22008-08-04 14:36:05 +020010022 * nec model
10023 * 0x15 = headphone
10024 * 0x16 = internal speaker
10025 * 0x18 = external mic
10026 */
10027
10028static struct snd_kcontrol_new alc262_nec_mixer[] = {
10029 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
10030 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 0, 0x0, HDA_OUTPUT),
10031
10032 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10033 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
10034 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10035
10036 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
10037 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
10038 { } /* end */
10039};
10040
10041static struct hda_verb alc262_nec_verbs[] = {
10042 /* Unmute Speaker */
10043 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10044
10045 /* Headphone */
10046 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
10047 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
10048
10049 /* External mic to headphone */
10050 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10051 /* External mic to speaker */
10052 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10053 {}
10054};
10055
10056/*
Takashi Iwai834be882006-03-01 14:16:17 +010010057 * fujitsu model
Tony Vroon5d9fab22008-03-14 17:09:18 +010010058 * 0x14 = headphone/spdif-out, 0x15 = internal speaker,
10059 * 0x1b = port replicator headphone out
Takashi Iwai834be882006-03-01 14:16:17 +010010060 */
10061
10062#define ALC_HP_EVENT 0x37
10063
10064static struct hda_verb alc262_fujitsu_unsol_verbs[] = {
10065 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
10066 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Tony Vroon5d9fab22008-03-14 17:09:18 +010010067 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
10068 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai834be882006-03-01 14:16:17 +010010069 {}
10070};
10071
Jiang zhe0e31daf2008-03-20 12:12:39 +010010072static struct hda_verb alc262_lenovo_3000_unsol_verbs[] = {
10073 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
10074 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
10075 {}
10076};
10077
Takashi Iwai834be882006-03-01 14:16:17 +010010078static struct hda_input_mux alc262_fujitsu_capture_source = {
Takashi Iwai39d3ed32007-10-12 15:03:48 +020010079 .num_items = 3,
Takashi Iwai834be882006-03-01 14:16:17 +010010080 .items = {
10081 { "Mic", 0x0 },
Takashi Iwai39d3ed32007-10-12 15:03:48 +020010082 { "Int Mic", 0x1 },
Takashi Iwai834be882006-03-01 14:16:17 +010010083 { "CD", 0x4 },
10084 },
10085};
10086
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010087static struct hda_input_mux alc262_HP_capture_source = {
10088 .num_items = 5,
10089 .items = {
10090 { "Mic", 0x0 },
zhejiangaccbe492007-08-31 12:36:05 +020010091 { "Front Mic", 0x1 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010092 { "Line", 0x2 },
10093 { "CD", 0x4 },
10094 { "AUX IN", 0x6 },
10095 },
10096};
10097
zhejiangaccbe492007-08-31 12:36:05 +020010098static struct hda_input_mux alc262_HP_D7000_capture_source = {
10099 .num_items = 4,
10100 .items = {
10101 { "Mic", 0x0 },
10102 { "Front Mic", 0x2 },
10103 { "Line", 0x1 },
10104 { "CD", 0x4 },
10105 },
10106};
10107
Takashi Iwaiebc7a402008-05-20 09:23:05 +020010108/* mute/unmute internal speaker according to the hp jacks and mute state */
Takashi Iwai834be882006-03-01 14:16:17 +010010109static void alc262_fujitsu_automute(struct hda_codec *codec, int force)
10110{
10111 struct alc_spec *spec = codec->spec;
10112 unsigned int mute;
10113
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010114 if (force || !spec->sense_updated) {
Takashi Iwaiebc7a402008-05-20 09:23:05 +020010115 unsigned int present;
Takashi Iwai834be882006-03-01 14:16:17 +010010116 /* need to execute and sync at first */
10117 snd_hda_codec_read(codec, 0x14, 0, AC_VERB_SET_PIN_SENSE, 0);
Takashi Iwaiebc7a402008-05-20 09:23:05 +020010118 /* check laptop HP jack */
10119 present = snd_hda_codec_read(codec, 0x14, 0,
10120 AC_VERB_GET_PIN_SENSE, 0);
10121 /* need to execute and sync at first */
10122 snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
10123 /* check docking HP jack */
10124 present |= snd_hda_codec_read(codec, 0x1b, 0,
10125 AC_VERB_GET_PIN_SENSE, 0);
10126 if (present & AC_PINSENSE_PRESENCE)
10127 spec->jack_present = 1;
10128 else
10129 spec->jack_present = 0;
Takashi Iwai834be882006-03-01 14:16:17 +010010130 spec->sense_updated = 1;
10131 }
Takashi Iwaiebc7a402008-05-20 09:23:05 +020010132 /* unmute internal speaker only if both HPs are unplugged and
10133 * master switch is on
10134 */
10135 if (spec->jack_present)
10136 mute = HDA_AMP_MUTE;
10137 else
Takashi Iwai834be882006-03-01 14:16:17 +010010138 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
Takashi Iwaiebc7a402008-05-20 09:23:05 +020010139 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
10140 HDA_AMP_MUTE, mute);
Takashi Iwai834be882006-03-01 14:16:17 +010010141}
10142
10143/* unsolicited event for HP jack sensing */
10144static void alc262_fujitsu_unsol_event(struct hda_codec *codec,
10145 unsigned int res)
10146{
10147 if ((res >> 26) != ALC_HP_EVENT)
10148 return;
10149 alc262_fujitsu_automute(codec, 1);
10150}
10151
Takashi Iwaiebc7a402008-05-20 09:23:05 +020010152static void alc262_fujitsu_init_hook(struct hda_codec *codec)
10153{
10154 alc262_fujitsu_automute(codec, 1);
10155}
10156
Takashi Iwai834be882006-03-01 14:16:17 +010010157/* bind volumes of both NID 0x0c and 0x0d */
Takashi Iwaicca3b372007-08-10 17:12:15 +020010158static struct hda_bind_ctls alc262_fujitsu_bind_master_vol = {
10159 .ops = &snd_hda_bind_vol,
10160 .values = {
10161 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT),
10162 HDA_COMPOSE_AMP_VAL(0x0d, 3, 0, HDA_OUTPUT),
10163 0
10164 },
10165};
Takashi Iwai834be882006-03-01 14:16:17 +010010166
Jiang zhe0e31daf2008-03-20 12:12:39 +010010167/* mute/unmute internal speaker according to the hp jack and mute state */
10168static void alc262_lenovo_3000_automute(struct hda_codec *codec, int force)
10169{
10170 struct alc_spec *spec = codec->spec;
10171 unsigned int mute;
10172
10173 if (force || !spec->sense_updated) {
10174 unsigned int present_int_hp;
10175 /* need to execute and sync at first */
10176 snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
10177 present_int_hp = snd_hda_codec_read(codec, 0x1b, 0,
10178 AC_VERB_GET_PIN_SENSE, 0);
10179 spec->jack_present = (present_int_hp & 0x80000000) != 0;
10180 spec->sense_updated = 1;
10181 }
10182 if (spec->jack_present) {
10183 /* mute internal speaker */
10184 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
10185 HDA_AMP_MUTE, HDA_AMP_MUTE);
10186 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
10187 HDA_AMP_MUTE, HDA_AMP_MUTE);
10188 } else {
10189 /* unmute internal speaker if necessary */
10190 mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
10191 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
10192 HDA_AMP_MUTE, mute);
10193 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
10194 HDA_AMP_MUTE, mute);
10195 }
10196}
10197
10198/* unsolicited event for HP jack sensing */
10199static void alc262_lenovo_3000_unsol_event(struct hda_codec *codec,
10200 unsigned int res)
10201{
10202 if ((res >> 26) != ALC_HP_EVENT)
10203 return;
10204 alc262_lenovo_3000_automute(codec, 1);
10205}
10206
Takashi Iwai834be882006-03-01 14:16:17 +010010207/* bind hp and internal speaker mute (with plug check) */
10208static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol,
10209 struct snd_ctl_elem_value *ucontrol)
10210{
10211 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
10212 long *valp = ucontrol->value.integer.value;
10213 int change;
10214
Tony Vroon5d9fab22008-03-14 17:09:18 +010010215 change = snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
10216 HDA_AMP_MUTE,
10217 valp ? 0 : HDA_AMP_MUTE);
10218 change |= snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
10219 HDA_AMP_MUTE,
10220 valp ? 0 : HDA_AMP_MUTE);
10221
Takashi Iwai82beb8f2007-08-10 17:09:26 +020010222 if (change)
10223 alc262_fujitsu_automute(codec, 0);
Takashi Iwai834be882006-03-01 14:16:17 +010010224 return change;
10225}
10226
10227static struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +020010228 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
Takashi Iwai834be882006-03-01 14:16:17 +010010229 {
10230 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10231 .name = "Master Playback Switch",
10232 .info = snd_hda_mixer_amp_switch_info,
10233 .get = snd_hda_mixer_amp_switch_get,
10234 .put = alc262_fujitsu_master_sw_put,
10235 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
10236 },
10237 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
10238 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
10239 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10240 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10241 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai39d3ed32007-10-12 15:03:48 +020010242 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
10243 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
10244 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai834be882006-03-01 14:16:17 +010010245 { } /* end */
10246};
10247
Jiang zhe0e31daf2008-03-20 12:12:39 +010010248/* bind hp and internal speaker mute (with plug check) */
10249static int alc262_lenovo_3000_master_sw_put(struct snd_kcontrol *kcontrol,
10250 struct snd_ctl_elem_value *ucontrol)
10251{
10252 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
10253 long *valp = ucontrol->value.integer.value;
10254 int change;
10255
10256 change = snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
10257 HDA_AMP_MUTE,
10258 valp ? 0 : HDA_AMP_MUTE);
10259
10260 if (change)
10261 alc262_lenovo_3000_automute(codec, 0);
10262 return change;
10263}
10264
10265static struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = {
10266 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
10267 {
10268 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10269 .name = "Master Playback Switch",
10270 .info = snd_hda_mixer_amp_switch_info,
10271 .get = snd_hda_mixer_amp_switch_get,
10272 .put = alc262_lenovo_3000_master_sw_put,
10273 .private_value = HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
10274 },
10275 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
10276 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
10277 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10278 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10279 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
10280 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
10281 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
10282 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
10283 { } /* end */
10284};
10285
Hiroshi Miura9f99a632008-08-28 16:09:06 +020010286static struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = {
10287 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
10288 {
10289 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10290 .name = "Master Playback Switch",
10291 .info = snd_hda_mixer_amp_switch_info,
10292 .get = snd_hda_mixer_amp_switch_get,
10293 .put = alc262_sony_master_sw_put,
10294 .private_value = HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
10295 },
10296 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10297 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
10298 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10299 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
10300 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
10301 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
10302 { } /* end */
10303};
10304
Takashi Iwai304dcaa2006-07-25 14:51:16 +020010305/* additional init verbs for Benq laptops */
10306static struct hda_verb alc262_EAPD_verbs[] = {
10307 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
10308 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
10309 {}
10310};
10311
Kailang Yang83c34212007-07-05 11:43:05 +020010312static struct hda_verb alc262_benq_t31_EAPD_verbs[] = {
10313 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
10314 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
10315
10316 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
10317 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
10318 {}
10319};
10320
Tobin Davisf651b502007-10-26 12:40:47 +020010321/* Samsung Q1 Ultra Vista model setup */
10322static struct snd_kcontrol_new alc262_ultra_mixer[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010323 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
10324 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +020010325 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
10326 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
10327 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010328 HDA_CODEC_VOLUME("Headphone Mic Boost", 0x15, 0, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +020010329 { } /* end */
10330};
10331
10332static struct hda_verb alc262_ultra_verbs[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010333 /* output mixer */
10334 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
10335 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10336 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10337 /* speaker */
10338 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
10339 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10340 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10341 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
10342 /* HP */
Tobin Davisf651b502007-10-26 12:40:47 +020010343 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010344 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10345 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10346 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
10347 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
10348 /* internal mic */
10349 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
10350 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10351 /* ADC, choose mic */
10352 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
10353 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
10354 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10355 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
10356 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
10357 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
10358 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
10359 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
10360 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
10361 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(8)},
Tobin Davisf651b502007-10-26 12:40:47 +020010362 {}
10363};
10364
Tobin Davisf651b502007-10-26 12:40:47 +020010365/* mute/unmute internal speaker according to the hp jack and mute state */
10366static void alc262_ultra_automute(struct hda_codec *codec)
10367{
10368 struct alc_spec *spec = codec->spec;
10369 unsigned int mute;
Tobin Davisf651b502007-10-26 12:40:47 +020010370
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010371 mute = 0;
10372 /* auto-mute only when HP is used as HP */
10373 if (!spec->cur_mux[0]) {
10374 unsigned int present;
10375 /* need to execute and sync at first */
10376 snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0);
10377 present = snd_hda_codec_read(codec, 0x15, 0,
10378 AC_VERB_GET_PIN_SENSE, 0);
10379 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
10380 if (spec->jack_present)
10381 mute = HDA_AMP_MUTE;
Tobin Davisf651b502007-10-26 12:40:47 +020010382 }
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010383 /* mute/unmute internal speaker */
10384 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
10385 HDA_AMP_MUTE, mute);
10386 /* mute/unmute HP */
10387 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
10388 HDA_AMP_MUTE, mute ? 0 : HDA_AMP_MUTE);
Tobin Davisf651b502007-10-26 12:40:47 +020010389}
10390
10391/* unsolicited event for HP jack sensing */
10392static void alc262_ultra_unsol_event(struct hda_codec *codec,
10393 unsigned int res)
10394{
10395 if ((res >> 26) != ALC880_HP_EVENT)
10396 return;
10397 alc262_ultra_automute(codec);
10398}
10399
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010400static struct hda_input_mux alc262_ultra_capture_source = {
10401 .num_items = 2,
10402 .items = {
10403 { "Mic", 0x1 },
10404 { "Headphone", 0x7 },
10405 },
10406};
10407
10408static int alc262_ultra_mux_enum_put(struct snd_kcontrol *kcontrol,
10409 struct snd_ctl_elem_value *ucontrol)
10410{
10411 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
10412 struct alc_spec *spec = codec->spec;
10413 int ret;
10414
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010010415 ret = alc_mux_enum_put(kcontrol, ucontrol);
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010416 if (!ret)
10417 return 0;
10418 /* reprogram the HP pin as mic or HP according to the input source */
10419 snd_hda_codec_write_cache(codec, 0x15, 0,
10420 AC_VERB_SET_PIN_WIDGET_CONTROL,
10421 spec->cur_mux[0] ? PIN_VREF80 : PIN_HP);
10422 alc262_ultra_automute(codec); /* mute/unmute HP */
10423 return ret;
10424}
10425
10426static struct snd_kcontrol_new alc262_ultra_capture_mixer[] = {
10427 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
10428 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
10429 {
10430 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10431 .name = "Capture Source",
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010010432 .info = alc_mux_enum_info,
10433 .get = alc_mux_enum_get,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010434 .put = alc262_ultra_mux_enum_put,
10435 },
10436 { } /* end */
10437};
10438
Kailang Yangdf694da2005-12-05 19:42:22 +010010439/* add playback controls from the parsed DAC table */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010440static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
10441 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010010442{
10443 hda_nid_t nid;
10444 int err;
10445
10446 spec->multiout.num_dacs = 1; /* only use one dac */
10447 spec->multiout.dac_nids = spec->private_dac_nids;
10448 spec->multiout.dac_nids[0] = 2;
10449
10450 nid = cfg->line_out_pins[0];
10451 if (nid) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010452 err = add_control(spec, ALC_CTL_WIDGET_VOL,
10453 "Front Playback Volume",
10454 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT));
10455 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010456 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010457 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10458 "Front Playback Switch",
10459 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
10460 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010461 return err;
10462 }
10463
Takashi Iwai82bc9552006-03-21 11:24:42 +010010464 nid = cfg->speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010010465 if (nid) {
10466 if (nid == 0x16) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010467 err = add_control(spec, ALC_CTL_WIDGET_VOL,
10468 "Speaker Playback Volume",
10469 HDA_COMPOSE_AMP_VAL(0x0e, 2, 0,
10470 HDA_OUTPUT));
10471 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010472 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010473 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10474 "Speaker Playback Switch",
10475 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
10476 HDA_OUTPUT));
10477 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010478 return err;
10479 } else {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010480 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10481 "Speaker Playback Switch",
10482 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
10483 HDA_OUTPUT));
10484 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010485 return err;
10486 }
10487 }
Takashi Iwaieb06ed82006-09-20 17:10:27 +020010488 nid = cfg->hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010010489 if (nid) {
10490 /* spec->multiout.hp_nid = 2; */
10491 if (nid == 0x16) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010492 err = add_control(spec, ALC_CTL_WIDGET_VOL,
10493 "Headphone Playback Volume",
10494 HDA_COMPOSE_AMP_VAL(0x0e, 2, 0,
10495 HDA_OUTPUT));
10496 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010497 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010498 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10499 "Headphone Playback Switch",
10500 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
10501 HDA_OUTPUT));
10502 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010503 return err;
10504 } else {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010505 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10506 "Headphone Playback Switch",
10507 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
10508 HDA_OUTPUT));
10509 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010510 return err;
10511 }
10512 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010513 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +010010514}
10515
10516/* identical with ALC880 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010517#define alc262_auto_create_analog_input_ctls \
10518 alc880_auto_create_analog_input_ctls
Kailang Yangdf694da2005-12-05 19:42:22 +010010519
10520/*
10521 * generic initialization of ADC, input mixers and output mixers
10522 */
10523static struct hda_verb alc262_volume_init_verbs[] = {
10524 /*
10525 * Unmute ADC0-2 and set the default input to mic-in
10526 */
10527 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
10528 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10529 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
10530 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10531 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
10532 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10533
Takashi Iwaicb53c622007-08-10 17:21:45 +020010534 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +010010535 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010536 * Note: PASD motherboards uses the Line In 2 as the input for
10537 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +010010538 */
10539 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020010540 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
10541 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10542 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
10543 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
10544 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +010010545
10546 /*
10547 * Set up output mixers (0x0c - 0x0f)
10548 */
10549 /* set vol=0 to output mixers */
10550 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10551 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10552 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yangea1fb292008-08-26 12:58:38 +020010553
Kailang Yangdf694da2005-12-05 19:42:22 +010010554 /* set up input amps for analog loopback */
10555 /* Amp Indices: DAC = 0, mixer = 1 */
10556 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10557 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10558 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10559 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10560 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10561 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10562
10563 /* FIXME: use matrix-type input source selection */
10564 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
10565 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
10566 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10567 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
10568 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
10569 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
10570 /* Input mixer2 */
10571 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10572 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
10573 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
10574 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
10575 /* Input mixer3 */
10576 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10577 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
10578 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
10579 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
10580
10581 { }
10582};
10583
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010584static struct hda_verb alc262_HP_BPC_init_verbs[] = {
10585 /*
10586 * Unmute ADC0-2 and set the default input to mic-in
10587 */
10588 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
10589 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10590 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
10591 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10592 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
10593 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10594
Takashi Iwaicb53c622007-08-10 17:21:45 +020010595 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010596 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010597 * Note: PASD motherboards uses the Line In 2 as the input for
10598 * front panel mic (mic 2)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010599 */
10600 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020010601 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
10602 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10603 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
10604 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
10605 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
10606 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
10607 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
Kailang Yangea1fb292008-08-26 12:58:38 +020010608
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010609 /*
10610 * Set up output mixers (0x0c - 0x0e)
10611 */
10612 /* set vol=0 to output mixers */
10613 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10614 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10615 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10616
10617 /* set up input amps for analog loopback */
10618 /* Amp Indices: DAC = 0, mixer = 1 */
10619 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10620 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10621 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10622 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10623 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10624 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10625
Takashi Iwaice875f02008-01-28 18:17:43 +010010626 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010627 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
10628 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
10629
10630 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
10631 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
10632
10633 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
10634 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
10635
10636 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10637 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
10638 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
10639 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10640 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10641
10642 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
10643 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10644 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10645 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
10646 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10647 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10648
10649
10650 /* FIXME: use matrix-type input source selection */
10651 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
10652 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
10653 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10654 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
10655 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
10656 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
10657 /* Input mixer2 */
10658 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10659 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
10660 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
10661 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
10662 /* Input mixer3 */
10663 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10664 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
10665 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
10666 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
10667
Takashi Iwaice875f02008-01-28 18:17:43 +010010668 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
10669
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010670 { }
10671};
10672
Kailang Yangcd7509a2007-01-26 18:33:17 +010010673static struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = {
10674 /*
10675 * Unmute ADC0-2 and set the default input to mic-in
10676 */
10677 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
10678 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10679 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
10680 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10681 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
10682 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10683
Takashi Iwaicb53c622007-08-10 17:21:45 +020010684 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangcd7509a2007-01-26 18:33:17 +010010685 * mixer widget
10686 * Note: PASD motherboards uses the Line In 2 as the input for front
10687 * panel mic (mic 2)
10688 */
10689 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020010690 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
10691 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10692 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
10693 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
10694 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
10695 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
10696 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
10697 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Kailang Yangcd7509a2007-01-26 18:33:17 +010010698 /*
10699 * Set up output mixers (0x0c - 0x0e)
10700 */
10701 /* set vol=0 to output mixers */
10702 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10703 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10704 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10705
10706 /* set up input amps for analog loopback */
10707 /* Amp Indices: DAC = 0, mixer = 1 */
10708 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10709 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10710 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10711 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10712 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10713 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10714
10715
10716 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP */
10717 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Mono */
10718 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* rear MIC */
10719 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* Line in */
10720 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
10721 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Line out */
10722 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD in */
10723
10724 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
10725 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
10726
10727 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
10728 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
10729
10730 /* {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, */
10731 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10732 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10733 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
10734 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10735 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10736
10737 /* FIXME: use matrix-type input source selection */
10738 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
10739 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
10740 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, /*rear MIC*/
10741 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, /*Line in*/
10742 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, /*F MIC*/
10743 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, /*Front*/
10744 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, /*CD*/
10745 /* {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
10746 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, /*HP*/
10747 /* Input mixer2 */
10748 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10749 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
10750 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
10751 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
10752 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
10753 /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
10754 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
10755 /* Input mixer3 */
10756 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10757 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
10758 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
10759 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
10760 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
10761 /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
10762 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
10763
Takashi Iwaice875f02008-01-28 18:17:43 +010010764 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
10765
Kailang Yangcd7509a2007-01-26 18:33:17 +010010766 { }
10767};
10768
Hiroshi Miura9f99a632008-08-28 16:09:06 +020010769static struct hda_verb alc262_toshiba_rx1_unsol_verbs[] = {
10770
10771 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Front Speaker */
10772 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
10773 {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
10774
10775 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* MIC jack */
10776 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
10777 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
10778 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
10779
10780 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP jack */
10781 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
10782 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
10783 {}
10784};
10785
10786
Takashi Iwaicb53c622007-08-10 17:21:45 +020010787#ifdef CONFIG_SND_HDA_POWER_SAVE
10788#define alc262_loopbacks alc880_loopbacks
10789#endif
10790
Kailang Yangdf694da2005-12-05 19:42:22 +010010791/* pcm configuration: identiacal with ALC880 */
10792#define alc262_pcm_analog_playback alc880_pcm_analog_playback
10793#define alc262_pcm_analog_capture alc880_pcm_analog_capture
10794#define alc262_pcm_digital_playback alc880_pcm_digital_playback
10795#define alc262_pcm_digital_capture alc880_pcm_digital_capture
10796
10797/*
10798 * BIOS auto configuration
10799 */
10800static int alc262_parse_auto_config(struct hda_codec *codec)
10801{
10802 struct alc_spec *spec = codec->spec;
10803 int err;
10804 static hda_nid_t alc262_ignore[] = { 0x1d, 0 };
10805
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010806 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
10807 alc262_ignore);
10808 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010809 return err;
Takashi Iwaie64f14f2009-01-20 18:32:55 +010010810 if (!spec->autocfg.line_outs) {
Takashi Iwai0852d7a2009-02-11 11:35:15 +010010811 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
Takashi Iwaie64f14f2009-01-20 18:32:55 +010010812 spec->multiout.max_channels = 2;
10813 spec->no_analog = 1;
10814 goto dig_only;
10815 }
Kailang Yangdf694da2005-12-05 19:42:22 +010010816 return 0; /* can't find valid BIOS pin config */
Takashi Iwaie64f14f2009-01-20 18:32:55 +010010817 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010818 err = alc262_auto_create_multi_out_ctls(spec, &spec->autocfg);
10819 if (err < 0)
10820 return err;
10821 err = alc262_auto_create_analog_input_ctls(spec, &spec->autocfg);
10822 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010823 return err;
10824
10825 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
10826
Takashi Iwaie64f14f2009-01-20 18:32:55 +010010827 dig_only:
Takashi Iwai0852d7a2009-02-11 11:35:15 +010010828 if (spec->autocfg.dig_outs) {
Kailang Yangdf694da2005-12-05 19:42:22 +010010829 spec->multiout.dig_out_nid = ALC262_DIGOUT_NID;
Takashi Iwai0852d7a2009-02-11 11:35:15 +010010830 spec->dig_out_type = spec->autocfg.dig_out_type[0];
Takashi Iwaie64f14f2009-01-20 18:32:55 +010010831 }
Kailang Yangdf694da2005-12-05 19:42:22 +010010832 if (spec->autocfg.dig_in_pin)
10833 spec->dig_in_nid = ALC262_DIGIN_NID;
10834
Takashi Iwai603c4012008-07-30 15:01:44 +020010835 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010010836 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +010010837
Takashi Iwaid88897e2008-10-31 15:01:37 +010010838 add_verb(spec, alc262_volume_init_verbs);
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020010839 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020010840 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010010841
Takashi Iwai776e1842007-08-29 15:07:11 +020010842 err = alc_auto_add_mic_boost(codec);
10843 if (err < 0)
10844 return err;
10845
Kailang Yangdf694da2005-12-05 19:42:22 +010010846 return 1;
10847}
10848
10849#define alc262_auto_init_multi_out alc882_auto_init_multi_out
10850#define alc262_auto_init_hp_out alc882_auto_init_hp_out
10851#define alc262_auto_init_analog_input alc882_auto_init_analog_input
Takashi Iwaif511b012008-08-15 16:46:42 +020010852#define alc262_auto_init_input_src alc882_auto_init_input_src
Kailang Yangdf694da2005-12-05 19:42:22 +010010853
10854
10855/* init callback for auto-configuration model -- overriding the default init */
Takashi Iwaiae6b8132006-03-03 16:47:17 +010010856static void alc262_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010010857{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010858 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010010859 alc262_auto_init_multi_out(codec);
10860 alc262_auto_init_hp_out(codec);
10861 alc262_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020010862 alc262_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010863 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020010864 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010010865}
10866
10867/*
10868 * configuration and preset
10869 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010870static const char *alc262_models[ALC262_MODEL_LAST] = {
10871 [ALC262_BASIC] = "basic",
10872 [ALC262_HIPPO] = "hippo",
10873 [ALC262_HIPPO_1] = "hippo_1",
10874 [ALC262_FUJITSU] = "fujitsu",
10875 [ALC262_HP_BPC] = "hp-bpc",
Kailang Yangcd7509a2007-01-26 18:33:17 +010010876 [ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000",
Takashi Iwai61dc35d2007-11-14 12:26:44 +010010877 [ALC262_HP_TC_T5735] = "hp-tc-t5735",
Kailang Yang8c427222008-01-10 13:03:59 +010010878 [ALC262_HP_RP5700] = "hp-rp5700",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010879 [ALC262_BENQ_ED8] = "benq",
Takashi Iwai0f405022007-07-06 12:24:11 +020010880 [ALC262_BENQ_T31] = "benq-t31",
10881 [ALC262_SONY_ASSAMD] = "sony-assamd",
Takashi Iwai2922c9a2008-08-27 18:12:42 +020010882 [ALC262_TOSHIBA_S06] = "toshiba-s06",
Hiroshi Miura9f99a632008-08-28 16:09:06 +020010883 [ALC262_TOSHIBA_RX1] = "toshiba-rx1",
Tobin Davisf651b502007-10-26 12:40:47 +020010884 [ALC262_ULTRA] = "ultra",
Jiang zhe0e31daf2008-03-20 12:12:39 +010010885 [ALC262_LENOVO_3000] = "lenovo-3000",
Pascal Terjane8f9ae22008-08-04 14:36:05 +020010886 [ALC262_NEC] = "nec",
Tony Vroonba340e82009-02-02 19:01:30 +000010887 [ALC262_TYAN] = "tyan",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010888 [ALC262_AUTO] = "auto",
10889};
10890
10891static struct snd_pci_quirk alc262_cfg_tbl[] = {
10892 SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO),
Pascal Terjane8f9ae22008-08-04 14:36:05 +020010893 SND_PCI_QUIRK(0x1033, 0x8895, "NEC Versa S9100", ALC262_NEC),
Takashi Iwaidea0a502009-02-09 17:14:52 +010010894 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1200, "HP xw series",
10895 ALC262_HP_BPC),
10896 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1300, "HP xw series",
10897 ALC262_HP_BPC),
Takashi Iwai53eff7e2009-02-27 17:49:44 +010010898 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1700, "HP xw series",
10899 ALC262_HP_BPC),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010900 SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010901 SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010902 SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010903 SND_PCI_QUIRK(0x103c, 0x2803, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010904 SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010905 SND_PCI_QUIRK(0x103c, 0x2805, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010906 SND_PCI_QUIRK(0x103c, 0x2806, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010907 SND_PCI_QUIRK(0x103c, 0x2807, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010908 SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC),
10909 SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC),
10910 SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC),
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010911 SND_PCI_QUIRK(0x103c, 0x302f, "HP Thin Client T5735",
10912 ALC262_HP_TC_T5735),
Kailang Yang8c427222008-01-10 13:03:59 +010010913 SND_PCI_QUIRK(0x103c, 0x2817, "HP RP5700", ALC262_HP_RP5700),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010914 SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010915 SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010916 SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD),
Takashi Iwaibd6afe32009-03-04 11:30:25 +010010917 SND_PCI_QUIRK(0x104d, 0x9016, "Sony VAIO", ALC262_AUTO), /* dig-only */
Takashi Iwaif872a912009-02-26 00:57:01 +010010918 SND_PCI_QUIRK_MASK(0x104d, 0xff00, 0x9000, "Sony VAIO",
10919 ALC262_SONY_ASSAMD),
Akio Idehara36ca6e12008-06-09 22:57:40 +090010920 SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1",
Hiroshi Miura9f99a632008-08-28 16:09:06 +020010921 ALC262_TOSHIBA_RX1),
Kailang Yang80ffe862008-10-15 11:23:27 +020010922 SND_PCI_QUIRK(0x1179, 0xff7b, "Toshiba S06", ALC262_TOSHIBA_S06),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010923 SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU),
Tony Vroon3f1eeae2008-02-25 16:44:13 +010010924 SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU),
Tony Vroonba340e82009-02-02 19:01:30 +000010925 SND_PCI_QUIRK(0x10f1, 0x2915, "Tyan Thunder n6650W", ALC262_TYAN),
Takashi Iwaidea0a502009-02-09 17:14:52 +010010926 SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc032, "Samsung Q1",
10927 ALC262_ULTRA),
Luke Yelavich3e420e72008-12-16 12:37:47 +110010928 SND_PCI_QUIRK(0x144d, 0xc510, "Samsung Q45", ALC262_HIPPO),
Jiang zhe0e31daf2008-03-20 12:12:39 +010010929 SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 y410", ALC262_LENOVO_3000),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010930 SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8),
Kailang Yang83c34212007-07-05 11:43:05 +020010931 SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010932 SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1),
Kailang Yangdf694da2005-12-05 19:42:22 +010010933 {}
10934};
10935
10936static struct alc_config_preset alc262_presets[] = {
10937 [ALC262_BASIC] = {
10938 .mixers = { alc262_base_mixer },
10939 .init_verbs = { alc262_init_verbs },
10940 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10941 .dac_nids = alc262_dac_nids,
10942 .hp_nid = 0x03,
10943 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10944 .channel_mode = alc262_modes,
Takashi Iwaia3bcba32005-12-06 19:05:29 +010010945 .input_mux = &alc262_capture_source,
Kailang Yangdf694da2005-12-05 19:42:22 +010010946 },
Kailang Yangccc656c2006-10-17 12:32:26 +020010947 [ALC262_HIPPO] = {
10948 .mixers = { alc262_base_mixer },
10949 .init_verbs = { alc262_init_verbs, alc262_hippo_unsol_verbs},
10950 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10951 .dac_nids = alc262_dac_nids,
10952 .hp_nid = 0x03,
10953 .dig_out_nid = ALC262_DIGOUT_NID,
10954 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10955 .channel_mode = alc262_modes,
10956 .input_mux = &alc262_capture_source,
10957 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +020010958 .init_hook = alc262_hippo_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020010959 },
10960 [ALC262_HIPPO_1] = {
10961 .mixers = { alc262_hippo1_mixer },
10962 .init_verbs = { alc262_init_verbs, alc262_hippo1_unsol_verbs},
10963 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10964 .dac_nids = alc262_dac_nids,
10965 .hp_nid = 0x02,
10966 .dig_out_nid = ALC262_DIGOUT_NID,
10967 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10968 .channel_mode = alc262_modes,
10969 .input_mux = &alc262_capture_source,
10970 .unsol_event = alc262_hippo1_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +020010971 .init_hook = alc262_hippo1_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020010972 },
Takashi Iwai834be882006-03-01 14:16:17 +010010973 [ALC262_FUJITSU] = {
10974 .mixers = { alc262_fujitsu_mixer },
Takashi Iwai39d3ed32007-10-12 15:03:48 +020010975 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
10976 alc262_fujitsu_unsol_verbs },
Takashi Iwai834be882006-03-01 14:16:17 +010010977 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10978 .dac_nids = alc262_dac_nids,
10979 .hp_nid = 0x03,
10980 .dig_out_nid = ALC262_DIGOUT_NID,
10981 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10982 .channel_mode = alc262_modes,
10983 .input_mux = &alc262_fujitsu_capture_source,
Takashi Iwaiae6b8132006-03-03 16:47:17 +010010984 .unsol_event = alc262_fujitsu_unsol_event,
Takashi Iwaiebc7a402008-05-20 09:23:05 +020010985 .init_hook = alc262_fujitsu_init_hook,
Takashi Iwai834be882006-03-01 14:16:17 +010010986 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010987 [ALC262_HP_BPC] = {
10988 .mixers = { alc262_HP_BPC_mixer },
10989 .init_verbs = { alc262_HP_BPC_init_verbs },
10990 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10991 .dac_nids = alc262_dac_nids,
10992 .hp_nid = 0x03,
10993 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10994 .channel_mode = alc262_modes,
10995 .input_mux = &alc262_HP_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010010996 .unsol_event = alc262_hp_bpc_unsol_event,
10997 .init_hook = alc262_hp_bpc_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010998 },
Kailang Yangcd7509a2007-01-26 18:33:17 +010010999 [ALC262_HP_BPC_D7000_WF] = {
11000 .mixers = { alc262_HP_BPC_WildWest_mixer },
11001 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
11002 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11003 .dac_nids = alc262_dac_nids,
11004 .hp_nid = 0x03,
11005 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11006 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +020011007 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010011008 .unsol_event = alc262_hp_wildwest_unsol_event,
11009 .init_hook = alc262_hp_wildwest_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011010 },
Kailang Yangcd7509a2007-01-26 18:33:17 +010011011 [ALC262_HP_BPC_D7000_WL] = {
11012 .mixers = { alc262_HP_BPC_WildWest_mixer,
11013 alc262_HP_BPC_WildWest_option_mixer },
11014 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
11015 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11016 .dac_nids = alc262_dac_nids,
11017 .hp_nid = 0x03,
11018 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11019 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +020011020 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010011021 .unsol_event = alc262_hp_wildwest_unsol_event,
11022 .init_hook = alc262_hp_wildwest_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011023 },
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011024 [ALC262_HP_TC_T5735] = {
11025 .mixers = { alc262_hp_t5735_mixer },
11026 .init_verbs = { alc262_init_verbs, alc262_hp_t5735_verbs },
11027 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11028 .dac_nids = alc262_dac_nids,
11029 .hp_nid = 0x03,
11030 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11031 .channel_mode = alc262_modes,
11032 .input_mux = &alc262_capture_source,
11033 .unsol_event = alc262_hp_t5735_unsol_event,
11034 .init_hook = alc262_hp_t5735_init_hook,
Kailang Yang8c427222008-01-10 13:03:59 +010011035 },
11036 [ALC262_HP_RP5700] = {
11037 .mixers = { alc262_hp_rp5700_mixer },
11038 .init_verbs = { alc262_init_verbs, alc262_hp_rp5700_verbs },
11039 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11040 .dac_nids = alc262_dac_nids,
11041 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11042 .channel_mode = alc262_modes,
11043 .input_mux = &alc262_hp_rp5700_capture_source,
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011044 },
Takashi Iwai304dcaa2006-07-25 14:51:16 +020011045 [ALC262_BENQ_ED8] = {
11046 .mixers = { alc262_base_mixer },
11047 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs },
11048 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11049 .dac_nids = alc262_dac_nids,
11050 .hp_nid = 0x03,
11051 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11052 .channel_mode = alc262_modes,
11053 .input_mux = &alc262_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011054 },
Kailang Yang272a5272007-05-14 11:00:38 +020011055 [ALC262_SONY_ASSAMD] = {
11056 .mixers = { alc262_sony_mixer },
11057 .init_verbs = { alc262_init_verbs, alc262_sony_unsol_verbs},
11058 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11059 .dac_nids = alc262_dac_nids,
11060 .hp_nid = 0x02,
11061 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11062 .channel_mode = alc262_modes,
11063 .input_mux = &alc262_capture_source,
11064 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +020011065 .init_hook = alc262_hippo_automute,
Kailang Yang83c34212007-07-05 11:43:05 +020011066 },
11067 [ALC262_BENQ_T31] = {
11068 .mixers = { alc262_benq_t31_mixer },
11069 .init_verbs = { alc262_init_verbs, alc262_benq_t31_EAPD_verbs, alc262_hippo_unsol_verbs },
11070 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11071 .dac_nids = alc262_dac_nids,
11072 .hp_nid = 0x03,
11073 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11074 .channel_mode = alc262_modes,
11075 .input_mux = &alc262_capture_source,
11076 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +020011077 .init_hook = alc262_hippo_automute,
Kailang Yangea1fb292008-08-26 12:58:38 +020011078 },
Tobin Davisf651b502007-10-26 12:40:47 +020011079 [ALC262_ULTRA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010011080 .mixers = { alc262_ultra_mixer },
11081 .cap_mixer = alc262_ultra_capture_mixer,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011082 .init_verbs = { alc262_ultra_verbs },
Tobin Davisf651b502007-10-26 12:40:47 +020011083 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11084 .dac_nids = alc262_dac_nids,
Tobin Davisf651b502007-10-26 12:40:47 +020011085 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11086 .channel_mode = alc262_modes,
11087 .input_mux = &alc262_ultra_capture_source,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011088 .adc_nids = alc262_adc_nids, /* ADC0 */
11089 .capsrc_nids = alc262_capsrc_nids,
11090 .num_adc_nids = 1, /* single ADC */
Tobin Davisf651b502007-10-26 12:40:47 +020011091 .unsol_event = alc262_ultra_unsol_event,
11092 .init_hook = alc262_ultra_automute,
11093 },
Jiang zhe0e31daf2008-03-20 12:12:39 +010011094 [ALC262_LENOVO_3000] = {
11095 .mixers = { alc262_lenovo_3000_mixer },
11096 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
11097 alc262_lenovo_3000_unsol_verbs },
11098 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11099 .dac_nids = alc262_dac_nids,
11100 .hp_nid = 0x03,
11101 .dig_out_nid = ALC262_DIGOUT_NID,
11102 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11103 .channel_mode = alc262_modes,
11104 .input_mux = &alc262_fujitsu_capture_source,
11105 .unsol_event = alc262_lenovo_3000_unsol_event,
11106 },
Pascal Terjane8f9ae22008-08-04 14:36:05 +020011107 [ALC262_NEC] = {
11108 .mixers = { alc262_nec_mixer },
11109 .init_verbs = { alc262_nec_verbs },
11110 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11111 .dac_nids = alc262_dac_nids,
11112 .hp_nid = 0x03,
11113 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11114 .channel_mode = alc262_modes,
11115 .input_mux = &alc262_capture_source,
11116 },
Kailang Yang4e555fe2008-08-26 13:05:55 +020011117 [ALC262_TOSHIBA_S06] = {
11118 .mixers = { alc262_toshiba_s06_mixer },
11119 .init_verbs = { alc262_init_verbs, alc262_toshiba_s06_verbs,
11120 alc262_eapd_verbs },
11121 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11122 .capsrc_nids = alc262_dmic_capsrc_nids,
11123 .dac_nids = alc262_dac_nids,
11124 .adc_nids = alc262_dmic_adc_nids, /* ADC0 */
11125 .dig_out_nid = ALC262_DIGOUT_NID,
11126 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11127 .channel_mode = alc262_modes,
11128 .input_mux = &alc262_dmic_capture_source,
11129 .unsol_event = alc262_toshiba_s06_unsol_event,
11130 .init_hook = alc262_toshiba_s06_init_hook,
11131 },
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011132 [ALC262_TOSHIBA_RX1] = {
11133 .mixers = { alc262_toshiba_rx1_mixer },
11134 .init_verbs = { alc262_init_verbs, alc262_toshiba_rx1_unsol_verbs },
11135 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11136 .dac_nids = alc262_dac_nids,
11137 .hp_nid = 0x03,
11138 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11139 .channel_mode = alc262_modes,
11140 .input_mux = &alc262_capture_source,
11141 .unsol_event = alc262_hippo_unsol_event,
11142 .init_hook = alc262_hippo_automute,
11143 },
Tony Vroonba340e82009-02-02 19:01:30 +000011144 [ALC262_TYAN] = {
11145 .mixers = { alc262_tyan_mixer },
11146 .init_verbs = { alc262_init_verbs, alc262_tyan_verbs},
11147 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11148 .dac_nids = alc262_dac_nids,
11149 .hp_nid = 0x02,
11150 .dig_out_nid = ALC262_DIGOUT_NID,
11151 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11152 .channel_mode = alc262_modes,
11153 .input_mux = &alc262_capture_source,
11154 .unsol_event = alc262_tyan_unsol_event,
11155 .init_hook = alc262_tyan_automute,
11156 },
Kailang Yangdf694da2005-12-05 19:42:22 +010011157};
11158
11159static int patch_alc262(struct hda_codec *codec)
11160{
11161 struct alc_spec *spec;
11162 int board_config;
11163 int err;
11164
Robert P. J. Daydc041e02006-12-19 14:44:15 +010011165 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010011166 if (spec == NULL)
11167 return -ENOMEM;
11168
11169 codec->spec = spec;
11170#if 0
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011171 /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is
11172 * under-run
11173 */
Kailang Yangdf694da2005-12-05 19:42:22 +010011174 {
11175 int tmp;
11176 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
11177 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
11178 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
11179 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80);
11180 }
11181#endif
11182
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020011183 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
11184
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011185 board_config = snd_hda_check_board_config(codec, ALC262_MODEL_LAST,
11186 alc262_models,
11187 alc262_cfg_tbl);
Kailang Yangcd7509a2007-01-26 18:33:17 +010011188
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011189 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011190 printk(KERN_INFO "hda_codec: Unknown model for ALC262, "
11191 "trying auto-probe from BIOS...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010011192 board_config = ALC262_AUTO;
11193 }
11194
11195 if (board_config == ALC262_AUTO) {
11196 /* automatic parse from the BIOS config */
11197 err = alc262_parse_auto_config(codec);
11198 if (err < 0) {
11199 alc_free(codec);
11200 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011201 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011202 printk(KERN_INFO
11203 "hda_codec: Cannot set up configuration "
11204 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010011205 board_config = ALC262_BASIC;
11206 }
11207 }
11208
Takashi Iwai07eba612009-02-19 08:06:35 +010011209 if (!spec->no_analog) {
11210 err = snd_hda_attach_beep_device(codec, 0x1);
11211 if (err < 0) {
11212 alc_free(codec);
11213 return err;
11214 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090011215 }
11216
Kailang Yangdf694da2005-12-05 19:42:22 +010011217 if (board_config != ALC262_AUTO)
11218 setup_preset(spec, &alc262_presets[board_config]);
11219
11220 spec->stream_name_analog = "ALC262 Analog";
11221 spec->stream_analog_playback = &alc262_pcm_analog_playback;
11222 spec->stream_analog_capture = &alc262_pcm_analog_capture;
Kailang Yangea1fb292008-08-26 12:58:38 +020011223
Kailang Yangdf694da2005-12-05 19:42:22 +010011224 spec->stream_name_digital = "ALC262 Digital";
11225 spec->stream_digital_playback = &alc262_pcm_digital_playback;
11226 spec->stream_digital_capture = &alc262_pcm_digital_capture;
11227
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020011228 spec->capture_style = CAPT_MIX;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011229 if (!spec->adc_nids && spec->input_mux) {
Kailang Yangdf694da2005-12-05 19:42:22 +010011230 /* check whether NID 0x07 is valid */
Takashi Iwai4a471b72005-12-07 13:56:29 +010011231 unsigned int wcap = get_wcaps(codec, 0x07);
11232
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011233 /* get type */
11234 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Kailang Yangdf694da2005-12-05 19:42:22 +010011235 if (wcap != AC_WID_AUD_IN) {
11236 spec->adc_nids = alc262_adc_nids_alt;
11237 spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids_alt);
Takashi Iwai88c71a92008-02-14 17:27:17 +010011238 spec->capsrc_nids = alc262_capsrc_nids_alt;
Kailang Yangdf694da2005-12-05 19:42:22 +010011239 } else {
11240 spec->adc_nids = alc262_adc_nids;
11241 spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids);
Takashi Iwai88c71a92008-02-14 17:27:17 +010011242 spec->capsrc_nids = alc262_capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +010011243 }
11244 }
Takashi Iwaie64f14f2009-01-20 18:32:55 +010011245 if (!spec->cap_mixer && !spec->no_analog)
Takashi Iwaif9e336f2008-10-31 16:37:07 +010011246 set_capture_mixer(spec);
Takashi Iwai07eba612009-02-19 08:06:35 +010011247 if (!spec->no_analog)
11248 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Kailang Yangdf694da2005-12-05 19:42:22 +010011249
Takashi Iwai2134ea42008-01-10 16:53:55 +010011250 spec->vmaster_nid = 0x0c;
11251
Kailang Yangdf694da2005-12-05 19:42:22 +010011252 codec->patch_ops = alc_patch_ops;
11253 if (board_config == ALC262_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +010011254 spec->init_hook = alc262_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020011255#ifdef CONFIG_SND_HDA_POWER_SAVE
11256 if (!spec->loopback.amplist)
11257 spec->loopback.amplist = alc262_loopbacks;
11258#endif
Takashi Iwaidaead532008-11-28 12:55:36 +010011259 codec->proc_widget_hook = print_realtek_coef;
Kailang Yangea1fb292008-08-26 12:58:38 +020011260
Kailang Yangdf694da2005-12-05 19:42:22 +010011261 return 0;
11262}
11263
Kailang Yangdf694da2005-12-05 19:42:22 +010011264/*
Kailang Yanga361d842007-06-05 12:30:55 +020011265 * ALC268 channel source setting (2 channel)
11266 */
11267#define ALC268_DIGOUT_NID ALC880_DIGOUT_NID
11268#define alc268_modes alc260_modes
Kailang Yangea1fb292008-08-26 12:58:38 +020011269
Kailang Yanga361d842007-06-05 12:30:55 +020011270static hda_nid_t alc268_dac_nids[2] = {
11271 /* front, hp */
11272 0x02, 0x03
11273};
11274
11275static hda_nid_t alc268_adc_nids[2] = {
11276 /* ADC0-1 */
11277 0x08, 0x07
11278};
11279
11280static hda_nid_t alc268_adc_nids_alt[1] = {
11281 /* ADC0 */
11282 0x08
11283};
11284
Takashi Iwaie1406342008-02-11 18:32:32 +010011285static hda_nid_t alc268_capsrc_nids[2] = { 0x23, 0x24 };
11286
Kailang Yanga361d842007-06-05 12:30:55 +020011287static struct snd_kcontrol_new alc268_base_mixer[] = {
11288 /* output mixer control */
11289 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
11290 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11291 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
11292 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai33bf17a2007-08-21 11:51:42 +020011293 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11294 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
11295 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
Kailang Yanga361d842007-06-05 12:30:55 +020011296 { }
11297};
11298
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011299/* bind Beep switches of both NID 0x0f and 0x10 */
11300static struct hda_bind_ctls alc268_bind_beep_sw = {
11301 .ops = &snd_hda_bind_sw,
11302 .values = {
11303 HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT),
11304 HDA_COMPOSE_AMP_VAL(0x10, 3, 1, HDA_INPUT),
11305 0
11306 },
11307};
11308
11309static struct snd_kcontrol_new alc268_beep_mixer[] = {
11310 HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT),
11311 HDA_BIND_SW("Beep Playback Switch", &alc268_bind_beep_sw),
11312 { }
11313};
11314
Kailang Yangd1a991a2007-08-15 16:21:59 +020011315static struct hda_verb alc268_eapd_verbs[] = {
11316 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
11317 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
11318 { }
11319};
11320
Takashi Iwaid2738092007-08-16 14:59:45 +020011321/* Toshiba specific */
11322#define alc268_toshiba_automute alc262_hippo_automute
11323
11324static struct hda_verb alc268_toshiba_verbs[] = {
11325 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
11326 { } /* end */
11327};
11328
Kailang Yang8ef355d2008-08-26 13:10:22 +020011329static struct hda_input_mux alc268_acer_lc_capture_source = {
11330 .num_items = 2,
11331 .items = {
11332 { "i-Mic", 0x6 },
11333 { "E-Mic", 0x0 },
11334 },
11335};
11336
Takashi Iwaid2738092007-08-16 14:59:45 +020011337/* Acer specific */
Takashi Iwai889c4392007-08-23 18:56:52 +020011338/* bind volumes of both NID 0x02 and 0x03 */
Takashi Iwai6bc96852007-08-17 09:02:12 +020011339static struct hda_bind_ctls alc268_acer_bind_master_vol = {
11340 .ops = &snd_hda_bind_vol,
11341 .values = {
11342 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
11343 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
11344 0
11345 },
11346};
11347
Takashi Iwai889c4392007-08-23 18:56:52 +020011348/* mute/unmute internal speaker according to the hp jack and mute state */
11349static void alc268_acer_automute(struct hda_codec *codec, int force)
11350{
11351 struct alc_spec *spec = codec->spec;
11352 unsigned int mute;
11353
11354 if (force || !spec->sense_updated) {
11355 unsigned int present;
11356 present = snd_hda_codec_read(codec, 0x14, 0,
11357 AC_VERB_GET_PIN_SENSE, 0);
11358 spec->jack_present = (present & 0x80000000) != 0;
11359 spec->sense_updated = 1;
11360 }
11361 if (spec->jack_present)
11362 mute = HDA_AMP_MUTE; /* mute internal speaker */
11363 else /* unmute internal speaker if necessary */
11364 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
11365 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
11366 HDA_AMP_MUTE, mute);
11367}
11368
11369
11370/* bind hp and internal speaker mute (with plug check) */
11371static int alc268_acer_master_sw_put(struct snd_kcontrol *kcontrol,
11372 struct snd_ctl_elem_value *ucontrol)
11373{
11374 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
11375 long *valp = ucontrol->value.integer.value;
11376 int change;
11377
11378 change = snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0,
11379 HDA_AMP_MUTE,
11380 valp[0] ? 0 : HDA_AMP_MUTE);
11381 change |= snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0,
11382 HDA_AMP_MUTE,
11383 valp[1] ? 0 : HDA_AMP_MUTE);
11384 if (change)
11385 alc268_acer_automute(codec, 0);
11386 return change;
11387}
Takashi Iwaid2738092007-08-16 14:59:45 +020011388
Kailang Yang8ef355d2008-08-26 13:10:22 +020011389static struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = {
11390 /* output mixer control */
11391 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
11392 {
11393 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11394 .name = "Master Playback Switch",
11395 .info = snd_hda_mixer_amp_switch_info,
11396 .get = snd_hda_mixer_amp_switch_get,
11397 .put = alc268_acer_master_sw_put,
11398 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
11399 },
11400 HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x18, 0, HDA_INPUT),
11401 { }
11402};
11403
Takashi Iwaid2738092007-08-16 14:59:45 +020011404static struct snd_kcontrol_new alc268_acer_mixer[] = {
11405 /* output mixer control */
11406 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
11407 {
11408 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11409 .name = "Master Playback Switch",
11410 .info = snd_hda_mixer_amp_switch_info,
11411 .get = snd_hda_mixer_amp_switch_get,
11412 .put = alc268_acer_master_sw_put,
11413 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
11414 },
Takashi Iwai33bf17a2007-08-21 11:51:42 +020011415 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11416 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
11417 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
Takashi Iwaid2738092007-08-16 14:59:45 +020011418 { }
11419};
11420
Takashi Iwaic238b4f2008-11-05 14:57:20 +010011421static struct snd_kcontrol_new alc268_acer_dmic_mixer[] = {
11422 /* output mixer control */
11423 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
11424 {
11425 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11426 .name = "Master Playback Switch",
11427 .info = snd_hda_mixer_amp_switch_info,
11428 .get = snd_hda_mixer_amp_switch_get,
11429 .put = alc268_acer_master_sw_put,
11430 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
11431 },
11432 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11433 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
11434 { }
11435};
11436
Kailang Yang8ef355d2008-08-26 13:10:22 +020011437static struct hda_verb alc268_acer_aspire_one_verbs[] = {
11438 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11439 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11440 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
11441 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
11442 {0x23, AC_VERB_SET_CONNECT_SEL, 0x06},
11443 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, 0xa017},
11444 { }
11445};
11446
Takashi Iwaid2738092007-08-16 14:59:45 +020011447static struct hda_verb alc268_acer_verbs[] = {
Takashi Iwai0ccb5412008-03-06 16:58:35 +010011448 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* internal dmic? */
11449 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaid2738092007-08-16 14:59:45 +020011450 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11451 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai0ccb5412008-03-06 16:58:35 +010011452 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
11453 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaid2738092007-08-16 14:59:45 +020011454 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
11455 { }
11456};
11457
11458/* unsolicited event for HP jack sensing */
11459static void alc268_toshiba_unsol_event(struct hda_codec *codec,
11460 unsigned int res)
11461{
Takashi Iwai889c4392007-08-23 18:56:52 +020011462 if ((res >> 26) != ALC880_HP_EVENT)
Takashi Iwaid2738092007-08-16 14:59:45 +020011463 return;
11464 alc268_toshiba_automute(codec);
11465}
11466
11467static void alc268_acer_unsol_event(struct hda_codec *codec,
11468 unsigned int res)
11469{
Takashi Iwai889c4392007-08-23 18:56:52 +020011470 if ((res >> 26) != ALC880_HP_EVENT)
Takashi Iwaid2738092007-08-16 14:59:45 +020011471 return;
11472 alc268_acer_automute(codec, 1);
11473}
11474
Takashi Iwai889c4392007-08-23 18:56:52 +020011475static void alc268_acer_init_hook(struct hda_codec *codec)
11476{
11477 alc268_acer_automute(codec, 1);
11478}
11479
Kailang Yang8ef355d2008-08-26 13:10:22 +020011480/* toggle speaker-output according to the hp-jack state */
11481static void alc268_aspire_one_speaker_automute(struct hda_codec *codec)
11482{
11483 unsigned int present;
11484 unsigned char bits;
11485
11486 present = snd_hda_codec_read(codec, 0x15, 0,
11487 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
11488 bits = present ? AMP_IN_MUTE(0) : 0;
11489 snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 0,
11490 AMP_IN_MUTE(0), bits);
11491 snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 1,
11492 AMP_IN_MUTE(0), bits);
11493}
11494
11495
11496static void alc268_acer_mic_automute(struct hda_codec *codec)
11497{
11498 unsigned int present;
11499
11500 present = snd_hda_codec_read(codec, 0x18, 0,
11501 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
11502 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_CONNECT_SEL,
11503 present ? 0x0 : 0x6);
11504}
11505
11506static void alc268_acer_lc_unsol_event(struct hda_codec *codec,
11507 unsigned int res)
11508{
11509 if ((res >> 26) == ALC880_HP_EVENT)
11510 alc268_aspire_one_speaker_automute(codec);
11511 if ((res >> 26) == ALC880_MIC_EVENT)
11512 alc268_acer_mic_automute(codec);
11513}
11514
11515static void alc268_acer_lc_init_hook(struct hda_codec *codec)
11516{
11517 alc268_aspire_one_speaker_automute(codec);
11518 alc268_acer_mic_automute(codec);
11519}
11520
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011521static struct snd_kcontrol_new alc268_dell_mixer[] = {
11522 /* output mixer control */
11523 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
11524 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11525 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
11526 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11527 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11528 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
11529 { }
11530};
11531
11532static struct hda_verb alc268_dell_verbs[] = {
11533 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11534 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11535 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
11536 { }
11537};
11538
11539/* mute/unmute internal speaker according to the hp jack and mute state */
11540static void alc268_dell_automute(struct hda_codec *codec)
11541{
11542 unsigned int present;
11543 unsigned int mute;
11544
11545 present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0);
11546 if (present & 0x80000000)
11547 mute = HDA_AMP_MUTE;
11548 else
11549 mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0);
11550 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
11551 HDA_AMP_MUTE, mute);
11552}
11553
11554static void alc268_dell_unsol_event(struct hda_codec *codec,
11555 unsigned int res)
11556{
11557 if ((res >> 26) != ALC880_HP_EVENT)
11558 return;
11559 alc268_dell_automute(codec);
11560}
11561
11562#define alc268_dell_init_hook alc268_dell_automute
11563
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020011564static struct snd_kcontrol_new alc267_quanta_il1_mixer[] = {
11565 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x2, 0x0, HDA_OUTPUT),
11566 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11567 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
11568 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11569 HDA_CODEC_VOLUME("Mic Capture Volume", 0x23, 0x0, HDA_OUTPUT),
11570 HDA_BIND_MUTE("Mic Capture Switch", 0x23, 2, HDA_OUTPUT),
11571 HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
11572 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
11573 { }
11574};
11575
11576static struct hda_verb alc267_quanta_il1_verbs[] = {
11577 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
11578 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
11579 { }
11580};
11581
11582static void alc267_quanta_il1_hp_automute(struct hda_codec *codec)
11583{
11584 unsigned int present;
11585
11586 present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0)
11587 & AC_PINSENSE_PRESENCE;
11588 snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
11589 present ? 0 : PIN_OUT);
11590}
11591
11592static void alc267_quanta_il1_mic_automute(struct hda_codec *codec)
11593{
11594 unsigned int present;
11595
11596 present = snd_hda_codec_read(codec, 0x18, 0,
11597 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
11598 snd_hda_codec_write(codec, 0x23, 0,
11599 AC_VERB_SET_CONNECT_SEL,
11600 present ? 0x00 : 0x01);
11601}
11602
11603static void alc267_quanta_il1_automute(struct hda_codec *codec)
11604{
11605 alc267_quanta_il1_hp_automute(codec);
11606 alc267_quanta_il1_mic_automute(codec);
11607}
11608
11609static void alc267_quanta_il1_unsol_event(struct hda_codec *codec,
11610 unsigned int res)
11611{
11612 switch (res >> 26) {
11613 case ALC880_HP_EVENT:
11614 alc267_quanta_il1_hp_automute(codec);
11615 break;
11616 case ALC880_MIC_EVENT:
11617 alc267_quanta_il1_mic_automute(codec);
11618 break;
11619 }
11620}
11621
Kailang Yanga361d842007-06-05 12:30:55 +020011622/*
11623 * generic initialization of ADC, input mixers and output mixers
11624 */
11625static struct hda_verb alc268_base_init_verbs[] = {
11626 /* Unmute DAC0-1 and set vol = 0 */
11627 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020011628 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020011629
11630 /*
11631 * Set up output mixers (0x0c - 0x0e)
11632 */
11633 /* set vol=0 to output mixers */
11634 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yanga361d842007-06-05 12:30:55 +020011635 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
11636
11637 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11638 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11639
11640 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
11641 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
11642 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
11643 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11644 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11645 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11646 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11647 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11648
11649 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11650 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11651 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11652 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020011653 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011654
11655 /* set PCBEEP vol = 0, mute connections */
11656 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11657 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11658 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020011659
Jiang Zhea9b3aa82007-12-20 13:13:13 +010011660 /* Unmute Selector 23h,24h and set the default input to mic-in */
Kailang Yangea1fb292008-08-26 12:58:38 +020011661
Jiang Zhea9b3aa82007-12-20 13:13:13 +010011662 {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
11663 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11664 {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
11665 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020011666
Kailang Yanga361d842007-06-05 12:30:55 +020011667 { }
11668};
11669
11670/*
11671 * generic initialization of ADC, input mixers and output mixers
11672 */
11673static struct hda_verb alc268_volume_init_verbs[] = {
11674 /* set output DAC */
Takashi Iwai4cfb91c2009-01-23 12:53:09 +010011675 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11676 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020011677
11678 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11679 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11680 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11681 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11682 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11683
Kailang Yanga361d842007-06-05 12:30:55 +020011684 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yanga361d842007-06-05 12:30:55 +020011685 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11686 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11687
11688 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020011689 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020011690
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011691 /* set PCBEEP vol = 0, mute connections */
11692 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11693 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11694 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020011695
11696 { }
11697};
11698
Kailang Yanga361d842007-06-05 12:30:55 +020011699static struct snd_kcontrol_new alc268_capture_alt_mixer[] = {
11700 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
11701 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
11702 {
11703 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11704 /* The multiple "Capture Source" controls confuse alsamixer
11705 * So call somewhat different..
Kailang Yanga361d842007-06-05 12:30:55 +020011706 */
11707 /* .name = "Capture Source", */
11708 .name = "Input Source",
11709 .count = 1,
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010011710 .info = alc_mux_enum_info,
11711 .get = alc_mux_enum_get,
11712 .put = alc_mux_enum_put,
Kailang Yanga361d842007-06-05 12:30:55 +020011713 },
11714 { } /* end */
11715};
11716
11717static struct snd_kcontrol_new alc268_capture_mixer[] = {
11718 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
11719 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
11720 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x24, 0x0, HDA_OUTPUT),
11721 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x24, 0x0, HDA_OUTPUT),
11722 {
11723 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11724 /* The multiple "Capture Source" controls confuse alsamixer
11725 * So call somewhat different..
Kailang Yanga361d842007-06-05 12:30:55 +020011726 */
11727 /* .name = "Capture Source", */
11728 .name = "Input Source",
11729 .count = 2,
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010011730 .info = alc_mux_enum_info,
11731 .get = alc_mux_enum_get,
11732 .put = alc_mux_enum_put,
Kailang Yanga361d842007-06-05 12:30:55 +020011733 },
11734 { } /* end */
11735};
11736
11737static struct hda_input_mux alc268_capture_source = {
11738 .num_items = 4,
11739 .items = {
11740 { "Mic", 0x0 },
11741 { "Front Mic", 0x1 },
11742 { "Line", 0x2 },
11743 { "CD", 0x3 },
11744 },
11745};
11746
Takashi Iwai0ccb5412008-03-06 16:58:35 +010011747static struct hda_input_mux alc268_acer_capture_source = {
11748 .num_items = 3,
11749 .items = {
11750 { "Mic", 0x0 },
Takashi Iwaic238b4f2008-11-05 14:57:20 +010011751 { "Internal Mic", 0x1 },
11752 { "Line", 0x2 },
11753 },
11754};
11755
11756static struct hda_input_mux alc268_acer_dmic_capture_source = {
11757 .num_items = 3,
11758 .items = {
11759 { "Mic", 0x0 },
Takashi Iwai0ccb5412008-03-06 16:58:35 +010011760 { "Internal Mic", 0x6 },
11761 { "Line", 0x2 },
11762 },
11763};
11764
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010011765#ifdef CONFIG_SND_DEBUG
11766static struct snd_kcontrol_new alc268_test_mixer[] = {
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010011767 /* Volume widgets */
11768 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x02, 0x0, HDA_OUTPUT),
11769 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x03, 0x0, HDA_OUTPUT),
11770 HDA_BIND_MUTE_MONO("Mono sum Playback Switch", 0x0e, 1, 2, HDA_INPUT),
11771 HDA_BIND_MUTE("LINE-OUT sum Playback Switch", 0x0f, 2, HDA_INPUT),
11772 HDA_BIND_MUTE("HP-OUT sum Playback Switch", 0x10, 2, HDA_INPUT),
11773 HDA_BIND_MUTE("LINE-OUT Playback Switch", 0x14, 2, HDA_OUTPUT),
11774 HDA_BIND_MUTE("HP-OUT Playback Switch", 0x15, 2, HDA_OUTPUT),
11775 HDA_BIND_MUTE("Mono Playback Switch", 0x16, 2, HDA_OUTPUT),
11776 HDA_CODEC_VOLUME("MIC1 Capture Volume", 0x18, 0x0, HDA_INPUT),
11777 HDA_BIND_MUTE("MIC1 Capture Switch", 0x18, 2, HDA_OUTPUT),
11778 HDA_CODEC_VOLUME("MIC2 Capture Volume", 0x19, 0x0, HDA_INPUT),
11779 HDA_CODEC_VOLUME("LINE1 Capture Volume", 0x1a, 0x0, HDA_INPUT),
11780 HDA_BIND_MUTE("LINE1 Capture Switch", 0x1a, 2, HDA_OUTPUT),
Takashi Iwaif0747ee2008-01-15 11:41:41 +010011781 /* The below appears problematic on some hardwares */
11782 /*HDA_CODEC_VOLUME("PCBEEP Playback Volume", 0x1d, 0x0, HDA_INPUT),*/
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010011783 HDA_CODEC_VOLUME("PCM-IN1 Capture Volume", 0x23, 0x0, HDA_OUTPUT),
11784 HDA_BIND_MUTE("PCM-IN1 Capture Switch", 0x23, 2, HDA_OUTPUT),
11785 HDA_CODEC_VOLUME("PCM-IN2 Capture Volume", 0x24, 0x0, HDA_OUTPUT),
11786 HDA_BIND_MUTE("PCM-IN2 Capture Switch", 0x24, 2, HDA_OUTPUT),
11787
11788 /* Modes for retasking pin widgets */
11789 ALC_PIN_MODE("LINE-OUT pin mode", 0x14, ALC_PIN_DIR_INOUT),
11790 ALC_PIN_MODE("HP-OUT pin mode", 0x15, ALC_PIN_DIR_INOUT),
11791 ALC_PIN_MODE("MIC1 pin mode", 0x18, ALC_PIN_DIR_INOUT),
11792 ALC_PIN_MODE("LINE1 pin mode", 0x1a, ALC_PIN_DIR_INOUT),
11793
11794 /* Controls for GPIO pins, assuming they are configured as outputs */
11795 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
11796 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
11797 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
11798 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
11799
11800 /* Switches to allow the digital SPDIF output pin to be enabled.
11801 * The ALC268 does not have an SPDIF input.
11802 */
11803 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x06, 0x01),
11804
11805 /* A switch allowing EAPD to be enabled. Some laptops seem to use
11806 * this output to turn on an external amplifier.
11807 */
11808 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
11809 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
11810
11811 { } /* end */
11812};
11813#endif
11814
Kailang Yanga361d842007-06-05 12:30:55 +020011815/* create input playback/capture controls for the given pin */
11816static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
11817 const char *ctlname, int idx)
11818{
11819 char name[32];
11820 int err;
11821
11822 sprintf(name, "%s Playback Volume", ctlname);
11823 if (nid == 0x14) {
11824 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
11825 HDA_COMPOSE_AMP_VAL(0x02, 3, idx,
11826 HDA_OUTPUT));
11827 if (err < 0)
11828 return err;
11829 } else if (nid == 0x15) {
11830 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
11831 HDA_COMPOSE_AMP_VAL(0x03, 3, idx,
11832 HDA_OUTPUT));
11833 if (err < 0)
11834 return err;
11835 } else
11836 return -1;
11837 sprintf(name, "%s Playback Switch", ctlname);
11838 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
11839 HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
11840 if (err < 0)
11841 return err;
11842 return 0;
11843}
11844
11845/* add playback controls from the parsed DAC table */
11846static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
11847 const struct auto_pin_cfg *cfg)
11848{
11849 hda_nid_t nid;
11850 int err;
11851
11852 spec->multiout.num_dacs = 2; /* only use one dac */
11853 spec->multiout.dac_nids = spec->private_dac_nids;
11854 spec->multiout.dac_nids[0] = 2;
11855 spec->multiout.dac_nids[1] = 3;
11856
11857 nid = cfg->line_out_pins[0];
11858 if (nid)
Kailang Yangea1fb292008-08-26 12:58:38 +020011859 alc268_new_analog_output(spec, nid, "Front", 0);
Kailang Yanga361d842007-06-05 12:30:55 +020011860
11861 nid = cfg->speaker_pins[0];
11862 if (nid == 0x1d) {
11863 err = add_control(spec, ALC_CTL_WIDGET_VOL,
11864 "Speaker Playback Volume",
11865 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
11866 if (err < 0)
11867 return err;
11868 }
11869 nid = cfg->hp_pins[0];
11870 if (nid)
11871 alc268_new_analog_output(spec, nid, "Headphone", 0);
11872
11873 nid = cfg->line_out_pins[1] | cfg->line_out_pins[2];
11874 if (nid == 0x16) {
11875 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
11876 "Mono Playback Switch",
11877 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_INPUT));
11878 if (err < 0)
11879 return err;
11880 }
Kailang Yangea1fb292008-08-26 12:58:38 +020011881 return 0;
Kailang Yanga361d842007-06-05 12:30:55 +020011882}
11883
11884/* create playback/capture controls for input pins */
11885static int alc268_auto_create_analog_input_ctls(struct alc_spec *spec,
11886 const struct auto_pin_cfg *cfg)
11887{
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020011888 struct hda_input_mux *imux = &spec->private_imux[0];
Kailang Yanga361d842007-06-05 12:30:55 +020011889 int i, idx1;
11890
11891 for (i = 0; i < AUTO_PIN_LAST; i++) {
11892 switch(cfg->input_pins[i]) {
11893 case 0x18:
11894 idx1 = 0; /* Mic 1 */
11895 break;
11896 case 0x19:
11897 idx1 = 1; /* Mic 2 */
11898 break;
11899 case 0x1a:
11900 idx1 = 2; /* Line In */
11901 break;
Kailang Yangea1fb292008-08-26 12:58:38 +020011902 case 0x1c:
Kailang Yanga361d842007-06-05 12:30:55 +020011903 idx1 = 3; /* CD */
11904 break;
Takashi Iwai7194cae2008-03-06 16:58:17 +010011905 case 0x12:
11906 case 0x13:
11907 idx1 = 6; /* digital mics */
11908 break;
Kailang Yanga361d842007-06-05 12:30:55 +020011909 default:
11910 continue;
11911 }
11912 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
11913 imux->items[imux->num_items].index = idx1;
Kailang Yangea1fb292008-08-26 12:58:38 +020011914 imux->num_items++;
Kailang Yanga361d842007-06-05 12:30:55 +020011915 }
11916 return 0;
11917}
11918
11919static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec)
11920{
11921 struct alc_spec *spec = codec->spec;
11922 hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
11923 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
11924 hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
11925 unsigned int dac_vol1, dac_vol2;
11926
11927 if (speaker_nid) {
11928 snd_hda_codec_write(codec, speaker_nid, 0,
11929 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
11930 snd_hda_codec_write(codec, 0x0f, 0,
11931 AC_VERB_SET_AMP_GAIN_MUTE,
11932 AMP_IN_UNMUTE(1));
11933 snd_hda_codec_write(codec, 0x10, 0,
11934 AC_VERB_SET_AMP_GAIN_MUTE,
11935 AMP_IN_UNMUTE(1));
11936 } else {
11937 snd_hda_codec_write(codec, 0x0f, 0,
11938 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
11939 snd_hda_codec_write(codec, 0x10, 0,
11940 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
11941 }
11942
11943 dac_vol1 = dac_vol2 = 0xb000 | 0x40; /* set max volume */
Kailang Yangea1fb292008-08-26 12:58:38 +020011944 if (line_nid == 0x14)
Kailang Yanga361d842007-06-05 12:30:55 +020011945 dac_vol2 = AMP_OUT_ZERO;
11946 else if (line_nid == 0x15)
11947 dac_vol1 = AMP_OUT_ZERO;
Kailang Yangea1fb292008-08-26 12:58:38 +020011948 if (hp_nid == 0x14)
Kailang Yanga361d842007-06-05 12:30:55 +020011949 dac_vol2 = AMP_OUT_ZERO;
11950 else if (hp_nid == 0x15)
11951 dac_vol1 = AMP_OUT_ZERO;
11952 if (line_nid != 0x16 || hp_nid != 0x16 ||
11953 spec->autocfg.line_out_pins[1] != 0x16 ||
11954 spec->autocfg.line_out_pins[2] != 0x16)
11955 dac_vol1 = dac_vol2 = AMP_OUT_ZERO;
11956
11957 snd_hda_codec_write(codec, 0x02, 0,
11958 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol1);
11959 snd_hda_codec_write(codec, 0x03, 0,
11960 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol2);
11961}
11962
11963/* pcm configuration: identiacal with ALC880 */
11964#define alc268_pcm_analog_playback alc880_pcm_analog_playback
11965#define alc268_pcm_analog_capture alc880_pcm_analog_capture
Takashi Iwai63300792008-01-24 15:31:36 +010011966#define alc268_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
Kailang Yanga361d842007-06-05 12:30:55 +020011967#define alc268_pcm_digital_playback alc880_pcm_digital_playback
11968
11969/*
11970 * BIOS auto configuration
11971 */
11972static int alc268_parse_auto_config(struct hda_codec *codec)
11973{
11974 struct alc_spec *spec = codec->spec;
11975 int err;
11976 static hda_nid_t alc268_ignore[] = { 0 };
11977
11978 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
11979 alc268_ignore);
11980 if (err < 0)
11981 return err;
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010011982 if (!spec->autocfg.line_outs) {
11983 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
11984 spec->multiout.max_channels = 2;
11985 spec->no_analog = 1;
11986 goto dig_only;
11987 }
Kailang Yanga361d842007-06-05 12:30:55 +020011988 return 0; /* can't find valid BIOS pin config */
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010011989 }
Kailang Yanga361d842007-06-05 12:30:55 +020011990 err = alc268_auto_create_multi_out_ctls(spec, &spec->autocfg);
11991 if (err < 0)
11992 return err;
11993 err = alc268_auto_create_analog_input_ctls(spec, &spec->autocfg);
11994 if (err < 0)
11995 return err;
11996
11997 spec->multiout.max_channels = 2;
11998
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010011999 dig_only:
Kailang Yanga361d842007-06-05 12:30:55 +020012000 /* digital only support output */
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010012001 if (spec->autocfg.dig_outs) {
Kailang Yanga361d842007-06-05 12:30:55 +020012002 spec->multiout.dig_out_nid = ALC268_DIGOUT_NID;
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010012003 spec->dig_out_type = spec->autocfg.dig_out_type[0];
12004 }
Takashi Iwai603c4012008-07-30 15:01:44 +020012005 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010012006 add_mixer(spec, spec->kctls.list);
Kailang Yanga361d842007-06-05 12:30:55 +020012007
Takashi Iwai892981f2009-03-02 08:04:35 +010012008 if (!spec->no_analog && spec->autocfg.speaker_pins[0] != 0x1d)
Takashi Iwaid88897e2008-10-31 15:01:37 +010012009 add_mixer(spec, alc268_beep_mixer);
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012010
Takashi Iwaid88897e2008-10-31 15:01:37 +010012011 add_verb(spec, alc268_volume_init_verbs);
Kailang Yanga361d842007-06-05 12:30:55 +020012012 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020012013 spec->input_mux = &spec->private_imux[0];
Kailang Yanga361d842007-06-05 12:30:55 +020012014
Takashi Iwai776e1842007-08-29 15:07:11 +020012015 err = alc_auto_add_mic_boost(codec);
12016 if (err < 0)
12017 return err;
12018
Kailang Yanga361d842007-06-05 12:30:55 +020012019 return 1;
12020}
12021
12022#define alc268_auto_init_multi_out alc882_auto_init_multi_out
12023#define alc268_auto_init_hp_out alc882_auto_init_hp_out
12024#define alc268_auto_init_analog_input alc882_auto_init_analog_input
12025
12026/* init callback for auto-configuration model -- overriding the default init */
12027static void alc268_auto_init(struct hda_codec *codec)
12028{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012029 struct alc_spec *spec = codec->spec;
Kailang Yanga361d842007-06-05 12:30:55 +020012030 alc268_auto_init_multi_out(codec);
12031 alc268_auto_init_hp_out(codec);
12032 alc268_auto_init_mono_speaker_out(codec);
12033 alc268_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012034 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020012035 alc_inithook(codec);
Kailang Yanga361d842007-06-05 12:30:55 +020012036}
12037
12038/*
12039 * configuration and preset
12040 */
12041static const char *alc268_models[ALC268_MODEL_LAST] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012042 [ALC267_QUANTA_IL1] = "quanta-il1",
Kailang Yanga361d842007-06-05 12:30:55 +020012043 [ALC268_3ST] = "3stack",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020012044 [ALC268_TOSHIBA] = "toshiba",
Takashi Iwaid2738092007-08-16 14:59:45 +020012045 [ALC268_ACER] = "acer",
Takashi Iwaic238b4f2008-11-05 14:57:20 +010012046 [ALC268_ACER_DMIC] = "acer-dmic",
Kailang Yang8ef355d2008-08-26 13:10:22 +020012047 [ALC268_ACER_ASPIRE_ONE] = "acer-aspire",
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012048 [ALC268_DELL] = "dell",
Mirco Tischlerf12462c2008-02-04 12:33:59 +010012049 [ALC268_ZEPTO] = "zepto",
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010012050#ifdef CONFIG_SND_DEBUG
12051 [ALC268_TEST] = "test",
12052#endif
Kailang Yanga361d842007-06-05 12:30:55 +020012053 [ALC268_AUTO] = "auto",
12054};
12055
12056static struct snd_pci_quirk alc268_cfg_tbl[] = {
Takashi Iwaia0b8f7d2008-04-22 19:39:49 +020012057 SND_PCI_QUIRK(0x1025, 0x011e, "Acer Aspire 5720z", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012058 SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER),
Andy Shevchenkodafc8352008-01-25 11:53:50 +010012059 SND_PCI_QUIRK(0x1025, 0x012e, "Acer Aspire 5310", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012060 SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER),
Andy Shevchenko29a52c22008-01-24 17:29:00 +010012061 SND_PCI_QUIRK(0x1025, 0x0136, "Acer Aspire 5315", ALC268_ACER),
Kailang Yang8ef355d2008-08-26 13:10:22 +020012062 SND_PCI_QUIRK(0x1025, 0x015b, "Acer Aspire One",
12063 ALC268_ACER_ASPIRE_ONE),
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012064 SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL),
Takashi Iwai57d13922009-01-08 15:52:09 +010012065 SND_PCI_QUIRK(0x1028, 0x02b0, "Dell Inspiron Mini9", ALC268_DELL),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012066 SND_PCI_QUIRK(0x103c, 0x30cc, "TOSHIBA", ALC268_TOSHIBA),
Adam Williamson87488952009-05-21 18:32:59 -040012067 SND_PCI_QUIRK(0x103c, 0x30f1, "HP TX25xx series", ALC268_TOSHIBA),
Kailang Yanga361d842007-06-05 12:30:55 +020012068 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST),
Kailang Yangd1a991a2007-08-15 16:21:59 +020012069 SND_PCI_QUIRK(0x1179, 0xff10, "TOSHIBA A205", ALC268_TOSHIBA),
Takashi Iwai8e7f00f2007-09-07 10:58:58 +020012070 SND_PCI_QUIRK(0x1179, 0xff50, "TOSHIBA A305", ALC268_TOSHIBA),
Travis Place2346d0c2008-09-01 08:24:00 +020012071 SND_PCI_QUIRK(0x1179, 0xff64, "TOSHIBA L305", ALC268_TOSHIBA),
Tony Vroon378bd6a2008-06-04 12:08:30 +020012072 SND_PCI_QUIRK(0x14c0, 0x0025, "COMPAL IFL90/JFL-92", ALC268_TOSHIBA),
Takashi Iwaib875bf32007-09-06 15:00:27 +020012073 SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER),
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012074 SND_PCI_QUIRK(0x152d, 0x0771, "Quanta IL1", ALC267_QUANTA_IL1),
Mirco Tischlerf12462c2008-02-04 12:33:59 +010012075 SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO),
Kailang Yanga361d842007-06-05 12:30:55 +020012076 {}
12077};
12078
12079static struct alc_config_preset alc268_presets[] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012080 [ALC267_QUANTA_IL1] = {
Takashi Iwai22971e32009-02-10 11:56:44 +010012081 .mixers = { alc267_quanta_il1_mixer, alc268_beep_mixer },
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012082 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
12083 alc267_quanta_il1_verbs },
12084 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
12085 .dac_nids = alc268_dac_nids,
12086 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
12087 .adc_nids = alc268_adc_nids_alt,
12088 .hp_nid = 0x03,
12089 .num_channel_mode = ARRAY_SIZE(alc268_modes),
12090 .channel_mode = alc268_modes,
12091 .input_mux = &alc268_capture_source,
12092 .unsol_event = alc267_quanta_il1_unsol_event,
12093 .init_hook = alc267_quanta_il1_automute,
12094 },
Kailang Yanga361d842007-06-05 12:30:55 +020012095 [ALC268_3ST] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012096 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
12097 alc268_beep_mixer },
Kailang Yanga361d842007-06-05 12:30:55 +020012098 .init_verbs = { alc268_base_init_verbs },
12099 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
12100 .dac_nids = alc268_dac_nids,
12101 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
12102 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010012103 .capsrc_nids = alc268_capsrc_nids,
Kailang Yanga361d842007-06-05 12:30:55 +020012104 .hp_nid = 0x03,
12105 .dig_out_nid = ALC268_DIGOUT_NID,
12106 .num_channel_mode = ARRAY_SIZE(alc268_modes),
12107 .channel_mode = alc268_modes,
12108 .input_mux = &alc268_capture_source,
12109 },
Kailang Yangd1a991a2007-08-15 16:21:59 +020012110 [ALC268_TOSHIBA] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012111 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
12112 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020012113 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
12114 alc268_toshiba_verbs },
Kailang Yangd1a991a2007-08-15 16:21:59 +020012115 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
12116 .dac_nids = alc268_dac_nids,
12117 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
12118 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010012119 .capsrc_nids = alc268_capsrc_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020012120 .hp_nid = 0x03,
12121 .num_channel_mode = ARRAY_SIZE(alc268_modes),
12122 .channel_mode = alc268_modes,
12123 .input_mux = &alc268_capture_source,
Takashi Iwaid2738092007-08-16 14:59:45 +020012124 .unsol_event = alc268_toshiba_unsol_event,
12125 .init_hook = alc268_toshiba_automute,
12126 },
12127 [ALC268_ACER] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012128 .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer,
12129 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020012130 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
12131 alc268_acer_verbs },
12132 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
12133 .dac_nids = alc268_dac_nids,
12134 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
12135 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010012136 .capsrc_nids = alc268_capsrc_nids,
Takashi Iwaid2738092007-08-16 14:59:45 +020012137 .hp_nid = 0x02,
12138 .num_channel_mode = ARRAY_SIZE(alc268_modes),
12139 .channel_mode = alc268_modes,
Takashi Iwai0ccb5412008-03-06 16:58:35 +010012140 .input_mux = &alc268_acer_capture_source,
Takashi Iwaid2738092007-08-16 14:59:45 +020012141 .unsol_event = alc268_acer_unsol_event,
Takashi Iwai889c4392007-08-23 18:56:52 +020012142 .init_hook = alc268_acer_init_hook,
Kailang Yangd1a991a2007-08-15 16:21:59 +020012143 },
Takashi Iwaic238b4f2008-11-05 14:57:20 +010012144 [ALC268_ACER_DMIC] = {
12145 .mixers = { alc268_acer_dmic_mixer, alc268_capture_alt_mixer,
12146 alc268_beep_mixer },
12147 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
12148 alc268_acer_verbs },
12149 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
12150 .dac_nids = alc268_dac_nids,
12151 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
12152 .adc_nids = alc268_adc_nids_alt,
12153 .capsrc_nids = alc268_capsrc_nids,
12154 .hp_nid = 0x02,
12155 .num_channel_mode = ARRAY_SIZE(alc268_modes),
12156 .channel_mode = alc268_modes,
12157 .input_mux = &alc268_acer_dmic_capture_source,
12158 .unsol_event = alc268_acer_unsol_event,
12159 .init_hook = alc268_acer_init_hook,
12160 },
Kailang Yang8ef355d2008-08-26 13:10:22 +020012161 [ALC268_ACER_ASPIRE_ONE] = {
12162 .mixers = { alc268_acer_aspire_one_mixer,
Takashi Iwai22971e32009-02-10 11:56:44 +010012163 alc268_beep_mixer,
12164 alc268_capture_alt_mixer },
Kailang Yang8ef355d2008-08-26 13:10:22 +020012165 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
12166 alc268_acer_aspire_one_verbs },
12167 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
12168 .dac_nids = alc268_dac_nids,
12169 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
12170 .adc_nids = alc268_adc_nids_alt,
12171 .capsrc_nids = alc268_capsrc_nids,
12172 .hp_nid = 0x03,
12173 .num_channel_mode = ARRAY_SIZE(alc268_modes),
12174 .channel_mode = alc268_modes,
12175 .input_mux = &alc268_acer_lc_capture_source,
12176 .unsol_event = alc268_acer_lc_unsol_event,
12177 .init_hook = alc268_acer_lc_init_hook,
12178 },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012179 [ALC268_DELL] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012180 .mixers = { alc268_dell_mixer, alc268_beep_mixer },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012181 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
12182 alc268_dell_verbs },
12183 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
12184 .dac_nids = alc268_dac_nids,
12185 .hp_nid = 0x02,
12186 .num_channel_mode = ARRAY_SIZE(alc268_modes),
12187 .channel_mode = alc268_modes,
12188 .unsol_event = alc268_dell_unsol_event,
12189 .init_hook = alc268_dell_init_hook,
12190 .input_mux = &alc268_capture_source,
12191 },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010012192 [ALC268_ZEPTO] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012193 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
12194 alc268_beep_mixer },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010012195 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
12196 alc268_toshiba_verbs },
12197 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
12198 .dac_nids = alc268_dac_nids,
12199 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
12200 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010012201 .capsrc_nids = alc268_capsrc_nids,
Mirco Tischlerf12462c2008-02-04 12:33:59 +010012202 .hp_nid = 0x03,
12203 .dig_out_nid = ALC268_DIGOUT_NID,
12204 .num_channel_mode = ARRAY_SIZE(alc268_modes),
12205 .channel_mode = alc268_modes,
12206 .input_mux = &alc268_capture_source,
12207 .unsol_event = alc268_toshiba_unsol_event,
12208 .init_hook = alc268_toshiba_automute
12209 },
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010012210#ifdef CONFIG_SND_DEBUG
12211 [ALC268_TEST] = {
12212 .mixers = { alc268_test_mixer, alc268_capture_mixer },
12213 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
12214 alc268_volume_init_verbs },
12215 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
12216 .dac_nids = alc268_dac_nids,
12217 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
12218 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010012219 .capsrc_nids = alc268_capsrc_nids,
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010012220 .hp_nid = 0x03,
12221 .dig_out_nid = ALC268_DIGOUT_NID,
12222 .num_channel_mode = ARRAY_SIZE(alc268_modes),
12223 .channel_mode = alc268_modes,
12224 .input_mux = &alc268_capture_source,
12225 },
12226#endif
Kailang Yanga361d842007-06-05 12:30:55 +020012227};
12228
12229static int patch_alc268(struct hda_codec *codec)
12230{
12231 struct alc_spec *spec;
12232 int board_config;
Takashi Iwai22971e32009-02-10 11:56:44 +010012233 int i, has_beep, err;
Kailang Yanga361d842007-06-05 12:30:55 +020012234
12235 spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
12236 if (spec == NULL)
12237 return -ENOMEM;
12238
12239 codec->spec = spec;
12240
12241 board_config = snd_hda_check_board_config(codec, ALC268_MODEL_LAST,
12242 alc268_models,
12243 alc268_cfg_tbl);
12244
12245 if (board_config < 0 || board_config >= ALC268_MODEL_LAST) {
12246 printk(KERN_INFO "hda_codec: Unknown model for ALC268, "
12247 "trying auto-probe from BIOS...\n");
12248 board_config = ALC268_AUTO;
12249 }
12250
12251 if (board_config == ALC268_AUTO) {
12252 /* automatic parse from the BIOS config */
12253 err = alc268_parse_auto_config(codec);
12254 if (err < 0) {
12255 alc_free(codec);
12256 return err;
12257 } else if (!err) {
12258 printk(KERN_INFO
12259 "hda_codec: Cannot set up configuration "
12260 "from BIOS. Using base mode...\n");
12261 board_config = ALC268_3ST;
12262 }
12263 }
12264
12265 if (board_config != ALC268_AUTO)
12266 setup_preset(spec, &alc268_presets[board_config]);
12267
Kailang Yang2f893282008-05-27 12:14:47 +020012268 if (codec->vendor_id == 0x10ec0267) {
12269 spec->stream_name_analog = "ALC267 Analog";
12270 spec->stream_name_digital = "ALC267 Digital";
12271 } else {
12272 spec->stream_name_analog = "ALC268 Analog";
12273 spec->stream_name_digital = "ALC268 Digital";
12274 }
12275
Kailang Yanga361d842007-06-05 12:30:55 +020012276 spec->stream_analog_playback = &alc268_pcm_analog_playback;
12277 spec->stream_analog_capture = &alc268_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +010012278 spec->stream_analog_alt_capture = &alc268_pcm_analog_alt_capture;
Kailang Yanga361d842007-06-05 12:30:55 +020012279
Kailang Yanga361d842007-06-05 12:30:55 +020012280 spec->stream_digital_playback = &alc268_pcm_digital_playback;
12281
Takashi Iwai22971e32009-02-10 11:56:44 +010012282 has_beep = 0;
12283 for (i = 0; i < spec->num_mixers; i++) {
12284 if (spec->mixers[i] == alc268_beep_mixer) {
12285 has_beep = 1;
12286 break;
12287 }
12288 }
12289
12290 if (has_beep) {
12291 err = snd_hda_attach_beep_device(codec, 0x1);
12292 if (err < 0) {
12293 alc_free(codec);
12294 return err;
12295 }
12296 if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
12297 /* override the amp caps for beep generator */
12298 snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012299 (0x0c << AC_AMPCAP_OFFSET_SHIFT) |
12300 (0x0c << AC_AMPCAP_NUM_STEPS_SHIFT) |
12301 (0x07 << AC_AMPCAP_STEP_SIZE_SHIFT) |
12302 (0 << AC_AMPCAP_MUTE_SHIFT));
Takashi Iwai22971e32009-02-10 11:56:44 +010012303 }
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012304
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010012305 if (!spec->no_analog && !spec->adc_nids && spec->input_mux) {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012306 /* check whether NID 0x07 is valid */
12307 unsigned int wcap = get_wcaps(codec, 0x07);
Takashi Iwai85860c02008-02-19 15:00:15 +010012308 int i;
Kailang Yanga361d842007-06-05 12:30:55 +020012309
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012310 /* get type */
12311 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Takashi Iwai67ebcb02008-02-19 15:03:57 +010012312 if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012313 spec->adc_nids = alc268_adc_nids_alt;
12314 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt);
Takashi Iwaid88897e2008-10-31 15:01:37 +010012315 add_mixer(spec, alc268_capture_alt_mixer);
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012316 } else {
12317 spec->adc_nids = alc268_adc_nids;
12318 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids);
Takashi Iwaid88897e2008-10-31 15:01:37 +010012319 add_mixer(spec, alc268_capture_mixer);
Kailang Yanga361d842007-06-05 12:30:55 +020012320 }
Takashi Iwaie1406342008-02-11 18:32:32 +010012321 spec->capsrc_nids = alc268_capsrc_nids;
Takashi Iwai85860c02008-02-19 15:00:15 +010012322 /* set default input source */
12323 for (i = 0; i < spec->num_adc_nids; i++)
12324 snd_hda_codec_write_cache(codec, alc268_capsrc_nids[i],
12325 0, AC_VERB_SET_CONNECT_SEL,
12326 spec->input_mux->items[0].index);
Kailang Yanga361d842007-06-05 12:30:55 +020012327 }
Takashi Iwai2134ea42008-01-10 16:53:55 +010012328
12329 spec->vmaster_nid = 0x02;
12330
Kailang Yanga361d842007-06-05 12:30:55 +020012331 codec->patch_ops = alc_patch_ops;
12332 if (board_config == ALC268_AUTO)
12333 spec->init_hook = alc268_auto_init;
Kailang Yangea1fb292008-08-26 12:58:38 +020012334
Takashi Iwaidaead532008-11-28 12:55:36 +010012335 codec->proc_widget_hook = print_realtek_coef;
12336
Kailang Yanga361d842007-06-05 12:30:55 +020012337 return 0;
12338}
12339
12340/*
Kailang Yangf6a92242007-12-13 16:52:54 +010012341 * ALC269 channel source setting (2 channel)
12342 */
12343#define ALC269_DIGOUT_NID ALC880_DIGOUT_NID
12344
12345#define alc269_dac_nids alc260_dac_nids
12346
12347static hda_nid_t alc269_adc_nids[1] = {
12348 /* ADC1 */
Kailang Yangf53281e2008-07-18 12:36:43 +020012349 0x08,
12350};
12351
Takashi Iwaie01bf502008-08-21 16:25:07 +020012352static hda_nid_t alc269_capsrc_nids[1] = {
12353 0x23,
12354};
12355
12356/* NOTE: ADC2 (0x07) is connected from a recording *MIXER* (0x24),
12357 * not a mux!
12358 */
12359
Kailang Yangf53281e2008-07-18 12:36:43 +020012360static struct hda_input_mux alc269_eeepc_dmic_capture_source = {
12361 .num_items = 2,
12362 .items = {
12363 { "i-Mic", 0x5 },
12364 { "e-Mic", 0x0 },
12365 },
12366};
12367
12368static struct hda_input_mux alc269_eeepc_amic_capture_source = {
12369 .num_items = 2,
12370 .items = {
12371 { "i-Mic", 0x1 },
12372 { "e-Mic", 0x0 },
12373 },
Kailang Yangf6a92242007-12-13 16:52:54 +010012374};
12375
12376#define alc269_modes alc260_modes
12377#define alc269_capture_source alc880_lg_lw_capture_source
12378
12379static struct snd_kcontrol_new alc269_base_mixer[] = {
12380 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
12381 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
12382 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
12383 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
12384 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
12385 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
12386 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12387 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
12388 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
12389 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
12390 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
12391 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
12392 { } /* end */
12393};
12394
Kailang Yang60db6b52008-08-26 13:13:00 +020012395static struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = {
12396 /* output mixer control */
12397 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
12398 {
12399 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12400 .name = "Master Playback Switch",
12401 .info = snd_hda_mixer_amp_switch_info,
12402 .get = snd_hda_mixer_amp_switch_get,
12403 .put = alc268_acer_master_sw_put,
12404 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
12405 },
12406 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
12407 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
12408 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12409 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
12410 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
12411 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yang60db6b52008-08-26 13:13:00 +020012412 { }
12413};
12414
Tony Vroon64154832008-11-06 15:08:49 +000012415static struct snd_kcontrol_new alc269_lifebook_mixer[] = {
12416 /* output mixer control */
12417 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
12418 {
12419 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12420 .name = "Master Playback Switch",
12421 .info = snd_hda_mixer_amp_switch_info,
12422 .get = snd_hda_mixer_amp_switch_get,
12423 .put = alc268_acer_master_sw_put,
12424 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
12425 },
12426 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
12427 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
12428 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12429 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
12430 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
12431 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
12432 HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x0b, 0x03, HDA_INPUT),
12433 HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x0b, 0x03, HDA_INPUT),
12434 HDA_CODEC_VOLUME("Dock Mic Boost", 0x1b, 0, HDA_INPUT),
Tony Vroon64154832008-11-06 15:08:49 +000012435 { }
12436};
12437
Kailang Yangf53281e2008-07-18 12:36:43 +020012438/* bind volumes of both NID 0x0c and 0x0d */
12439static struct hda_bind_ctls alc269_epc_bind_vol = {
12440 .ops = &snd_hda_bind_vol,
12441 .values = {
12442 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
12443 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
12444 0
12445 },
12446};
12447
12448static struct snd_kcontrol_new alc269_eeepc_mixer[] = {
12449 HDA_CODEC_MUTE("iSpeaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
12450 HDA_BIND_VOL("LineOut Playback Volume", &alc269_epc_bind_vol),
12451 HDA_CODEC_MUTE("LineOut Playback Switch", 0x15, 0x0, HDA_OUTPUT),
12452 { } /* end */
12453};
12454
Kailang Yangf6a92242007-12-13 16:52:54 +010012455/* capture mixer elements */
Kailang Yangf53281e2008-07-18 12:36:43 +020012456static struct snd_kcontrol_new alc269_epc_capture_mixer[] = {
12457 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
12458 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
Takashi Iwai26f5df22008-11-03 17:39:46 +010012459 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12460 { } /* end */
12461};
12462
12463/* FSC amilo */
12464static struct snd_kcontrol_new alc269_fujitsu_mixer[] = {
12465 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
12466 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
12467 HDA_BIND_VOL("PCM Playback Volume", &alc269_epc_bind_vol),
Kailang Yangf53281e2008-07-18 12:36:43 +020012468 { } /* end */
12469};
12470
Kailang Yang60db6b52008-08-26 13:13:00 +020012471static struct hda_verb alc269_quanta_fl1_verbs[] = {
12472 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
12473 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12474 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12475 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12476 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
12477 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12478 { }
12479};
12480
Tony Vroon64154832008-11-06 15:08:49 +000012481static struct hda_verb alc269_lifebook_verbs[] = {
12482 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
12483 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
12484 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12485 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12486 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12487 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12488 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12489 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12490 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
12491 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12492 { }
12493};
12494
Kailang Yang60db6b52008-08-26 13:13:00 +020012495/* toggle speaker-output according to the hp-jack state */
12496static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec)
12497{
12498 unsigned int present;
12499 unsigned char bits;
12500
12501 present = snd_hda_codec_read(codec, 0x15, 0,
12502 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
12503 bits = present ? AMP_IN_MUTE(0) : 0;
12504 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
12505 AMP_IN_MUTE(0), bits);
12506 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
12507 AMP_IN_MUTE(0), bits);
12508
12509 snd_hda_codec_write(codec, 0x20, 0,
12510 AC_VERB_SET_COEF_INDEX, 0x0c);
12511 snd_hda_codec_write(codec, 0x20, 0,
12512 AC_VERB_SET_PROC_COEF, 0x680);
12513
12514 snd_hda_codec_write(codec, 0x20, 0,
12515 AC_VERB_SET_COEF_INDEX, 0x0c);
12516 snd_hda_codec_write(codec, 0x20, 0,
12517 AC_VERB_SET_PROC_COEF, 0x480);
12518}
12519
Tony Vroon64154832008-11-06 15:08:49 +000012520/* toggle speaker-output according to the hp-jacks state */
12521static void alc269_lifebook_speaker_automute(struct hda_codec *codec)
12522{
12523 unsigned int present;
12524 unsigned char bits;
12525
12526 /* Check laptop headphone socket */
12527 present = snd_hda_codec_read(codec, 0x15, 0,
12528 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
12529
12530 /* Check port replicator headphone socket */
12531 present |= snd_hda_codec_read(codec, 0x1a, 0,
12532 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
12533
12534 bits = present ? AMP_IN_MUTE(0) : 0;
12535 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
12536 AMP_IN_MUTE(0), bits);
12537 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
12538 AMP_IN_MUTE(0), bits);
12539
12540 snd_hda_codec_write(codec, 0x20, 0,
12541 AC_VERB_SET_COEF_INDEX, 0x0c);
12542 snd_hda_codec_write(codec, 0x20, 0,
12543 AC_VERB_SET_PROC_COEF, 0x680);
12544
12545 snd_hda_codec_write(codec, 0x20, 0,
12546 AC_VERB_SET_COEF_INDEX, 0x0c);
12547 snd_hda_codec_write(codec, 0x20, 0,
12548 AC_VERB_SET_PROC_COEF, 0x480);
12549}
12550
Kailang Yang60db6b52008-08-26 13:13:00 +020012551static void alc269_quanta_fl1_mic_automute(struct hda_codec *codec)
12552{
12553 unsigned int present;
12554
12555 present = snd_hda_codec_read(codec, 0x18, 0,
12556 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
12557 snd_hda_codec_write(codec, 0x23, 0,
12558 AC_VERB_SET_CONNECT_SEL, present ? 0x0 : 0x1);
12559}
12560
Tony Vroon64154832008-11-06 15:08:49 +000012561static void alc269_lifebook_mic_autoswitch(struct hda_codec *codec)
12562{
12563 unsigned int present_laptop;
12564 unsigned int present_dock;
12565
12566 present_laptop = snd_hda_codec_read(codec, 0x18, 0,
12567 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
12568
12569 present_dock = snd_hda_codec_read(codec, 0x1b, 0,
12570 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
12571
12572 /* Laptop mic port overrides dock mic port, design decision */
12573 if (present_dock)
12574 snd_hda_codec_write(codec, 0x23, 0,
12575 AC_VERB_SET_CONNECT_SEL, 0x3);
12576 if (present_laptop)
12577 snd_hda_codec_write(codec, 0x23, 0,
12578 AC_VERB_SET_CONNECT_SEL, 0x0);
12579 if (!present_dock && !present_laptop)
12580 snd_hda_codec_write(codec, 0x23, 0,
12581 AC_VERB_SET_CONNECT_SEL, 0x1);
12582}
12583
Kailang Yang60db6b52008-08-26 13:13:00 +020012584static void alc269_quanta_fl1_unsol_event(struct hda_codec *codec,
12585 unsigned int res)
12586{
12587 if ((res >> 26) == ALC880_HP_EVENT)
12588 alc269_quanta_fl1_speaker_automute(codec);
12589 if ((res >> 26) == ALC880_MIC_EVENT)
12590 alc269_quanta_fl1_mic_automute(codec);
12591}
12592
Tony Vroon64154832008-11-06 15:08:49 +000012593static void alc269_lifebook_unsol_event(struct hda_codec *codec,
12594 unsigned int res)
12595{
12596 if ((res >> 26) == ALC880_HP_EVENT)
12597 alc269_lifebook_speaker_automute(codec);
12598 if ((res >> 26) == ALC880_MIC_EVENT)
12599 alc269_lifebook_mic_autoswitch(codec);
12600}
12601
Kailang Yang60db6b52008-08-26 13:13:00 +020012602static void alc269_quanta_fl1_init_hook(struct hda_codec *codec)
12603{
12604 alc269_quanta_fl1_speaker_automute(codec);
12605 alc269_quanta_fl1_mic_automute(codec);
12606}
12607
Tony Vroon64154832008-11-06 15:08:49 +000012608static void alc269_lifebook_init_hook(struct hda_codec *codec)
12609{
12610 alc269_lifebook_speaker_automute(codec);
12611 alc269_lifebook_mic_autoswitch(codec);
12612}
12613
Kailang Yang60db6b52008-08-26 13:13:00 +020012614static struct hda_verb alc269_eeepc_dmic_init_verbs[] = {
12615 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
12616 {0x23, AC_VERB_SET_CONNECT_SEL, 0x05},
12617 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
12618 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
12619 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12620 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
12621 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
12622 {}
12623};
12624
12625static struct hda_verb alc269_eeepc_amic_init_verbs[] = {
12626 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
12627 {0x23, AC_VERB_SET_CONNECT_SEL, 0x01},
12628 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
12629 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x701b | (0x00 << 8))},
12630 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
12631 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
12632 {}
12633};
12634
12635/* toggle speaker-output according to the hp-jack state */
12636static void alc269_speaker_automute(struct hda_codec *codec)
12637{
12638 unsigned int present;
12639 unsigned char bits;
12640
12641 present = snd_hda_codec_read(codec, 0x15, 0,
12642 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
12643 bits = present ? AMP_IN_MUTE(0) : 0;
12644 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
12645 AMP_IN_MUTE(0), bits);
12646 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
12647 AMP_IN_MUTE(0), bits);
12648}
12649
12650static void alc269_eeepc_dmic_automute(struct hda_codec *codec)
12651{
12652 unsigned int present;
12653
12654 present = snd_hda_codec_read(codec, 0x18, 0,
12655 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
12656 snd_hda_codec_write(codec, 0x23, 0,
12657 AC_VERB_SET_CONNECT_SEL, (present ? 0 : 5));
12658}
12659
12660static void alc269_eeepc_amic_automute(struct hda_codec *codec)
12661{
12662 unsigned int present;
12663
12664 present = snd_hda_codec_read(codec, 0x18, 0,
12665 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
12666 snd_hda_codec_write(codec, 0x24, 0, AC_VERB_SET_AMP_GAIN_MUTE,
12667 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
12668 snd_hda_codec_write(codec, 0x24, 0, AC_VERB_SET_AMP_GAIN_MUTE,
12669 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
12670}
12671
12672/* unsolicited event for HP jack sensing */
12673static void alc269_eeepc_dmic_unsol_event(struct hda_codec *codec,
12674 unsigned int res)
12675{
12676 if ((res >> 26) == ALC880_HP_EVENT)
12677 alc269_speaker_automute(codec);
12678
12679 if ((res >> 26) == ALC880_MIC_EVENT)
12680 alc269_eeepc_dmic_automute(codec);
12681}
12682
12683static void alc269_eeepc_dmic_inithook(struct hda_codec *codec)
12684{
12685 alc269_speaker_automute(codec);
12686 alc269_eeepc_dmic_automute(codec);
12687}
12688
12689/* unsolicited event for HP jack sensing */
12690static void alc269_eeepc_amic_unsol_event(struct hda_codec *codec,
12691 unsigned int res)
12692{
12693 if ((res >> 26) == ALC880_HP_EVENT)
12694 alc269_speaker_automute(codec);
12695
12696 if ((res >> 26) == ALC880_MIC_EVENT)
12697 alc269_eeepc_amic_automute(codec);
12698}
12699
12700static void alc269_eeepc_amic_inithook(struct hda_codec *codec)
12701{
12702 alc269_speaker_automute(codec);
12703 alc269_eeepc_amic_automute(codec);
12704}
12705
Kailang Yangf6a92242007-12-13 16:52:54 +010012706/*
12707 * generic initialization of ADC, input mixers and output mixers
12708 */
12709static struct hda_verb alc269_init_verbs[] = {
12710 /*
12711 * Unmute ADC0 and set the default input to mic-in
12712 */
Kailang Yang60db6b52008-08-26 13:13:00 +020012713 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangf6a92242007-12-13 16:52:54 +010012714
12715 /* Mute input amps (PCBeep, Line In, Mic 1 & Mic 2) of the
12716 * analog-loopback mixer widget
12717 * Note: PASD motherboards uses the Line In 2 as the input for
12718 * front panel mic (mic 2)
12719 */
12720 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
12721 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12722 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12723 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12724 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12725 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
12726
12727 /*
12728 * Set up output mixers (0x0c - 0x0e)
12729 */
12730 /* set vol=0 to output mixers */
12731 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12732 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12733
12734 /* set up input amps for analog loopback */
12735 /* Amp Indices: DAC = 0, mixer = 1 */
12736 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12737 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12738 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12739 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12740 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12741 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12742
12743 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12744 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12745 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12746 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
12747 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
12748 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12749 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12750
12751 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12752 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12753 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12754 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12755 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12756 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12757 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12758
12759 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
12760 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
12761
12762 /* FIXME: use matrix-type input source selection */
12763 /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
12764 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yang60db6b52008-08-26 13:13:00 +020012765 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12766 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangf6a92242007-12-13 16:52:54 +010012767 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12768 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12769
12770 /* set EAPD */
12771 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
12772 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
12773 { }
12774};
12775
12776/* add playback controls from the parsed DAC table */
12777static int alc269_auto_create_multi_out_ctls(struct alc_spec *spec,
12778 const struct auto_pin_cfg *cfg)
12779{
12780 hda_nid_t nid;
12781 int err;
12782
12783 spec->multiout.num_dacs = 1; /* only use one dac */
12784 spec->multiout.dac_nids = spec->private_dac_nids;
12785 spec->multiout.dac_nids[0] = 2;
12786
12787 nid = cfg->line_out_pins[0];
12788 if (nid) {
12789 err = add_control(spec, ALC_CTL_WIDGET_VOL,
12790 "Front Playback Volume",
12791 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT));
12792 if (err < 0)
12793 return err;
12794 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
12795 "Front Playback Switch",
12796 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
12797 if (err < 0)
12798 return err;
12799 }
12800
12801 nid = cfg->speaker_pins[0];
12802 if (nid) {
12803 if (!cfg->line_out_pins[0]) {
12804 err = add_control(spec, ALC_CTL_WIDGET_VOL,
12805 "Speaker Playback Volume",
12806 HDA_COMPOSE_AMP_VAL(0x02, 3, 0,
12807 HDA_OUTPUT));
12808 if (err < 0)
12809 return err;
12810 }
12811 if (nid == 0x16) {
12812 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
12813 "Speaker Playback Switch",
12814 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
12815 HDA_OUTPUT));
12816 if (err < 0)
12817 return err;
12818 } else {
12819 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
12820 "Speaker Playback Switch",
12821 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
12822 HDA_OUTPUT));
12823 if (err < 0)
12824 return err;
12825 }
12826 }
12827 nid = cfg->hp_pins[0];
12828 if (nid) {
12829 /* spec->multiout.hp_nid = 2; */
12830 if (!cfg->line_out_pins[0] && !cfg->speaker_pins[0]) {
12831 err = add_control(spec, ALC_CTL_WIDGET_VOL,
12832 "Headphone Playback Volume",
12833 HDA_COMPOSE_AMP_VAL(0x02, 3, 0,
12834 HDA_OUTPUT));
12835 if (err < 0)
12836 return err;
12837 }
12838 if (nid == 0x16) {
12839 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
12840 "Headphone Playback Switch",
12841 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
12842 HDA_OUTPUT));
12843 if (err < 0)
12844 return err;
12845 } else {
12846 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
12847 "Headphone Playback Switch",
12848 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
12849 HDA_OUTPUT));
12850 if (err < 0)
12851 return err;
12852 }
12853 }
12854 return 0;
12855}
12856
Takashi Iwaiee956e02008-10-31 17:16:31 +010012857static int alc269_auto_create_analog_input_ctls(struct alc_spec *spec,
12858 const struct auto_pin_cfg *cfg)
12859{
12860 int err;
12861
12862 err = alc880_auto_create_analog_input_ctls(spec, cfg);
12863 if (err < 0)
12864 return err;
12865 /* digital-mic input pin is excluded in alc880_auto_create..()
12866 * because it's under 0x18
12867 */
12868 if (cfg->input_pins[AUTO_PIN_MIC] == 0x12 ||
12869 cfg->input_pins[AUTO_PIN_FRONT_MIC] == 0x12) {
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020012870 struct hda_input_mux *imux = &spec->private_imux[0];
Takashi Iwaiee956e02008-10-31 17:16:31 +010012871 imux->items[imux->num_items].label = "Int Mic";
12872 imux->items[imux->num_items].index = 0x05;
12873 imux->num_items++;
12874 }
12875 return 0;
12876}
Kailang Yangf6a92242007-12-13 16:52:54 +010012877
12878#ifdef CONFIG_SND_HDA_POWER_SAVE
12879#define alc269_loopbacks alc880_loopbacks
12880#endif
12881
12882/* pcm configuration: identiacal with ALC880 */
12883#define alc269_pcm_analog_playback alc880_pcm_analog_playback
12884#define alc269_pcm_analog_capture alc880_pcm_analog_capture
12885#define alc269_pcm_digital_playback alc880_pcm_digital_playback
12886#define alc269_pcm_digital_capture alc880_pcm_digital_capture
12887
Takashi Iwaif03d3112009-03-05 14:18:16 +010012888static struct hda_pcm_stream alc269_44k_pcm_analog_playback = {
12889 .substreams = 1,
12890 .channels_min = 2,
12891 .channels_max = 8,
12892 .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
12893 /* NID is set in alc_build_pcms */
12894 .ops = {
12895 .open = alc880_playback_pcm_open,
12896 .prepare = alc880_playback_pcm_prepare,
12897 .cleanup = alc880_playback_pcm_cleanup
12898 },
12899};
12900
12901static struct hda_pcm_stream alc269_44k_pcm_analog_capture = {
12902 .substreams = 1,
12903 .channels_min = 2,
12904 .channels_max = 2,
12905 .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
12906 /* NID is set in alc_build_pcms */
12907};
12908
Kailang Yangf6a92242007-12-13 16:52:54 +010012909/*
12910 * BIOS auto configuration
12911 */
12912static int alc269_parse_auto_config(struct hda_codec *codec)
12913{
12914 struct alc_spec *spec = codec->spec;
Takashi Iwaicfb9fb52009-02-06 17:34:03 +010012915 int err;
Kailang Yangf6a92242007-12-13 16:52:54 +010012916 static hda_nid_t alc269_ignore[] = { 0x1d, 0 };
12917
12918 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
12919 alc269_ignore);
12920 if (err < 0)
12921 return err;
12922
12923 err = alc269_auto_create_multi_out_ctls(spec, &spec->autocfg);
12924 if (err < 0)
12925 return err;
12926 err = alc269_auto_create_analog_input_ctls(spec, &spec->autocfg);
12927 if (err < 0)
12928 return err;
12929
12930 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
12931
Takashi Iwai0852d7a2009-02-11 11:35:15 +010012932 if (spec->autocfg.dig_outs)
Kailang Yangf6a92242007-12-13 16:52:54 +010012933 spec->multiout.dig_out_nid = ALC269_DIGOUT_NID;
12934
Takashi Iwai603c4012008-07-30 15:01:44 +020012935 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010012936 add_mixer(spec, spec->kctls.list);
Kailang Yangf6a92242007-12-13 16:52:54 +010012937
Takashi Iwaid88897e2008-10-31 15:01:37 +010012938 add_verb(spec, alc269_init_verbs);
Kailang Yangf6a92242007-12-13 16:52:54 +010012939 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020012940 spec->input_mux = &spec->private_imux[0];
Takashi Iwaie01bf502008-08-21 16:25:07 +020012941 /* set default input source */
12942 snd_hda_codec_write_cache(codec, alc269_capsrc_nids[0],
12943 0, AC_VERB_SET_CONNECT_SEL,
12944 spec->input_mux->items[0].index);
Kailang Yangf6a92242007-12-13 16:52:54 +010012945
12946 err = alc_auto_add_mic_boost(codec);
12947 if (err < 0)
12948 return err;
12949
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010012950 if (!spec->cap_mixer && !spec->no_analog)
Takashi Iwaif9e336f2008-10-31 16:37:07 +010012951 set_capture_mixer(spec);
Kailang Yangf53281e2008-07-18 12:36:43 +020012952
Kailang Yangf6a92242007-12-13 16:52:54 +010012953 return 1;
12954}
12955
12956#define alc269_auto_init_multi_out alc882_auto_init_multi_out
12957#define alc269_auto_init_hp_out alc882_auto_init_hp_out
12958#define alc269_auto_init_analog_input alc882_auto_init_analog_input
12959
12960
12961/* init callback for auto-configuration model -- overriding the default init */
12962static void alc269_auto_init(struct hda_codec *codec)
12963{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012964 struct alc_spec *spec = codec->spec;
Kailang Yangf6a92242007-12-13 16:52:54 +010012965 alc269_auto_init_multi_out(codec);
12966 alc269_auto_init_hp_out(codec);
12967 alc269_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012968 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020012969 alc_inithook(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010012970}
12971
12972/*
12973 * configuration and preset
12974 */
12975static const char *alc269_models[ALC269_MODEL_LAST] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020012976 [ALC269_BASIC] = "basic",
Takashi Iwai2922c9a2008-08-27 18:12:42 +020012977 [ALC269_QUANTA_FL1] = "quanta",
12978 [ALC269_ASUS_EEEPC_P703] = "eeepc-p703",
Takashi Iwai26f5df22008-11-03 17:39:46 +010012979 [ALC269_ASUS_EEEPC_P901] = "eeepc-p901",
Tony Vroon64154832008-11-06 15:08:49 +000012980 [ALC269_FUJITSU] = "fujitsu",
12981 [ALC269_LIFEBOOK] = "lifebook"
Kailang Yangf6a92242007-12-13 16:52:54 +010012982};
12983
12984static struct snd_pci_quirk alc269_cfg_tbl[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020012985 SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_QUANTA_FL1),
Kailang Yangf53281e2008-07-18 12:36:43 +020012986 SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A",
12987 ALC269_ASUS_EEEPC_P703),
Kailang Yang622e84c2009-04-21 07:39:04 +020012988 SND_PCI_QUIRK(0x1043, 0x1883, "ASUS F81Se", ALC269_ASUS_EEEPC_P703),
12989 SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS F5Q", ALC269_ASUS_EEEPC_P703),
12990 SND_PCI_QUIRK(0x1043, 0x1723, "ASUS P80", ALC269_ASUS_EEEPC_P703),
12991 SND_PCI_QUIRK(0x1043, 0x1773, "ASUS U20A", ALC269_ASUS_EEEPC_P703),
12992 SND_PCI_QUIRK(0x1043, 0x1743, "ASUS U80", ALC269_ASUS_EEEPC_P703),
12993 SND_PCI_QUIRK(0x1043, 0x1653, "ASUS U50", ALC269_ASUS_EEEPC_P703),
Kailang Yangf53281e2008-07-18 12:36:43 +020012994 SND_PCI_QUIRK(0x1043, 0x831a, "ASUS Eeepc P901",
12995 ALC269_ASUS_EEEPC_P901),
Kailang Yang60db6b52008-08-26 13:13:00 +020012996 SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101",
12997 ALC269_ASUS_EEEPC_P901),
Kailang Yang622e84c2009-04-21 07:39:04 +020012998 SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_ASUS_EEEPC_P901),
Takashi Iwai26f5df22008-11-03 17:39:46 +010012999 SND_PCI_QUIRK(0x1734, 0x115d, "FSC Amilo", ALC269_FUJITSU),
Tony Vroon64154832008-11-06 15:08:49 +000013000 SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook ICH9M-based", ALC269_LIFEBOOK),
Kailang Yangf6a92242007-12-13 16:52:54 +010013001 {}
13002};
13003
13004static struct alc_config_preset alc269_presets[] = {
13005 [ALC269_BASIC] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010013006 .mixers = { alc269_base_mixer },
Kailang Yangf6a92242007-12-13 16:52:54 +010013007 .init_verbs = { alc269_init_verbs },
13008 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
13009 .dac_nids = alc269_dac_nids,
13010 .hp_nid = 0x03,
13011 .num_channel_mode = ARRAY_SIZE(alc269_modes),
13012 .channel_mode = alc269_modes,
13013 .input_mux = &alc269_capture_source,
13014 },
Kailang Yang60db6b52008-08-26 13:13:00 +020013015 [ALC269_QUANTA_FL1] = {
13016 .mixers = { alc269_quanta_fl1_mixer },
13017 .init_verbs = { alc269_init_verbs, alc269_quanta_fl1_verbs },
13018 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
13019 .dac_nids = alc269_dac_nids,
13020 .hp_nid = 0x03,
13021 .num_channel_mode = ARRAY_SIZE(alc269_modes),
13022 .channel_mode = alc269_modes,
13023 .input_mux = &alc269_capture_source,
13024 .unsol_event = alc269_quanta_fl1_unsol_event,
13025 .init_hook = alc269_quanta_fl1_init_hook,
13026 },
Kailang Yangf53281e2008-07-18 12:36:43 +020013027 [ALC269_ASUS_EEEPC_P703] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010013028 .mixers = { alc269_eeepc_mixer },
13029 .cap_mixer = alc269_epc_capture_mixer,
Kailang Yangf53281e2008-07-18 12:36:43 +020013030 .init_verbs = { alc269_init_verbs,
13031 alc269_eeepc_amic_init_verbs },
13032 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
13033 .dac_nids = alc269_dac_nids,
13034 .hp_nid = 0x03,
13035 .num_channel_mode = ARRAY_SIZE(alc269_modes),
13036 .channel_mode = alc269_modes,
13037 .input_mux = &alc269_eeepc_amic_capture_source,
13038 .unsol_event = alc269_eeepc_amic_unsol_event,
13039 .init_hook = alc269_eeepc_amic_inithook,
13040 },
13041 [ALC269_ASUS_EEEPC_P901] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010013042 .mixers = { alc269_eeepc_mixer },
13043 .cap_mixer = alc269_epc_capture_mixer,
Kailang Yangf53281e2008-07-18 12:36:43 +020013044 .init_verbs = { alc269_init_verbs,
13045 alc269_eeepc_dmic_init_verbs },
13046 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
13047 .dac_nids = alc269_dac_nids,
13048 .hp_nid = 0x03,
13049 .num_channel_mode = ARRAY_SIZE(alc269_modes),
13050 .channel_mode = alc269_modes,
13051 .input_mux = &alc269_eeepc_dmic_capture_source,
13052 .unsol_event = alc269_eeepc_dmic_unsol_event,
13053 .init_hook = alc269_eeepc_dmic_inithook,
13054 },
Takashi Iwai26f5df22008-11-03 17:39:46 +010013055 [ALC269_FUJITSU] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010013056 .mixers = { alc269_fujitsu_mixer },
Takashi Iwai26f5df22008-11-03 17:39:46 +010013057 .cap_mixer = alc269_epc_capture_mixer,
13058 .init_verbs = { alc269_init_verbs,
13059 alc269_eeepc_dmic_init_verbs },
13060 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
13061 .dac_nids = alc269_dac_nids,
13062 .hp_nid = 0x03,
13063 .num_channel_mode = ARRAY_SIZE(alc269_modes),
13064 .channel_mode = alc269_modes,
13065 .input_mux = &alc269_eeepc_dmic_capture_source,
13066 .unsol_event = alc269_eeepc_dmic_unsol_event,
13067 .init_hook = alc269_eeepc_dmic_inithook,
13068 },
Tony Vroon64154832008-11-06 15:08:49 +000013069 [ALC269_LIFEBOOK] = {
13070 .mixers = { alc269_lifebook_mixer },
13071 .init_verbs = { alc269_init_verbs, alc269_lifebook_verbs },
13072 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
13073 .dac_nids = alc269_dac_nids,
13074 .hp_nid = 0x03,
13075 .num_channel_mode = ARRAY_SIZE(alc269_modes),
13076 .channel_mode = alc269_modes,
13077 .input_mux = &alc269_capture_source,
13078 .unsol_event = alc269_lifebook_unsol_event,
13079 .init_hook = alc269_lifebook_init_hook,
13080 },
Kailang Yangf6a92242007-12-13 16:52:54 +010013081};
13082
13083static int patch_alc269(struct hda_codec *codec)
13084{
13085 struct alc_spec *spec;
13086 int board_config;
13087 int err;
13088
13089 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
13090 if (spec == NULL)
13091 return -ENOMEM;
13092
13093 codec->spec = spec;
13094
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020013095 alc_fix_pll_init(codec, 0x20, 0x04, 15);
13096
Kailang Yangf6a92242007-12-13 16:52:54 +010013097 board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST,
13098 alc269_models,
13099 alc269_cfg_tbl);
13100
13101 if (board_config < 0) {
13102 printk(KERN_INFO "hda_codec: Unknown model for ALC269, "
13103 "trying auto-probe from BIOS...\n");
13104 board_config = ALC269_AUTO;
13105 }
13106
13107 if (board_config == ALC269_AUTO) {
13108 /* automatic parse from the BIOS config */
13109 err = alc269_parse_auto_config(codec);
13110 if (err < 0) {
13111 alc_free(codec);
13112 return err;
13113 } else if (!err) {
13114 printk(KERN_INFO
13115 "hda_codec: Cannot set up configuration "
13116 "from BIOS. Using base mode...\n");
13117 board_config = ALC269_BASIC;
13118 }
13119 }
13120
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090013121 err = snd_hda_attach_beep_device(codec, 0x1);
13122 if (err < 0) {
13123 alc_free(codec);
13124 return err;
13125 }
13126
Kailang Yangf6a92242007-12-13 16:52:54 +010013127 if (board_config != ALC269_AUTO)
13128 setup_preset(spec, &alc269_presets[board_config]);
13129
13130 spec->stream_name_analog = "ALC269 Analog";
Takashi Iwaif03d3112009-03-05 14:18:16 +010013131 if (codec->subsystem_id == 0x17aa3bf8) {
13132 /* Due to a hardware problem on Lenovo Ideadpad, we need to
13133 * fix the sample rate of analog I/O to 44.1kHz
13134 */
13135 spec->stream_analog_playback = &alc269_44k_pcm_analog_playback;
13136 spec->stream_analog_capture = &alc269_44k_pcm_analog_capture;
13137 } else {
13138 spec->stream_analog_playback = &alc269_pcm_analog_playback;
13139 spec->stream_analog_capture = &alc269_pcm_analog_capture;
13140 }
Kailang Yangf6a92242007-12-13 16:52:54 +010013141 spec->stream_name_digital = "ALC269 Digital";
13142 spec->stream_digital_playback = &alc269_pcm_digital_playback;
13143 spec->stream_digital_capture = &alc269_pcm_digital_capture;
13144
13145 spec->adc_nids = alc269_adc_nids;
13146 spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids);
Takashi Iwaie01bf502008-08-21 16:25:07 +020013147 spec->capsrc_nids = alc269_capsrc_nids;
Takashi Iwaif9e336f2008-10-31 16:37:07 +010013148 if (!spec->cap_mixer)
13149 set_capture_mixer(spec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010013150 set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
Kailang Yangf6a92242007-12-13 16:52:54 +010013151
13152 codec->patch_ops = alc_patch_ops;
13153 if (board_config == ALC269_AUTO)
13154 spec->init_hook = alc269_auto_init;
13155#ifdef CONFIG_SND_HDA_POWER_SAVE
13156 if (!spec->loopback.amplist)
13157 spec->loopback.amplist = alc269_loopbacks;
13158#endif
Takashi Iwaidaead532008-11-28 12:55:36 +010013159 codec->proc_widget_hook = print_realtek_coef;
Kailang Yangf6a92242007-12-13 16:52:54 +010013160
13161 return 0;
13162}
13163
13164/*
Kailang Yangdf694da2005-12-05 19:42:22 +010013165 * ALC861 channel source setting (2/6 channel selection for 3-stack)
13166 */
13167
13168/*
13169 * set the path ways for 2 channel output
13170 * need to set the codec line out and mic 1 pin widgets to inputs
13171 */
13172static struct hda_verb alc861_threestack_ch2_init[] = {
13173 /* set pin widget 1Ah (line in) for input */
13174 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013175 /* set pin widget 18h (mic1/2) for input, for mic also enable
13176 * the vref
13177 */
Kailang Yangdf694da2005-12-05 19:42:22 +010013178 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13179
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013180 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
13181#if 0
13182 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
13183 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
13184#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010013185 { } /* end */
13186};
13187/*
13188 * 6ch mode
13189 * need to set the codec line out and mic 1 pin widgets to outputs
13190 */
13191static struct hda_verb alc861_threestack_ch6_init[] = {
13192 /* set pin widget 1Ah (line in) for output (Back Surround)*/
13193 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13194 /* set pin widget 18h (mic1) for output (CLFE)*/
13195 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13196
13197 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013198 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010013199
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013200 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
13201#if 0
13202 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
13203 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
13204#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010013205 { } /* end */
13206};
13207
13208static struct hda_channel_mode alc861_threestack_modes[2] = {
13209 { 2, alc861_threestack_ch2_init },
13210 { 6, alc861_threestack_ch6_init },
13211};
Takashi Iwai22309c32006-08-09 16:57:28 +020013212/* Set mic1 as input and unmute the mixer */
13213static struct hda_verb alc861_uniwill_m31_ch2_init[] = {
13214 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13215 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
13216 { } /* end */
13217};
13218/* Set mic1 as output and mute mixer */
13219static struct hda_verb alc861_uniwill_m31_ch4_init[] = {
13220 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13221 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
13222 { } /* end */
13223};
13224
13225static struct hda_channel_mode alc861_uniwill_m31_modes[2] = {
13226 { 2, alc861_uniwill_m31_ch2_init },
13227 { 4, alc861_uniwill_m31_ch4_init },
13228};
Kailang Yangdf694da2005-12-05 19:42:22 +010013229
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013230/* Set mic1 and line-in as input and unmute the mixer */
13231static struct hda_verb alc861_asus_ch2_init[] = {
13232 /* set pin widget 1Ah (line in) for input */
13233 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013234 /* set pin widget 18h (mic1/2) for input, for mic also enable
13235 * the vref
13236 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013237 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13238
13239 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
13240#if 0
13241 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
13242 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
13243#endif
13244 { } /* end */
13245};
13246/* Set mic1 nad line-in as output and mute mixer */
13247static struct hda_verb alc861_asus_ch6_init[] = {
13248 /* set pin widget 1Ah (line in) for output (Back Surround)*/
13249 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13250 /* { 0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
13251 /* set pin widget 18h (mic1) for output (CLFE)*/
13252 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13253 /* { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
13254 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
13255 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
13256
13257 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
13258#if 0
13259 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
13260 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
13261#endif
13262 { } /* end */
13263};
13264
13265static struct hda_channel_mode alc861_asus_modes[2] = {
13266 { 2, alc861_asus_ch2_init },
13267 { 6, alc861_asus_ch6_init },
13268};
13269
Kailang Yangdf694da2005-12-05 19:42:22 +010013270/* patch-ALC861 */
13271
13272static struct snd_kcontrol_new alc861_base_mixer[] = {
13273 /* output mixer control */
13274 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
13275 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
13276 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
13277 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
13278 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
13279
13280 /*Input mixer control */
13281 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
13282 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
13283 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
13284 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
13285 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
13286 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
13287 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
13288 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
13289 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
13290 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013291
Kailang Yangdf694da2005-12-05 19:42:22 +010013292 { } /* end */
13293};
13294
13295static struct snd_kcontrol_new alc861_3ST_mixer[] = {
13296 /* output mixer control */
13297 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
13298 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
13299 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
13300 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
13301 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
13302
13303 /* Input mixer control */
13304 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
13305 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
13306 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
13307 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
13308 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
13309 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
13310 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
13311 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
13312 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
13313 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013314
Kailang Yangdf694da2005-12-05 19:42:22 +010013315 {
13316 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13317 .name = "Channel Mode",
13318 .info = alc_ch_mode_info,
13319 .get = alc_ch_mode_get,
13320 .put = alc_ch_mode_put,
13321 .private_value = ARRAY_SIZE(alc861_threestack_modes),
13322 },
13323 { } /* end */
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013324};
13325
Takashi Iwaid1d985f2006-11-23 19:27:12 +010013326static struct snd_kcontrol_new alc861_toshiba_mixer[] = {
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013327 /* output mixer control */
13328 HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT),
13329 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
13330 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
Kailang Yangea1fb292008-08-26 12:58:38 +020013331
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013332 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013333};
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013334
Takashi Iwai22309c32006-08-09 16:57:28 +020013335static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = {
13336 /* output mixer control */
13337 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
13338 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
13339 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
13340 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
13341 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
13342
13343 /* Input mixer control */
13344 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
13345 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
13346 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
13347 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
13348 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
13349 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
13350 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
13351 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
13352 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
13353 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013354
Takashi Iwai22309c32006-08-09 16:57:28 +020013355 {
13356 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13357 .name = "Channel Mode",
13358 .info = alc_ch_mode_info,
13359 .get = alc_ch_mode_get,
13360 .put = alc_ch_mode_put,
13361 .private_value = ARRAY_SIZE(alc861_uniwill_m31_modes),
13362 },
13363 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013364};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013365
13366static struct snd_kcontrol_new alc861_asus_mixer[] = {
13367 /* output mixer control */
13368 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
13369 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
13370 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
13371 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
13372 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
13373
13374 /* Input mixer control */
13375 HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
13376 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT),
13377 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
13378 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
13379 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
13380 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
13381 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
13382 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
13383 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013384 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_OUTPUT),
13385
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013386 {
13387 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13388 .name = "Channel Mode",
13389 .info = alc_ch_mode_info,
13390 .get = alc_ch_mode_get,
13391 .put = alc_ch_mode_put,
13392 .private_value = ARRAY_SIZE(alc861_asus_modes),
13393 },
13394 { }
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010013395};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013396
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010013397/* additional mixer */
Takashi Iwaid1d985f2006-11-23 19:27:12 +010013398static struct snd_kcontrol_new alc861_asus_laptop_mixer[] = {
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010013399 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
13400 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010013401 { }
13402};
13403
Kailang Yangdf694da2005-12-05 19:42:22 +010013404/*
13405 * generic initialization of ADC, input mixers and output mixers
13406 */
13407static struct hda_verb alc861_base_init_verbs[] = {
13408 /*
13409 * Unmute ADC0 and set the default input to mic-in
13410 */
13411 /* port-A for surround (rear panel) */
13412 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13413 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x00 },
13414 /* port-B for mic-in (rear panel) with vref */
13415 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13416 /* port-C for line-in (rear panel) */
13417 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
13418 /* port-D for Front */
13419 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13420 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
13421 /* port-E for HP out (front panel) */
13422 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
13423 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010013424 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010013425 /* port-F for mic-in (front panel) with vref */
13426 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13427 /* port-G for CLFE (rear panel) */
13428 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13429 { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x00 },
13430 /* port-H for side (rear panel) */
13431 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13432 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x00 },
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)},
Kailang Yangea1fb292008-08-26 12:58:38 +020013438
Kailang Yangdf694da2005-12-05 19:42:22 +010013439 /* Unmute DAC0~3 & spdif out*/
13440 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13441 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13442 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13443 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13444 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020013445
Kailang Yangdf694da2005-12-05 19:42:22 +010013446 /* Unmute Mixer 14 (mic) 1c (Line in)*/
13447 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13448 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13449 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13450 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020013451
Kailang Yangdf694da2005-12-05 19:42:22 +010013452 /* Unmute Stereo Mixer 15 */
13453 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13454 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13455 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013456 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010013457
13458 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13459 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13460 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13461 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13462 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13463 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13464 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13465 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013466 /* hp used DAC 3 (Front) */
13467 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010013468 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
13469
13470 { }
13471};
13472
13473static struct hda_verb alc861_threestack_init_verbs[] = {
13474 /*
13475 * Unmute ADC0 and set the default input to mic-in
13476 */
13477 /* port-A for surround (rear panel) */
13478 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
13479 /* port-B for mic-in (rear panel) with vref */
13480 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13481 /* port-C for line-in (rear panel) */
13482 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
13483 /* port-D for Front */
13484 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13485 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
13486 /* port-E for HP out (front panel) */
13487 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
13488 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010013489 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010013490 /* port-F for mic-in (front panel) with vref */
13491 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13492 /* port-G for CLFE (rear panel) */
13493 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
13494 /* port-H for side (rear panel) */
13495 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
13496 /* CD-in */
13497 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
13498 /* route front mic to ADC1*/
13499 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
13500 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13501 /* Unmute DAC0~3 & spdif out*/
13502 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13503 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13504 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13505 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13506 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020013507
Kailang Yangdf694da2005-12-05 19:42:22 +010013508 /* Unmute Mixer 14 (mic) 1c (Line in)*/
13509 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13510 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13511 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13512 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020013513
Kailang Yangdf694da2005-12-05 19:42:22 +010013514 /* Unmute Stereo Mixer 15 */
13515 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13516 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13517 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013518 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010013519
13520 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13521 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13522 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13523 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13524 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13525 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13526 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13527 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013528 /* hp used DAC 3 (Front) */
13529 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010013530 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
13531 { }
13532};
Takashi Iwai22309c32006-08-09 16:57:28 +020013533
13534static struct hda_verb alc861_uniwill_m31_init_verbs[] = {
13535 /*
13536 * Unmute ADC0 and set the default input to mic-in
13537 */
13538 /* port-A for surround (rear panel) */
13539 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
13540 /* port-B for mic-in (rear panel) with vref */
13541 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13542 /* port-C for line-in (rear panel) */
13543 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
13544 /* port-D for Front */
13545 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13546 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
13547 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013548 /* this has to be set to VREF80 */
13549 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Takashi Iwai22309c32006-08-09 16:57:28 +020013550 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010013551 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai22309c32006-08-09 16:57:28 +020013552 /* port-F for mic-in (front panel) with vref */
13553 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13554 /* port-G for CLFE (rear panel) */
13555 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
13556 /* port-H for side (rear panel) */
13557 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
13558 /* CD-in */
13559 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
13560 /* route front mic to ADC1*/
13561 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
13562 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13563 /* Unmute DAC0~3 & spdif out*/
13564 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13565 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13566 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13567 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13568 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020013569
Takashi Iwai22309c32006-08-09 16:57:28 +020013570 /* Unmute Mixer 14 (mic) 1c (Line in)*/
13571 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13572 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13573 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13574 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020013575
Takashi Iwai22309c32006-08-09 16:57:28 +020013576 /* Unmute Stereo Mixer 15 */
13577 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13578 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13579 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013580 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Takashi Iwai22309c32006-08-09 16:57:28 +020013581
13582 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13583 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13584 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13585 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13586 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13587 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13588 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13589 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013590 /* hp used DAC 3 (Front) */
13591 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Takashi Iwai22309c32006-08-09 16:57:28 +020013592 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
13593 { }
13594};
13595
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013596static struct hda_verb alc861_asus_init_verbs[] = {
13597 /*
13598 * Unmute ADC0 and set the default input to mic-in
13599 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013600 /* port-A for surround (rear panel)
13601 * according to codec#0 this is the HP jack
13602 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013603 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* was 0x00 */
13604 /* route front PCM to HP */
13605 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x01 },
13606 /* port-B for mic-in (rear panel) with vref */
13607 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13608 /* port-C for line-in (rear panel) */
13609 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
13610 /* port-D for Front */
13611 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13612 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
13613 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013614 /* this has to be set to VREF80 */
13615 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013616 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010013617 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013618 /* port-F for mic-in (front panel) with vref */
13619 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13620 /* port-G for CLFE (rear panel) */
13621 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13622 /* port-H for side (rear panel) */
13623 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13624 /* CD-in */
13625 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
13626 /* route front mic to ADC1*/
13627 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
13628 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13629 /* Unmute DAC0~3 & spdif out*/
13630 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13631 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13632 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13633 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13634 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13635 /* Unmute Mixer 14 (mic) 1c (Line in)*/
13636 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13637 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13638 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13639 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020013640
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013641 /* Unmute Stereo Mixer 15 */
13642 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13643 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13644 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013645 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013646
13647 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13648 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13649 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13650 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13651 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13652 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13653 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13654 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013655 /* hp used DAC 3 (Front) */
13656 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013657 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
13658 { }
13659};
13660
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010013661/* additional init verbs for ASUS laptops */
13662static struct hda_verb alc861_asus_laptop_init_verbs[] = {
13663 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x45 }, /* HP-out */
13664 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2) }, /* mute line-in */
13665 { }
13666};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013667
Kailang Yangdf694da2005-12-05 19:42:22 +010013668/*
13669 * generic initialization of ADC, input mixers and output mixers
13670 */
13671static struct hda_verb alc861_auto_init_verbs[] = {
13672 /*
13673 * Unmute ADC0 and set the default input to mic-in
13674 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013675 /* {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, */
Kailang Yangdf694da2005-12-05 19:42:22 +010013676 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020013677
Kailang Yangdf694da2005-12-05 19:42:22 +010013678 /* Unmute DAC0~3 & spdif out*/
13679 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13680 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13681 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13682 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13683 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020013684
Kailang Yangdf694da2005-12-05 19:42:22 +010013685 /* Unmute Mixer 14 (mic) 1c (Line in)*/
13686 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13687 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13688 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13689 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020013690
Kailang Yangdf694da2005-12-05 19:42:22 +010013691 /* Unmute Stereo Mixer 15 */
13692 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13693 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13694 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
13695 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c},
13696
13697 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13698 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13699 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13700 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13701 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13702 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13703 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13704 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13705
13706 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13707 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013708 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
13709 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010013710 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13711 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013712 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
13713 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010013714
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013715 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, /* set Mic 1 */
Kailang Yangdf694da2005-12-05 19:42:22 +010013716
13717 { }
13718};
13719
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013720static struct hda_verb alc861_toshiba_init_verbs[] = {
13721 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013722
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013723 { }
13724};
13725
13726/* toggle speaker-output according to the hp-jack state */
13727static void alc861_toshiba_automute(struct hda_codec *codec)
13728{
13729 unsigned int present;
13730
13731 present = snd_hda_codec_read(codec, 0x0f, 0,
13732 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020013733 snd_hda_codec_amp_stereo(codec, 0x16, HDA_INPUT, 0,
13734 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
13735 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_INPUT, 3,
13736 HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE);
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013737}
13738
13739static void alc861_toshiba_unsol_event(struct hda_codec *codec,
13740 unsigned int res)
13741{
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013742 if ((res >> 26) == ALC880_HP_EVENT)
13743 alc861_toshiba_automute(codec);
13744}
13745
Kailang Yangdf694da2005-12-05 19:42:22 +010013746/* pcm configuration: identiacal with ALC880 */
13747#define alc861_pcm_analog_playback alc880_pcm_analog_playback
13748#define alc861_pcm_analog_capture alc880_pcm_analog_capture
13749#define alc861_pcm_digital_playback alc880_pcm_digital_playback
13750#define alc861_pcm_digital_capture alc880_pcm_digital_capture
13751
13752
13753#define ALC861_DIGOUT_NID 0x07
13754
13755static struct hda_channel_mode alc861_8ch_modes[1] = {
13756 { 8, NULL }
13757};
13758
13759static hda_nid_t alc861_dac_nids[4] = {
13760 /* front, surround, clfe, side */
13761 0x03, 0x06, 0x05, 0x04
13762};
13763
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013764static hda_nid_t alc660_dac_nids[3] = {
13765 /* front, clfe, surround */
13766 0x03, 0x05, 0x06
13767};
13768
Kailang Yangdf694da2005-12-05 19:42:22 +010013769static hda_nid_t alc861_adc_nids[1] = {
13770 /* ADC0-2 */
13771 0x08,
13772};
13773
13774static struct hda_input_mux alc861_capture_source = {
13775 .num_items = 5,
13776 .items = {
13777 { "Mic", 0x0 },
13778 { "Front Mic", 0x3 },
13779 { "Line", 0x1 },
13780 { "CD", 0x4 },
13781 { "Mixer", 0x5 },
13782 },
13783};
13784
13785/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013786static int alc861_auto_fill_dac_nids(struct alc_spec *spec,
13787 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010013788{
13789 int i;
13790 hda_nid_t nid;
13791
13792 spec->multiout.dac_nids = spec->private_dac_nids;
13793 for (i = 0; i < cfg->line_outs; i++) {
13794 nid = cfg->line_out_pins[i];
13795 if (nid) {
13796 if (i >= ARRAY_SIZE(alc861_dac_nids))
13797 continue;
13798 spec->multiout.dac_nids[i] = alc861_dac_nids[i];
13799 }
13800 }
13801 spec->multiout.num_dacs = cfg->line_outs;
13802 return 0;
13803}
13804
13805/* add playback controls from the parsed DAC table */
13806static int alc861_auto_create_multi_out_ctls(struct alc_spec *spec,
13807 const struct auto_pin_cfg *cfg)
13808{
13809 char name[32];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013810 static const char *chname[4] = {
13811 "Front", "Surround", NULL /*CLFE*/, "Side"
13812 };
Kailang Yangdf694da2005-12-05 19:42:22 +010013813 hda_nid_t nid;
13814 int i, idx, err;
13815
13816 for (i = 0; i < cfg->line_outs; i++) {
13817 nid = spec->multiout.dac_nids[i];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013818 if (!nid)
Kailang Yangdf694da2005-12-05 19:42:22 +010013819 continue;
13820 if (nid == 0x05) {
13821 /* Center/LFE */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013822 err = add_control(spec, ALC_CTL_BIND_MUTE,
13823 "Center Playback Switch",
13824 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
13825 HDA_OUTPUT));
13826 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010013827 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013828 err = add_control(spec, ALC_CTL_BIND_MUTE,
13829 "LFE Playback Switch",
13830 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
13831 HDA_OUTPUT));
13832 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010013833 return err;
13834 } else {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013835 for (idx = 0; idx < ARRAY_SIZE(alc861_dac_nids) - 1;
13836 idx++)
Kailang Yangdf694da2005-12-05 19:42:22 +010013837 if (nid == alc861_dac_nids[idx])
13838 break;
13839 sprintf(name, "%s Playback Switch", chname[idx]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013840 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
13841 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
13842 HDA_OUTPUT));
13843 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010013844 return err;
13845 }
13846 }
13847 return 0;
13848}
13849
13850static int alc861_auto_create_hp_ctls(struct alc_spec *spec, hda_nid_t pin)
13851{
13852 int err;
13853 hda_nid_t nid;
13854
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013855 if (!pin)
Kailang Yangdf694da2005-12-05 19:42:22 +010013856 return 0;
13857
13858 if ((pin >= 0x0b && pin <= 0x10) || pin == 0x1f || pin == 0x20) {
13859 nid = 0x03;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013860 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
13861 "Headphone Playback Switch",
13862 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
13863 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010013864 return err;
13865 spec->multiout.hp_nid = nid;
13866 }
13867 return 0;
13868}
13869
13870/* create playback/capture controls for input pins */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013871static int alc861_auto_create_analog_input_ctls(struct alc_spec *spec,
13872 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010013873{
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020013874 struct hda_input_mux *imux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010013875 int i, err, idx, idx1;
13876
13877 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013878 switch (cfg->input_pins[i]) {
Kailang Yangdf694da2005-12-05 19:42:22 +010013879 case 0x0c:
13880 idx1 = 1;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013881 idx = 2; /* Line In */
Kailang Yangdf694da2005-12-05 19:42:22 +010013882 break;
13883 case 0x0f:
13884 idx1 = 2;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013885 idx = 2; /* Line In */
Kailang Yangdf694da2005-12-05 19:42:22 +010013886 break;
13887 case 0x0d:
13888 idx1 = 0;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013889 idx = 1; /* Mic In */
Kailang Yangdf694da2005-12-05 19:42:22 +010013890 break;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013891 case 0x10:
Kailang Yangdf694da2005-12-05 19:42:22 +010013892 idx1 = 3;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013893 idx = 1; /* Mic In */
Kailang Yangdf694da2005-12-05 19:42:22 +010013894 break;
13895 case 0x11:
13896 idx1 = 4;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013897 idx = 0; /* CD */
Kailang Yangdf694da2005-12-05 19:42:22 +010013898 break;
13899 default:
13900 continue;
13901 }
13902
Takashi Iwai4a471b72005-12-07 13:56:29 +010013903 err = new_analog_input(spec, cfg->input_pins[i],
13904 auto_pin_cfg_labels[i], idx, 0x15);
Kailang Yangdf694da2005-12-05 19:42:22 +010013905 if (err < 0)
13906 return err;
13907
Takashi Iwai4a471b72005-12-07 13:56:29 +010013908 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
Kailang Yangdf694da2005-12-05 19:42:22 +010013909 imux->items[imux->num_items].index = idx1;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013910 imux->num_items++;
Kailang Yangdf694da2005-12-05 19:42:22 +010013911 }
13912 return 0;
13913}
13914
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013915static void alc861_auto_set_output_and_unmute(struct hda_codec *codec,
13916 hda_nid_t nid,
Kailang Yangdf694da2005-12-05 19:42:22 +010013917 int pin_type, int dac_idx)
13918{
Jacek Luczak564c5be2008-05-03 18:41:23 +020013919 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
13920 pin_type);
13921 snd_hda_codec_write(codec, dac_idx, 0, AC_VERB_SET_AMP_GAIN_MUTE,
13922 AMP_OUT_UNMUTE);
Kailang Yangdf694da2005-12-05 19:42:22 +010013923}
13924
13925static void alc861_auto_init_multi_out(struct hda_codec *codec)
13926{
13927 struct alc_spec *spec = codec->spec;
13928 int i;
13929
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013930 alc_subsystem_id(codec, 0x0e, 0x0f, 0x0b);
Kailang Yangdf694da2005-12-05 19:42:22 +010013931 for (i = 0; i < spec->autocfg.line_outs; i++) {
13932 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020013933 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangdf694da2005-12-05 19:42:22 +010013934 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020013935 alc861_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013936 spec->multiout.dac_nids[i]);
Kailang Yangdf694da2005-12-05 19:42:22 +010013937 }
13938}
13939
13940static void alc861_auto_init_hp_out(struct hda_codec *codec)
13941{
13942 struct alc_spec *spec = codec->spec;
13943 hda_nid_t pin;
13944
Takashi Iwaieb06ed82006-09-20 17:10:27 +020013945 pin = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010013946 if (pin) /* connect to front */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013947 alc861_auto_set_output_and_unmute(codec, pin, PIN_HP,
13948 spec->multiout.dac_nids[0]);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013949 pin = spec->autocfg.speaker_pins[0];
13950 if (pin)
13951 alc861_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Kailang Yangdf694da2005-12-05 19:42:22 +010013952}
13953
13954static void alc861_auto_init_analog_input(struct hda_codec *codec)
13955{
13956 struct alc_spec *spec = codec->spec;
13957 int i;
13958
13959 for (i = 0; i < AUTO_PIN_LAST; i++) {
13960 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwai23f0c042009-02-26 13:03:58 +010013961 if (nid >= 0x0c && nid <= 0x11)
13962 alc_set_input_pin(codec, nid, i);
Kailang Yangdf694da2005-12-05 19:42:22 +010013963 }
13964}
13965
13966/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013967/* return 1 if successful, 0 if the proper config is not found,
13968 * or a negative error code
13969 */
Kailang Yangdf694da2005-12-05 19:42:22 +010013970static int alc861_parse_auto_config(struct hda_codec *codec)
13971{
13972 struct alc_spec *spec = codec->spec;
13973 int err;
13974 static hda_nid_t alc861_ignore[] = { 0x1d, 0 };
13975
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013976 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
13977 alc861_ignore);
13978 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010013979 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013980 if (!spec->autocfg.line_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +010013981 return 0; /* can't find valid BIOS pin config */
13982
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013983 err = alc861_auto_fill_dac_nids(spec, &spec->autocfg);
13984 if (err < 0)
13985 return err;
13986 err = alc861_auto_create_multi_out_ctls(spec, &spec->autocfg);
13987 if (err < 0)
13988 return err;
13989 err = alc861_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
13990 if (err < 0)
13991 return err;
13992 err = alc861_auto_create_analog_input_ctls(spec, &spec->autocfg);
13993 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010013994 return err;
13995
13996 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
13997
Takashi Iwai0852d7a2009-02-11 11:35:15 +010013998 if (spec->autocfg.dig_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +010013999 spec->multiout.dig_out_nid = ALC861_DIGOUT_NID;
14000
Takashi Iwai603c4012008-07-30 15:01:44 +020014001 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010014002 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +010014003
Takashi Iwaid88897e2008-10-31 15:01:37 +010014004 add_verb(spec, alc861_auto_init_verbs);
Kailang Yangdf694da2005-12-05 19:42:22 +010014005
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020014006 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020014007 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010014008
14009 spec->adc_nids = alc861_adc_nids;
14010 spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids);
Takashi Iwaif9e336f2008-10-31 16:37:07 +010014011 set_capture_mixer(spec);
Kailang Yangdf694da2005-12-05 19:42:22 +010014012
14013 return 1;
14014}
14015
Takashi Iwaiae6b8132006-03-03 16:47:17 +010014016/* additional initialization for auto-configuration model */
14017static void alc861_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010014018{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014019 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010014020 alc861_auto_init_multi_out(codec);
14021 alc861_auto_init_hp_out(codec);
14022 alc861_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014023 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020014024 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010014025}
14026
Takashi Iwaicb53c622007-08-10 17:21:45 +020014027#ifdef CONFIG_SND_HDA_POWER_SAVE
14028static struct hda_amp_list alc861_loopbacks[] = {
14029 { 0x15, HDA_INPUT, 0 },
14030 { 0x15, HDA_INPUT, 1 },
14031 { 0x15, HDA_INPUT, 2 },
14032 { 0x15, HDA_INPUT, 3 },
14033 { } /* end */
14034};
14035#endif
14036
Kailang Yangdf694da2005-12-05 19:42:22 +010014037
14038/*
14039 * configuration and preset
14040 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010014041static const char *alc861_models[ALC861_MODEL_LAST] = {
14042 [ALC861_3ST] = "3stack",
14043 [ALC660_3ST] = "3stack-660",
14044 [ALC861_3ST_DIG] = "3stack-dig",
14045 [ALC861_6ST_DIG] = "6stack-dig",
14046 [ALC861_UNIWILL_M31] = "uniwill-m31",
14047 [ALC861_TOSHIBA] = "toshiba",
14048 [ALC861_ASUS] = "asus",
14049 [ALC861_ASUS_LAPTOP] = "asus-laptop",
14050 [ALC861_AUTO] = "auto",
14051};
14052
14053static struct snd_pci_quirk alc861_cfg_tbl[] = {
Takashi Iwai687a47b2007-01-10 11:25:58 +010014054 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010014055 SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP),
14056 SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP),
14057 SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010014058 SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP),
Kailang Yang83c34212007-07-05 11:43:05 +020014059 SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS P1-AH2", ALC861_3ST_DIG),
Tobin Davisad5e7732007-01-08 10:57:32 +010014060 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA),
Takashi Iwai341d4eb2007-07-09 17:53:18 +020014061 /* FIXME: the entry below breaks Toshiba A100 (model=auto works!)
14062 * Any other models that need this preset?
14063 */
14064 /* SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), */
Claudio Matsuokaef64adb2007-07-14 00:26:16 +020014065 SND_PCI_QUIRK(0x1462, 0x7254, "HP dx2200 (MSI MS-7254)", ALC861_3ST),
14066 SND_PCI_QUIRK(0x1462, 0x7297, "HP dx2250 (MSI MS-7297)", ALC861_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010014067 SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31),
14068 SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31),
14069 SND_PCI_QUIRK(0x1584, 0x9075, "Airis Praxis N1212", ALC861_ASUS_LAPTOP),
14070 /* FIXME: the below seems conflict */
14071 /* SND_PCI_QUIRK(0x1584, 0x9075, "Uniwill", ALC861_UNIWILL_M31), */
14072 SND_PCI_QUIRK(0x1849, 0x0660, "Asrock 939SLI32", ALC660_3ST),
14073 SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST),
Kailang Yangdf694da2005-12-05 19:42:22 +010014074 {}
14075};
14076
14077static struct alc_config_preset alc861_presets[] = {
14078 [ALC861_3ST] = {
14079 .mixers = { alc861_3ST_mixer },
14080 .init_verbs = { alc861_threestack_init_verbs },
14081 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
14082 .dac_nids = alc861_dac_nids,
14083 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
14084 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020014085 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010014086 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
14087 .adc_nids = alc861_adc_nids,
14088 .input_mux = &alc861_capture_source,
14089 },
14090 [ALC861_3ST_DIG] = {
14091 .mixers = { alc861_base_mixer },
14092 .init_verbs = { alc861_threestack_init_verbs },
14093 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
14094 .dac_nids = alc861_dac_nids,
14095 .dig_out_nid = ALC861_DIGOUT_NID,
14096 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
14097 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020014098 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010014099 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
14100 .adc_nids = alc861_adc_nids,
14101 .input_mux = &alc861_capture_source,
14102 },
14103 [ALC861_6ST_DIG] = {
14104 .mixers = { alc861_base_mixer },
14105 .init_verbs = { alc861_base_init_verbs },
14106 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
14107 .dac_nids = alc861_dac_nids,
14108 .dig_out_nid = ALC861_DIGOUT_NID,
14109 .num_channel_mode = ARRAY_SIZE(alc861_8ch_modes),
14110 .channel_mode = alc861_8ch_modes,
14111 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
14112 .adc_nids = alc861_adc_nids,
14113 .input_mux = &alc861_capture_source,
14114 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014115 [ALC660_3ST] = {
14116 .mixers = { alc861_3ST_mixer },
14117 .init_verbs = { alc861_threestack_init_verbs },
14118 .num_dacs = ARRAY_SIZE(alc660_dac_nids),
14119 .dac_nids = alc660_dac_nids,
14120 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
14121 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020014122 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014123 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
14124 .adc_nids = alc861_adc_nids,
14125 .input_mux = &alc861_capture_source,
14126 },
Takashi Iwai22309c32006-08-09 16:57:28 +020014127 [ALC861_UNIWILL_M31] = {
14128 .mixers = { alc861_uniwill_m31_mixer },
14129 .init_verbs = { alc861_uniwill_m31_init_verbs },
14130 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
14131 .dac_nids = alc861_dac_nids,
14132 .dig_out_nid = ALC861_DIGOUT_NID,
14133 .num_channel_mode = ARRAY_SIZE(alc861_uniwill_m31_modes),
14134 .channel_mode = alc861_uniwill_m31_modes,
14135 .need_dac_fix = 1,
14136 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
14137 .adc_nids = alc861_adc_nids,
14138 .input_mux = &alc861_capture_source,
14139 },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020014140 [ALC861_TOSHIBA] = {
14141 .mixers = { alc861_toshiba_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014142 .init_verbs = { alc861_base_init_verbs,
14143 alc861_toshiba_init_verbs },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020014144 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
14145 .dac_nids = alc861_dac_nids,
14146 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
14147 .channel_mode = alc883_3ST_2ch_modes,
14148 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
14149 .adc_nids = alc861_adc_nids,
14150 .input_mux = &alc861_capture_source,
14151 .unsol_event = alc861_toshiba_unsol_event,
14152 .init_hook = alc861_toshiba_automute,
14153 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014154 [ALC861_ASUS] = {
14155 .mixers = { alc861_asus_mixer },
14156 .init_verbs = { alc861_asus_init_verbs },
14157 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
14158 .dac_nids = alc861_dac_nids,
14159 .dig_out_nid = ALC861_DIGOUT_NID,
14160 .num_channel_mode = ARRAY_SIZE(alc861_asus_modes),
14161 .channel_mode = alc861_asus_modes,
14162 .need_dac_fix = 1,
14163 .hp_nid = 0x06,
14164 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
14165 .adc_nids = alc861_adc_nids,
14166 .input_mux = &alc861_capture_source,
14167 },
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010014168 [ALC861_ASUS_LAPTOP] = {
14169 .mixers = { alc861_toshiba_mixer, alc861_asus_laptop_mixer },
14170 .init_verbs = { alc861_asus_init_verbs,
14171 alc861_asus_laptop_init_verbs },
14172 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
14173 .dac_nids = alc861_dac_nids,
14174 .dig_out_nid = ALC861_DIGOUT_NID,
14175 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
14176 .channel_mode = alc883_3ST_2ch_modes,
14177 .need_dac_fix = 1,
14178 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
14179 .adc_nids = alc861_adc_nids,
14180 .input_mux = &alc861_capture_source,
14181 },
14182};
Kailang Yangdf694da2005-12-05 19:42:22 +010014183
14184
14185static int patch_alc861(struct hda_codec *codec)
14186{
14187 struct alc_spec *spec;
14188 int board_config;
14189 int err;
14190
Robert P. J. Daydc041e02006-12-19 14:44:15 +010014191 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010014192 if (spec == NULL)
14193 return -ENOMEM;
14194
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014195 codec->spec = spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010014196
Takashi Iwaif5fcc132006-11-24 17:07:44 +010014197 board_config = snd_hda_check_board_config(codec, ALC861_MODEL_LAST,
14198 alc861_models,
14199 alc861_cfg_tbl);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014200
Takashi Iwaif5fcc132006-11-24 17:07:44 +010014201 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014202 printk(KERN_INFO "hda_codec: Unknown model for ALC861, "
14203 "trying auto-probe from BIOS...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010014204 board_config = ALC861_AUTO;
14205 }
14206
14207 if (board_config == ALC861_AUTO) {
14208 /* automatic parse from the BIOS config */
14209 err = alc861_parse_auto_config(codec);
14210 if (err < 0) {
14211 alc_free(codec);
14212 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014213 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014214 printk(KERN_INFO
14215 "hda_codec: Cannot set up configuration "
14216 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010014217 board_config = ALC861_3ST_DIG;
14218 }
14219 }
14220
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090014221 err = snd_hda_attach_beep_device(codec, 0x23);
14222 if (err < 0) {
14223 alc_free(codec);
14224 return err;
14225 }
14226
Kailang Yangdf694da2005-12-05 19:42:22 +010014227 if (board_config != ALC861_AUTO)
14228 setup_preset(spec, &alc861_presets[board_config]);
14229
14230 spec->stream_name_analog = "ALC861 Analog";
14231 spec->stream_analog_playback = &alc861_pcm_analog_playback;
14232 spec->stream_analog_capture = &alc861_pcm_analog_capture;
14233
14234 spec->stream_name_digital = "ALC861 Digital";
14235 spec->stream_digital_playback = &alc861_pcm_digital_playback;
14236 spec->stream_digital_capture = &alc861_pcm_digital_capture;
14237
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010014238 set_beep_amp(spec, 0x23, 0, HDA_OUTPUT);
14239
Takashi Iwai2134ea42008-01-10 16:53:55 +010014240 spec->vmaster_nid = 0x03;
14241
Kailang Yangdf694da2005-12-05 19:42:22 +010014242 codec->patch_ops = alc_patch_ops;
14243 if (board_config == ALC861_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +010014244 spec->init_hook = alc861_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020014245#ifdef CONFIG_SND_HDA_POWER_SAVE
14246 if (!spec->loopback.amplist)
14247 spec->loopback.amplist = alc861_loopbacks;
14248#endif
Takashi Iwaidaead532008-11-28 12:55:36 +010014249 codec->proc_widget_hook = print_realtek_coef;
Kailang Yangea1fb292008-08-26 12:58:38 +020014250
Kailang Yangdf694da2005-12-05 19:42:22 +010014251 return 0;
14252}
14253
14254/*
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014255 * ALC861-VD support
14256 *
14257 * Based on ALC882
14258 *
14259 * In addition, an independent DAC
14260 */
14261#define ALC861VD_DIGOUT_NID 0x06
14262
14263static hda_nid_t alc861vd_dac_nids[4] = {
14264 /* front, surr, clfe, side surr */
14265 0x02, 0x03, 0x04, 0x05
14266};
14267
14268/* dac_nids for ALC660vd are in a different order - according to
14269 * Realtek's driver.
14270 * This should probably tesult in a different mixer for 6stack models
14271 * of ALC660vd codecs, but for now there is only 3stack mixer
14272 * - and it is the same as in 861vd.
14273 * adc_nids in ALC660vd are (is) the same as in 861vd
14274 */
14275static hda_nid_t alc660vd_dac_nids[3] = {
14276 /* front, rear, clfe, rear_surr */
14277 0x02, 0x04, 0x03
14278};
14279
14280static hda_nid_t alc861vd_adc_nids[1] = {
14281 /* ADC0 */
14282 0x09,
14283};
14284
Takashi Iwaie1406342008-02-11 18:32:32 +010014285static hda_nid_t alc861vd_capsrc_nids[1] = { 0x22 };
14286
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014287/* input MUX */
14288/* FIXME: should be a matrix-type input source selection */
14289static struct hda_input_mux alc861vd_capture_source = {
14290 .num_items = 4,
14291 .items = {
14292 { "Mic", 0x0 },
14293 { "Front Mic", 0x1 },
14294 { "Line", 0x2 },
14295 { "CD", 0x4 },
14296 },
14297};
14298
Kailang Yang272a5272007-05-14 11:00:38 +020014299static struct hda_input_mux alc861vd_dallas_capture_source = {
Tobin Davisb419f342008-03-07 11:57:51 +010014300 .num_items = 2,
Kailang Yang272a5272007-05-14 11:00:38 +020014301 .items = {
Tobin Davisb419f342008-03-07 11:57:51 +010014302 { "Ext Mic", 0x0 },
14303 { "Int Mic", 0x1 },
Kailang Yang272a5272007-05-14 11:00:38 +020014304 },
14305};
14306
Kailang Yangd1a991a2007-08-15 16:21:59 +020014307static struct hda_input_mux alc861vd_hp_capture_source = {
14308 .num_items = 2,
14309 .items = {
14310 { "Front Mic", 0x0 },
14311 { "ATAPI Mic", 0x1 },
14312 },
14313};
14314
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014315/*
14316 * 2ch mode
14317 */
14318static struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = {
14319 { 2, NULL }
14320};
14321
14322/*
14323 * 6ch mode
14324 */
14325static struct hda_verb alc861vd_6stack_ch6_init[] = {
14326 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
14327 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14328 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14329 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14330 { } /* end */
14331};
14332
14333/*
14334 * 8ch mode
14335 */
14336static struct hda_verb alc861vd_6stack_ch8_init[] = {
14337 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14338 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14339 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14340 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14341 { } /* end */
14342};
14343
14344static struct hda_channel_mode alc861vd_6stack_modes[2] = {
14345 { 6, alc861vd_6stack_ch6_init },
14346 { 8, alc861vd_6stack_ch8_init },
14347};
14348
14349static struct snd_kcontrol_new alc861vd_chmode_mixer[] = {
14350 {
14351 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
14352 .name = "Channel Mode",
14353 .info = alc_ch_mode_info,
14354 .get = alc_ch_mode_get,
14355 .put = alc_ch_mode_put,
14356 },
14357 { } /* end */
14358};
14359
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014360/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
14361 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
14362 */
14363static struct snd_kcontrol_new alc861vd_6st_mixer[] = {
14364 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14365 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
14366
14367 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
14368 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
14369
14370 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0,
14371 HDA_OUTPUT),
14372 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0,
14373 HDA_OUTPUT),
14374 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
14375 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
14376
14377 HDA_CODEC_VOLUME("Side Playback Volume", 0x05, 0x0, HDA_OUTPUT),
14378 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
14379
14380 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
14381
14382 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
14383 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14384 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14385
14386 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
14387 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14388 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14389
14390 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
14391 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
14392
14393 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
14394 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
14395
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014396 { } /* end */
14397};
14398
14399static struct snd_kcontrol_new alc861vd_3st_mixer[] = {
14400 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14401 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
14402
14403 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
14404
14405 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
14406 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14407 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14408
14409 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
14410 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14411 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14412
14413 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
14414 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
14415
14416 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
14417 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
14418
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014419 { } /* end */
14420};
14421
Kailang Yangbdd148a2007-05-08 15:19:08 +020014422static struct snd_kcontrol_new alc861vd_lenovo_mixer[] = {
14423 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14424 /*HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),*/
14425 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
14426
14427 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
14428
14429 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
14430 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14431 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14432
14433 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
14434 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14435 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14436
14437 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
14438 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
14439
14440 { } /* end */
14441};
14442
Tobin Davisb419f342008-03-07 11:57:51 +010014443/* Pin assignment: Speaker=0x14, HP = 0x15,
14444 * Ext Mic=0x18, Int Mic = 0x19, CD = 0x1c, PC Beep = 0x1d
Kailang Yang272a5272007-05-14 11:00:38 +020014445 */
14446static struct snd_kcontrol_new alc861vd_dallas_mixer[] = {
Tobin Davisb419f342008-03-07 11:57:51 +010014447 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14448 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020014449 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
14450 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
Tobin Davisb419f342008-03-07 11:57:51 +010014451 HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
14452 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14453 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14454 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
14455 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14456 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020014457 { } /* end */
14458};
14459
Kailang Yangd1a991a2007-08-15 16:21:59 +020014460/* Pin assignment: Speaker=0x14, Line-out = 0x15,
14461 * Front Mic=0x18, ATAPI Mic = 0x19,
14462 */
14463static struct snd_kcontrol_new alc861vd_hp_mixer[] = {
14464 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14465 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
14466 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
14467 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
14468 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14469 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14470 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14471 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangea1fb292008-08-26 12:58:38 +020014472
Kailang Yangd1a991a2007-08-15 16:21:59 +020014473 { } /* end */
14474};
14475
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014476/*
14477 * generic initialization of ADC, input mixers and output mixers
14478 */
14479static struct hda_verb alc861vd_volume_init_verbs[] = {
14480 /*
14481 * Unmute ADC0 and set the default input to mic-in
14482 */
14483 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
14484 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14485
14486 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of
14487 * the analog-loopback mixer widget
14488 */
14489 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020014490 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14491 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
14492 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
14493 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
14494 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014495
14496 /* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yangbdd148a2007-05-08 15:19:08 +020014497 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14498 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14499 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014500 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014501
14502 /*
14503 * Set up output mixers (0x02 - 0x05)
14504 */
14505 /* set vol=0 to output mixers */
14506 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14507 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14508 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14509 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14510
14511 /* set up input amps for analog loopback */
14512 /* Amp Indices: DAC = 0, mixer = 1 */
14513 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14514 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
14515 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14516 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
14517 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14518 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
14519 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14520 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
14521
14522 { }
14523};
14524
14525/*
14526 * 3-stack pin configuration:
14527 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
14528 */
14529static struct hda_verb alc861vd_3stack_init_verbs[] = {
14530 /*
14531 * Set pin mode and muting
14532 */
14533 /* set front pin widgets 0x14 for output */
14534 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14535 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14536 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
14537
14538 /* Mic (rear) pin: input vref at 80% */
14539 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14540 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14541 /* Front Mic pin: input vref at 80% */
14542 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14543 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14544 /* Line In pin: input */
14545 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14546 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14547 /* Line-2 In: Headphone output (output 0 - 0x0c) */
14548 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14549 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14550 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
14551 /* CD pin widget for input */
14552 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14553
14554 { }
14555};
14556
14557/*
14558 * 6-stack pin configuration:
14559 */
14560static struct hda_verb alc861vd_6stack_init_verbs[] = {
14561 /*
14562 * Set pin mode and muting
14563 */
14564 /* set front pin widgets 0x14 for output */
14565 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14566 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14567 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
14568
14569 /* Rear Pin: output 1 (0x0d) */
14570 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14571 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14572 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
14573 /* CLFE Pin: output 2 (0x0e) */
14574 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14575 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14576 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
14577 /* Side Pin: output 3 (0x0f) */
14578 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14579 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14580 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
14581
14582 /* Mic (rear) pin: input vref at 80% */
14583 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14584 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14585 /* Front Mic pin: input vref at 80% */
14586 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14587 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14588 /* Line In pin: input */
14589 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14590 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14591 /* Line-2 In: Headphone output (output 0 - 0x0c) */
14592 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14593 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14594 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
14595 /* CD pin widget for input */
14596 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14597
14598 { }
14599};
14600
Kailang Yangbdd148a2007-05-08 15:19:08 +020014601static struct hda_verb alc861vd_eapd_verbs[] = {
14602 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
14603 { }
14604};
14605
Kailang Yangf9423e72008-05-27 12:32:25 +020014606static struct hda_verb alc660vd_eapd_verbs[] = {
14607 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
14608 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
14609 { }
14610};
14611
Kailang Yangbdd148a2007-05-08 15:19:08 +020014612static struct hda_verb alc861vd_lenovo_unsol_verbs[] = {
14613 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14614 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14615 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
14616 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Kailang Yangea1fb292008-08-26 12:58:38 +020014617 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
Kailang Yangbdd148a2007-05-08 15:19:08 +020014618 {}
14619};
14620
14621/* toggle speaker-output according to the hp-jack state */
14622static void alc861vd_lenovo_hp_automute(struct hda_codec *codec)
14623{
14624 unsigned int present;
14625 unsigned char bits;
14626
14627 present = snd_hda_codec_read(codec, 0x1b, 0,
14628 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020014629 bits = present ? HDA_AMP_MUTE : 0;
14630 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
14631 HDA_AMP_MUTE, bits);
Kailang Yangbdd148a2007-05-08 15:19:08 +020014632}
14633
14634static void alc861vd_lenovo_mic_automute(struct hda_codec *codec)
14635{
14636 unsigned int present;
14637 unsigned char bits;
14638
14639 present = snd_hda_codec_read(codec, 0x18, 0,
14640 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020014641 bits = present ? HDA_AMP_MUTE : 0;
14642 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
14643 HDA_AMP_MUTE, bits);
Kailang Yangbdd148a2007-05-08 15:19:08 +020014644}
14645
14646static void alc861vd_lenovo_automute(struct hda_codec *codec)
14647{
14648 alc861vd_lenovo_hp_automute(codec);
14649 alc861vd_lenovo_mic_automute(codec);
14650}
14651
14652static void alc861vd_lenovo_unsol_event(struct hda_codec *codec,
14653 unsigned int res)
14654{
14655 switch (res >> 26) {
14656 case ALC880_HP_EVENT:
14657 alc861vd_lenovo_hp_automute(codec);
14658 break;
14659 case ALC880_MIC_EVENT:
14660 alc861vd_lenovo_mic_automute(codec);
14661 break;
14662 }
14663}
14664
Kailang Yang272a5272007-05-14 11:00:38 +020014665static struct hda_verb alc861vd_dallas_verbs[] = {
14666 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14667 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14668 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14669 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14670
14671 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14672 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14673 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14674 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
14675 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14676 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
14677 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14678 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020014679
Kailang Yang272a5272007-05-14 11:00:38 +020014680 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14681 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14682 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14683 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14684 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14685 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14686 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14687 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14688
14689 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
14690 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14691 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
14692 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14693 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14694 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14695 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14696 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14697
14698 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14699 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
14700 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
14701 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
14702
14703 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020014704 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yang272a5272007-05-14 11:00:38 +020014705 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14706
14707 { } /* end */
14708};
14709
14710/* toggle speaker-output according to the hp-jack state */
14711static void alc861vd_dallas_automute(struct hda_codec *codec)
14712{
14713 unsigned int present;
14714
14715 present = snd_hda_codec_read(codec, 0x15, 0,
14716 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020014717 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
14718 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +020014719}
14720
14721static void alc861vd_dallas_unsol_event(struct hda_codec *codec, unsigned int res)
14722{
14723 if ((res >> 26) == ALC880_HP_EVENT)
14724 alc861vd_dallas_automute(codec);
14725}
14726
Takashi Iwaicb53c622007-08-10 17:21:45 +020014727#ifdef CONFIG_SND_HDA_POWER_SAVE
14728#define alc861vd_loopbacks alc880_loopbacks
14729#endif
14730
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014731/* pcm configuration: identiacal with ALC880 */
14732#define alc861vd_pcm_analog_playback alc880_pcm_analog_playback
14733#define alc861vd_pcm_analog_capture alc880_pcm_analog_capture
14734#define alc861vd_pcm_digital_playback alc880_pcm_digital_playback
14735#define alc861vd_pcm_digital_capture alc880_pcm_digital_capture
14736
14737/*
14738 * configuration and preset
14739 */
14740static const char *alc861vd_models[ALC861VD_MODEL_LAST] = {
14741 [ALC660VD_3ST] = "3stack-660",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020014742 [ALC660VD_3ST_DIG] = "3stack-660-digout",
Takashi Iwai13c94742008-11-05 08:06:08 +010014743 [ALC660VD_ASUS_V1S] = "asus-v1s",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014744 [ALC861VD_3ST] = "3stack",
14745 [ALC861VD_3ST_DIG] = "3stack-digout",
14746 [ALC861VD_6ST_DIG] = "6stack-digout",
Kailang Yangbdd148a2007-05-08 15:19:08 +020014747 [ALC861VD_LENOVO] = "lenovo",
Kailang Yang272a5272007-05-14 11:00:38 +020014748 [ALC861VD_DALLAS] = "dallas",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020014749 [ALC861VD_HP] = "hp",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014750 [ALC861VD_AUTO] = "auto",
14751};
14752
14753static struct snd_pci_quirk alc861vd_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +010014754 SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST),
14755 SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP),
Takashi Iwai07e038b2007-02-15 18:23:41 +010014756 SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014757 SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),
Takashi Iwai13c94742008-11-05 08:06:08 +010014758 SND_PCI_QUIRK(0x1043, 0x1633, "Asus V1Sn", ALC660VD_ASUS_V1S),
Mike Crash6963f842007-06-25 12:12:51 +020014759 SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014760 SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010014761 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO),
Takashi Iwai38baf5a2007-08-16 17:52:43 +020014762 /*SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS),*/ /*lenovo*/
Kailang Yang272a5272007-05-14 11:00:38 +020014763 SND_PCI_QUIRK(0x1179, 0xff01, "DALLAS", ALC861VD_DALLAS),
Takashi Iwai542d7c62007-08-16 18:57:30 +020014764 SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO),
Tobin Davisb419f342008-03-07 11:57:51 +010014765 SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_DALLAS),
Takashi Iwai39c5d412007-08-15 16:24:17 +020014766 SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +010014767 SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", ALC861VD_LENOVO),
Tobin Davis625dc0b2007-07-30 21:42:10 +020014768 SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014769 {}
14770};
14771
14772static struct alc_config_preset alc861vd_presets[] = {
14773 [ALC660VD_3ST] = {
14774 .mixers = { alc861vd_3st_mixer },
14775 .init_verbs = { alc861vd_volume_init_verbs,
14776 alc861vd_3stack_init_verbs },
14777 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
14778 .dac_nids = alc660vd_dac_nids,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014779 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14780 .channel_mode = alc861vd_3stack_2ch_modes,
14781 .input_mux = &alc861vd_capture_source,
14782 },
Mike Crash6963f842007-06-25 12:12:51 +020014783 [ALC660VD_3ST_DIG] = {
14784 .mixers = { alc861vd_3st_mixer },
14785 .init_verbs = { alc861vd_volume_init_verbs,
14786 alc861vd_3stack_init_verbs },
14787 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
14788 .dac_nids = alc660vd_dac_nids,
14789 .dig_out_nid = ALC861VD_DIGOUT_NID,
Mike Crash6963f842007-06-25 12:12:51 +020014790 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14791 .channel_mode = alc861vd_3stack_2ch_modes,
14792 .input_mux = &alc861vd_capture_source,
14793 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014794 [ALC861VD_3ST] = {
14795 .mixers = { alc861vd_3st_mixer },
14796 .init_verbs = { alc861vd_volume_init_verbs,
14797 alc861vd_3stack_init_verbs },
14798 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
14799 .dac_nids = alc861vd_dac_nids,
14800 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14801 .channel_mode = alc861vd_3stack_2ch_modes,
14802 .input_mux = &alc861vd_capture_source,
14803 },
14804 [ALC861VD_3ST_DIG] = {
14805 .mixers = { alc861vd_3st_mixer },
14806 .init_verbs = { alc861vd_volume_init_verbs,
14807 alc861vd_3stack_init_verbs },
14808 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
14809 .dac_nids = alc861vd_dac_nids,
14810 .dig_out_nid = ALC861VD_DIGOUT_NID,
14811 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14812 .channel_mode = alc861vd_3stack_2ch_modes,
14813 .input_mux = &alc861vd_capture_source,
14814 },
14815 [ALC861VD_6ST_DIG] = {
14816 .mixers = { alc861vd_6st_mixer, alc861vd_chmode_mixer },
14817 .init_verbs = { alc861vd_volume_init_verbs,
14818 alc861vd_6stack_init_verbs },
14819 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
14820 .dac_nids = alc861vd_dac_nids,
14821 .dig_out_nid = ALC861VD_DIGOUT_NID,
14822 .num_channel_mode = ARRAY_SIZE(alc861vd_6stack_modes),
14823 .channel_mode = alc861vd_6stack_modes,
14824 .input_mux = &alc861vd_capture_source,
14825 },
Kailang Yangbdd148a2007-05-08 15:19:08 +020014826 [ALC861VD_LENOVO] = {
14827 .mixers = { alc861vd_lenovo_mixer },
14828 .init_verbs = { alc861vd_volume_init_verbs,
14829 alc861vd_3stack_init_verbs,
14830 alc861vd_eapd_verbs,
14831 alc861vd_lenovo_unsol_verbs },
14832 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
14833 .dac_nids = alc660vd_dac_nids,
Kailang Yangbdd148a2007-05-08 15:19:08 +020014834 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14835 .channel_mode = alc861vd_3stack_2ch_modes,
14836 .input_mux = &alc861vd_capture_source,
14837 .unsol_event = alc861vd_lenovo_unsol_event,
14838 .init_hook = alc861vd_lenovo_automute,
14839 },
Kailang Yang272a5272007-05-14 11:00:38 +020014840 [ALC861VD_DALLAS] = {
14841 .mixers = { alc861vd_dallas_mixer },
14842 .init_verbs = { alc861vd_dallas_verbs },
14843 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
14844 .dac_nids = alc861vd_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +020014845 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14846 .channel_mode = alc861vd_3stack_2ch_modes,
14847 .input_mux = &alc861vd_dallas_capture_source,
14848 .unsol_event = alc861vd_dallas_unsol_event,
14849 .init_hook = alc861vd_dallas_automute,
Kailang Yangd1a991a2007-08-15 16:21:59 +020014850 },
14851 [ALC861VD_HP] = {
14852 .mixers = { alc861vd_hp_mixer },
14853 .init_verbs = { alc861vd_dallas_verbs, alc861vd_eapd_verbs },
14854 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
14855 .dac_nids = alc861vd_dac_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020014856 .dig_out_nid = ALC861VD_DIGOUT_NID,
Kailang Yangd1a991a2007-08-15 16:21:59 +020014857 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14858 .channel_mode = alc861vd_3stack_2ch_modes,
14859 .input_mux = &alc861vd_hp_capture_source,
14860 .unsol_event = alc861vd_dallas_unsol_event,
14861 .init_hook = alc861vd_dallas_automute,
Kailang Yangea1fb292008-08-26 12:58:38 +020014862 },
Takashi Iwai13c94742008-11-05 08:06:08 +010014863 [ALC660VD_ASUS_V1S] = {
14864 .mixers = { alc861vd_lenovo_mixer },
14865 .init_verbs = { alc861vd_volume_init_verbs,
14866 alc861vd_3stack_init_verbs,
14867 alc861vd_eapd_verbs,
14868 alc861vd_lenovo_unsol_verbs },
14869 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
14870 .dac_nids = alc660vd_dac_nids,
14871 .dig_out_nid = ALC861VD_DIGOUT_NID,
14872 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14873 .channel_mode = alc861vd_3stack_2ch_modes,
14874 .input_mux = &alc861vd_capture_source,
14875 .unsol_event = alc861vd_lenovo_unsol_event,
14876 .init_hook = alc861vd_lenovo_automute,
14877 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014878};
14879
14880/*
14881 * BIOS auto configuration
14882 */
14883static void alc861vd_auto_set_output_and_unmute(struct hda_codec *codec,
14884 hda_nid_t nid, int pin_type, int dac_idx)
14885{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014886 alc_set_pin_output(codec, nid, pin_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014887}
14888
14889static void alc861vd_auto_init_multi_out(struct hda_codec *codec)
14890{
14891 struct alc_spec *spec = codec->spec;
14892 int i;
14893
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014894 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014895 for (i = 0; i <= HDA_SIDE; i++) {
14896 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020014897 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014898 if (nid)
14899 alc861vd_auto_set_output_and_unmute(codec, nid,
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020014900 pin_type, i);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014901 }
14902}
14903
14904
14905static void alc861vd_auto_init_hp_out(struct hda_codec *codec)
14906{
14907 struct alc_spec *spec = codec->spec;
14908 hda_nid_t pin;
14909
14910 pin = spec->autocfg.hp_pins[0];
14911 if (pin) /* connect to front and use dac 0 */
14912 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014913 pin = spec->autocfg.speaker_pins[0];
14914 if (pin)
14915 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014916}
14917
14918#define alc861vd_is_input_pin(nid) alc880_is_input_pin(nid)
14919#define ALC861VD_PIN_CD_NID ALC880_PIN_CD_NID
14920
14921static void alc861vd_auto_init_analog_input(struct hda_codec *codec)
14922{
14923 struct alc_spec *spec = codec->spec;
14924 int i;
14925
14926 for (i = 0; i < AUTO_PIN_LAST; i++) {
14927 hda_nid_t nid = spec->autocfg.input_pins[i];
14928 if (alc861vd_is_input_pin(nid)) {
Takashi Iwai23f0c042009-02-26 13:03:58 +010014929 alc_set_input_pin(codec, nid, i);
Takashi Iwaie82c0252009-03-23 15:17:38 +010014930 if (nid != ALC861VD_PIN_CD_NID &&
14931 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014932 snd_hda_codec_write(codec, nid, 0,
14933 AC_VERB_SET_AMP_GAIN_MUTE,
14934 AMP_OUT_MUTE);
14935 }
14936 }
14937}
14938
Takashi Iwaif511b012008-08-15 16:46:42 +020014939#define alc861vd_auto_init_input_src alc882_auto_init_input_src
14940
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014941#define alc861vd_idx_to_mixer_vol(nid) ((nid) + 0x02)
14942#define alc861vd_idx_to_mixer_switch(nid) ((nid) + 0x0c)
14943
14944/* add playback controls from the parsed DAC table */
14945/* Based on ALC880 version. But ALC861VD has separate,
14946 * different NIDs for mute/unmute switch and volume control */
14947static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
14948 const struct auto_pin_cfg *cfg)
14949{
14950 char name[32];
14951 static const char *chname[4] = {"Front", "Surround", "CLFE", "Side"};
14952 hda_nid_t nid_v, nid_s;
14953 int i, err;
14954
14955 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014956 if (!spec->multiout.dac_nids[i])
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014957 continue;
14958 nid_v = alc861vd_idx_to_mixer_vol(
14959 alc880_dac_to_idx(
14960 spec->multiout.dac_nids[i]));
14961 nid_s = alc861vd_idx_to_mixer_switch(
14962 alc880_dac_to_idx(
14963 spec->multiout.dac_nids[i]));
14964
14965 if (i == 2) {
14966 /* Center/LFE */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014967 err = add_control(spec, ALC_CTL_WIDGET_VOL,
14968 "Center Playback Volume",
14969 HDA_COMPOSE_AMP_VAL(nid_v, 1, 0,
14970 HDA_OUTPUT));
14971 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014972 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014973 err = add_control(spec, ALC_CTL_WIDGET_VOL,
14974 "LFE Playback Volume",
14975 HDA_COMPOSE_AMP_VAL(nid_v, 2, 0,
14976 HDA_OUTPUT));
14977 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014978 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014979 err = add_control(spec, ALC_CTL_BIND_MUTE,
14980 "Center Playback Switch",
14981 HDA_COMPOSE_AMP_VAL(nid_s, 1, 2,
14982 HDA_INPUT));
14983 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014984 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014985 err = add_control(spec, ALC_CTL_BIND_MUTE,
14986 "LFE Playback Switch",
14987 HDA_COMPOSE_AMP_VAL(nid_s, 2, 2,
14988 HDA_INPUT));
14989 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014990 return err;
14991 } else {
14992 sprintf(name, "%s Playback Volume", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014993 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
14994 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0,
14995 HDA_OUTPUT));
14996 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014997 return err;
14998 sprintf(name, "%s Playback Switch", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014999 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
Kailang Yangbdd148a2007-05-08 15:19:08 +020015000 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015001 HDA_INPUT));
15002 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015003 return err;
15004 }
15005 }
15006 return 0;
15007}
15008
15009/* add playback controls for speaker and HP outputs */
15010/* Based on ALC880 version. But ALC861VD has separate,
15011 * different NIDs for mute/unmute switch and volume control */
15012static int alc861vd_auto_create_extra_out(struct alc_spec *spec,
15013 hda_nid_t pin, const char *pfx)
15014{
15015 hda_nid_t nid_v, nid_s;
15016 int err;
15017 char name[32];
15018
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015019 if (!pin)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015020 return 0;
15021
15022 if (alc880_is_fixed_pin(pin)) {
15023 nid_v = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
15024 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015025 if (!spec->multiout.hp_nid)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015026 spec->multiout.hp_nid = nid_v;
15027 else
15028 spec->multiout.extra_out_nid[0] = nid_v;
15029 /* control HP volume/switch on the output mixer amp */
15030 nid_v = alc861vd_idx_to_mixer_vol(
15031 alc880_fixed_pin_idx(pin));
15032 nid_s = alc861vd_idx_to_mixer_switch(
15033 alc880_fixed_pin_idx(pin));
15034
15035 sprintf(name, "%s Playback Volume", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015036 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
15037 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0, HDA_OUTPUT));
15038 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015039 return err;
15040 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015041 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
15042 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2, HDA_INPUT));
15043 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015044 return err;
15045 } else if (alc880_is_multi_pin(pin)) {
15046 /* set manual connection */
15047 /* we have only a switch on HP-out PIN */
15048 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015049 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
15050 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
15051 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015052 return err;
15053 }
15054 return 0;
15055}
15056
15057/* parse the BIOS configuration and set up the alc_spec
15058 * return 1 if successful, 0 if the proper config is not found,
15059 * or a negative error code
15060 * Based on ALC880 version - had to change it to override
15061 * alc880_auto_create_extra_out and alc880_auto_create_multi_out_ctls */
15062static int alc861vd_parse_auto_config(struct hda_codec *codec)
15063{
15064 struct alc_spec *spec = codec->spec;
15065 int err;
15066 static hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
15067
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015068 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
15069 alc861vd_ignore);
15070 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015071 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015072 if (!spec->autocfg.line_outs)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015073 return 0; /* can't find valid BIOS pin config */
15074
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015075 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
15076 if (err < 0)
15077 return err;
15078 err = alc861vd_auto_create_multi_out_ctls(spec, &spec->autocfg);
15079 if (err < 0)
15080 return err;
15081 err = alc861vd_auto_create_extra_out(spec,
15082 spec->autocfg.speaker_pins[0],
15083 "Speaker");
15084 if (err < 0)
15085 return err;
15086 err = alc861vd_auto_create_extra_out(spec,
15087 spec->autocfg.hp_pins[0],
15088 "Headphone");
15089 if (err < 0)
15090 return err;
15091 err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg);
15092 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015093 return err;
15094
15095 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
15096
Takashi Iwai0852d7a2009-02-11 11:35:15 +010015097 if (spec->autocfg.dig_outs)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015098 spec->multiout.dig_out_nid = ALC861VD_DIGOUT_NID;
15099
Takashi Iwai603c4012008-07-30 15:01:44 +020015100 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010015101 add_mixer(spec, spec->kctls.list);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015102
Takashi Iwaid88897e2008-10-31 15:01:37 +010015103 add_verb(spec, alc861vd_volume_init_verbs);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015104
15105 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020015106 spec->input_mux = &spec->private_imux[0];
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015107
Takashi Iwai776e1842007-08-29 15:07:11 +020015108 err = alc_auto_add_mic_boost(codec);
15109 if (err < 0)
15110 return err;
15111
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015112 return 1;
15113}
15114
15115/* additional initialization for auto-configuration model */
15116static void alc861vd_auto_init(struct hda_codec *codec)
15117{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010015118 struct alc_spec *spec = codec->spec;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015119 alc861vd_auto_init_multi_out(codec);
15120 alc861vd_auto_init_hp_out(codec);
15121 alc861vd_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020015122 alc861vd_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010015123 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020015124 alc_inithook(codec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015125}
15126
15127static int patch_alc861vd(struct hda_codec *codec)
15128{
15129 struct alc_spec *spec;
15130 int err, board_config;
15131
15132 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
15133 if (spec == NULL)
15134 return -ENOMEM;
15135
15136 codec->spec = spec;
15137
15138 board_config = snd_hda_check_board_config(codec, ALC861VD_MODEL_LAST,
15139 alc861vd_models,
15140 alc861vd_cfg_tbl);
15141
15142 if (board_config < 0 || board_config >= ALC861VD_MODEL_LAST) {
15143 printk(KERN_INFO "hda_codec: Unknown model for ALC660VD/"
15144 "ALC861VD, trying auto-probe from BIOS...\n");
15145 board_config = ALC861VD_AUTO;
15146 }
15147
15148 if (board_config == ALC861VD_AUTO) {
15149 /* automatic parse from the BIOS config */
15150 err = alc861vd_parse_auto_config(codec);
15151 if (err < 0) {
15152 alc_free(codec);
15153 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015154 } else if (!err) {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015155 printk(KERN_INFO
15156 "hda_codec: Cannot set up configuration "
15157 "from BIOS. Using base mode...\n");
15158 board_config = ALC861VD_3ST;
15159 }
15160 }
15161
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090015162 err = snd_hda_attach_beep_device(codec, 0x23);
15163 if (err < 0) {
15164 alc_free(codec);
15165 return err;
15166 }
15167
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015168 if (board_config != ALC861VD_AUTO)
15169 setup_preset(spec, &alc861vd_presets[board_config]);
15170
Kailang Yang2f893282008-05-27 12:14:47 +020015171 if (codec->vendor_id == 0x10ec0660) {
15172 spec->stream_name_analog = "ALC660-VD Analog";
15173 spec->stream_name_digital = "ALC660-VD Digital";
Kailang Yangf9423e72008-05-27 12:32:25 +020015174 /* always turn on EAPD */
Takashi Iwaid88897e2008-10-31 15:01:37 +010015175 add_verb(spec, alc660vd_eapd_verbs);
Kailang Yang2f893282008-05-27 12:14:47 +020015176 } else {
15177 spec->stream_name_analog = "ALC861VD Analog";
15178 spec->stream_name_digital = "ALC861VD Digital";
15179 }
15180
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015181 spec->stream_analog_playback = &alc861vd_pcm_analog_playback;
15182 spec->stream_analog_capture = &alc861vd_pcm_analog_capture;
15183
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015184 spec->stream_digital_playback = &alc861vd_pcm_digital_playback;
15185 spec->stream_digital_capture = &alc861vd_pcm_digital_capture;
15186
15187 spec->adc_nids = alc861vd_adc_nids;
15188 spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids);
Takashi Iwaie1406342008-02-11 18:32:32 +010015189 spec->capsrc_nids = alc861vd_capsrc_nids;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020015190 spec->capture_style = CAPT_MIX;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015191
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015192 set_capture_mixer(spec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010015193 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015194
Takashi Iwai2134ea42008-01-10 16:53:55 +010015195 spec->vmaster_nid = 0x02;
15196
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015197 codec->patch_ops = alc_patch_ops;
15198
15199 if (board_config == ALC861VD_AUTO)
15200 spec->init_hook = alc861vd_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020015201#ifdef CONFIG_SND_HDA_POWER_SAVE
15202 if (!spec->loopback.amplist)
15203 spec->loopback.amplist = alc861vd_loopbacks;
15204#endif
Takashi Iwaidaead532008-11-28 12:55:36 +010015205 codec->proc_widget_hook = print_realtek_coef;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015206
15207 return 0;
15208}
15209
15210/*
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015211 * ALC662 support
15212 *
15213 * ALC662 is almost identical with ALC880 but has cleaner and more flexible
15214 * configuration. Each pin widget can choose any input DACs and a mixer.
15215 * Each ADC is connected from a mixer of all inputs. This makes possible
15216 * 6-channel independent captures.
15217 *
15218 * In addition, an independent DAC for the multi-playback (not used in this
15219 * driver yet).
15220 */
15221#define ALC662_DIGOUT_NID 0x06
15222#define ALC662_DIGIN_NID 0x0a
15223
15224static hda_nid_t alc662_dac_nids[4] = {
15225 /* front, rear, clfe, rear_surr */
15226 0x02, 0x03, 0x04
15227};
15228
Kailang Yang622e84c2009-04-21 07:39:04 +020015229static hda_nid_t alc272_dac_nids[2] = {
15230 0x02, 0x03
15231};
15232
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015233static hda_nid_t alc662_adc_nids[1] = {
15234 /* ADC1-2 */
15235 0x09,
15236};
Takashi Iwaie1406342008-02-11 18:32:32 +010015237
Kailang Yang622e84c2009-04-21 07:39:04 +020015238static hda_nid_t alc272_adc_nids[1] = {
15239 /* ADC1-2 */
15240 0x08,
15241};
15242
Kailang Yang77a261b2008-02-19 11:38:05 +010015243static hda_nid_t alc662_capsrc_nids[1] = { 0x22 };
Kailang Yang622e84c2009-04-21 07:39:04 +020015244static hda_nid_t alc272_capsrc_nids[1] = { 0x23 };
15245
Takashi Iwaie1406342008-02-11 18:32:32 +010015246
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015247/* input MUX */
15248/* FIXME: should be a matrix-type input source selection */
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015249static struct hda_input_mux alc662_capture_source = {
15250 .num_items = 4,
15251 .items = {
15252 { "Mic", 0x0 },
15253 { "Front Mic", 0x1 },
15254 { "Line", 0x2 },
15255 { "CD", 0x4 },
15256 },
15257};
15258
15259static struct hda_input_mux alc662_lenovo_101e_capture_source = {
15260 .num_items = 2,
15261 .items = {
15262 { "Mic", 0x1 },
15263 { "Line", 0x2 },
15264 },
15265};
Kailang Yang291702f2007-10-16 14:28:03 +020015266
15267static struct hda_input_mux alc662_eeepc_capture_source = {
15268 .num_items = 2,
15269 .items = {
15270 { "i-Mic", 0x1 },
15271 { "e-Mic", 0x0 },
15272 },
15273};
15274
Kailang Yang6dda9f42008-05-27 12:05:31 +020015275static struct hda_input_mux alc663_capture_source = {
15276 .num_items = 3,
15277 .items = {
15278 { "Mic", 0x0 },
15279 { "Front Mic", 0x1 },
15280 { "Line", 0x2 },
15281 },
15282};
15283
15284static struct hda_input_mux alc663_m51va_capture_source = {
15285 .num_items = 2,
15286 .items = {
15287 { "Ext-Mic", 0x0 },
15288 { "D-Mic", 0x9 },
15289 },
15290};
15291
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015292/*
15293 * 2ch mode
15294 */
15295static struct hda_channel_mode alc662_3ST_2ch_modes[1] = {
15296 { 2, NULL }
15297};
15298
15299/*
15300 * 2ch mode
15301 */
15302static struct hda_verb alc662_3ST_ch2_init[] = {
15303 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
15304 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
15305 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
15306 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
15307 { } /* end */
15308};
15309
15310/*
15311 * 6ch mode
15312 */
15313static struct hda_verb alc662_3ST_ch6_init[] = {
15314 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15315 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
15316 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
15317 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15318 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
15319 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
15320 { } /* end */
15321};
15322
15323static struct hda_channel_mode alc662_3ST_6ch_modes[2] = {
15324 { 2, alc662_3ST_ch2_init },
15325 { 6, alc662_3ST_ch6_init },
15326};
15327
15328/*
15329 * 2ch mode
15330 */
15331static struct hda_verb alc662_sixstack_ch6_init[] = {
15332 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15333 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15334 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15335 { } /* end */
15336};
15337
15338/*
15339 * 6ch mode
15340 */
15341static struct hda_verb alc662_sixstack_ch8_init[] = {
15342 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15343 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15344 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15345 { } /* end */
15346};
15347
15348static struct hda_channel_mode alc662_5stack_modes[2] = {
15349 { 2, alc662_sixstack_ch6_init },
15350 { 6, alc662_sixstack_ch8_init },
15351};
15352
15353/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
15354 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
15355 */
15356
15357static struct snd_kcontrol_new alc662_base_mixer[] = {
15358 /* output mixer control */
15359 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010015360 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015361 HDA_CODEC_VOLUME("Surround Playback Volume", 0x3, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010015362 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015363 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
15364 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010015365 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
15366 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015367 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
15368
15369 /*Input mixer control */
15370 HDA_CODEC_VOLUME("CD Playback Volume", 0xb, 0x4, HDA_INPUT),
15371 HDA_CODEC_MUTE("CD Playback Switch", 0xb, 0x4, HDA_INPUT),
15372 HDA_CODEC_VOLUME("Line Playback Volume", 0xb, 0x02, HDA_INPUT),
15373 HDA_CODEC_MUTE("Line Playback Switch", 0xb, 0x02, HDA_INPUT),
15374 HDA_CODEC_VOLUME("Mic Playback Volume", 0xb, 0x0, HDA_INPUT),
15375 HDA_CODEC_MUTE("Mic Playback Switch", 0xb, 0x0, HDA_INPUT),
15376 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0xb, 0x01, HDA_INPUT),
15377 HDA_CODEC_MUTE("Front Mic Playback Switch", 0xb, 0x01, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015378 { } /* end */
15379};
15380
15381static struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = {
15382 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010015383 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015384 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
15385 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
15386 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
15387 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
15388 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
15389 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15390 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15391 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15392 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015393 { } /* end */
15394};
15395
15396static struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = {
15397 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010015398 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015399 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010015400 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015401 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
15402 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010015403 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
15404 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015405 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
15406 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
15407 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
15408 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
15409 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
15410 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15411 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15412 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15413 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015414 { } /* end */
15415};
15416
15417static struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = {
15418 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15419 HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010015420 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x03, 0x0, HDA_OUTPUT),
15421 HDA_BIND_MUTE("Speaker Playback Switch", 0x03, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015422 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
15423 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
15424 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
15425 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15426 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015427 { } /* end */
15428};
15429
Kailang Yang291702f2007-10-16 14:28:03 +020015430static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = {
Takashi Iwai86cd9292008-01-28 18:09:56 +010015431 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang291702f2007-10-16 14:28:03 +020015432
Herton Ronaldo Krzesinskib4818492008-02-23 11:34:12 +010015433 HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15434 HDA_CODEC_MUTE("Line-Out Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yang291702f2007-10-16 14:28:03 +020015435
15436 HDA_CODEC_VOLUME("e-Mic Boost", 0x18, 0, HDA_INPUT),
15437 HDA_CODEC_VOLUME("e-Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15438 HDA_CODEC_MUTE("e-Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15439
15440 HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT),
15441 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15442 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
15443 { } /* end */
15444};
15445
Kailang Yang8c427222008-01-10 13:03:59 +010015446static struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = {
Takashi Iwai31bffaa2008-02-27 16:10:44 +010015447 HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15448 HDA_CODEC_MUTE("Line-Out Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010015449 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
15450 HDA_BIND_MUTE("Surround Playback Switch", 0x03, 2, HDA_INPUT),
15451 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
15452 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
15453 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x04, 1, 2, HDA_INPUT),
15454 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x04, 2, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010015455 HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010015456 HDA_BIND_MUTE("MuteCtrl Playback Switch", 0x0c, 2, HDA_INPUT),
15457 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
15458 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
15459 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15460 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15461 { } /* end */
15462};
15463
Kailang Yangf1d4e282008-08-26 14:03:29 +020015464static struct hda_bind_ctls alc663_asus_bind_master_vol = {
15465 .ops = &snd_hda_bind_vol,
15466 .values = {
15467 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
15468 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
15469 0
15470 },
15471};
15472
15473static struct hda_bind_ctls alc663_asus_one_bind_switch = {
15474 .ops = &snd_hda_bind_sw,
15475 .values = {
15476 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
15477 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
15478 0
15479 },
15480};
15481
Kailang Yang6dda9f42008-05-27 12:05:31 +020015482static struct snd_kcontrol_new alc663_m51va_mixer[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020015483 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
15484 HDA_BIND_SW("Master Playback Switch", &alc663_asus_one_bind_switch),
15485 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15486 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15487 { } /* end */
15488};
15489
15490static struct hda_bind_ctls alc663_asus_tree_bind_switch = {
15491 .ops = &snd_hda_bind_sw,
15492 .values = {
15493 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
15494 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
15495 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
15496 0
15497 },
15498};
15499
15500static struct snd_kcontrol_new alc663_two_hp_m1_mixer[] = {
15501 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
15502 HDA_BIND_SW("Master Playback Switch", &alc663_asus_tree_bind_switch),
15503 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15504 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15505 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15506 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
15507
15508 { } /* end */
15509};
15510
15511static struct hda_bind_ctls alc663_asus_four_bind_switch = {
15512 .ops = &snd_hda_bind_sw,
15513 .values = {
15514 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
15515 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
15516 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
15517 0
15518 },
15519};
15520
15521static struct snd_kcontrol_new alc663_two_hp_m2_mixer[] = {
15522 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
15523 HDA_BIND_SW("Master Playback Switch", &alc663_asus_four_bind_switch),
15524 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15525 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15526 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15527 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
15528 { } /* end */
15529};
15530
15531static struct snd_kcontrol_new alc662_1bjd_mixer[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020015532 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15533 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020015534 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
15535 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15536 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15537 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15538 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
15539 { } /* end */
15540};
15541
15542static struct hda_bind_ctls alc663_asus_two_bind_master_vol = {
15543 .ops = &snd_hda_bind_vol,
15544 .values = {
15545 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
15546 HDA_COMPOSE_AMP_VAL(0x04, 3, 0, HDA_OUTPUT),
15547 0
15548 },
15549};
15550
15551static struct hda_bind_ctls alc663_asus_two_bind_switch = {
15552 .ops = &snd_hda_bind_sw,
15553 .values = {
15554 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
15555 HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT),
15556 0
15557 },
15558};
15559
15560static struct snd_kcontrol_new alc663_asus_21jd_clfe_mixer[] = {
15561 HDA_BIND_VOL("Master Playback Volume",
15562 &alc663_asus_two_bind_master_vol),
15563 HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
15564 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020015565 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
15566 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15567 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020015568 { } /* end */
15569};
15570
15571static struct snd_kcontrol_new alc663_asus_15jd_clfe_mixer[] = {
15572 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
15573 HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
15574 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
15575 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
15576 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15577 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020015578 { } /* end */
15579};
15580
15581static struct snd_kcontrol_new alc663_g71v_mixer[] = {
15582 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15583 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
15584 HDA_CODEC_VOLUME("Front Playback Volume", 0x03, 0x0, HDA_OUTPUT),
15585 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
15586 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
15587
15588 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15589 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15590 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15591 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
15592 { } /* end */
15593};
15594
15595static struct snd_kcontrol_new alc663_g50v_mixer[] = {
15596 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15597 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
15598 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
15599
15600 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15601 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15602 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15603 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
15604 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
15605 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
15606 { } /* end */
15607};
15608
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015609static struct snd_kcontrol_new alc662_chmode_mixer[] = {
15610 {
15611 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
15612 .name = "Channel Mode",
15613 .info = alc_ch_mode_info,
15614 .get = alc_ch_mode_get,
15615 .put = alc_ch_mode_put,
15616 },
15617 { } /* end */
15618};
15619
15620static struct hda_verb alc662_init_verbs[] = {
15621 /* ADC: mute amp left and right */
15622 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15623 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
15624 /* Front mixer: unmute input/output amp left and right (volume = 0) */
15625
Takashi Iwaicb53c622007-08-10 17:21:45 +020015626 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15627 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15628 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
15629 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
15630 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015631
Kailang Yangb60dd392007-09-20 12:50:29 +020015632 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15633 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15634 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15635 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15636 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15637 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015638
15639 /* Front Pin: output 0 (0x0c) */
15640 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
15641 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15642
15643 /* Rear Pin: output 1 (0x0d) */
15644 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
15645 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15646
15647 /* CLFE Pin: output 2 (0x0e) */
15648 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
15649 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15650
15651 /* Mic (rear) pin: input vref at 80% */
15652 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
15653 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15654 /* Front Mic pin: input vref at 80% */
15655 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
15656 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15657 /* Line In pin: input */
15658 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15659 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15660 /* Line-2 In: Headphone output (output 0 - 0x0c) */
15661 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15662 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15663 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
15664 /* CD pin widget for input */
15665 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15666
15667 /* FIXME: use matrix-type input source selection */
15668 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
15669 /* Input mixer */
15670 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yang291702f2007-10-16 14:28:03 +020015671 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yang6dda9f42008-05-27 12:05:31 +020015672
15673 /* always trun on EAPD */
15674 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
15675 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
15676
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015677 { }
15678};
15679
15680static struct hda_verb alc662_sue_init_verbs[] = {
15681 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
15682 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
Kailang Yang291702f2007-10-16 14:28:03 +020015683 {}
15684};
15685
15686static struct hda_verb alc662_eeepc_sue_init_verbs[] = {
15687 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15688 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15689 {}
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015690};
15691
Kailang Yang8c427222008-01-10 13:03:59 +010015692/* Set Unsolicited Event*/
15693static struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = {
15694 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
15695 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15696 {}
15697};
15698
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015699/*
15700 * generic initialization of ADC, input mixers and output mixers
15701 */
15702static struct hda_verb alc662_auto_init_verbs[] = {
15703 /*
15704 * Unmute ADC and set the default input to mic-in
15705 */
15706 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
15707 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15708
15709 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
15710 * mixer widget
15711 * Note: PASD motherboards uses the Line In 2 as the input for front
15712 * panel mic (mic 2)
15713 */
15714 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020015715 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15716 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15717 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
15718 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
15719 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015720
15721 /*
15722 * Set up output mixers (0x0c - 0x0f)
15723 */
15724 /* set vol=0 to output mixers */
15725 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
15726 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
15727 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
15728
15729 /* set up input amps for analog loopback */
15730 /* Amp Indices: DAC = 0, mixer = 1 */
Kailang Yangb60dd392007-09-20 12:50:29 +020015731 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15732 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15733 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15734 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15735 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15736 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015737
15738
15739 /* FIXME: use matrix-type input source selection */
15740 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
15741 /* Input mixer */
15742 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangd1a991a2007-08-15 16:21:59 +020015743 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015744 { }
15745};
15746
Takashi Iwai24fb9172008-09-02 14:48:20 +020015747/* additional verbs for ALC663 */
15748static struct hda_verb alc663_auto_init_verbs[] = {
15749 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15750 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15751 { }
15752};
15753
Kailang Yang6dda9f42008-05-27 12:05:31 +020015754static struct hda_verb alc663_m51va_init_verbs[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020015755 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15756 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yang6dda9f42008-05-27 12:05:31 +020015757 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15758 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangf1d4e282008-08-26 14:03:29 +020015759 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
15760 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15761 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
Kailang Yang6dda9f42008-05-27 12:05:31 +020015762 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15763 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15764 {}
15765};
15766
Kailang Yangf1d4e282008-08-26 14:03:29 +020015767static struct hda_verb alc663_21jd_amic_init_verbs[] = {
15768 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15769 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15770 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
15771 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15772 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15773 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15774 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15775 {}
15776};
15777
15778static struct hda_verb alc662_1bjd_amic_init_verbs[] = {
15779 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15780 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15781 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15782 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
15783 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15784 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15785 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15786 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15787 {}
15788};
15789
15790static struct hda_verb alc663_15jd_amic_init_verbs[] = {
15791 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15792 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15793 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
15794 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15795 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15796 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15797 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15798 {}
15799};
15800
15801static struct hda_verb alc663_two_hp_amic_m1_init_verbs[] = {
15802 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15803 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15804 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15805 {0x21, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */
15806 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15807 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15808 {0x15, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */
15809 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15810 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15811 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15812 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15813 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15814 {}
15815};
15816
15817static struct hda_verb alc663_two_hp_amic_m2_init_verbs[] = {
15818 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15819 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15820 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15821 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
15822 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15823 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15824 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
15825 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15826 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15827 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15828 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15829 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15830 {}
15831};
15832
Kailang Yang6dda9f42008-05-27 12:05:31 +020015833static struct hda_verb alc663_g71v_init_verbs[] = {
15834 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15835 /* {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
15836 /* {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, */ /* Headphone */
15837
15838 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15839 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15840 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
15841
15842 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
15843 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_MIC_EVENT},
15844 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
15845 {}
15846};
15847
15848static struct hda_verb alc663_g50v_init_verbs[] = {
15849 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15850 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15851 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
15852
15853 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15854 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15855 {}
15856};
15857
Kailang Yangf1d4e282008-08-26 14:03:29 +020015858static struct hda_verb alc662_ecs_init_verbs[] = {
15859 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
15860 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15861 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15862 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15863 {}
15864};
15865
Kailang Yang622e84c2009-04-21 07:39:04 +020015866static struct hda_verb alc272_dell_zm1_init_verbs[] = {
15867 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15868 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15869 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15870 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15871 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15872 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15873 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
15874 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15875 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
15876 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15877 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15878 {}
15879};
15880
15881static struct hda_verb alc272_dell_init_verbs[] = {
15882 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15883 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15884 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15885 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15886 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15887 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15888 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
15889 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15890 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
15891 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15892 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15893 {}
15894};
15895
Kailang Yangf1d4e282008-08-26 14:03:29 +020015896static struct snd_kcontrol_new alc662_auto_capture_mixer[] = {
15897 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
15898 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
15899 { } /* end */
15900};
15901
Kailang Yang622e84c2009-04-21 07:39:04 +020015902static struct snd_kcontrol_new alc272_auto_capture_mixer[] = {
15903 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
15904 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
15905 { } /* end */
15906};
15907
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015908static void alc662_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
15909{
15910 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015911 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015912
15913 present = snd_hda_codec_read(codec, 0x14, 0,
15914 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020015915 bits = present ? HDA_AMP_MUTE : 0;
15916 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
15917 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015918}
15919
15920static void alc662_lenovo_101e_all_automute(struct hda_codec *codec)
15921{
15922 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015923 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015924
15925 present = snd_hda_codec_read(codec, 0x1b, 0,
15926 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020015927 bits = present ? HDA_AMP_MUTE : 0;
15928 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
15929 HDA_AMP_MUTE, bits);
15930 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
15931 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015932}
15933
15934static void alc662_lenovo_101e_unsol_event(struct hda_codec *codec,
15935 unsigned int res)
15936{
15937 if ((res >> 26) == ALC880_HP_EVENT)
15938 alc662_lenovo_101e_all_automute(codec);
15939 if ((res >> 26) == ALC880_FRONT_EVENT)
15940 alc662_lenovo_101e_ispeaker_automute(codec);
15941}
15942
Kailang Yang291702f2007-10-16 14:28:03 +020015943static void alc662_eeepc_mic_automute(struct hda_codec *codec)
15944{
15945 unsigned int present;
15946
15947 present = snd_hda_codec_read(codec, 0x18, 0,
15948 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
15949 snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
15950 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
15951 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
15952 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
15953 snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
15954 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
15955 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
15956 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
15957}
15958
15959/* unsolicited event for HP jack sensing */
15960static void alc662_eeepc_unsol_event(struct hda_codec *codec,
15961 unsigned int res)
15962{
15963 if ((res >> 26) == ALC880_HP_EVENT)
15964 alc262_hippo1_automute( codec );
15965
15966 if ((res >> 26) == ALC880_MIC_EVENT)
15967 alc662_eeepc_mic_automute(codec);
15968}
15969
15970static void alc662_eeepc_inithook(struct hda_codec *codec)
15971{
15972 alc262_hippo1_automute( codec );
15973 alc662_eeepc_mic_automute(codec);
15974}
15975
Kailang Yang8c427222008-01-10 13:03:59 +010015976static void alc662_eeepc_ep20_automute(struct hda_codec *codec)
15977{
15978 unsigned int mute;
15979 unsigned int present;
15980
15981 snd_hda_codec_read(codec, 0x14, 0, AC_VERB_SET_PIN_SENSE, 0);
15982 present = snd_hda_codec_read(codec, 0x14, 0,
15983 AC_VERB_GET_PIN_SENSE, 0);
15984 present = (present & 0x80000000) != 0;
15985 if (present) {
15986 /* mute internal speaker */
15987 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +020015988 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yang8c427222008-01-10 13:03:59 +010015989 } else {
15990 /* unmute internal speaker if necessary */
15991 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
15992 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +020015993 HDA_AMP_MUTE, mute);
Kailang Yang8c427222008-01-10 13:03:59 +010015994 }
15995}
15996
15997/* unsolicited event for HP jack sensing */
15998static void alc662_eeepc_ep20_unsol_event(struct hda_codec *codec,
15999 unsigned int res)
16000{
16001 if ((res >> 26) == ALC880_HP_EVENT)
16002 alc662_eeepc_ep20_automute(codec);
16003}
16004
16005static void alc662_eeepc_ep20_inithook(struct hda_codec *codec)
16006{
16007 alc662_eeepc_ep20_automute(codec);
16008}
16009
Kailang Yang6dda9f42008-05-27 12:05:31 +020016010static void alc663_m51va_speaker_automute(struct hda_codec *codec)
16011{
16012 unsigned int present;
16013 unsigned char bits;
16014
16015 present = snd_hda_codec_read(codec, 0x21, 0,
Kailang Yangf1d4e282008-08-26 14:03:29 +020016016 AC_VERB_GET_PIN_SENSE, 0)
16017 & AC_PINSENSE_PRESENCE;
Kailang Yang6dda9f42008-05-27 12:05:31 +020016018 bits = present ? HDA_AMP_MUTE : 0;
Kailang Yangf1d4e282008-08-26 14:03:29 +020016019 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
16020 AMP_IN_MUTE(0), bits);
16021 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
16022 AMP_IN_MUTE(0), bits);
16023}
16024
16025static void alc663_21jd_two_speaker_automute(struct hda_codec *codec)
16026{
16027 unsigned int present;
16028 unsigned char bits;
16029
16030 present = snd_hda_codec_read(codec, 0x21, 0,
16031 AC_VERB_GET_PIN_SENSE, 0)
16032 & AC_PINSENSE_PRESENCE;
16033 bits = present ? HDA_AMP_MUTE : 0;
16034 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
16035 AMP_IN_MUTE(0), bits);
16036 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
16037 AMP_IN_MUTE(0), bits);
16038 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0,
16039 AMP_IN_MUTE(0), bits);
16040 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1,
16041 AMP_IN_MUTE(0), bits);
16042}
16043
16044static void alc663_15jd_two_speaker_automute(struct hda_codec *codec)
16045{
16046 unsigned int present;
16047 unsigned char bits;
16048
16049 present = snd_hda_codec_read(codec, 0x15, 0,
16050 AC_VERB_GET_PIN_SENSE, 0)
16051 & AC_PINSENSE_PRESENCE;
16052 bits = present ? HDA_AMP_MUTE : 0;
16053 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
16054 AMP_IN_MUTE(0), bits);
16055 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
16056 AMP_IN_MUTE(0), bits);
16057 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0,
16058 AMP_IN_MUTE(0), bits);
16059 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1,
16060 AMP_IN_MUTE(0), bits);
16061}
16062
16063static void alc662_f5z_speaker_automute(struct hda_codec *codec)
16064{
16065 unsigned int present;
16066 unsigned char bits;
16067
16068 present = snd_hda_codec_read(codec, 0x1b, 0,
16069 AC_VERB_GET_PIN_SENSE, 0)
16070 & AC_PINSENSE_PRESENCE;
16071 bits = present ? 0 : PIN_OUT;
16072 snd_hda_codec_write(codec, 0x14, 0,
16073 AC_VERB_SET_PIN_WIDGET_CONTROL, bits);
16074}
16075
16076static void alc663_two_hp_m1_speaker_automute(struct hda_codec *codec)
16077{
16078 unsigned int present1, present2;
16079
16080 present1 = snd_hda_codec_read(codec, 0x21, 0,
16081 AC_VERB_GET_PIN_SENSE, 0)
16082 & AC_PINSENSE_PRESENCE;
16083 present2 = snd_hda_codec_read(codec, 0x15, 0,
16084 AC_VERB_GET_PIN_SENSE, 0)
16085 & AC_PINSENSE_PRESENCE;
16086
16087 if (present1 || present2) {
16088 snd_hda_codec_write_cache(codec, 0x14, 0,
16089 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
16090 } else {
16091 snd_hda_codec_write_cache(codec, 0x14, 0,
16092 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
16093 }
16094}
16095
16096static void alc663_two_hp_m2_speaker_automute(struct hda_codec *codec)
16097{
16098 unsigned int present1, present2;
16099
16100 present1 = snd_hda_codec_read(codec, 0x1b, 0,
16101 AC_VERB_GET_PIN_SENSE, 0)
16102 & AC_PINSENSE_PRESENCE;
16103 present2 = snd_hda_codec_read(codec, 0x15, 0,
16104 AC_VERB_GET_PIN_SENSE, 0)
16105 & AC_PINSENSE_PRESENCE;
16106
16107 if (present1 || present2) {
16108 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
16109 AMP_IN_MUTE(0), AMP_IN_MUTE(0));
16110 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
16111 AMP_IN_MUTE(0), AMP_IN_MUTE(0));
16112 } else {
16113 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
16114 AMP_IN_MUTE(0), 0);
16115 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
16116 AMP_IN_MUTE(0), 0);
16117 }
Kailang Yang6dda9f42008-05-27 12:05:31 +020016118}
16119
16120static void alc663_m51va_mic_automute(struct hda_codec *codec)
16121{
16122 unsigned int present;
16123
16124 present = snd_hda_codec_read(codec, 0x18, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +020016125 AC_VERB_GET_PIN_SENSE, 0)
16126 & AC_PINSENSE_PRESENCE;
Kailang Yang6dda9f42008-05-27 12:05:31 +020016127 snd_hda_codec_write_cache(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangea1fb292008-08-26 12:58:38 +020016128 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
Kailang Yang6dda9f42008-05-27 12:05:31 +020016129 snd_hda_codec_write_cache(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangea1fb292008-08-26 12:58:38 +020016130 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
Kailang Yang6dda9f42008-05-27 12:05:31 +020016131 snd_hda_codec_write_cache(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangea1fb292008-08-26 12:58:38 +020016132 0x7000 | (0x09 << 8) | (present ? 0x80 : 0));
Kailang Yang6dda9f42008-05-27 12:05:31 +020016133 snd_hda_codec_write_cache(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangea1fb292008-08-26 12:58:38 +020016134 0x7000 | (0x09 << 8) | (present ? 0x80 : 0));
Kailang Yang6dda9f42008-05-27 12:05:31 +020016135}
16136
16137static void alc663_m51va_unsol_event(struct hda_codec *codec,
16138 unsigned int res)
16139{
16140 switch (res >> 26) {
16141 case ALC880_HP_EVENT:
16142 alc663_m51va_speaker_automute(codec);
16143 break;
16144 case ALC880_MIC_EVENT:
16145 alc663_m51va_mic_automute(codec);
16146 break;
16147 }
16148}
16149
16150static void alc663_m51va_inithook(struct hda_codec *codec)
16151{
16152 alc663_m51va_speaker_automute(codec);
16153 alc663_m51va_mic_automute(codec);
16154}
16155
Kailang Yangf1d4e282008-08-26 14:03:29 +020016156/* ***************** Mode1 ******************************/
16157static void alc663_mode1_unsol_event(struct hda_codec *codec,
16158 unsigned int res)
16159{
16160 switch (res >> 26) {
16161 case ALC880_HP_EVENT:
16162 alc663_m51va_speaker_automute(codec);
16163 break;
16164 case ALC880_MIC_EVENT:
16165 alc662_eeepc_mic_automute(codec);
16166 break;
16167 }
16168}
16169
16170static void alc663_mode1_inithook(struct hda_codec *codec)
16171{
16172 alc663_m51va_speaker_automute(codec);
16173 alc662_eeepc_mic_automute(codec);
16174}
16175/* ***************** Mode2 ******************************/
16176static void alc662_mode2_unsol_event(struct hda_codec *codec,
16177 unsigned int res)
16178{
16179 switch (res >> 26) {
16180 case ALC880_HP_EVENT:
16181 alc662_f5z_speaker_automute(codec);
16182 break;
16183 case ALC880_MIC_EVENT:
16184 alc662_eeepc_mic_automute(codec);
16185 break;
16186 }
16187}
16188
16189static void alc662_mode2_inithook(struct hda_codec *codec)
16190{
16191 alc662_f5z_speaker_automute(codec);
16192 alc662_eeepc_mic_automute(codec);
16193}
16194/* ***************** Mode3 ******************************/
16195static void alc663_mode3_unsol_event(struct hda_codec *codec,
16196 unsigned int res)
16197{
16198 switch (res >> 26) {
16199 case ALC880_HP_EVENT:
16200 alc663_two_hp_m1_speaker_automute(codec);
16201 break;
16202 case ALC880_MIC_EVENT:
16203 alc662_eeepc_mic_automute(codec);
16204 break;
16205 }
16206}
16207
16208static void alc663_mode3_inithook(struct hda_codec *codec)
16209{
16210 alc663_two_hp_m1_speaker_automute(codec);
16211 alc662_eeepc_mic_automute(codec);
16212}
16213/* ***************** Mode4 ******************************/
16214static void alc663_mode4_unsol_event(struct hda_codec *codec,
16215 unsigned int res)
16216{
16217 switch (res >> 26) {
16218 case ALC880_HP_EVENT:
16219 alc663_21jd_two_speaker_automute(codec);
16220 break;
16221 case ALC880_MIC_EVENT:
16222 alc662_eeepc_mic_automute(codec);
16223 break;
16224 }
16225}
16226
16227static void alc663_mode4_inithook(struct hda_codec *codec)
16228{
16229 alc663_21jd_two_speaker_automute(codec);
16230 alc662_eeepc_mic_automute(codec);
16231}
16232/* ***************** Mode5 ******************************/
16233static void alc663_mode5_unsol_event(struct hda_codec *codec,
16234 unsigned int res)
16235{
16236 switch (res >> 26) {
16237 case ALC880_HP_EVENT:
16238 alc663_15jd_two_speaker_automute(codec);
16239 break;
16240 case ALC880_MIC_EVENT:
16241 alc662_eeepc_mic_automute(codec);
16242 break;
16243 }
16244}
16245
16246static void alc663_mode5_inithook(struct hda_codec *codec)
16247{
16248 alc663_15jd_two_speaker_automute(codec);
16249 alc662_eeepc_mic_automute(codec);
16250}
16251/* ***************** Mode6 ******************************/
16252static void alc663_mode6_unsol_event(struct hda_codec *codec,
16253 unsigned int res)
16254{
16255 switch (res >> 26) {
16256 case ALC880_HP_EVENT:
16257 alc663_two_hp_m2_speaker_automute(codec);
16258 break;
16259 case ALC880_MIC_EVENT:
16260 alc662_eeepc_mic_automute(codec);
16261 break;
16262 }
16263}
16264
16265static void alc663_mode6_inithook(struct hda_codec *codec)
16266{
16267 alc663_two_hp_m2_speaker_automute(codec);
16268 alc662_eeepc_mic_automute(codec);
16269}
16270
Kailang Yang6dda9f42008-05-27 12:05:31 +020016271static void alc663_g71v_hp_automute(struct hda_codec *codec)
16272{
16273 unsigned int present;
16274 unsigned char bits;
16275
16276 present = snd_hda_codec_read(codec, 0x21, 0,
16277 AC_VERB_GET_PIN_SENSE, 0)
16278 & AC_PINSENSE_PRESENCE;
16279 bits = present ? HDA_AMP_MUTE : 0;
16280 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
16281 HDA_AMP_MUTE, bits);
16282 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
16283 HDA_AMP_MUTE, bits);
16284}
16285
16286static void alc663_g71v_front_automute(struct hda_codec *codec)
16287{
16288 unsigned int present;
16289 unsigned char bits;
16290
16291 present = snd_hda_codec_read(codec, 0x15, 0,
16292 AC_VERB_GET_PIN_SENSE, 0)
16293 & AC_PINSENSE_PRESENCE;
16294 bits = present ? HDA_AMP_MUTE : 0;
16295 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
16296 HDA_AMP_MUTE, bits);
16297}
16298
16299static void alc663_g71v_unsol_event(struct hda_codec *codec,
16300 unsigned int res)
16301{
16302 switch (res >> 26) {
16303 case ALC880_HP_EVENT:
16304 alc663_g71v_hp_automute(codec);
16305 break;
16306 case ALC880_FRONT_EVENT:
16307 alc663_g71v_front_automute(codec);
16308 break;
16309 case ALC880_MIC_EVENT:
16310 alc662_eeepc_mic_automute(codec);
16311 break;
16312 }
16313}
16314
16315static void alc663_g71v_inithook(struct hda_codec *codec)
16316{
16317 alc663_g71v_front_automute(codec);
16318 alc663_g71v_hp_automute(codec);
16319 alc662_eeepc_mic_automute(codec);
16320}
16321
16322static void alc663_g50v_unsol_event(struct hda_codec *codec,
16323 unsigned int res)
16324{
16325 switch (res >> 26) {
16326 case ALC880_HP_EVENT:
16327 alc663_m51va_speaker_automute(codec);
16328 break;
16329 case ALC880_MIC_EVENT:
16330 alc662_eeepc_mic_automute(codec);
16331 break;
16332 }
16333}
16334
16335static void alc663_g50v_inithook(struct hda_codec *codec)
16336{
16337 alc663_m51va_speaker_automute(codec);
16338 alc662_eeepc_mic_automute(codec);
16339}
16340
Kailang Yangf1d4e282008-08-26 14:03:29 +020016341/* bind hp and internal speaker mute (with plug check) */
16342static int alc662_ecs_master_sw_put(struct snd_kcontrol *kcontrol,
16343 struct snd_ctl_elem_value *ucontrol)
16344{
16345 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
16346 long *valp = ucontrol->value.integer.value;
16347 int change;
16348
16349 change = snd_hda_codec_amp_update(codec, 0x1b, 0, HDA_OUTPUT, 0,
16350 HDA_AMP_MUTE,
16351 valp[0] ? 0 : HDA_AMP_MUTE);
16352 change |= snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0,
16353 HDA_AMP_MUTE,
16354 valp[1] ? 0 : HDA_AMP_MUTE);
16355 if (change)
16356 alc262_hippo1_automute(codec);
16357 return change;
16358}
16359
16360static struct snd_kcontrol_new alc662_ecs_mixer[] = {
16361 HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16362 {
16363 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
16364 .name = "Master Playback Switch",
16365 .info = snd_hda_mixer_amp_switch_info,
16366 .get = snd_hda_mixer_amp_switch_get,
16367 .put = alc662_ecs_master_sw_put,
16368 .private_value = HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
16369 },
16370
16371 HDA_CODEC_VOLUME("e-Mic/LineIn Boost", 0x18, 0, HDA_INPUT),
16372 HDA_CODEC_VOLUME("e-Mic/LineIn Playback Volume", 0x0b, 0x0, HDA_INPUT),
16373 HDA_CODEC_MUTE("e-Mic/LineIn Playback Switch", 0x0b, 0x0, HDA_INPUT),
16374
16375 HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT),
16376 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16377 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16378 { } /* end */
16379};
16380
Takashi Iwaicb53c622007-08-10 17:21:45 +020016381#ifdef CONFIG_SND_HDA_POWER_SAVE
16382#define alc662_loopbacks alc880_loopbacks
16383#endif
16384
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016385
16386/* pcm configuration: identiacal with ALC880 */
16387#define alc662_pcm_analog_playback alc880_pcm_analog_playback
16388#define alc662_pcm_analog_capture alc880_pcm_analog_capture
16389#define alc662_pcm_digital_playback alc880_pcm_digital_playback
16390#define alc662_pcm_digital_capture alc880_pcm_digital_capture
16391
16392/*
16393 * configuration and preset
16394 */
16395static const char *alc662_models[ALC662_MODEL_LAST] = {
16396 [ALC662_3ST_2ch_DIG] = "3stack-dig",
16397 [ALC662_3ST_6ch_DIG] = "3stack-6ch-dig",
16398 [ALC662_3ST_6ch] = "3stack-6ch",
16399 [ALC662_5ST_DIG] = "6stack-dig",
16400 [ALC662_LENOVO_101E] = "lenovo-101e",
Takashi Iwaib995d762007-10-17 10:41:06 +020016401 [ALC662_ASUS_EEEPC_P701] = "eeepc-p701",
Kailang Yang8c427222008-01-10 13:03:59 +010016402 [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20",
Kailang Yangf1d4e282008-08-26 14:03:29 +020016403 [ALC662_ECS] = "ecs",
Kailang Yang6dda9f42008-05-27 12:05:31 +020016404 [ALC663_ASUS_M51VA] = "m51va",
16405 [ALC663_ASUS_G71V] = "g71v",
16406 [ALC663_ASUS_H13] = "h13",
16407 [ALC663_ASUS_G50V] = "g50v",
Kailang Yangf1d4e282008-08-26 14:03:29 +020016408 [ALC663_ASUS_MODE1] = "asus-mode1",
16409 [ALC662_ASUS_MODE2] = "asus-mode2",
16410 [ALC663_ASUS_MODE3] = "asus-mode3",
16411 [ALC663_ASUS_MODE4] = "asus-mode4",
16412 [ALC663_ASUS_MODE5] = "asus-mode5",
16413 [ALC663_ASUS_MODE6] = "asus-mode6",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016414 [ALC662_AUTO] = "auto",
16415};
16416
16417static struct snd_pci_quirk alc662_cfg_tbl[] = {
Takashi Iwaidea0a502009-02-09 17:14:52 +010016418 SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_ECS),
Kailang Yang622e84c2009-04-21 07:39:04 +020016419 SND_PCI_QUIRK(0x1028, 0x02d6, "DELL", ALC272_DELL),
16420 SND_PCI_QUIRK(0x1028, 0x02f4, "DELL ZM1", ALC272_DELL_ZM1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016421 SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC663_ASUS_MODE1),
16422 SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC663_ASUS_MODE3),
16423 SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC663_ASUS_MODE3),
16424 SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC663_ASUS_MODE1),
16425 SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_ASUS_MODE2),
16426 SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC663_ASUS_MODE1),
16427 SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_ASUS_MODE2),
16428 SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_ASUS_MODE2),
16429 SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_ASUS_MODE2),
16430 SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC663_ASUS_MODE6),
16431 SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC663_ASUS_MODE6),
16432 SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020016433 SND_PCI_QUIRK(0x1043, 0x17b3, "ASUS F70SL", ALC663_ASUS_MODE3),
16434 SND_PCI_QUIRK(0x1043, 0x17c3, "ASUS UX20", ALC663_ASUS_M51VA),
16435 SND_PCI_QUIRK(0x1043, 0x17f3, "ASUS X58LE", ALC662_ASUS_MODE2),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016436 SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_ASUS_MODE2),
16437 SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC663_ASUS_MODE5),
16438 SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC663_ASUS_MODE6),
16439 SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020016440 SND_PCI_QUIRK(0x1043, 0x1853, "ASUS F50Z", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016441 SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_ASUS_MODE2),
16442 SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yang6dda9f42008-05-27 12:05:31 +020016443 SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M51VA", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016444 /*SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M50Vr", ALC663_ASUS_MODE1),*/
16445 SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC663_ASUS_MODE3),
16446 SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC663_ASUS_MODE3),
Kailang Yang622e84c2009-04-21 07:39:04 +020016447 SND_PCI_QUIRK(0x1043, 0x18b3, "ASUS N80Vc", ALC663_ASUS_MODE1),
16448 SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS N81Te", ALC663_ASUS_MODE1),
16449 SND_PCI_QUIRK(0x1043, 0x18f3, "ASUS N505Tp", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016450 SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC663_ASUS_MODE1),
16451 SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_ASUS_MODE2),
16452 SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020016453 SND_PCI_QUIRK(0x1043, 0x1943, "ASUS Vx3V", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016454 SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC663_ASUS_MODE1),
16455 SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC663_ASUS_MODE3),
Kailang Yang622e84c2009-04-21 07:39:04 +020016456 SND_PCI_QUIRK(0x1043, 0x1983, "ASUS N5051A", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016457 SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC663_ASUS_MODE1),
Kailang Yang80ffe862008-10-15 11:23:27 +020016458 SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS G50V", ALC663_ASUS_G50V),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016459 /*SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS NB", ALC663_ASUS_MODE1),*/
16460 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC663_ASUS_MODE1),
16461 SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020016462 SND_PCI_QUIRK(0x1043, 0x19d3, "ASUS NB", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016463 SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC663_ASUS_MODE1),
16464 SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC663_ASUS_MODE4),
Herton Ronaldo Krzesinski3da23ca2008-03-14 12:52:59 +010016465 SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG),
Kailang Yang291702f2007-10-16 14:28:03 +020016466 SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701),
Kailang Yang8c427222008-01-10 13:03:59 +010016467 SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016468 SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS),
Herton Ronaldo Krzesinski95fe5f22008-09-26 23:48:45 -030016469 SND_PCI_QUIRK(0x105b, 0x0d47, "Foxconn 45CMX/45GMX/45CMX-K",
16470 ALC662_3ST_6ch_DIG),
Herton Ronaldo Krzesinskicb559742008-09-26 23:47:45 -030016471 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L",
16472 ALC662_3ST_6ch_DIG),
Vedran Miletic19c009a2008-09-29 20:29:25 +020016473 SND_PCI_QUIRK(0x1565, 0x820f, "Biostar TA780G M2+", ALC662_3ST_6ch_DIG),
Takashi Iwai5bd37292009-04-21 18:36:30 +020016474 SND_PCI_QUIRK(0x1631, 0xc10c, "PB RS65", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016475 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E),
Takashi Iwai238713d2008-10-05 10:57:39 +020016476 SND_PCI_QUIRK(0x1849, 0x3662, "ASROCK K10N78FullHD-hSLI R3.0",
Vedran Miletic19c009a2008-09-29 20:29:25 +020016477 ALC662_3ST_6ch_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016478 SND_PCI_QUIRK_MASK(0x1854, 0xf000, 0x2000, "ASUS H13-200x",
16479 ALC663_ASUS_H13),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016480 {}
16481};
16482
16483static struct alc_config_preset alc662_presets[] = {
16484 [ALC662_3ST_2ch_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016485 .mixers = { alc662_3ST_2ch_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016486 .init_verbs = { alc662_init_verbs },
16487 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16488 .dac_nids = alc662_dac_nids,
16489 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016490 .dig_in_nid = ALC662_DIGIN_NID,
16491 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16492 .channel_mode = alc662_3ST_2ch_modes,
16493 .input_mux = &alc662_capture_source,
16494 },
16495 [ALC662_3ST_6ch_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016496 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016497 .init_verbs = { alc662_init_verbs },
16498 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16499 .dac_nids = alc662_dac_nids,
16500 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016501 .dig_in_nid = ALC662_DIGIN_NID,
16502 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
16503 .channel_mode = alc662_3ST_6ch_modes,
16504 .need_dac_fix = 1,
16505 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016506 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016507 [ALC662_3ST_6ch] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016508 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016509 .init_verbs = { alc662_init_verbs },
16510 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16511 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016512 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
16513 .channel_mode = alc662_3ST_6ch_modes,
16514 .need_dac_fix = 1,
16515 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016516 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016517 [ALC662_5ST_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016518 .mixers = { alc662_base_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016519 .init_verbs = { alc662_init_verbs },
16520 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16521 .dac_nids = alc662_dac_nids,
16522 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016523 .dig_in_nid = ALC662_DIGIN_NID,
16524 .num_channel_mode = ARRAY_SIZE(alc662_5stack_modes),
16525 .channel_mode = alc662_5stack_modes,
16526 .input_mux = &alc662_capture_source,
16527 },
16528 [ALC662_LENOVO_101E] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016529 .mixers = { alc662_lenovo_101e_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016530 .init_verbs = { alc662_init_verbs, alc662_sue_init_verbs },
16531 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16532 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016533 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16534 .channel_mode = alc662_3ST_2ch_modes,
16535 .input_mux = &alc662_lenovo_101e_capture_source,
16536 .unsol_event = alc662_lenovo_101e_unsol_event,
16537 .init_hook = alc662_lenovo_101e_all_automute,
16538 },
Kailang Yang291702f2007-10-16 14:28:03 +020016539 [ALC662_ASUS_EEEPC_P701] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016540 .mixers = { alc662_eeepc_p701_mixer },
Kailang Yang291702f2007-10-16 14:28:03 +020016541 .init_verbs = { alc662_init_verbs,
16542 alc662_eeepc_sue_init_verbs },
16543 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16544 .dac_nids = alc662_dac_nids,
Kailang Yang291702f2007-10-16 14:28:03 +020016545 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16546 .channel_mode = alc662_3ST_2ch_modes,
16547 .input_mux = &alc662_eeepc_capture_source,
16548 .unsol_event = alc662_eeepc_unsol_event,
16549 .init_hook = alc662_eeepc_inithook,
16550 },
Kailang Yang8c427222008-01-10 13:03:59 +010016551 [ALC662_ASUS_EEEPC_EP20] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016552 .mixers = { alc662_eeepc_ep20_mixer,
Kailang Yang8c427222008-01-10 13:03:59 +010016553 alc662_chmode_mixer },
16554 .init_verbs = { alc662_init_verbs,
16555 alc662_eeepc_ep20_sue_init_verbs },
16556 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16557 .dac_nids = alc662_dac_nids,
Kailang Yang8c427222008-01-10 13:03:59 +010016558 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
16559 .channel_mode = alc662_3ST_6ch_modes,
16560 .input_mux = &alc662_lenovo_101e_capture_source,
16561 .unsol_event = alc662_eeepc_ep20_unsol_event,
16562 .init_hook = alc662_eeepc_ep20_inithook,
16563 },
Kailang Yangf1d4e282008-08-26 14:03:29 +020016564 [ALC662_ECS] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016565 .mixers = { alc662_ecs_mixer },
Kailang Yangf1d4e282008-08-26 14:03:29 +020016566 .init_verbs = { alc662_init_verbs,
16567 alc662_ecs_init_verbs },
16568 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16569 .dac_nids = alc662_dac_nids,
16570 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16571 .channel_mode = alc662_3ST_2ch_modes,
16572 .input_mux = &alc662_eeepc_capture_source,
16573 .unsol_event = alc662_eeepc_unsol_event,
16574 .init_hook = alc662_eeepc_inithook,
16575 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020016576 [ALC663_ASUS_M51VA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016577 .mixers = { alc663_m51va_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020016578 .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
16579 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16580 .dac_nids = alc662_dac_nids,
16581 .dig_out_nid = ALC662_DIGOUT_NID,
16582 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16583 .channel_mode = alc662_3ST_2ch_modes,
16584 .input_mux = &alc663_m51va_capture_source,
16585 .unsol_event = alc663_m51va_unsol_event,
16586 .init_hook = alc663_m51va_inithook,
16587 },
16588 [ALC663_ASUS_G71V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016589 .mixers = { alc663_g71v_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020016590 .init_verbs = { alc662_init_verbs, alc663_g71v_init_verbs },
16591 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16592 .dac_nids = alc662_dac_nids,
16593 .dig_out_nid = ALC662_DIGOUT_NID,
16594 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16595 .channel_mode = alc662_3ST_2ch_modes,
16596 .input_mux = &alc662_eeepc_capture_source,
16597 .unsol_event = alc663_g71v_unsol_event,
16598 .init_hook = alc663_g71v_inithook,
16599 },
16600 [ALC663_ASUS_H13] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016601 .mixers = { alc663_m51va_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020016602 .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
16603 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16604 .dac_nids = alc662_dac_nids,
16605 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16606 .channel_mode = alc662_3ST_2ch_modes,
16607 .input_mux = &alc663_m51va_capture_source,
16608 .unsol_event = alc663_m51va_unsol_event,
16609 .init_hook = alc663_m51va_inithook,
16610 },
16611 [ALC663_ASUS_G50V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016612 .mixers = { alc663_g50v_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020016613 .init_verbs = { alc662_init_verbs, alc663_g50v_init_verbs },
16614 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16615 .dac_nids = alc662_dac_nids,
16616 .dig_out_nid = ALC662_DIGOUT_NID,
16617 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
16618 .channel_mode = alc662_3ST_6ch_modes,
16619 .input_mux = &alc663_capture_source,
16620 .unsol_event = alc663_g50v_unsol_event,
16621 .init_hook = alc663_g50v_inithook,
16622 },
Kailang Yangf1d4e282008-08-26 14:03:29 +020016623 [ALC663_ASUS_MODE1] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016624 .mixers = { alc663_m51va_mixer },
16625 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020016626 .init_verbs = { alc662_init_verbs,
16627 alc663_21jd_amic_init_verbs },
16628 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16629 .hp_nid = 0x03,
16630 .dac_nids = alc662_dac_nids,
16631 .dig_out_nid = ALC662_DIGOUT_NID,
16632 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16633 .channel_mode = alc662_3ST_2ch_modes,
16634 .input_mux = &alc662_eeepc_capture_source,
16635 .unsol_event = alc663_mode1_unsol_event,
16636 .init_hook = alc663_mode1_inithook,
16637 },
16638 [ALC662_ASUS_MODE2] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016639 .mixers = { alc662_1bjd_mixer },
16640 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020016641 .init_verbs = { alc662_init_verbs,
16642 alc662_1bjd_amic_init_verbs },
16643 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16644 .dac_nids = alc662_dac_nids,
16645 .dig_out_nid = ALC662_DIGOUT_NID,
16646 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16647 .channel_mode = alc662_3ST_2ch_modes,
16648 .input_mux = &alc662_eeepc_capture_source,
16649 .unsol_event = alc662_mode2_unsol_event,
16650 .init_hook = alc662_mode2_inithook,
16651 },
16652 [ALC663_ASUS_MODE3] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016653 .mixers = { alc663_two_hp_m1_mixer },
16654 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020016655 .init_verbs = { alc662_init_verbs,
16656 alc663_two_hp_amic_m1_init_verbs },
16657 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16658 .hp_nid = 0x03,
16659 .dac_nids = alc662_dac_nids,
16660 .dig_out_nid = ALC662_DIGOUT_NID,
16661 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16662 .channel_mode = alc662_3ST_2ch_modes,
16663 .input_mux = &alc662_eeepc_capture_source,
16664 .unsol_event = alc663_mode3_unsol_event,
16665 .init_hook = alc663_mode3_inithook,
16666 },
16667 [ALC663_ASUS_MODE4] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016668 .mixers = { alc663_asus_21jd_clfe_mixer },
16669 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020016670 .init_verbs = { alc662_init_verbs,
16671 alc663_21jd_amic_init_verbs},
16672 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16673 .hp_nid = 0x03,
16674 .dac_nids = alc662_dac_nids,
16675 .dig_out_nid = ALC662_DIGOUT_NID,
16676 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16677 .channel_mode = alc662_3ST_2ch_modes,
16678 .input_mux = &alc662_eeepc_capture_source,
16679 .unsol_event = alc663_mode4_unsol_event,
16680 .init_hook = alc663_mode4_inithook,
16681 },
16682 [ALC663_ASUS_MODE5] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016683 .mixers = { alc663_asus_15jd_clfe_mixer },
16684 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020016685 .init_verbs = { alc662_init_verbs,
16686 alc663_15jd_amic_init_verbs },
16687 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16688 .hp_nid = 0x03,
16689 .dac_nids = alc662_dac_nids,
16690 .dig_out_nid = ALC662_DIGOUT_NID,
16691 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16692 .channel_mode = alc662_3ST_2ch_modes,
16693 .input_mux = &alc662_eeepc_capture_source,
16694 .unsol_event = alc663_mode5_unsol_event,
16695 .init_hook = alc663_mode5_inithook,
16696 },
16697 [ALC663_ASUS_MODE6] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016698 .mixers = { alc663_two_hp_m2_mixer },
16699 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020016700 .init_verbs = { alc662_init_verbs,
16701 alc663_two_hp_amic_m2_init_verbs },
16702 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16703 .hp_nid = 0x03,
16704 .dac_nids = alc662_dac_nids,
16705 .dig_out_nid = ALC662_DIGOUT_NID,
16706 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16707 .channel_mode = alc662_3ST_2ch_modes,
16708 .input_mux = &alc662_eeepc_capture_source,
16709 .unsol_event = alc663_mode6_unsol_event,
16710 .init_hook = alc663_mode6_inithook,
16711 },
Kailang Yang622e84c2009-04-21 07:39:04 +020016712 [ALC272_DELL] = {
16713 .mixers = { alc663_m51va_mixer },
16714 .cap_mixer = alc272_auto_capture_mixer,
16715 .init_verbs = { alc662_init_verbs, alc272_dell_init_verbs },
16716 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
16717 .dac_nids = alc662_dac_nids,
16718 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16719 .adc_nids = alc272_adc_nids,
16720 .num_adc_nids = ARRAY_SIZE(alc272_adc_nids),
16721 .capsrc_nids = alc272_capsrc_nids,
16722 .channel_mode = alc662_3ST_2ch_modes,
16723 .input_mux = &alc663_m51va_capture_source,
16724 .unsol_event = alc663_m51va_unsol_event,
16725 .init_hook = alc663_m51va_inithook,
16726 },
16727 [ALC272_DELL_ZM1] = {
16728 .mixers = { alc663_m51va_mixer },
16729 .cap_mixer = alc662_auto_capture_mixer,
16730 .init_verbs = { alc662_init_verbs, alc272_dell_zm1_init_verbs },
16731 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
16732 .dac_nids = alc662_dac_nids,
16733 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16734 .adc_nids = alc662_adc_nids,
16735 .num_adc_nids = ARRAY_SIZE(alc662_adc_nids),
16736 .capsrc_nids = alc662_capsrc_nids,
16737 .channel_mode = alc662_3ST_2ch_modes,
16738 .input_mux = &alc663_m51va_capture_source,
16739 .unsol_event = alc663_m51va_unsol_event,
16740 .init_hook = alc663_m51va_inithook,
16741 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016742};
16743
16744
16745/*
16746 * BIOS auto configuration
16747 */
16748
16749/* add playback controls from the parsed DAC table */
16750static int alc662_auto_create_multi_out_ctls(struct alc_spec *spec,
16751 const struct auto_pin_cfg *cfg)
16752{
16753 char name[32];
16754 static const char *chname[4] = {
16755 "Front", "Surround", NULL /*CLFE*/, "Side"
16756 };
16757 hda_nid_t nid;
16758 int i, err;
16759
16760 for (i = 0; i < cfg->line_outs; i++) {
16761 if (!spec->multiout.dac_nids[i])
16762 continue;
Kailang Yangb60dd392007-09-20 12:50:29 +020016763 nid = alc880_idx_to_dac(i);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016764 if (i == 2) {
16765 /* Center/LFE */
16766 err = add_control(spec, ALC_CTL_WIDGET_VOL,
16767 "Center Playback Volume",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016768 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
16769 HDA_OUTPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016770 if (err < 0)
16771 return err;
16772 err = add_control(spec, ALC_CTL_WIDGET_VOL,
16773 "LFE Playback Volume",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016774 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
16775 HDA_OUTPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016776 if (err < 0)
16777 return err;
Herton Ronaldo Krzesinskib69ce012008-09-18 16:41:49 -030016778 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016779 "Center Playback Switch",
Herton Ronaldo Krzesinskib69ce012008-09-18 16:41:49 -030016780 HDA_COMPOSE_AMP_VAL(0x0e, 1, 0,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016781 HDA_INPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016782 if (err < 0)
16783 return err;
Herton Ronaldo Krzesinskib69ce012008-09-18 16:41:49 -030016784 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016785 "LFE Playback Switch",
Herton Ronaldo Krzesinskib69ce012008-09-18 16:41:49 -030016786 HDA_COMPOSE_AMP_VAL(0x0e, 2, 0,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016787 HDA_INPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016788 if (err < 0)
16789 return err;
16790 } else {
16791 sprintf(name, "%s Playback Volume", chname[i]);
16792 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016793 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
16794 HDA_OUTPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016795 if (err < 0)
16796 return err;
16797 sprintf(name, "%s Playback Switch", chname[i]);
Herton Ronaldo Krzesinskib69ce012008-09-18 16:41:49 -030016798 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
16799 HDA_COMPOSE_AMP_VAL(alc880_idx_to_mixer(i),
16800 3, 0, HDA_INPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016801 if (err < 0)
16802 return err;
16803 }
16804 }
16805 return 0;
16806}
16807
16808/* add playback controls for speaker and HP outputs */
16809static int alc662_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
16810 const char *pfx)
16811{
16812 hda_nid_t nid;
16813 int err;
16814 char name[32];
16815
16816 if (!pin)
16817 return 0;
16818
Takashi Iwai24fb9172008-09-02 14:48:20 +020016819 if (pin == 0x17) {
16820 /* ALC663 has a mono output pin on 0x17 */
16821 sprintf(name, "%s Playback Switch", pfx);
16822 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
16823 HDA_COMPOSE_AMP_VAL(pin, 2, 0, HDA_OUTPUT));
16824 return err;
16825 }
16826
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016827 if (alc880_is_fixed_pin(pin)) {
16828 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
Takashi Iwai939778a2009-02-05 15:57:55 +010016829 /* printk(KERN_DEBUG "DAC nid=%x\n",nid); */
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016830 /* specify the DAC as the extra output */
16831 if (!spec->multiout.hp_nid)
16832 spec->multiout.hp_nid = nid;
16833 else
16834 spec->multiout.extra_out_nid[0] = nid;
16835 /* control HP volume/switch on the output mixer amp */
16836 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
16837 sprintf(name, "%s Playback Volume", pfx);
16838 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
16839 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
16840 if (err < 0)
16841 return err;
16842 sprintf(name, "%s Playback Switch", pfx);
16843 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
16844 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
16845 if (err < 0)
16846 return err;
16847 } else if (alc880_is_multi_pin(pin)) {
16848 /* set manual connection */
16849 /* we have only a switch on HP-out PIN */
16850 sprintf(name, "%s Playback Switch", pfx);
16851 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
16852 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
16853 if (err < 0)
16854 return err;
16855 }
16856 return 0;
16857}
16858
Takashi Iwai2d864c42009-03-20 12:52:47 +010016859/* return the index of the src widget from the connection list of the nid.
16860 * return -1 if not found
16861 */
16862static int alc662_input_pin_idx(struct hda_codec *codec, hda_nid_t nid,
16863 hda_nid_t src)
16864{
16865 hda_nid_t conn_list[HDA_MAX_CONNECTIONS];
16866 int i, conns;
16867
16868 conns = snd_hda_get_connections(codec, nid, conn_list,
16869 ARRAY_SIZE(conn_list));
16870 if (conns < 0)
16871 return -1;
16872 for (i = 0; i < conns; i++)
16873 if (conn_list[i] == src)
16874 return i;
16875 return -1;
16876}
16877
16878static int alc662_is_input_pin(struct hda_codec *codec, hda_nid_t nid)
16879{
Takashi Iwai1327a322009-03-23 13:07:47 +010016880 unsigned int pincap = snd_hda_query_pin_caps(codec, nid);
Takashi Iwai2d864c42009-03-20 12:52:47 +010016881 return (pincap & AC_PINCAP_IN) != 0;
16882}
16883
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016884/* create playback/capture controls for input pins */
Takashi Iwai2d864c42009-03-20 12:52:47 +010016885static int alc662_auto_create_analog_input_ctls(struct hda_codec *codec,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016886 const struct auto_pin_cfg *cfg)
16887{
Takashi Iwai2d864c42009-03-20 12:52:47 +010016888 struct alc_spec *spec = codec->spec;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020016889 struct hda_input_mux *imux = &spec->private_imux[0];
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016890 int i, err, idx;
16891
16892 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwai2d864c42009-03-20 12:52:47 +010016893 if (alc662_is_input_pin(codec, cfg->input_pins[i])) {
16894 idx = alc662_input_pin_idx(codec, 0x0b,
16895 cfg->input_pins[i]);
16896 if (idx >= 0) {
16897 err = new_analog_input(spec, cfg->input_pins[i],
16898 auto_pin_cfg_labels[i],
16899 idx, 0x0b);
16900 if (err < 0)
16901 return err;
16902 }
16903 idx = alc662_input_pin_idx(codec, 0x22,
16904 cfg->input_pins[i]);
16905 if (idx >= 0) {
16906 imux->items[imux->num_items].label =
16907 auto_pin_cfg_labels[i];
16908 imux->items[imux->num_items].index = idx;
16909 imux->num_items++;
16910 }
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016911 }
16912 }
16913 return 0;
16914}
16915
16916static void alc662_auto_set_output_and_unmute(struct hda_codec *codec,
16917 hda_nid_t nid, int pin_type,
16918 int dac_idx)
16919{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016920 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016921 /* need the manual connection? */
16922 if (alc880_is_multi_pin(nid)) {
16923 struct alc_spec *spec = codec->spec;
16924 int idx = alc880_multi_pin_idx(nid);
16925 snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
16926 AC_VERB_SET_CONNECT_SEL,
16927 alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
16928 }
16929}
16930
16931static void alc662_auto_init_multi_out(struct hda_codec *codec)
16932{
16933 struct alc_spec *spec = codec->spec;
16934 int i;
16935
Kailang Yang8c427222008-01-10 13:03:59 +010016936 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016937 for (i = 0; i <= HDA_SIDE; i++) {
16938 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020016939 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016940 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020016941 alc662_auto_set_output_and_unmute(codec, nid, pin_type,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016942 i);
16943 }
16944}
16945
16946static void alc662_auto_init_hp_out(struct hda_codec *codec)
16947{
16948 struct alc_spec *spec = codec->spec;
16949 hda_nid_t pin;
16950
16951 pin = spec->autocfg.hp_pins[0];
16952 if (pin) /* connect to front */
16953 /* use dac 0 */
16954 alc662_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016955 pin = spec->autocfg.speaker_pins[0];
16956 if (pin)
16957 alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016958}
16959
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016960#define ALC662_PIN_CD_NID ALC880_PIN_CD_NID
16961
16962static void alc662_auto_init_analog_input(struct hda_codec *codec)
16963{
16964 struct alc_spec *spec = codec->spec;
16965 int i;
16966
16967 for (i = 0; i < AUTO_PIN_LAST; i++) {
16968 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwai2d864c42009-03-20 12:52:47 +010016969 if (alc662_is_input_pin(codec, nid)) {
Takashi Iwai23f0c042009-02-26 13:03:58 +010016970 alc_set_input_pin(codec, nid, i);
Takashi Iwai52ca15b2009-03-23 12:51:55 +010016971 if (nid != ALC662_PIN_CD_NID &&
Takashi Iwaie82c0252009-03-23 15:17:38 +010016972 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016973 snd_hda_codec_write(codec, nid, 0,
16974 AC_VERB_SET_AMP_GAIN_MUTE,
16975 AMP_OUT_MUTE);
16976 }
16977 }
16978}
16979
Takashi Iwaif511b012008-08-15 16:46:42 +020016980#define alc662_auto_init_input_src alc882_auto_init_input_src
16981
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016982static int alc662_parse_auto_config(struct hda_codec *codec)
16983{
16984 struct alc_spec *spec = codec->spec;
16985 int err;
16986 static hda_nid_t alc662_ignore[] = { 0x1d, 0 };
16987
16988 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
16989 alc662_ignore);
16990 if (err < 0)
16991 return err;
16992 if (!spec->autocfg.line_outs)
16993 return 0; /* can't find valid BIOS pin config */
16994
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016995 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
16996 if (err < 0)
16997 return err;
16998 err = alc662_auto_create_multi_out_ctls(spec, &spec->autocfg);
16999 if (err < 0)
17000 return err;
17001 err = alc662_auto_create_extra_out(spec,
17002 spec->autocfg.speaker_pins[0],
17003 "Speaker");
17004 if (err < 0)
17005 return err;
17006 err = alc662_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
17007 "Headphone");
17008 if (err < 0)
17009 return err;
Takashi Iwai2d864c42009-03-20 12:52:47 +010017010 err = alc662_auto_create_analog_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017011 if (err < 0)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017012 return err;
17013
17014 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
17015
Takashi Iwai0852d7a2009-02-11 11:35:15 +010017016 if (spec->autocfg.dig_outs)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017017 spec->multiout.dig_out_nid = ALC880_DIGOUT_NID;
17018
Takashi Iwai603c4012008-07-30 15:01:44 +020017019 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010017020 add_mixer(spec, spec->kctls.list);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017021
17022 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020017023 spec->input_mux = &spec->private_imux[0];
Kailang Yangea1fb292008-08-26 12:58:38 +020017024
Takashi Iwaid88897e2008-10-31 15:01:37 +010017025 add_verb(spec, alc662_auto_init_verbs);
Takashi Iwai24fb9172008-09-02 14:48:20 +020017026 if (codec->vendor_id == 0x10ec0663)
Takashi Iwaid88897e2008-10-31 15:01:37 +010017027 add_verb(spec, alc663_auto_init_verbs);
Takashi Iwaiee979a142008-09-02 15:42:20 +020017028
17029 err = alc_auto_add_mic_boost(codec);
17030 if (err < 0)
17031 return err;
17032
Takashi Iwai8c872862007-06-19 12:11:16 +020017033 return 1;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017034}
17035
17036/* additional initialization for auto-configuration model */
17037static void alc662_auto_init(struct hda_codec *codec)
17038{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010017039 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017040 alc662_auto_init_multi_out(codec);
17041 alc662_auto_init_hp_out(codec);
17042 alc662_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020017043 alc662_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010017044 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020017045 alc_inithook(codec);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017046}
17047
17048static int patch_alc662(struct hda_codec *codec)
17049{
17050 struct alc_spec *spec;
17051 int err, board_config;
17052
17053 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
17054 if (!spec)
17055 return -ENOMEM;
17056
17057 codec->spec = spec;
17058
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020017059 alc_fix_pll_init(codec, 0x20, 0x04, 15);
17060
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017061 board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST,
17062 alc662_models,
17063 alc662_cfg_tbl);
17064 if (board_config < 0) {
17065 printk(KERN_INFO "hda_codec: Unknown model for ALC662, "
17066 "trying auto-probe from BIOS...\n");
17067 board_config = ALC662_AUTO;
17068 }
17069
17070 if (board_config == ALC662_AUTO) {
17071 /* automatic parse from the BIOS config */
17072 err = alc662_parse_auto_config(codec);
17073 if (err < 0) {
17074 alc_free(codec);
17075 return err;
Takashi Iwai8c872862007-06-19 12:11:16 +020017076 } else if (!err) {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017077 printk(KERN_INFO
17078 "hda_codec: Cannot set up configuration "
17079 "from BIOS. Using base mode...\n");
17080 board_config = ALC662_3ST_2ch_DIG;
17081 }
17082 }
17083
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090017084 err = snd_hda_attach_beep_device(codec, 0x1);
17085 if (err < 0) {
17086 alc_free(codec);
17087 return err;
17088 }
17089
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017090 if (board_config != ALC662_AUTO)
17091 setup_preset(spec, &alc662_presets[board_config]);
17092
Kailang Yang6dda9f42008-05-27 12:05:31 +020017093 if (codec->vendor_id == 0x10ec0663) {
17094 spec->stream_name_analog = "ALC663 Analog";
17095 spec->stream_name_digital = "ALC663 Digital";
Kailang Yang01afd412008-10-15 11:22:09 +020017096 } else if (codec->vendor_id == 0x10ec0272) {
17097 spec->stream_name_analog = "ALC272 Analog";
17098 spec->stream_name_digital = "ALC272 Digital";
Kailang Yang6dda9f42008-05-27 12:05:31 +020017099 } else {
17100 spec->stream_name_analog = "ALC662 Analog";
17101 spec->stream_name_digital = "ALC662 Digital";
17102 }
17103
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017104 spec->stream_analog_playback = &alc662_pcm_analog_playback;
17105 spec->stream_analog_capture = &alc662_pcm_analog_capture;
17106
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017107 spec->stream_digital_playback = &alc662_pcm_digital_playback;
17108 spec->stream_digital_capture = &alc662_pcm_digital_capture;
17109
Takashi Iwaie1406342008-02-11 18:32:32 +010017110 spec->adc_nids = alc662_adc_nids;
17111 spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids);
17112 spec->capsrc_nids = alc662_capsrc_nids;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020017113 spec->capture_style = CAPT_MIX;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017114
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017115 if (!spec->cap_mixer)
17116 set_capture_mixer(spec);
Takashi Iwaib9591442009-03-16 15:25:00 +010017117 if (codec->vendor_id == 0x10ec0662)
17118 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
17119 else
17120 set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017121
Takashi Iwai2134ea42008-01-10 16:53:55 +010017122 spec->vmaster_nid = 0x02;
17123
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017124 codec->patch_ops = alc_patch_ops;
17125 if (board_config == ALC662_AUTO)
17126 spec->init_hook = alc662_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020017127#ifdef CONFIG_SND_HDA_POWER_SAVE
17128 if (!spec->loopback.amplist)
17129 spec->loopback.amplist = alc662_loopbacks;
17130#endif
Takashi Iwaidaead532008-11-28 12:55:36 +010017131 codec->proc_widget_hook = print_realtek_coef;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017132
17133 return 0;
17134}
17135
17136/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070017137 * patch entries
17138 */
Takashi Iwai1289e9e2008-11-27 15:47:11 +010017139static struct hda_codec_preset snd_hda_preset_realtek[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070017140 { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
Kailang Yangdf694da2005-12-05 19:42:22 +010017141 { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
Kailang Yangf6a92242007-12-13 16:52:54 +010017142 { .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 },
Kailang Yanga361d842007-06-05 12:30:55 +020017143 { .id = 0x10ec0268, .name = "ALC268", .patch = patch_alc268 },
Kailang Yangf6a92242007-12-13 16:52:54 +010017144 { .id = 0x10ec0269, .name = "ALC269", .patch = patch_alc269 },
Kailang Yang01afd412008-10-15 11:22:09 +020017145 { .id = 0x10ec0272, .name = "ALC272", .patch = patch_alc662 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017146 { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017147 .patch = patch_alc861 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017148 { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
17149 { .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 },
17150 { .id = 0x10ec0862, .name = "ALC861-VD", .patch = patch_alc861vd },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017151 { .id = 0x10ec0662, .rev = 0x100002, .name = "ALC662 rev2",
17152 .patch = patch_alc883 },
17153 { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1",
17154 .patch = patch_alc662 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020017155 { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017156 { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070017157 { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020017158 { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc883 },
Clive Messer669faba2008-09-30 15:49:13 +020017159 { .id = 0x10ec0885, .rev = 0x100101, .name = "ALC889A",
17160 .patch = patch_alc882 }, /* should be patch_alc883() in future */
Takashi Iwaicb308f92008-04-16 14:13:29 +020017161 { .id = 0x10ec0885, .rev = 0x100103, .name = "ALC889A",
Takashi Iwai7943a8a2008-04-16 17:29:09 +020017162 .patch = patch_alc882 }, /* should be patch_alc883() in future */
Kailang Yangdf694da2005-12-05 19:42:22 +010017163 { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
Kailang Yanga385a522008-10-15 11:20:21 +020017164 { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc883 },
Kailang Yang44426082008-10-15 11:18:05 +020017165 { .id = 0x10ec0888, .rev = 0x100101, .name = "ALC1200",
17166 .patch = patch_alc883 },
Wu Fengguang3fea2cb2008-12-26 12:20:43 +080017167 { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc883 },
Kailang Yangf6a92242007-12-13 16:52:54 +010017168 { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc883 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070017169 {} /* terminator */
17170};
Takashi Iwai1289e9e2008-11-27 15:47:11 +010017171
17172MODULE_ALIAS("snd-hda-codec-id:10ec*");
17173
17174MODULE_LICENSE("GPL");
17175MODULE_DESCRIPTION("Realtek HD-audio codec");
17176
17177static struct hda_codec_preset_list realtek_list = {
17178 .preset = snd_hda_preset_realtek,
17179 .owner = THIS_MODULE,
17180};
17181
17182static int __init patch_realtek_init(void)
17183{
17184 return snd_hda_add_codec_preset(&realtek_list);
17185}
17186
17187static void __exit patch_realtek_exit(void)
17188{
17189 snd_hda_delete_codec_preset(&realtek_list);
17190}
17191
17192module_init(patch_realtek_init)
17193module_exit(patch_realtek_exit)