blob: bcbb736f94f0916e6dc57e9ec623f6f9efeffd80 [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;
779 }
780 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, val);
781}
782
783/*
Takashi Iwaid88897e2008-10-31 15:01:37 +0100784 */
785static void add_mixer(struct alc_spec *spec, struct snd_kcontrol_new *mix)
786{
787 if (snd_BUG_ON(spec->num_mixers >= ARRAY_SIZE(spec->mixers)))
788 return;
789 spec->mixers[spec->num_mixers++] = mix;
790}
791
792static void add_verb(struct alc_spec *spec, const struct hda_verb *verb)
793{
794 if (snd_BUG_ON(spec->num_init_verbs >= ARRAY_SIZE(spec->init_verbs)))
795 return;
796 spec->init_verbs[spec->num_init_verbs++] = verb;
797}
798
Takashi Iwaidaead532008-11-28 12:55:36 +0100799#ifdef CONFIG_PROC_FS
800/*
801 * hook for proc
802 */
803static void print_realtek_coef(struct snd_info_buffer *buffer,
804 struct hda_codec *codec, hda_nid_t nid)
805{
806 int coeff;
807
808 if (nid != 0x20)
809 return;
810 coeff = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PROC_COEF, 0);
811 snd_iprintf(buffer, " Processing Coefficient: 0x%02x\n", coeff);
812 coeff = snd_hda_codec_read(codec, nid, 0,
813 AC_VERB_GET_COEF_INDEX, 0);
814 snd_iprintf(buffer, " Coefficient Index: 0x%02x\n", coeff);
815}
816#else
817#define print_realtek_coef NULL
818#endif
819
Takashi Iwaid88897e2008-10-31 15:01:37 +0100820/*
Kailang Yangdf694da2005-12-05 19:42:22 +0100821 * set up from the preset table
822 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200823static void setup_preset(struct alc_spec *spec,
824 const struct alc_config_preset *preset)
Kailang Yangdf694da2005-12-05 19:42:22 +0100825{
826 int i;
827
828 for (i = 0; i < ARRAY_SIZE(preset->mixers) && preset->mixers[i]; i++)
Takashi Iwaid88897e2008-10-31 15:01:37 +0100829 add_mixer(spec, preset->mixers[i]);
Takashi Iwaif9e336f2008-10-31 16:37:07 +0100830 spec->cap_mixer = preset->cap_mixer;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200831 for (i = 0; i < ARRAY_SIZE(preset->init_verbs) && preset->init_verbs[i];
832 i++)
Takashi Iwaid88897e2008-10-31 15:01:37 +0100833 add_verb(spec, preset->init_verbs[i]);
Kailang Yangea1fb292008-08-26 12:58:38 +0200834
Kailang Yangdf694da2005-12-05 19:42:22 +0100835 spec->channel_mode = preset->channel_mode;
836 spec->num_channel_mode = preset->num_channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200837 spec->need_dac_fix = preset->need_dac_fix;
Kailang Yangdf694da2005-12-05 19:42:22 +0100838
839 spec->multiout.max_channels = spec->channel_mode[0].channels;
840
841 spec->multiout.num_dacs = preset->num_dacs;
842 spec->multiout.dac_nids = preset->dac_nids;
843 spec->multiout.dig_out_nid = preset->dig_out_nid;
Wu Fengguangb25c9da2009-02-06 15:02:27 +0800844 spec->multiout.slave_dig_outs = preset->slave_dig_outs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100845 spec->multiout.hp_nid = preset->hp_nid;
Kailang Yangea1fb292008-08-26 12:58:38 +0200846
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200847 spec->num_mux_defs = preset->num_mux_defs;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200848 if (!spec->num_mux_defs)
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200849 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +0100850 spec->input_mux = preset->input_mux;
851
852 spec->num_adc_nids = preset->num_adc_nids;
853 spec->adc_nids = preset->adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100854 spec->capsrc_nids = preset->capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +0100855 spec->dig_in_nid = preset->dig_in_nid;
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100856
857 spec->unsol_event = preset->unsol_event;
858 spec->init_hook = preset->init_hook;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200859#ifdef CONFIG_SND_HDA_POWER_SAVE
860 spec->loopback.amplist = preset->loopbacks;
861#endif
Kailang Yangdf694da2005-12-05 19:42:22 +0100862}
863
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200864/* Enable GPIO mask and set output */
865static struct hda_verb alc_gpio1_init_verbs[] = {
866 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
867 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
868 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
869 { }
870};
871
872static struct hda_verb alc_gpio2_init_verbs[] = {
873 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
874 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
875 {0x01, AC_VERB_SET_GPIO_DATA, 0x02},
876 { }
877};
878
Kailang Yangbdd148a2007-05-08 15:19:08 +0200879static struct hda_verb alc_gpio3_init_verbs[] = {
880 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
881 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
882 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
883 { }
884};
885
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +0200886/*
887 * Fix hardware PLL issue
888 * On some codecs, the analog PLL gating control must be off while
889 * the default value is 1.
890 */
891static void alc_fix_pll(struct hda_codec *codec)
892{
893 struct alc_spec *spec = codec->spec;
894 unsigned int val;
895
896 if (!spec->pll_nid)
897 return;
898 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
899 spec->pll_coef_idx);
900 val = snd_hda_codec_read(codec, spec->pll_nid, 0,
901 AC_VERB_GET_PROC_COEF, 0);
902 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
903 spec->pll_coef_idx);
904 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_PROC_COEF,
905 val & ~(1 << spec->pll_coef_bit));
906}
907
908static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
909 unsigned int coef_idx, unsigned int coef_bit)
910{
911 struct alc_spec *spec = codec->spec;
912 spec->pll_nid = nid;
913 spec->pll_coef_idx = coef_idx;
914 spec->pll_coef_bit = coef_bit;
915 alc_fix_pll(codec);
916}
917
Kailang Yangc9b58002007-10-16 14:30:01 +0200918static void alc_sku_automute(struct hda_codec *codec)
919{
920 struct alc_spec *spec = codec->spec;
Kailang Yangc9b58002007-10-16 14:30:01 +0200921 unsigned int present;
922 unsigned int hp_nid = spec->autocfg.hp_pins[0];
923 unsigned int sp_nid = spec->autocfg.speaker_pins[0];
924
925 /* need to execute and sync at first */
926 snd_hda_codec_read(codec, hp_nid, 0, AC_VERB_SET_PIN_SENSE, 0);
927 present = snd_hda_codec_read(codec, hp_nid, 0,
928 AC_VERB_GET_PIN_SENSE, 0);
929 spec->jack_present = (present & 0x80000000) != 0;
Takashi Iwaif6c7e542008-02-12 18:32:23 +0100930 snd_hda_codec_write(codec, sp_nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
931 spec->jack_present ? 0 : PIN_OUT);
Kailang Yangc9b58002007-10-16 14:30:01 +0200932}
933
Takashi Iwai4605b712008-10-31 14:18:24 +0100934#if 0 /* it's broken in some acses -- temporarily disabled */
Kailang Yang7fb0d782008-10-15 11:12:35 +0200935static void alc_mic_automute(struct hda_codec *codec)
936{
937 struct alc_spec *spec = codec->spec;
938 unsigned int present;
939 unsigned int mic_nid = spec->autocfg.input_pins[AUTO_PIN_MIC];
940 unsigned int fmic_nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC];
941 unsigned int mix_nid = spec->capsrc_nids[0];
942 unsigned int capsrc_idx_mic, capsrc_idx_fmic;
943
944 capsrc_idx_mic = mic_nid - 0x18;
945 capsrc_idx_fmic = fmic_nid - 0x18;
946 present = snd_hda_codec_read(codec, mic_nid, 0,
947 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
948 snd_hda_codec_write(codec, mix_nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
949 0x7000 | (capsrc_idx_mic << 8) | (present ? 0 : 0x80));
950 snd_hda_codec_write(codec, mix_nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
951 0x7000 | (capsrc_idx_fmic << 8) | (present ? 0x80 : 0));
952 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, capsrc_idx_fmic,
953 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
954}
Takashi Iwai4605b712008-10-31 14:18:24 +0100955#else
Takashi Iwai45bdd1c2009-02-06 16:11:25 +0100956#define alc_mic_automute(codec) do {} while(0) /* NOP */
Takashi Iwai4605b712008-10-31 14:18:24 +0100957#endif /* disabled */
Kailang Yang7fb0d782008-10-15 11:12:35 +0200958
Kailang Yangc9b58002007-10-16 14:30:01 +0200959/* unsolicited event for HP jack sensing */
960static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res)
961{
962 if (codec->vendor_id == 0x10ec0880)
963 res >>= 28;
964 else
965 res >>= 26;
Kailang Yang7fb0d782008-10-15 11:12:35 +0200966 if (res == ALC880_HP_EVENT)
967 alc_sku_automute(codec);
Kailang Yangc9b58002007-10-16 14:30:01 +0200968
Kailang Yang7fb0d782008-10-15 11:12:35 +0200969 if (res == ALC880_MIC_EVENT)
970 alc_mic_automute(codec);
971}
972
973static void alc_inithook(struct hda_codec *codec)
974{
Kailang Yangc9b58002007-10-16 14:30:01 +0200975 alc_sku_automute(codec);
Kailang Yang7fb0d782008-10-15 11:12:35 +0200976 alc_mic_automute(codec);
Kailang Yangc9b58002007-10-16 14:30:01 +0200977}
978
Kailang Yangf9423e72008-05-27 12:32:25 +0200979/* additional initialization for ALC888 variants */
980static void alc888_coef_init(struct hda_codec *codec)
981{
982 unsigned int tmp;
983
984 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0);
985 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
986 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
Takashi Iwai37db6232009-03-05 09:40:16 +0100987 if ((tmp & 0xf0) == 0x20)
Kailang Yangf9423e72008-05-27 12:32:25 +0200988 /* alc888S-VC */
989 snd_hda_codec_read(codec, 0x20, 0,
990 AC_VERB_SET_PROC_COEF, 0x830);
991 else
992 /* alc888-VB */
993 snd_hda_codec_read(codec, 0x20, 0,
994 AC_VERB_SET_PROC_COEF, 0x3030);
995}
996
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200997/* 32-bit subsystem ID for BIOS loading in HD Audio codec.
998 * 31 ~ 16 : Manufacture ID
999 * 15 ~ 8 : SKU ID
1000 * 7 ~ 0 : Assembly ID
1001 * port-A --> pin 39/41, port-E --> pin 14/15, port-D --> pin 35/36
1002 */
1003static void alc_subsystem_id(struct hda_codec *codec,
1004 unsigned int porta, unsigned int porte,
1005 unsigned int portd)
1006{
Kailang Yangc9b58002007-10-16 14:30:01 +02001007 unsigned int ass, tmp, i;
1008 unsigned nid;
1009 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001010
Kailang Yangc9b58002007-10-16 14:30:01 +02001011 ass = codec->subsystem_id & 0xffff;
1012 if ((ass != codec->bus->pci->subsystem_device) && (ass & 1))
1013 goto do_sku;
1014
Kailang Yangea1fb292008-08-26 12:58:38 +02001015 /*
Kailang Yangc9b58002007-10-16 14:30:01 +02001016 * 31~30 : port conetcivity
1017 * 29~21 : reserve
1018 * 20 : PCBEEP input
1019 * 19~16 : Check sum (15:1)
1020 * 15~1 : Custom
1021 * 0 : override
1022 */
1023 nid = 0x1d;
1024 if (codec->vendor_id == 0x10ec0260)
1025 nid = 0x17;
Takashi Iwai0e8a21b2009-02-20 14:13:06 +01001026 ass = snd_hda_codec_get_pincfg(codec, nid);
Kailang Yangc9b58002007-10-16 14:30:01 +02001027 if (!(ass & 1) && !(ass & 0x100000))
1028 return;
1029 if ((ass >> 30) != 1) /* no physical connection */
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001030 return;
1031
Kailang Yangc9b58002007-10-16 14:30:01 +02001032 /* check sum */
1033 tmp = 0;
1034 for (i = 1; i < 16; i++) {
Kailang Yang8c427222008-01-10 13:03:59 +01001035 if ((ass >> i) & 1)
Kailang Yangc9b58002007-10-16 14:30:01 +02001036 tmp++;
1037 }
1038 if (((ass >> 16) & 0xf) != tmp)
1039 return;
1040do_sku:
1041 /*
1042 * 0 : override
1043 * 1 : Swap Jack
1044 * 2 : 0 --> Desktop, 1 --> Laptop
1045 * 3~5 : External Amplifier control
1046 * 7~6 : Reserved
1047 */
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001048 tmp = (ass & 0x38) >> 3; /* external Amp control */
1049 switch (tmp) {
1050 case 1:
1051 snd_hda_sequence_write(codec, alc_gpio1_init_verbs);
1052 break;
1053 case 3:
1054 snd_hda_sequence_write(codec, alc_gpio2_init_verbs);
1055 break;
Kailang Yangbdd148a2007-05-08 15:19:08 +02001056 case 7:
1057 snd_hda_sequence_write(codec, alc_gpio3_init_verbs);
1058 break;
Kailang Yangc9b58002007-10-16 14:30:01 +02001059 case 5: /* set EAPD output high */
Kailang Yangbdd148a2007-05-08 15:19:08 +02001060 switch (codec->vendor_id) {
Kailang Yangc9b58002007-10-16 14:30:01 +02001061 case 0x10ec0260:
1062 snd_hda_codec_write(codec, 0x0f, 0,
1063 AC_VERB_SET_EAPD_BTLENABLE, 2);
1064 snd_hda_codec_write(codec, 0x10, 0,
1065 AC_VERB_SET_EAPD_BTLENABLE, 2);
1066 break;
1067 case 0x10ec0262:
Kailang Yangbdd148a2007-05-08 15:19:08 +02001068 case 0x10ec0267:
1069 case 0x10ec0268:
Kailang Yangc9b58002007-10-16 14:30:01 +02001070 case 0x10ec0269:
Takashi Iwaic6e8f2d2009-02-06 12:45:52 +01001071 case 0x10ec0272:
Kailang Yangf9423e72008-05-27 12:32:25 +02001072 case 0x10ec0660:
1073 case 0x10ec0662:
1074 case 0x10ec0663:
Kailang Yangc9b58002007-10-16 14:30:01 +02001075 case 0x10ec0862:
Takashi Iwai20a3a052008-05-23 17:52:53 +02001076 case 0x10ec0889:
Kailang Yangbdd148a2007-05-08 15:19:08 +02001077 snd_hda_codec_write(codec, 0x14, 0,
1078 AC_VERB_SET_EAPD_BTLENABLE, 2);
1079 snd_hda_codec_write(codec, 0x15, 0,
1080 AC_VERB_SET_EAPD_BTLENABLE, 2);
Kailang Yangc9b58002007-10-16 14:30:01 +02001081 break;
Kailang Yangbdd148a2007-05-08 15:19:08 +02001082 }
Kailang Yangc9b58002007-10-16 14:30:01 +02001083 switch (codec->vendor_id) {
1084 case 0x10ec0260:
1085 snd_hda_codec_write(codec, 0x1a, 0,
1086 AC_VERB_SET_COEF_INDEX, 7);
1087 tmp = snd_hda_codec_read(codec, 0x1a, 0,
1088 AC_VERB_GET_PROC_COEF, 0);
1089 snd_hda_codec_write(codec, 0x1a, 0,
1090 AC_VERB_SET_COEF_INDEX, 7);
1091 snd_hda_codec_write(codec, 0x1a, 0,
1092 AC_VERB_SET_PROC_COEF,
1093 tmp | 0x2010);
1094 break;
1095 case 0x10ec0262:
1096 case 0x10ec0880:
1097 case 0x10ec0882:
1098 case 0x10ec0883:
1099 case 0x10ec0885:
Takashi Iwai4a5a4c52009-02-06 12:46:59 +01001100 case 0x10ec0887:
Takashi Iwai20a3a052008-05-23 17:52:53 +02001101 case 0x10ec0889:
Kailang Yangc9b58002007-10-16 14:30:01 +02001102 snd_hda_codec_write(codec, 0x20, 0,
1103 AC_VERB_SET_COEF_INDEX, 7);
1104 tmp = snd_hda_codec_read(codec, 0x20, 0,
1105 AC_VERB_GET_PROC_COEF, 0);
1106 snd_hda_codec_write(codec, 0x20, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +02001107 AC_VERB_SET_COEF_INDEX, 7);
Kailang Yangc9b58002007-10-16 14:30:01 +02001108 snd_hda_codec_write(codec, 0x20, 0,
1109 AC_VERB_SET_PROC_COEF,
1110 tmp | 0x2010);
1111 break;
Kailang Yangf9423e72008-05-27 12:32:25 +02001112 case 0x10ec0888:
Takashi Iwai1082c742008-08-22 15:24:22 +02001113 /*alc888_coef_init(codec);*/ /* called in alc_init() */
Kailang Yangf9423e72008-05-27 12:32:25 +02001114 break;
Kailang Yangc9b58002007-10-16 14:30:01 +02001115 case 0x10ec0267:
1116 case 0x10ec0268:
1117 snd_hda_codec_write(codec, 0x20, 0,
1118 AC_VERB_SET_COEF_INDEX, 7);
1119 tmp = snd_hda_codec_read(codec, 0x20, 0,
1120 AC_VERB_GET_PROC_COEF, 0);
1121 snd_hda_codec_write(codec, 0x20, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +02001122 AC_VERB_SET_COEF_INDEX, 7);
Kailang Yangc9b58002007-10-16 14:30:01 +02001123 snd_hda_codec_write(codec, 0x20, 0,
1124 AC_VERB_SET_PROC_COEF,
1125 tmp | 0x3000);
1126 break;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001127 }
Kailang Yangc9b58002007-10-16 14:30:01 +02001128 default:
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001129 break;
1130 }
Kailang Yangea1fb292008-08-26 12:58:38 +02001131
Kailang Yang8c427222008-01-10 13:03:59 +01001132 /* is laptop or Desktop and enable the function "Mute internal speaker
Kailang Yangc9b58002007-10-16 14:30:01 +02001133 * when the external headphone out jack is plugged"
1134 */
Kailang Yang8c427222008-01-10 13:03:59 +01001135 if (!(ass & 0x8000))
Kailang Yangc9b58002007-10-16 14:30:01 +02001136 return;
1137 /*
1138 * 10~8 : Jack location
1139 * 12~11: Headphone out -> 00: PortA, 01: PortE, 02: PortD, 03: Resvered
1140 * 14~13: Resvered
1141 * 15 : 1 --> enable the function "Mute internal speaker
1142 * when the external headphone out jack is plugged"
1143 */
1144 if (!spec->autocfg.speaker_pins[0]) {
Kailang Yang8c427222008-01-10 13:03:59 +01001145 if (spec->autocfg.line_out_pins[0])
Kailang Yangc9b58002007-10-16 14:30:01 +02001146 spec->autocfg.speaker_pins[0] =
Kailang Yang8c427222008-01-10 13:03:59 +01001147 spec->autocfg.line_out_pins[0];
Kailang Yangc9b58002007-10-16 14:30:01 +02001148 else
1149 return;
1150 }
1151
1152 if (!spec->autocfg.hp_pins[0]) {
1153 tmp = (ass >> 11) & 0x3; /* HP to chassis */
1154 if (tmp == 0)
1155 spec->autocfg.hp_pins[0] = porta;
1156 else if (tmp == 1)
1157 spec->autocfg.hp_pins[0] = porte;
1158 else if (tmp == 2)
1159 spec->autocfg.hp_pins[0] = portd;
1160 else
1161 return;
1162 }
Kailang Yang7fb0d782008-10-15 11:12:35 +02001163 if (spec->autocfg.hp_pins[0])
1164 snd_hda_codec_write(codec, spec->autocfg.hp_pins[0], 0,
1165 AC_VERB_SET_UNSOLICITED_ENABLE,
1166 AC_USRSP_EN | ALC880_HP_EVENT);
Kailang Yangc9b58002007-10-16 14:30:01 +02001167
Takashi Iwai4605b712008-10-31 14:18:24 +01001168#if 0 /* it's broken in some acses -- temporarily disabled */
Kailang Yang7fb0d782008-10-15 11:12:35 +02001169 if (spec->autocfg.input_pins[AUTO_PIN_MIC] &&
1170 spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC])
1171 snd_hda_codec_write(codec,
1172 spec->autocfg.input_pins[AUTO_PIN_MIC], 0,
1173 AC_VERB_SET_UNSOLICITED_ENABLE,
1174 AC_USRSP_EN | ALC880_MIC_EVENT);
Takashi Iwai4605b712008-10-31 14:18:24 +01001175#endif /* disabled */
Kailang Yangea1fb292008-08-26 12:58:38 +02001176
Kailang Yangc9b58002007-10-16 14:30:01 +02001177 spec->unsol_event = alc_sku_unsol_event;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001178}
1179
Takashi Iwai41e41f12005-06-08 14:48:49 +02001180/*
Takashi Iwaif95474e2007-07-10 00:47:43 +02001181 * Fix-up pin default configurations
1182 */
1183
1184struct alc_pincfg {
1185 hda_nid_t nid;
1186 u32 val;
1187};
1188
1189static void alc_fix_pincfg(struct hda_codec *codec,
1190 const struct snd_pci_quirk *quirk,
1191 const struct alc_pincfg **pinfix)
1192{
1193 const struct alc_pincfg *cfg;
1194
1195 quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk);
1196 if (!quirk)
1197 return;
1198
1199 cfg = pinfix[quirk->value];
Takashi Iwai0e8a21b2009-02-20 14:13:06 +01001200 for (; cfg->nid; cfg++)
1201 snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val);
Takashi Iwaif95474e2007-07-10 00:47:43 +02001202}
1203
1204/*
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001205 * ALC888
1206 */
1207
1208/*
1209 * 2ch mode
1210 */
1211static struct hda_verb alc888_4ST_ch2_intel_init[] = {
1212/* Mic-in jack as mic in */
1213 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1214 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1215/* Line-in jack as Line in */
1216 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
1217 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1218/* Line-Out as Front */
1219 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00},
1220 { } /* end */
1221};
1222
1223/*
1224 * 4ch mode
1225 */
1226static struct hda_verb alc888_4ST_ch4_intel_init[] = {
1227/* Mic-in jack as mic in */
1228 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1229 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1230/* Line-in jack as Surround */
1231 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1232 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1233/* Line-Out as Front */
1234 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00},
1235 { } /* end */
1236};
1237
1238/*
1239 * 6ch mode
1240 */
1241static struct hda_verb alc888_4ST_ch6_intel_init[] = {
1242/* Mic-in jack as CLFE */
1243 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1244 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1245/* Line-in jack as Surround */
1246 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1247 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1248/* Line-Out as CLFE (workaround because Mic-in is not loud enough) */
1249 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
1250 { } /* end */
1251};
1252
1253/*
1254 * 8ch mode
1255 */
1256static struct hda_verb alc888_4ST_ch8_intel_init[] = {
1257/* Mic-in jack as CLFE */
1258 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1259 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1260/* Line-in jack as Surround */
1261 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1262 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1263/* Line-Out as Side */
1264 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
1265 { } /* end */
1266};
1267
1268static struct hda_channel_mode alc888_4ST_8ch_intel_modes[4] = {
1269 { 2, alc888_4ST_ch2_intel_init },
1270 { 4, alc888_4ST_ch4_intel_init },
1271 { 6, alc888_4ST_ch6_intel_init },
1272 { 8, alc888_4ST_ch8_intel_init },
1273};
1274
1275/*
1276 * ALC888 Fujitsu Siemens Amillo xa3530
1277 */
1278
1279static struct hda_verb alc888_fujitsu_xa3530_verbs[] = {
1280/* Front Mic: set to PIN_IN (empty by default) */
1281 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1282/* Connect Internal HP to Front */
1283 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1284 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1285 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
1286/* Connect Bass HP to Front */
1287 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1288 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1289 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
1290/* Connect Line-Out side jack (SPDIF) to Side */
1291 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1292 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1293 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
1294/* Connect Mic jack to CLFE */
1295 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1296 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1297 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02},
1298/* Connect Line-in jack to Surround */
1299 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1300 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1301 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
1302/* Connect HP out jack to Front */
1303 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1304 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1305 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
1306/* Enable unsolicited event for HP jack and Line-out jack */
1307 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
1308 {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
1309 {}
1310};
1311
1312static void alc888_fujitsu_xa3530_automute(struct hda_codec *codec)
1313{
1314 unsigned int present;
1315 unsigned int bits;
1316 /* Line out presence */
1317 present = snd_hda_codec_read(codec, 0x17, 0,
1318 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
1319 /* HP out presence */
1320 present = present || snd_hda_codec_read(codec, 0x1b, 0,
1321 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
1322 bits = present ? HDA_AMP_MUTE : 0;
1323 /* Toggle internal speakers muting */
1324 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
1325 HDA_AMP_MUTE, bits);
1326 /* Toggle internal bass muting */
1327 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
1328 HDA_AMP_MUTE, bits);
1329}
1330
1331static void alc888_fujitsu_xa3530_unsol_event(struct hda_codec *codec,
1332 unsigned int res)
1333{
1334 if (res >> 26 == ALC880_HP_EVENT)
1335 alc888_fujitsu_xa3530_automute(codec);
1336}
1337
1338
1339/*
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001340 * ALC888 Acer Aspire 4930G model
1341 */
1342
1343static struct hda_verb alc888_acer_aspire_4930g_verbs[] = {
1344/* Front Mic: set to PIN_IN (empty by default) */
1345 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1346/* Unselect Front Mic by default in input mixer 3 */
1347 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001348/* Enable unsolicited event for HP jack */
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001349 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
1350/* Connect Internal HP to front */
1351 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1352 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1353 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
1354/* Connect HP out to front */
1355 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1356 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1357 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
1358 { }
1359};
1360
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001361static struct hda_input_mux alc888_2_capture_sources[2] = {
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001362 /* Front mic only available on one ADC */
1363 {
1364 .num_items = 4,
1365 .items = {
1366 { "Mic", 0x0 },
1367 { "Line", 0x2 },
1368 { "CD", 0x4 },
1369 { "Front Mic", 0xb },
1370 },
1371 },
1372 {
1373 .num_items = 3,
1374 .items = {
1375 { "Mic", 0x0 },
1376 { "Line", 0x2 },
1377 { "CD", 0x4 },
1378 },
1379 }
1380};
1381
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001382static struct snd_kcontrol_new alc888_base_mixer[] = {
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001383 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1384 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
1385 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1386 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
1387 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
1388 HDA_OUTPUT),
1389 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
1390 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1391 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
1392 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
1393 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
1394 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1395 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1396 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1397 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1398 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1399 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
1400 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001401 { } /* end */
1402};
1403
1404static void alc888_acer_aspire_4930g_automute(struct hda_codec *codec)
1405{
1406 unsigned int present;
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001407 unsigned int bits;
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001408 present = snd_hda_codec_read(codec, 0x15, 0,
1409 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001410 bits = present ? HDA_AMP_MUTE : 0;
1411 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
1412 HDA_AMP_MUTE, bits);
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001413}
1414
1415static void alc888_acer_aspire_4930g_unsol_event(struct hda_codec *codec,
1416 unsigned int res)
1417{
1418 if (res >> 26 == ALC880_HP_EVENT)
1419 alc888_acer_aspire_4930g_automute(codec);
1420}
1421
1422/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001423 * ALC880 3-stack model
1424 *
1425 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0e)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001426 * Pin assignment: Front = 0x14, Line-In/Surr = 0x1a, Mic/CLFE = 0x18,
1427 * F-Mic = 0x1b, HP = 0x19
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428 */
1429
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001430static hda_nid_t alc880_dac_nids[4] = {
1431 /* front, rear, clfe, rear_surr */
1432 0x02, 0x05, 0x04, 0x03
1433};
1434
1435static hda_nid_t alc880_adc_nids[3] = {
1436 /* ADC0-2 */
1437 0x07, 0x08, 0x09,
1438};
1439
1440/* The datasheet says the node 0x07 is connected from inputs,
1441 * but it shows zero connection in the real implementation on some devices.
Kailang Yangdf694da2005-12-05 19:42:22 +01001442 * Note: this is a 915GAV bug, fixed on 915GLV
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001444static hda_nid_t alc880_adc_nids_alt[2] = {
1445 /* ADC1-2 */
1446 0x08, 0x09,
1447};
1448
1449#define ALC880_DIGOUT_NID 0x06
1450#define ALC880_DIGIN_NID 0x0a
1451
1452static struct hda_input_mux alc880_capture_source = {
1453 .num_items = 4,
1454 .items = {
1455 { "Mic", 0x0 },
1456 { "Front Mic", 0x3 },
1457 { "Line", 0x2 },
1458 { "CD", 0x4 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459 },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001460};
1461
1462/* channel source setting (2/6 channel selection for 3-stack) */
1463/* 2ch mode */
1464static struct hda_verb alc880_threestack_ch2_init[] = {
1465 /* set line-in to input, mute it */
1466 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
1467 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1468 /* set mic-in to input vref 80%, mute it */
1469 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1470 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471 { } /* end */
1472};
1473
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001474/* 6ch mode */
1475static struct hda_verb alc880_threestack_ch6_init[] = {
1476 /* set line-in to output, unmute it */
1477 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1478 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1479 /* set mic-in to output, unmute it */
1480 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1481 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1482 { } /* end */
1483};
1484
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001485static struct hda_channel_mode alc880_threestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001486 { 2, alc880_threestack_ch2_init },
1487 { 6, alc880_threestack_ch6_init },
1488};
1489
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001490static struct snd_kcontrol_new alc880_three_stack_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02001491 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001492 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02001493 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001494 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02001495 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1496 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001497 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1498 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1500 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1501 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1502 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1503 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1504 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1505 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
1506 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507 HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001508 {
1509 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1510 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01001511 .info = alc_ch_mode_info,
1512 .get = alc_ch_mode_get,
1513 .put = alc_ch_mode_put,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001514 },
1515 { } /* end */
1516};
1517
1518/* capture mixer elements */
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001519static int alc_cap_vol_info(struct snd_kcontrol *kcontrol,
1520 struct snd_ctl_elem_info *uinfo)
1521{
1522 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1523 struct alc_spec *spec = codec->spec;
1524 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001525
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001526 mutex_lock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001527 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0,
1528 HDA_INPUT);
1529 err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001530 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001531 return err;
1532}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001534static int alc_cap_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
1535 unsigned int size, unsigned int __user *tlv)
1536{
1537 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1538 struct alc_spec *spec = codec->spec;
1539 int err;
1540
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001541 mutex_lock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001542 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0,
1543 HDA_INPUT);
1544 err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001545 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001546 return err;
1547}
1548
1549typedef int (*getput_call_t)(struct snd_kcontrol *kcontrol,
1550 struct snd_ctl_elem_value *ucontrol);
1551
1552static int alc_cap_getput_caller(struct snd_kcontrol *kcontrol,
1553 struct snd_ctl_elem_value *ucontrol,
1554 getput_call_t func)
1555{
1556 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1557 struct alc_spec *spec = codec->spec;
1558 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1559 int err;
1560
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001561 mutex_lock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001562 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[adc_idx],
1563 3, 0, HDA_INPUT);
1564 err = func(kcontrol, ucontrol);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001565 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001566 return err;
1567}
1568
1569static int alc_cap_vol_get(struct snd_kcontrol *kcontrol,
1570 struct snd_ctl_elem_value *ucontrol)
1571{
1572 return alc_cap_getput_caller(kcontrol, ucontrol,
1573 snd_hda_mixer_amp_volume_get);
1574}
1575
1576static int alc_cap_vol_put(struct snd_kcontrol *kcontrol,
1577 struct snd_ctl_elem_value *ucontrol)
1578{
1579 return alc_cap_getput_caller(kcontrol, ucontrol,
1580 snd_hda_mixer_amp_volume_put);
1581}
1582
1583/* capture mixer elements */
1584#define alc_cap_sw_info snd_ctl_boolean_stereo_info
1585
1586static int alc_cap_sw_get(struct snd_kcontrol *kcontrol,
1587 struct snd_ctl_elem_value *ucontrol)
1588{
1589 return alc_cap_getput_caller(kcontrol, ucontrol,
1590 snd_hda_mixer_amp_switch_get);
1591}
1592
1593static int alc_cap_sw_put(struct snd_kcontrol *kcontrol,
1594 struct snd_ctl_elem_value *ucontrol)
1595{
1596 return alc_cap_getput_caller(kcontrol, ucontrol,
1597 snd_hda_mixer_amp_switch_put);
1598}
1599
Takashi Iwaia23b6882009-03-23 15:21:36 +01001600#define _DEFINE_CAPMIX(num) \
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001601 { \
1602 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
1603 .name = "Capture Switch", \
1604 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
1605 .count = num, \
1606 .info = alc_cap_sw_info, \
1607 .get = alc_cap_sw_get, \
1608 .put = alc_cap_sw_put, \
1609 }, \
1610 { \
1611 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
1612 .name = "Capture Volume", \
1613 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | \
1614 SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
1615 SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK), \
1616 .count = num, \
1617 .info = alc_cap_vol_info, \
1618 .get = alc_cap_vol_get, \
1619 .put = alc_cap_vol_put, \
1620 .tlv = { .c = alc_cap_vol_tlv }, \
Takashi Iwaia23b6882009-03-23 15:21:36 +01001621 }
1622
1623#define _DEFINE_CAPSRC(num) \
Takashi Iwai3c3e9892008-10-31 17:48:56 +01001624 { \
1625 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
1626 /* .name = "Capture Source", */ \
1627 .name = "Input Source", \
1628 .count = num, \
1629 .info = alc_mux_enum_info, \
1630 .get = alc_mux_enum_get, \
1631 .put = alc_mux_enum_put, \
Takashi Iwaia23b6882009-03-23 15:21:36 +01001632 }
1633
1634#define DEFINE_CAPMIX(num) \
1635static struct snd_kcontrol_new alc_capture_mixer ## num[] = { \
1636 _DEFINE_CAPMIX(num), \
1637 _DEFINE_CAPSRC(num), \
1638 { } /* end */ \
1639}
1640
1641#define DEFINE_CAPMIX_NOSRC(num) \
1642static struct snd_kcontrol_new alc_capture_mixer_nosrc ## num[] = { \
1643 _DEFINE_CAPMIX(num), \
1644 { } /* end */ \
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001645}
1646
1647/* up to three ADCs */
1648DEFINE_CAPMIX(1);
1649DEFINE_CAPMIX(2);
1650DEFINE_CAPMIX(3);
Takashi Iwaia23b6882009-03-23 15:21:36 +01001651DEFINE_CAPMIX_NOSRC(1);
1652DEFINE_CAPMIX_NOSRC(2);
1653DEFINE_CAPMIX_NOSRC(3);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001654
1655/*
1656 * ALC880 5-stack model
1657 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001658 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0d),
1659 * Side = 0x02 (0xd)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001660 * Pin assignment: Front = 0x14, Surr = 0x17, CLFE = 0x16
1661 * Line-In/Side = 0x1a, Mic = 0x18, F-Mic = 0x1b, HP = 0x19
1662 */
1663
1664/* additional mixers to alc880_three_stack_mixer */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001665static struct snd_kcontrol_new alc880_five_stack_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001666 HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001667 HDA_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668 { } /* end */
1669};
1670
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001671/* channel source setting (6/8 channel selection for 5-stack) */
1672/* 6ch mode */
1673static struct hda_verb alc880_fivestack_ch6_init[] = {
1674 /* set line-in to input, mute it */
1675 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
1676 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02001677 { } /* end */
1678};
1679
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001680/* 8ch mode */
1681static struct hda_verb alc880_fivestack_ch8_init[] = {
1682 /* set line-in to output, unmute it */
1683 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1684 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1685 { } /* end */
1686};
1687
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001688static struct hda_channel_mode alc880_fivestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001689 { 6, alc880_fivestack_ch6_init },
1690 { 8, alc880_fivestack_ch8_init },
1691};
1692
1693
1694/*
1695 * ALC880 6-stack model
1696 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001697 * DAC: Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e),
1698 * Side = 0x05 (0x0f)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001699 * Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, Side = 0x17,
1700 * Mic = 0x18, F-Mic = 0x19, Line = 0x1a, HP = 0x1b
1701 */
1702
1703static hda_nid_t alc880_6st_dac_nids[4] = {
1704 /* front, rear, clfe, rear_surr */
1705 0x02, 0x03, 0x04, 0x05
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02001706};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001707
1708static struct hda_input_mux alc880_6stack_capture_source = {
1709 .num_items = 4,
1710 .items = {
1711 { "Mic", 0x0 },
1712 { "Front Mic", 0x1 },
1713 { "Line", 0x2 },
1714 { "CD", 0x4 },
1715 },
1716};
1717
1718/* fixed 8-channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001719static struct hda_channel_mode alc880_sixstack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001720 { 8, NULL },
1721};
1722
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001723static struct snd_kcontrol_new alc880_six_stack_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001724 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001725 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001726 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001727 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001728 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1729 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001730 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1731 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001732 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001733 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001734 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1735 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1736 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1737 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1738 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1739 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1740 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1741 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001742 {
1743 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1744 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01001745 .info = alc_ch_mode_info,
1746 .get = alc_ch_mode_get,
1747 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02001748 },
1749 { } /* end */
1750};
1751
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001752
1753/*
1754 * ALC880 W810 model
1755 *
1756 * W810 has rear IO for:
1757 * Front (DAC 02)
1758 * Surround (DAC 03)
1759 * Center/LFE (DAC 04)
1760 * Digital out (06)
1761 *
1762 * The system also has a pair of internal speakers, and a headphone jack.
1763 * These are both connected to Line2 on the codec, hence to DAC 02.
Kailang Yangea1fb292008-08-26 12:58:38 +02001764 *
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001765 * There is a variable resistor to control the speaker or headphone
1766 * volume. This is a hardware-only device without a software API.
1767 *
1768 * Plugging headphones in will disable the internal speakers. This is
1769 * implemented in hardware, not via the driver using jack sense. In
1770 * a similar fashion, plugging into the rear socket marked "front" will
1771 * disable both the speakers and headphones.
1772 *
1773 * For input, there's a microphone jack, and an "audio in" jack.
1774 * These may not do anything useful with this driver yet, because I
1775 * haven't setup any initialization verbs for these yet...
1776 */
1777
1778static hda_nid_t alc880_w810_dac_nids[3] = {
1779 /* front, rear/surround, clfe */
1780 0x02, 0x03, 0x04
1781};
1782
1783/* fixed 6 channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001784static struct hda_channel_mode alc880_w810_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001785 { 6, NULL }
1786};
1787
1788/* Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, HP = 0x1b */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001789static struct snd_kcontrol_new alc880_w810_base_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001790 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001791 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001792 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001793 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001794 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1795 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001796 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1797 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001798 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
1799 { } /* end */
1800};
1801
1802
1803/*
1804 * Z710V model
1805 *
1806 * DAC: Front = 0x02 (0x0c), HP = 0x03 (0x0d)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001807 * Pin assignment: Front = 0x14, HP = 0x15, Mic = 0x18, Mic2 = 0x19(?),
1808 * Line = 0x1a
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001809 */
1810
1811static hda_nid_t alc880_z71v_dac_nids[1] = {
1812 0x02
1813};
1814#define ALC880_Z71V_HP_DAC 0x03
1815
1816/* fixed 2 channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001817static struct hda_channel_mode alc880_2_jack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001818 { 2, NULL }
1819};
1820
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001821static struct snd_kcontrol_new alc880_z71v_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001822 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001823 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001824 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001825 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001826 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1827 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1828 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1829 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1830 { } /* end */
1831};
1832
1833
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001834/*
1835 * ALC880 F1734 model
1836 *
1837 * DAC: HP = 0x02 (0x0c), Front = 0x03 (0x0d)
1838 * Pin assignment: HP = 0x14, Front = 0x15, Mic = 0x18
1839 */
1840
1841static hda_nid_t alc880_f1734_dac_nids[1] = {
1842 0x03
1843};
1844#define ALC880_F1734_HP_DAC 0x02
1845
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001846static struct snd_kcontrol_new alc880_f1734_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001847 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001848 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01001849 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1850 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001851 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1852 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Takashi Iwai937b4162008-02-11 14:52:36 +01001853 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1854 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001855 { } /* end */
1856};
1857
Takashi Iwai937b4162008-02-11 14:52:36 +01001858static struct hda_input_mux alc880_f1734_capture_source = {
1859 .num_items = 2,
1860 .items = {
1861 { "Mic", 0x1 },
1862 { "CD", 0x4 },
1863 },
1864};
1865
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001866
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001867/*
1868 * ALC880 ASUS model
1869 *
1870 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
1871 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
1872 * Mic = 0x18, Line = 0x1a
1873 */
1874
1875#define alc880_asus_dac_nids alc880_w810_dac_nids /* identical with w810 */
1876#define alc880_asus_modes alc880_threestack_modes /* 2/6 channel mode */
1877
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001878static struct snd_kcontrol_new alc880_asus_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001879 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001880 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001881 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001882 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001883 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1884 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001885 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1886 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001887 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1888 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1889 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1890 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1891 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1892 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001893 {
1894 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1895 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01001896 .info = alc_ch_mode_info,
1897 .get = alc_ch_mode_get,
1898 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02001899 },
1900 { } /* end */
1901};
1902
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001903/*
1904 * ALC880 ASUS W1V model
1905 *
1906 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
1907 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
1908 * Mic = 0x18, Line = 0x1a, Line2 = 0x1b
1909 */
1910
1911/* additional mixers to alc880_asus_mixer */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001912static struct snd_kcontrol_new alc880_asus_w1v_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001913 HDA_CODEC_VOLUME("Line2 Playback Volume", 0x0b, 0x03, HDA_INPUT),
1914 HDA_CODEC_MUTE("Line2 Playback Switch", 0x0b, 0x03, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001915 { } /* end */
1916};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001917
Kailang Yangdf694da2005-12-05 19:42:22 +01001918/* TCL S700 */
1919static struct snd_kcontrol_new alc880_tcl_s700_mixer[] = {
1920 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1921 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
1922 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
1923 HDA_CODEC_VOLUME("CD Playback Volume", 0x0B, 0x04, HDA_INPUT),
1924 HDA_CODEC_MUTE("CD Playback Switch", 0x0B, 0x04, HDA_INPUT),
1925 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0B, 0x0, HDA_INPUT),
1926 HDA_CODEC_MUTE("Mic Playback Switch", 0x0B, 0x0, HDA_INPUT),
1927 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
1928 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01001929 { } /* end */
1930};
1931
Kailang Yangccc656c2006-10-17 12:32:26 +02001932/* Uniwill */
1933static struct snd_kcontrol_new alc880_uniwill_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01001934 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1935 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
1936 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1937 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02001938 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1939 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
1940 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1941 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
1942 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1943 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1944 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1945 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1946 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1947 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1948 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1949 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02001950 {
1951 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1952 .name = "Channel Mode",
1953 .info = alc_ch_mode_info,
1954 .get = alc_ch_mode_get,
1955 .put = alc_ch_mode_put,
1956 },
1957 { } /* end */
1958};
1959
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01001960static struct snd_kcontrol_new alc880_fujitsu_mixer[] = {
1961 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1962 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
1963 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1964 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
1965 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1966 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1967 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1968 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1969 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1970 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
1971 { } /* end */
1972};
1973
Kailang Yangccc656c2006-10-17 12:32:26 +02001974static struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01001975 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1976 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
1977 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1978 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02001979 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1980 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1981 { } /* end */
1982};
1983
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984/*
Takashi Iwai2134ea42008-01-10 16:53:55 +01001985 * virtual master controls
1986 */
1987
1988/*
1989 * slave controls for virtual master
1990 */
1991static const char *alc_slave_vols[] = {
1992 "Front Playback Volume",
1993 "Surround Playback Volume",
1994 "Center Playback Volume",
1995 "LFE Playback Volume",
1996 "Side Playback Volume",
1997 "Headphone Playback Volume",
1998 "Speaker Playback Volume",
1999 "Mono Playback Volume",
Takashi Iwai2134ea42008-01-10 16:53:55 +01002000 "Line-Out Playback Volume",
Takashi Iwai26f5df22008-11-03 17:39:46 +01002001 "PCM Playback Volume",
Takashi Iwai2134ea42008-01-10 16:53:55 +01002002 NULL,
2003};
2004
2005static const char *alc_slave_sws[] = {
2006 "Front Playback Switch",
2007 "Surround Playback Switch",
2008 "Center Playback Switch",
2009 "LFE Playback Switch",
2010 "Side Playback Switch",
2011 "Headphone Playback Switch",
2012 "Speaker Playback Switch",
2013 "Mono Playback Switch",
Takashi Iwaiedb54a52008-01-29 12:47:02 +01002014 "IEC958 Playback Switch",
Takashi Iwai2134ea42008-01-10 16:53:55 +01002015 NULL,
2016};
2017
2018/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002019 * build control elements
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020 */
Takashi Iwai603c4012008-07-30 15:01:44 +02002021
2022static void alc_free_kctls(struct hda_codec *codec);
2023
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002024/* additional beep mixers; the actual parameters are overwritten at build */
2025static struct snd_kcontrol_new alc_beep_mixer[] = {
2026 HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_INPUT),
2027 HDA_CODEC_MUTE("Beep Playback Switch", 0, 0, HDA_INPUT),
2028 { } /* end */
2029};
2030
Linus Torvalds1da177e2005-04-16 15:20:36 -07002031static int alc_build_controls(struct hda_codec *codec)
2032{
2033 struct alc_spec *spec = codec->spec;
2034 int err;
2035 int i;
2036
2037 for (i = 0; i < spec->num_mixers; i++) {
2038 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
2039 if (err < 0)
2040 return err;
2041 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002042 if (spec->cap_mixer) {
2043 err = snd_hda_add_new_ctls(codec, spec->cap_mixer);
2044 if (err < 0)
2045 return err;
2046 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002047 if (spec->multiout.dig_out_nid) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002048 err = snd_hda_create_spdif_out_ctls(codec,
2049 spec->multiout.dig_out_nid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002050 if (err < 0)
2051 return err;
Takashi Iwaie64f14f2009-01-20 18:32:55 +01002052 if (!spec->no_analog) {
2053 err = snd_hda_create_spdif_share_sw(codec,
2054 &spec->multiout);
2055 if (err < 0)
2056 return err;
2057 spec->multiout.share_spdif = 1;
2058 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002059 }
2060 if (spec->dig_in_nid) {
2061 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
2062 if (err < 0)
2063 return err;
2064 }
Takashi Iwai2134ea42008-01-10 16:53:55 +01002065
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002066 /* create beep controls if needed */
2067 if (spec->beep_amp) {
2068 struct snd_kcontrol_new *knew;
2069 for (knew = alc_beep_mixer; knew->name; knew++) {
2070 struct snd_kcontrol *kctl;
2071 kctl = snd_ctl_new1(knew, codec);
2072 if (!kctl)
2073 return -ENOMEM;
2074 kctl->private_value = spec->beep_amp;
2075 err = snd_hda_ctl_add(codec, kctl);
2076 if (err < 0)
2077 return err;
2078 }
2079 }
2080
Takashi Iwai2134ea42008-01-10 16:53:55 +01002081 /* if we have no master control, let's create it */
Takashi Iwaie64f14f2009-01-20 18:32:55 +01002082 if (!spec->no_analog &&
2083 !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
Takashi Iwai1c82ed12008-02-18 13:05:50 +01002084 unsigned int vmaster_tlv[4];
Takashi Iwai2134ea42008-01-10 16:53:55 +01002085 snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
Takashi Iwai1c82ed12008-02-18 13:05:50 +01002086 HDA_OUTPUT, vmaster_tlv);
Takashi Iwai2134ea42008-01-10 16:53:55 +01002087 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
Takashi Iwai1c82ed12008-02-18 13:05:50 +01002088 vmaster_tlv, alc_slave_vols);
Takashi Iwai2134ea42008-01-10 16:53:55 +01002089 if (err < 0)
2090 return err;
2091 }
Takashi Iwaie64f14f2009-01-20 18:32:55 +01002092 if (!spec->no_analog &&
2093 !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
Takashi Iwai2134ea42008-01-10 16:53:55 +01002094 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
2095 NULL, alc_slave_sws);
2096 if (err < 0)
2097 return err;
2098 }
2099
Takashi Iwai603c4012008-07-30 15:01:44 +02002100 alc_free_kctls(codec); /* no longer needed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101 return 0;
2102}
2103
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002104
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105/*
2106 * initialize the codec volumes, etc
2107 */
2108
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002109/*
2110 * generic initialization of ADC, input mixers and output mixers
2111 */
2112static struct hda_verb alc880_volume_init_verbs[] = {
2113 /*
2114 * Unmute ADC0-2 and set the default input to mic-in
2115 */
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002116 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002117 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002118 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002119 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002120 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002121 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002123 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
2124 * mixer widget
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002125 * Note: PASD motherboards uses the Line In 2 as the input for front
2126 * panel mic (mic 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002127 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002128 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02002129 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2130 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2131 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
2132 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2133 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
2134 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
2135 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002136
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002137 /*
2138 * Set up output mixers (0x0c - 0x0f)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002139 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002140 /* set vol=0 to output mixers */
2141 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2142 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2143 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2144 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2145 /* set up input amps for analog loopback */
2146 /* Amp Indices: DAC = 0, mixer = 1 */
Takashi Iwai05acb862005-06-10 19:50:25 +02002147 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2148 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02002149 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2150 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02002151 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2152 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02002153 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2154 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002155
2156 { }
2157};
2158
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002159/*
2160 * 3-stack pin configuration:
2161 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
2162 */
2163static struct hda_verb alc880_pin_3stack_init_verbs[] = {
2164 /*
2165 * preset connection lists of input pins
2166 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
2167 */
2168 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
2169 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2170 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
2171
2172 /*
2173 * Set pin mode and muting
2174 */
2175 /* set front pin widgets 0x14 for output */
2176 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2177 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2178 /* Mic1 (rear panel) pin widget for input and vref at 80% */
2179 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2180 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2181 /* Mic2 (as headphone out) for HP output */
2182 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2183 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2184 /* Line In pin widget for input */
2185 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2186 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2187 /* Line2 (as front mic) pin widget for input and vref at 80% */
2188 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2189 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2190 /* CD pin widget for input */
2191 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2192
2193 { }
2194};
2195
2196/*
2197 * 5-stack pin configuration:
2198 * front = 0x14, surround = 0x17, clfe = 0x16, mic = 0x18, HP = 0x19,
2199 * line-in/side = 0x1a, f-mic = 0x1b
2200 */
2201static struct hda_verb alc880_pin_5stack_init_verbs[] = {
2202 /*
2203 * preset connection lists of input pins
2204 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
2205 */
2206 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2207 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/side */
2208
2209 /*
2210 * Set pin mode and muting
2211 */
2212 /* set pin widgets 0x14-0x17 for output */
Takashi Iwai05acb862005-06-10 19:50:25 +02002213 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2214 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2215 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2216 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002217 /* unmute pins for output (no gain on this amp) */
2218 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2219 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2220 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2221 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2222
Linus Torvalds1da177e2005-04-16 15:20:36 -07002223 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02002224 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002225 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2226 /* Mic2 (as headphone out) for HP output */
2227 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02002228 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002229 /* Line In pin widget for input */
2230 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2231 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2232 /* Line2 (as front mic) pin widget for input and vref at 80% */
2233 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2234 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2235 /* CD pin widget for input */
2236 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237
2238 { }
2239};
2240
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002241/*
2242 * W810 pin configuration:
2243 * front = 0x14, surround = 0x15, clfe = 0x16, HP = 0x1b
2244 */
2245static struct hda_verb alc880_pin_w810_init_verbs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246 /* hphone/speaker input selector: front DAC */
2247 {0x13, AC_VERB_SET_CONNECT_SEL, 0x0},
2248
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002249 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2250 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2251 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2252 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2253 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2254 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2255
2256 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02002257 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259 { }
2260};
2261
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002262/*
2263 * Z71V pin configuration:
2264 * Speaker-out = 0x14, HP = 0x15, Mic = 0x18, Line-in = 0x1a, Mic2 = 0x1b (?)
2265 */
2266static struct hda_verb alc880_pin_z71v_init_verbs[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02002267 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002268 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai05acb862005-06-10 19:50:25 +02002269 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002270 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02002271
Takashi Iwai16ded522005-06-10 19:58:24 +02002272 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002273 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02002274 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002275 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02002276
2277 { }
2278};
2279
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002280/*
2281 * 6-stack pin configuration:
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002282 * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18,
2283 * f-mic = 0x19, line = 0x1a, HP = 0x1b
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002284 */
2285static struct hda_verb alc880_pin_6stack_init_verbs[] = {
2286 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2287
Takashi Iwai16ded522005-06-10 19:58:24 +02002288 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002289 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002290 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002291 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002292 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002293 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002294 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002295 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2296
Takashi Iwai16ded522005-06-10 19:58:24 +02002297 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002298 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002299 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002300 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002301 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002302 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002303 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai16ded522005-06-10 19:58:24 +02002304 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002305 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangea1fb292008-08-26 12:58:38 +02002306
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002307 { }
2308};
Takashi Iwai16ded522005-06-10 19:58:24 +02002309
Kailang Yangccc656c2006-10-17 12:32:26 +02002310/*
2311 * Uniwill pin configuration:
2312 * HP = 0x14, InternalSpeaker = 0x15, mic = 0x18, internal mic = 0x19,
2313 * line = 0x1a
2314 */
2315static struct hda_verb alc880_uniwill_init_verbs[] = {
2316 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2317
2318 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2319 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2320 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2321 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2322 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2323 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2324 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2325 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2326 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2327 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2328 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2329 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2330 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2331 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2332
2333 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2334 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2335 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2336 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2337 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2338 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2339 /* {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, */
2340 /* {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
2341 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2342
2343 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
2344 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
2345
2346 { }
2347};
2348
2349/*
2350* Uniwill P53
Kailang Yangea1fb292008-08-26 12:58:38 +02002351* HP = 0x14, InternalSpeaker = 0x15, mic = 0x19,
Kailang Yangccc656c2006-10-17 12:32:26 +02002352 */
2353static struct hda_verb alc880_uniwill_p53_init_verbs[] = {
2354 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2355
2356 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2357 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2358 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2359 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2360 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2361 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2362 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2363 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2364 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2365 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2366 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2367 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2368
2369 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2370 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2371 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2372 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2373 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2374 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2375
2376 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
2377 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_DCVOL_EVENT},
2378
2379 { }
2380};
2381
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01002382static struct hda_verb alc880_beep_init_verbs[] = {
2383 { 0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) },
2384 { }
2385};
2386
Kailang Yangccc656c2006-10-17 12:32:26 +02002387/* toggle speaker-output according to the hp-jack state */
Takashi Iwai458a4fa2007-05-05 12:18:40 +02002388static void alc880_uniwill_hp_automute(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02002389{
2390 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002391 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02002392
2393 present = snd_hda_codec_read(codec, 0x14, 0,
2394 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02002395 bits = present ? HDA_AMP_MUTE : 0;
2396 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
2397 HDA_AMP_MUTE, bits);
2398 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
2399 HDA_AMP_MUTE, bits);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02002400}
2401
2402/* auto-toggle front mic */
2403static void alc880_uniwill_mic_automute(struct hda_codec *codec)
2404{
2405 unsigned int present;
2406 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02002407
2408 present = snd_hda_codec_read(codec, 0x18, 0,
2409 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02002410 bits = present ? HDA_AMP_MUTE : 0;
2411 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02002412}
2413
2414static void alc880_uniwill_automute(struct hda_codec *codec)
2415{
2416 alc880_uniwill_hp_automute(codec);
2417 alc880_uniwill_mic_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02002418}
2419
2420static void alc880_uniwill_unsol_event(struct hda_codec *codec,
2421 unsigned int res)
2422{
2423 /* Looks like the unsol event is incompatible with the standard
2424 * definition. 4bit tag is placed at 28 bit!
2425 */
Takashi Iwai458a4fa2007-05-05 12:18:40 +02002426 switch (res >> 28) {
2427 case ALC880_HP_EVENT:
2428 alc880_uniwill_hp_automute(codec);
2429 break;
2430 case ALC880_MIC_EVENT:
2431 alc880_uniwill_mic_automute(codec);
2432 break;
2433 }
Kailang Yangccc656c2006-10-17 12:32:26 +02002434}
2435
2436static void alc880_uniwill_p53_hp_automute(struct hda_codec *codec)
2437{
2438 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002439 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02002440
2441 present = snd_hda_codec_read(codec, 0x14, 0,
2442 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02002443 bits = present ? HDA_AMP_MUTE : 0;
Jiang zhe64654c22008-04-14 13:26:21 +02002444 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, HDA_AMP_MUTE, bits);
Kailang Yangccc656c2006-10-17 12:32:26 +02002445}
2446
2447static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec)
2448{
2449 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02002450
Kailang Yangccc656c2006-10-17 12:32:26 +02002451 present = snd_hda_codec_read(codec, 0x21, 0,
Takashi Iwai47fd8302007-08-10 17:11:07 +02002452 AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
2453 present &= HDA_AMP_VOLMASK;
2454 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0,
2455 HDA_AMP_VOLMASK, present);
2456 snd_hda_codec_amp_stereo(codec, 0x0d, HDA_OUTPUT, 0,
2457 HDA_AMP_VOLMASK, present);
Kailang Yangccc656c2006-10-17 12:32:26 +02002458}
Takashi Iwai47fd8302007-08-10 17:11:07 +02002459
Kailang Yangccc656c2006-10-17 12:32:26 +02002460static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec,
2461 unsigned int res)
2462{
2463 /* Looks like the unsol event is incompatible with the standard
2464 * definition. 4bit tag is placed at 28 bit!
2465 */
2466 if ((res >> 28) == ALC880_HP_EVENT)
2467 alc880_uniwill_p53_hp_automute(codec);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002468 if ((res >> 28) == ALC880_DCVOL_EVENT)
Kailang Yangccc656c2006-10-17 12:32:26 +02002469 alc880_uniwill_p53_dcvol_automute(codec);
2470}
2471
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002472/*
2473 * F1734 pin configuration:
2474 * HP = 0x14, speaker-out = 0x15, mic = 0x18
2475 */
2476static struct hda_verb alc880_pin_f1734_init_verbs[] = {
Michael Gruberee7a9c72008-03-10 11:30:59 +01002477 {0x07, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002478 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
2479 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
2480 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
2481 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
2482
2483 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2484 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2485 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2486 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2487
2488 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2489 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Michael Gruberee7a9c72008-03-10 11:30:59 +01002490 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002491 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2492 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2493 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2494 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2495 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2496 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02002497
Takashi Iwai937b4162008-02-11 14:52:36 +01002498 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
2499 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_DCVOL_EVENT},
2500
Takashi Iwai16ded522005-06-10 19:58:24 +02002501 { }
2502};
2503
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002504/*
2505 * ASUS pin configuration:
2506 * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a
2507 */
2508static struct hda_verb alc880_pin_asus_init_verbs[] = {
2509 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
2510 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
2511 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
2512 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
2513
2514 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2515 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2516 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2517 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2518 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2519 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2520 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2521 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2522
2523 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2524 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2525 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2526 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2527 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2528 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2529 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2530 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2531 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangea1fb292008-08-26 12:58:38 +02002532
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002533 { }
2534};
2535
2536/* Enable GPIO mask and set output */
Kailang Yangbc9f98a2007-04-12 13:06:07 +02002537#define alc880_gpio1_init_verbs alc_gpio1_init_verbs
2538#define alc880_gpio2_init_verbs alc_gpio2_init_verbs
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002539
Kailang Yangdf694da2005-12-05 19:42:22 +01002540/* Clevo m520g init */
2541static struct hda_verb alc880_pin_clevo_init_verbs[] = {
2542 /* headphone output */
2543 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
2544 /* line-out */
2545 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2546 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2547 /* Line-in */
2548 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2549 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2550 /* CD */
2551 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2552 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2553 /* Mic1 (rear panel) */
2554 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2555 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2556 /* Mic2 (front panel) */
2557 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2558 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2559 /* headphone */
2560 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2561 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2562 /* change to EAPD mode */
2563 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
2564 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
2565
2566 { }
2567};
2568
2569static struct hda_verb alc880_pin_tcl_S700_init_verbs[] = {
Takashi Iwai4b146cb2006-07-28 14:42:36 +02002570 /* change to EAPD mode */
2571 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
2572 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
2573
Kailang Yangdf694da2005-12-05 19:42:22 +01002574 /* Headphone output */
2575 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2576 /* Front output*/
2577 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2578 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
2579
2580 /* Line In pin widget for input */
2581 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2582 /* CD pin widget for input */
2583 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2584 /* Mic1 (rear panel) pin widget for input and vref at 80% */
2585 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2586
2587 /* change to EAPD mode */
2588 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
2589 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
2590
2591 { }
2592};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002593
2594/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002595 * LG m1 express dual
2596 *
2597 * Pin assignment:
2598 * Rear Line-In/Out (blue): 0x14
2599 * Build-in Mic-In: 0x15
2600 * Speaker-out: 0x17
2601 * HP-Out (green): 0x1b
2602 * Mic-In/Out (red): 0x19
2603 * SPDIF-Out: 0x1e
2604 */
2605
2606/* To make 5.1 output working (green=Front, blue=Surr, red=CLFE) */
2607static hda_nid_t alc880_lg_dac_nids[3] = {
2608 0x05, 0x02, 0x03
2609};
2610
2611/* seems analog CD is not working */
2612static struct hda_input_mux alc880_lg_capture_source = {
2613 .num_items = 3,
2614 .items = {
2615 { "Mic", 0x1 },
2616 { "Line", 0x5 },
2617 { "Internal Mic", 0x6 },
2618 },
2619};
2620
2621/* 2,4,6 channel modes */
2622static struct hda_verb alc880_lg_ch2_init[] = {
2623 /* set line-in and mic-in to input */
2624 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2625 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2626 { }
2627};
2628
2629static struct hda_verb alc880_lg_ch4_init[] = {
2630 /* set line-in to out and mic-in to input */
2631 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
2632 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2633 { }
2634};
2635
2636static struct hda_verb alc880_lg_ch6_init[] = {
2637 /* set line-in and mic-in to output */
2638 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
2639 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
2640 { }
2641};
2642
2643static struct hda_channel_mode alc880_lg_ch_modes[3] = {
2644 { 2, alc880_lg_ch2_init },
2645 { 4, alc880_lg_ch4_init },
2646 { 6, alc880_lg_ch6_init },
2647};
2648
2649static struct snd_kcontrol_new alc880_lg_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01002650 HDA_CODEC_VOLUME("Front Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
2651 HDA_BIND_MUTE("Front Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002652 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2653 HDA_BIND_MUTE("Surround Playback Switch", 0x0c, 2, HDA_INPUT),
2654 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
2655 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
2656 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
2657 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
2658 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2659 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
2660 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x06, HDA_INPUT),
2661 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x06, HDA_INPUT),
2662 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x07, HDA_INPUT),
2663 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x07, HDA_INPUT),
2664 {
2665 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2666 .name = "Channel Mode",
2667 .info = alc_ch_mode_info,
2668 .get = alc_ch_mode_get,
2669 .put = alc_ch_mode_put,
2670 },
2671 { } /* end */
2672};
2673
2674static struct hda_verb alc880_lg_init_verbs[] = {
2675 /* set capture source to mic-in */
2676 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2677 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2678 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2679 /* mute all amp mixer inputs */
2680 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02002681 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
2682 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002683 /* line-in to input */
2684 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2685 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2686 /* built-in mic */
2687 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2688 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2689 /* speaker-out */
2690 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2691 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2692 /* mic-in to input */
2693 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
2694 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2695 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2696 /* HP-out */
2697 {0x13, AC_VERB_SET_CONNECT_SEL, 0x03},
2698 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2699 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2700 /* jack sense */
2701 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | 0x1},
2702 { }
2703};
2704
2705/* toggle speaker-output according to the hp-jack state */
2706static void alc880_lg_automute(struct hda_codec *codec)
2707{
2708 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002709 unsigned char bits;
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002710
2711 present = snd_hda_codec_read(codec, 0x1b, 0,
2712 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02002713 bits = present ? HDA_AMP_MUTE : 0;
2714 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
2715 HDA_AMP_MUTE, bits);
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002716}
2717
2718static void alc880_lg_unsol_event(struct hda_codec *codec, unsigned int res)
2719{
2720 /* Looks like the unsol event is incompatible with the standard
2721 * definition. 4bit tag is placed at 28 bit!
2722 */
2723 if ((res >> 28) == 0x01)
2724 alc880_lg_automute(codec);
2725}
2726
2727/*
Takashi Iwaid6815182006-03-23 16:06:23 +01002728 * LG LW20
2729 *
2730 * Pin assignment:
2731 * Speaker-out: 0x14
2732 * Mic-In: 0x18
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02002733 * Built-in Mic-In: 0x19
2734 * Line-In: 0x1b
2735 * HP-Out: 0x1a
Takashi Iwaid6815182006-03-23 16:06:23 +01002736 * SPDIF-Out: 0x1e
2737 */
2738
Takashi Iwaid6815182006-03-23 16:06:23 +01002739static struct hda_input_mux alc880_lg_lw_capture_source = {
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02002740 .num_items = 3,
Takashi Iwaid6815182006-03-23 16:06:23 +01002741 .items = {
2742 { "Mic", 0x0 },
2743 { "Internal Mic", 0x1 },
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02002744 { "Line In", 0x2 },
Takashi Iwaid6815182006-03-23 16:06:23 +01002745 },
2746};
2747
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002748#define alc880_lg_lw_modes alc880_threestack_modes
2749
Takashi Iwaid6815182006-03-23 16:06:23 +01002750static struct snd_kcontrol_new alc880_lg_lw_mixer[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002751 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2752 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
2753 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
2754 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
2755 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2756 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
2757 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2758 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
2759 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2760 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaid6815182006-03-23 16:06:23 +01002761 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2762 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2763 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
2764 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002765 {
2766 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2767 .name = "Channel Mode",
2768 .info = alc_ch_mode_info,
2769 .get = alc_ch_mode_get,
2770 .put = alc_ch_mode_put,
2771 },
Takashi Iwaid6815182006-03-23 16:06:23 +01002772 { } /* end */
2773};
2774
2775static struct hda_verb alc880_lg_lw_init_verbs[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002776 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2777 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
2778 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
2779
Takashi Iwaid6815182006-03-23 16:06:23 +01002780 /* set capture source to mic-in */
2781 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2782 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2783 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02002784 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaid6815182006-03-23 16:06:23 +01002785 /* speaker-out */
2786 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2787 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2788 /* HP-out */
Takashi Iwaid6815182006-03-23 16:06:23 +01002789 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2790 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2791 /* mic-in to input */
2792 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2793 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2794 /* built-in mic */
2795 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2796 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2797 /* jack sense */
2798 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | 0x1},
2799 { }
2800};
2801
2802/* toggle speaker-output according to the hp-jack state */
2803static void alc880_lg_lw_automute(struct hda_codec *codec)
2804{
2805 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002806 unsigned char bits;
Takashi Iwaid6815182006-03-23 16:06:23 +01002807
2808 present = snd_hda_codec_read(codec, 0x1b, 0,
2809 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02002810 bits = present ? HDA_AMP_MUTE : 0;
2811 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
2812 HDA_AMP_MUTE, bits);
Takashi Iwaid6815182006-03-23 16:06:23 +01002813}
2814
2815static void alc880_lg_lw_unsol_event(struct hda_codec *codec, unsigned int res)
2816{
2817 /* Looks like the unsol event is incompatible with the standard
2818 * definition. 4bit tag is placed at 28 bit!
2819 */
2820 if ((res >> 28) == 0x01)
2821 alc880_lg_lw_automute(codec);
2822}
2823
Takashi Iwaidf99cd32008-04-25 15:25:04 +02002824static struct snd_kcontrol_new alc880_medion_rim_mixer[] = {
2825 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2826 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
2827 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2828 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2829 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2830 HDA_CODEC_MUTE("Internal Playback Switch", 0x0b, 0x1, HDA_INPUT),
2831 { } /* end */
2832};
2833
2834static struct hda_input_mux alc880_medion_rim_capture_source = {
2835 .num_items = 2,
2836 .items = {
2837 { "Mic", 0x0 },
2838 { "Internal Mic", 0x1 },
2839 },
2840};
2841
2842static struct hda_verb alc880_medion_rim_init_verbs[] = {
2843 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2844
2845 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2846 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2847
2848 /* Mic1 (rear panel) pin widget for input and vref at 80% */
2849 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2850 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2851 /* Mic2 (as headphone out) for HP output */
2852 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2853 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2854 /* Internal Speaker */
2855 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2856 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2857
2858 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
2859 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
2860
2861 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
2862 { }
2863};
2864
2865/* toggle speaker-output according to the hp-jack state */
2866static void alc880_medion_rim_automute(struct hda_codec *codec)
2867{
2868 unsigned int present;
2869 unsigned char bits;
2870
2871 present = snd_hda_codec_read(codec, 0x14, 0,
2872 AC_VERB_GET_PIN_SENSE, 0)
2873 & AC_PINSENSE_PRESENCE;
2874 bits = present ? HDA_AMP_MUTE : 0;
2875 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
2876 HDA_AMP_MUTE, bits);
2877 if (present)
2878 snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0);
2879 else
2880 snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 2);
2881}
2882
2883static void alc880_medion_rim_unsol_event(struct hda_codec *codec,
2884 unsigned int res)
2885{
2886 /* Looks like the unsol event is incompatible with the standard
2887 * definition. 4bit tag is placed at 28 bit!
2888 */
2889 if ((res >> 28) == ALC880_HP_EVENT)
2890 alc880_medion_rim_automute(codec);
2891}
2892
Takashi Iwaicb53c622007-08-10 17:21:45 +02002893#ifdef CONFIG_SND_HDA_POWER_SAVE
2894static struct hda_amp_list alc880_loopbacks[] = {
2895 { 0x0b, HDA_INPUT, 0 },
2896 { 0x0b, HDA_INPUT, 1 },
2897 { 0x0b, HDA_INPUT, 2 },
2898 { 0x0b, HDA_INPUT, 3 },
2899 { 0x0b, HDA_INPUT, 4 },
2900 { } /* end */
2901};
2902
2903static struct hda_amp_list alc880_lg_loopbacks[] = {
2904 { 0x0b, HDA_INPUT, 1 },
2905 { 0x0b, HDA_INPUT, 6 },
2906 { 0x0b, HDA_INPUT, 7 },
2907 { } /* end */
2908};
2909#endif
2910
Takashi Iwaid6815182006-03-23 16:06:23 +01002911/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002912 * Common callbacks
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002913 */
Takashi Iwai16ded522005-06-10 19:58:24 +02002914
Linus Torvalds1da177e2005-04-16 15:20:36 -07002915static int alc_init(struct hda_codec *codec)
2916{
2917 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002918 unsigned int i;
2919
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02002920 alc_fix_pll(codec);
Takashi Iwai1082c742008-08-22 15:24:22 +02002921 if (codec->vendor_id == 0x10ec0888)
2922 alc888_coef_init(codec);
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02002923
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002924 for (i = 0; i < spec->num_init_verbs; i++)
2925 snd_hda_sequence_write(codec, spec->init_verbs[i]);
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002926
2927 if (spec->init_hook)
2928 spec->init_hook(codec);
2929
Linus Torvalds1da177e2005-04-16 15:20:36 -07002930 return 0;
2931}
2932
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002933static void alc_unsol_event(struct hda_codec *codec, unsigned int res)
2934{
2935 struct alc_spec *spec = codec->spec;
2936
2937 if (spec->unsol_event)
2938 spec->unsol_event(codec, res);
2939}
2940
Takashi Iwaicb53c622007-08-10 17:21:45 +02002941#ifdef CONFIG_SND_HDA_POWER_SAVE
2942static int alc_check_power_status(struct hda_codec *codec, hda_nid_t nid)
2943{
2944 struct alc_spec *spec = codec->spec;
2945 return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
2946}
2947#endif
2948
Linus Torvalds1da177e2005-04-16 15:20:36 -07002949/*
2950 * Analog playback callbacks
2951 */
2952static int alc880_playback_pcm_open(struct hda_pcm_stream *hinfo,
2953 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002954 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002955{
2956 struct alc_spec *spec = codec->spec;
Takashi Iwai9a081602008-02-12 18:37:26 +01002957 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
2958 hinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002959}
2960
2961static int alc880_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
2962 struct hda_codec *codec,
2963 unsigned int stream_tag,
2964 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002965 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002966{
2967 struct alc_spec *spec = codec->spec;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002968 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
2969 stream_tag, format, substream);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970}
2971
2972static int alc880_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
2973 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002974 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002975{
2976 struct alc_spec *spec = codec->spec;
2977 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
2978}
2979
2980/*
2981 * Digital out
2982 */
2983static int alc880_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
2984 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002985 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002986{
2987 struct alc_spec *spec = codec->spec;
2988 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
2989}
2990
Takashi Iwai6b97eb42007-04-05 14:51:48 +02002991static int alc880_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
2992 struct hda_codec *codec,
2993 unsigned int stream_tag,
2994 unsigned int format,
2995 struct snd_pcm_substream *substream)
2996{
2997 struct alc_spec *spec = codec->spec;
2998 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
2999 stream_tag, format, substream);
3000}
3001
Takashi Iwai9b5f12e2009-02-13 11:47:37 +01003002static int alc880_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
3003 struct hda_codec *codec,
3004 struct snd_pcm_substream *substream)
3005{
3006 struct alc_spec *spec = codec->spec;
3007 return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
3008}
3009
Linus Torvalds1da177e2005-04-16 15:20:36 -07003010static int alc880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
3011 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003012 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003013{
3014 struct alc_spec *spec = codec->spec;
3015 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
3016}
3017
3018/*
3019 * Analog capture
3020 */
Takashi Iwai63300792008-01-24 15:31:36 +01003021static int alc880_alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003022 struct hda_codec *codec,
3023 unsigned int stream_tag,
3024 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003025 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003026{
3027 struct alc_spec *spec = codec->spec;
3028
Takashi Iwai63300792008-01-24 15:31:36 +01003029 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1],
Linus Torvalds1da177e2005-04-16 15:20:36 -07003030 stream_tag, 0, format);
3031 return 0;
3032}
3033
Takashi Iwai63300792008-01-24 15:31:36 +01003034static int alc880_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003035 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003036 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003037{
3038 struct alc_spec *spec = codec->spec;
3039
Takashi Iwai888afa12008-03-18 09:57:50 +01003040 snd_hda_codec_cleanup_stream(codec,
3041 spec->adc_nids[substream->number + 1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003042 return 0;
3043}
3044
3045
3046/*
3047 */
3048static struct hda_pcm_stream alc880_pcm_analog_playback = {
3049 .substreams = 1,
3050 .channels_min = 2,
3051 .channels_max = 8,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003052 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003053 .ops = {
3054 .open = alc880_playback_pcm_open,
3055 .prepare = alc880_playback_pcm_prepare,
3056 .cleanup = alc880_playback_pcm_cleanup
3057 },
3058};
3059
3060static struct hda_pcm_stream alc880_pcm_analog_capture = {
Takashi Iwai63300792008-01-24 15:31:36 +01003061 .substreams = 1,
3062 .channels_min = 2,
3063 .channels_max = 2,
3064 /* NID is set in alc_build_pcms */
3065};
3066
3067static struct hda_pcm_stream alc880_pcm_analog_alt_playback = {
3068 .substreams = 1,
3069 .channels_min = 2,
3070 .channels_max = 2,
3071 /* NID is set in alc_build_pcms */
3072};
3073
3074static struct hda_pcm_stream alc880_pcm_analog_alt_capture = {
3075 .substreams = 2, /* can be overridden */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003076 .channels_min = 2,
3077 .channels_max = 2,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003078 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003079 .ops = {
Takashi Iwai63300792008-01-24 15:31:36 +01003080 .prepare = alc880_alt_capture_pcm_prepare,
3081 .cleanup = alc880_alt_capture_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07003082 },
3083};
3084
3085static struct hda_pcm_stream alc880_pcm_digital_playback = {
3086 .substreams = 1,
3087 .channels_min = 2,
3088 .channels_max = 2,
3089 /* NID is set in alc_build_pcms */
3090 .ops = {
3091 .open = alc880_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02003092 .close = alc880_dig_playback_pcm_close,
Takashi Iwai9b5f12e2009-02-13 11:47:37 +01003093 .prepare = alc880_dig_playback_pcm_prepare,
3094 .cleanup = alc880_dig_playback_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07003095 },
3096};
3097
3098static struct hda_pcm_stream alc880_pcm_digital_capture = {
3099 .substreams = 1,
3100 .channels_min = 2,
3101 .channels_max = 2,
3102 /* NID is set in alc_build_pcms */
3103};
3104
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01003105/* Used by alc_build_pcms to flag that a PCM has no playback stream */
Takashi Iwai63300792008-01-24 15:31:36 +01003106static struct hda_pcm_stream alc_pcm_null_stream = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01003107 .substreams = 0,
3108 .channels_min = 0,
3109 .channels_max = 0,
3110};
3111
Linus Torvalds1da177e2005-04-16 15:20:36 -07003112static int alc_build_pcms(struct hda_codec *codec)
3113{
3114 struct alc_spec *spec = codec->spec;
3115 struct hda_pcm *info = spec->pcm_rec;
3116 int i;
3117
3118 codec->num_pcms = 1;
3119 codec->pcm_info = info;
3120
Takashi Iwaie64f14f2009-01-20 18:32:55 +01003121 if (spec->no_analog)
3122 goto skip_analog;
3123
Linus Torvalds1da177e2005-04-16 15:20:36 -07003124 info->name = spec->stream_name_analog;
Takashi Iwai4a471b72005-12-07 13:56:29 +01003125 if (spec->stream_analog_playback) {
Takashi Iwaida3cec32008-08-08 17:12:14 +02003126 if (snd_BUG_ON(!spec->multiout.dac_nids))
3127 return -EINVAL;
Takashi Iwai4a471b72005-12-07 13:56:29 +01003128 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
3129 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
3130 }
3131 if (spec->stream_analog_capture) {
Takashi Iwaida3cec32008-08-08 17:12:14 +02003132 if (snd_BUG_ON(!spec->adc_nids))
3133 return -EINVAL;
Takashi Iwai4a471b72005-12-07 13:56:29 +01003134 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
3135 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
3136 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003137
Takashi Iwai4a471b72005-12-07 13:56:29 +01003138 if (spec->channel_mode) {
3139 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0;
3140 for (i = 0; i < spec->num_channel_mode; i++) {
3141 if (spec->channel_mode[i].channels > info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max) {
3142 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->channel_mode[i].channels;
3143 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003144 }
3145 }
3146
Takashi Iwaie64f14f2009-01-20 18:32:55 +01003147 skip_analog:
Takashi Iwaie08a0072006-09-07 17:52:14 +02003148 /* SPDIF for stream index #1 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003149 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
Takashi Iwaie08a0072006-09-07 17:52:14 +02003150 codec->num_pcms = 2;
Wu Fengguangb25c9da2009-02-06 15:02:27 +08003151 codec->slave_dig_outs = spec->multiout.slave_dig_outs;
Takashi Iwaic06134d2006-10-11 18:49:13 +02003152 info = spec->pcm_rec + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003153 info->name = spec->stream_name_digital;
Takashi Iwai8c441982009-01-20 18:30:20 +01003154 if (spec->dig_out_type)
3155 info->pcm_type = spec->dig_out_type;
3156 else
3157 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Takashi Iwai4a471b72005-12-07 13:56:29 +01003158 if (spec->multiout.dig_out_nid &&
3159 spec->stream_digital_playback) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003160 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_digital_playback);
3161 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
3162 }
Takashi Iwai4a471b72005-12-07 13:56:29 +01003163 if (spec->dig_in_nid &&
3164 spec->stream_digital_capture) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003165 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_digital_capture);
3166 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
3167 }
Takashi Iwai963f8032008-08-11 10:04:40 +02003168 /* FIXME: do we need this for all Realtek codec models? */
3169 codec->spdif_status_reset = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003170 }
3171
Takashi Iwaie64f14f2009-01-20 18:32:55 +01003172 if (spec->no_analog)
3173 return 0;
3174
Takashi Iwaie08a0072006-09-07 17:52:14 +02003175 /* If the use of more than one ADC is requested for the current
3176 * model, configure a second analog capture-only PCM.
3177 */
3178 /* Additional Analaog capture for index #2 */
Takashi Iwai63300792008-01-24 15:31:36 +01003179 if ((spec->alt_dac_nid && spec->stream_analog_alt_playback) ||
3180 (spec->num_adc_nids > 1 && spec->stream_analog_alt_capture)) {
Takashi Iwaie08a0072006-09-07 17:52:14 +02003181 codec->num_pcms = 3;
Takashi Iwaic06134d2006-10-11 18:49:13 +02003182 info = spec->pcm_rec + 2;
Takashi Iwaie08a0072006-09-07 17:52:14 +02003183 info->name = spec->stream_name_analog;
Takashi Iwai63300792008-01-24 15:31:36 +01003184 if (spec->alt_dac_nid) {
3185 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
3186 *spec->stream_analog_alt_playback;
3187 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
3188 spec->alt_dac_nid;
3189 } else {
3190 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
3191 alc_pcm_null_stream;
3192 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
3193 }
3194 if (spec->num_adc_nids > 1) {
3195 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
3196 *spec->stream_analog_alt_capture;
3197 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
3198 spec->adc_nids[1];
3199 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams =
3200 spec->num_adc_nids - 1;
3201 } else {
3202 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
3203 alc_pcm_null_stream;
3204 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0;
Takashi Iwaie08a0072006-09-07 17:52:14 +02003205 }
3206 }
3207
Linus Torvalds1da177e2005-04-16 15:20:36 -07003208 return 0;
3209}
3210
Takashi Iwai603c4012008-07-30 15:01:44 +02003211static void alc_free_kctls(struct hda_codec *codec)
3212{
3213 struct alc_spec *spec = codec->spec;
3214
3215 if (spec->kctls.list) {
3216 struct snd_kcontrol_new *kctl = spec->kctls.list;
3217 int i;
3218 for (i = 0; i < spec->kctls.used; i++)
3219 kfree(kctl[i].name);
3220 }
3221 snd_array_free(&spec->kctls);
3222}
3223
Linus Torvalds1da177e2005-04-16 15:20:36 -07003224static void alc_free(struct hda_codec *codec)
3225{
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003226 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003227
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003228 if (!spec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003229 return;
3230
Takashi Iwai603c4012008-07-30 15:01:44 +02003231 alc_free_kctls(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003232 kfree(spec);
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09003233 snd_hda_detach_beep_device(codec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003234}
3235
Takashi Iwaie044c392008-10-27 16:56:24 +01003236#ifdef SND_HDA_NEEDS_RESUME
Takashi Iwaie044c392008-10-27 16:56:24 +01003237static int alc_resume(struct hda_codec *codec)
3238{
Takashi Iwaie044c392008-10-27 16:56:24 +01003239 codec->patch_ops.init(codec);
3240 snd_hda_codec_resume_amp(codec);
3241 snd_hda_codec_resume_cache(codec);
3242 return 0;
3243}
Takashi Iwaie044c392008-10-27 16:56:24 +01003244#endif
3245
Linus Torvalds1da177e2005-04-16 15:20:36 -07003246/*
3247 */
3248static struct hda_codec_ops alc_patch_ops = {
3249 .build_controls = alc_build_controls,
3250 .build_pcms = alc_build_pcms,
3251 .init = alc_init,
3252 .free = alc_free,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003253 .unsol_event = alc_unsol_event,
Takashi Iwaie044c392008-10-27 16:56:24 +01003254#ifdef SND_HDA_NEEDS_RESUME
3255 .resume = alc_resume,
3256#endif
Takashi Iwaicb53c622007-08-10 17:21:45 +02003257#ifdef CONFIG_SND_HDA_POWER_SAVE
3258 .check_power_status = alc_check_power_status,
3259#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07003260};
3261
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003262
3263/*
3264 * Test configuration for debugging
3265 *
3266 * Almost all inputs/outputs are enabled. I/O pins can be configured via
3267 * enum controls.
3268 */
3269#ifdef CONFIG_SND_DEBUG
3270static hda_nid_t alc880_test_dac_nids[4] = {
3271 0x02, 0x03, 0x04, 0x05
3272};
3273
3274static struct hda_input_mux alc880_test_capture_source = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003275 .num_items = 7,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003276 .items = {
3277 { "In-1", 0x0 },
3278 { "In-2", 0x1 },
3279 { "In-3", 0x2 },
3280 { "In-4", 0x3 },
3281 { "CD", 0x4 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003282 { "Front", 0x5 },
3283 { "Surround", 0x6 },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003284 },
3285};
3286
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01003287static struct hda_channel_mode alc880_test_modes[4] = {
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003288 { 2, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02003289 { 4, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003290 { 6, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02003291 { 8, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003292};
3293
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003294static int alc_test_pin_ctl_info(struct snd_kcontrol *kcontrol,
3295 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003296{
3297 static char *texts[] = {
3298 "N/A", "Line Out", "HP Out",
3299 "In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%"
3300 };
3301 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
3302 uinfo->count = 1;
3303 uinfo->value.enumerated.items = 8;
3304 if (uinfo->value.enumerated.item >= 8)
3305 uinfo->value.enumerated.item = 7;
3306 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
3307 return 0;
3308}
3309
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003310static int alc_test_pin_ctl_get(struct snd_kcontrol *kcontrol,
3311 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003312{
3313 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3314 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
3315 unsigned int pin_ctl, item = 0;
3316
3317 pin_ctl = snd_hda_codec_read(codec, nid, 0,
3318 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
3319 if (pin_ctl & AC_PINCTL_OUT_EN) {
3320 if (pin_ctl & AC_PINCTL_HP_EN)
3321 item = 2;
3322 else
3323 item = 1;
3324 } else if (pin_ctl & AC_PINCTL_IN_EN) {
3325 switch (pin_ctl & AC_PINCTL_VREFEN) {
3326 case AC_PINCTL_VREF_HIZ: item = 3; break;
3327 case AC_PINCTL_VREF_50: item = 4; break;
3328 case AC_PINCTL_VREF_GRD: item = 5; break;
3329 case AC_PINCTL_VREF_80: item = 6; break;
3330 case AC_PINCTL_VREF_100: item = 7; break;
3331 }
3332 }
3333 ucontrol->value.enumerated.item[0] = item;
3334 return 0;
3335}
3336
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003337static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol,
3338 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003339{
3340 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3341 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
3342 static unsigned int ctls[] = {
3343 0, AC_PINCTL_OUT_EN, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN,
3344 AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ,
3345 AC_PINCTL_IN_EN | AC_PINCTL_VREF_50,
3346 AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD,
3347 AC_PINCTL_IN_EN | AC_PINCTL_VREF_80,
3348 AC_PINCTL_IN_EN | AC_PINCTL_VREF_100,
3349 };
3350 unsigned int old_ctl, new_ctl;
3351
3352 old_ctl = snd_hda_codec_read(codec, nid, 0,
3353 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
3354 new_ctl = ctls[ucontrol->value.enumerated.item[0]];
3355 if (old_ctl != new_ctl) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003356 int val;
3357 snd_hda_codec_write_cache(codec, nid, 0,
3358 AC_VERB_SET_PIN_WIDGET_CONTROL,
3359 new_ctl);
Takashi Iwai47fd8302007-08-10 17:11:07 +02003360 val = ucontrol->value.enumerated.item[0] >= 3 ?
3361 HDA_AMP_MUTE : 0;
3362 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
3363 HDA_AMP_MUTE, val);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003364 return 1;
3365 }
3366 return 0;
3367}
3368
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003369static int alc_test_pin_src_info(struct snd_kcontrol *kcontrol,
3370 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003371{
3372 static char *texts[] = {
3373 "Front", "Surround", "CLFE", "Side"
3374 };
3375 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
3376 uinfo->count = 1;
3377 uinfo->value.enumerated.items = 4;
3378 if (uinfo->value.enumerated.item >= 4)
3379 uinfo->value.enumerated.item = 3;
3380 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
3381 return 0;
3382}
3383
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003384static int alc_test_pin_src_get(struct snd_kcontrol *kcontrol,
3385 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003386{
3387 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3388 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
3389 unsigned int sel;
3390
3391 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0);
3392 ucontrol->value.enumerated.item[0] = sel & 3;
3393 return 0;
3394}
3395
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003396static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol,
3397 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003398{
3399 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3400 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
3401 unsigned int sel;
3402
3403 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3;
3404 if (ucontrol->value.enumerated.item[0] != sel) {
3405 sel = ucontrol->value.enumerated.item[0] & 3;
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003406 snd_hda_codec_write_cache(codec, nid, 0,
3407 AC_VERB_SET_CONNECT_SEL, sel);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003408 return 1;
3409 }
3410 return 0;
3411}
3412
3413#define PIN_CTL_TEST(xname,nid) { \
3414 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
3415 .name = xname, \
3416 .info = alc_test_pin_ctl_info, \
3417 .get = alc_test_pin_ctl_get, \
3418 .put = alc_test_pin_ctl_put, \
3419 .private_value = nid \
3420 }
3421
3422#define PIN_SRC_TEST(xname,nid) { \
3423 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
3424 .name = xname, \
3425 .info = alc_test_pin_src_info, \
3426 .get = alc_test_pin_src_get, \
3427 .put = alc_test_pin_src_put, \
3428 .private_value = nid \
3429 }
3430
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003431static struct snd_kcontrol_new alc880_test_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02003432 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3433 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
3434 HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
3435 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003436 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
3437 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
3438 HDA_BIND_MUTE("CLFE Playback Switch", 0x0e, 2, HDA_INPUT),
3439 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003440 PIN_CTL_TEST("Front Pin Mode", 0x14),
3441 PIN_CTL_TEST("Surround Pin Mode", 0x15),
3442 PIN_CTL_TEST("CLFE Pin Mode", 0x16),
3443 PIN_CTL_TEST("Side Pin Mode", 0x17),
3444 PIN_CTL_TEST("In-1 Pin Mode", 0x18),
3445 PIN_CTL_TEST("In-2 Pin Mode", 0x19),
3446 PIN_CTL_TEST("In-3 Pin Mode", 0x1a),
3447 PIN_CTL_TEST("In-4 Pin Mode", 0x1b),
3448 PIN_SRC_TEST("In-1 Pin Source", 0x18),
3449 PIN_SRC_TEST("In-2 Pin Source", 0x19),
3450 PIN_SRC_TEST("In-3 Pin Source", 0x1a),
3451 PIN_SRC_TEST("In-4 Pin Source", 0x1b),
3452 HDA_CODEC_VOLUME("In-1 Playback Volume", 0x0b, 0x0, HDA_INPUT),
3453 HDA_CODEC_MUTE("In-1 Playback Switch", 0x0b, 0x0, HDA_INPUT),
3454 HDA_CODEC_VOLUME("In-2 Playback Volume", 0x0b, 0x1, HDA_INPUT),
3455 HDA_CODEC_MUTE("In-2 Playback Switch", 0x0b, 0x1, HDA_INPUT),
3456 HDA_CODEC_VOLUME("In-3 Playback Volume", 0x0b, 0x2, HDA_INPUT),
3457 HDA_CODEC_MUTE("In-3 Playback Switch", 0x0b, 0x2, HDA_INPUT),
3458 HDA_CODEC_VOLUME("In-4 Playback Volume", 0x0b, 0x3, HDA_INPUT),
3459 HDA_CODEC_MUTE("In-4 Playback Switch", 0x0b, 0x3, HDA_INPUT),
3460 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x4, HDA_INPUT),
3461 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x4, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003462 {
3463 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3464 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01003465 .info = alc_ch_mode_info,
3466 .get = alc_ch_mode_get,
3467 .put = alc_ch_mode_put,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003468 },
3469 { } /* end */
3470};
3471
3472static struct hda_verb alc880_test_init_verbs[] = {
3473 /* Unmute inputs of 0x0c - 0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02003474 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3475 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3476 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3477 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3478 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3479 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3480 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3481 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003482 /* Vol output for 0x0c-0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02003483 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3484 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3485 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3486 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003487 /* Set output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02003488 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3489 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3490 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3491 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003492 /* Unmute output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02003493 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3494 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3495 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3496 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003497 /* Set input pins 0x18-0x1c */
Takashi Iwai16ded522005-06-10 19:58:24 +02003498 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3499 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwai05acb862005-06-10 19:50:25 +02003500 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3501 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3502 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003503 /* Mute input pins 0x18-0x1b */
Takashi Iwai05acb862005-06-10 19:50:25 +02003504 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3505 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3506 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3507 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003508 /* ADC set up */
Takashi Iwai05acb862005-06-10 19:50:25 +02003509 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003510 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02003511 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003512 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02003513 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003514 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02003515 /* Analog input/passthru */
3516 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3517 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
3518 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
3519 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
3520 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003521 { }
3522};
3523#endif
3524
Linus Torvalds1da177e2005-04-16 15:20:36 -07003525/*
3526 */
3527
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003528static const char *alc880_models[ALC880_MODEL_LAST] = {
3529 [ALC880_3ST] = "3stack",
3530 [ALC880_TCL_S700] = "tcl",
3531 [ALC880_3ST_DIG] = "3stack-digout",
3532 [ALC880_CLEVO] = "clevo",
3533 [ALC880_5ST] = "5stack",
3534 [ALC880_5ST_DIG] = "5stack-digout",
3535 [ALC880_W810] = "w810",
3536 [ALC880_Z71V] = "z71v",
3537 [ALC880_6ST] = "6stack",
3538 [ALC880_6ST_DIG] = "6stack-digout",
3539 [ALC880_ASUS] = "asus",
3540 [ALC880_ASUS_W1V] = "asus-w1v",
3541 [ALC880_ASUS_DIG] = "asus-dig",
3542 [ALC880_ASUS_DIG2] = "asus-dig2",
3543 [ALC880_UNIWILL_DIG] = "uniwill",
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003544 [ALC880_UNIWILL_P53] = "uniwill-p53",
3545 [ALC880_FUJITSU] = "fujitsu",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003546 [ALC880_F1734] = "F1734",
3547 [ALC880_LG] = "lg",
3548 [ALC880_LG_LW] = "lg-lw",
Takashi Iwaidf99cd32008-04-25 15:25:04 +02003549 [ALC880_MEDION_RIM] = "medion",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003550#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003551 [ALC880_TEST] = "test",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003552#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003553 [ALC880_AUTO] = "auto",
3554};
3555
3556static struct snd_pci_quirk alc880_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003557 SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003558 SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG),
3559 SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST),
3560 SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_3ST_DIG),
3561 SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_6ST_DIG),
3562 SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_6ST_DIG),
3563 SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_6ST_DIG),
3564 SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_3ST_DIG),
3565 SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003566 SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_6ST_DIG),
3567 SND_PCI_QUIRK(0x103c, 0x2a09, "HP", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003568 SND_PCI_QUIRK(0x1043, 0x10b3, "ASUS W1V", ALC880_ASUS_W1V),
3569 SND_PCI_QUIRK(0x1043, 0x10c2, "ASUS W6A", ALC880_ASUS_DIG),
3570 SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS Wxx", ALC880_ASUS_DIG),
3571 SND_PCI_QUIRK(0x1043, 0x1113, "ASUS", ALC880_ASUS_DIG),
3572 SND_PCI_QUIRK(0x1043, 0x1123, "ASUS", ALC880_ASUS_DIG),
3573 SND_PCI_QUIRK(0x1043, 0x1173, "ASUS", ALC880_ASUS_DIG),
3574 SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_Z71V),
3575 /* SND_PCI_QUIRK(0x1043, 0x1964, "ASUS", ALC880_ASUS_DIG), */
3576 SND_PCI_QUIRK(0x1043, 0x1973, "ASUS", ALC880_ASUS_DIG),
3577 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS", ALC880_ASUS_DIG),
Travis Place186c3112008-05-20 11:54:41 +02003578 SND_PCI_QUIRK(0x1043, 0x814e, "ASUS P5GD1 w/SPDIF", ALC880_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003579 SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG),
3580 SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST),
3581 SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST),
Takashi Iwaidea0a502009-02-09 17:14:52 +01003582 SND_PCI_QUIRK_VENDOR(0x1043, "ASUS", ALC880_ASUS), /* default ASUS */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003583 SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003584 SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST),
3585 SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003586 SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_5ST),
3587 SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003588 SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_6ST_DIG),
3589 SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_6ST_DIG),
3590 SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_6ST_DIG),
3591 SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003592 SND_PCI_QUIRK(0x1558, 0x0520, "Clevo m520G", ALC880_CLEVO),
3593 SND_PCI_QUIRK(0x1558, 0x0660, "Clevo m655n", ALC880_CLEVO),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003594 SND_PCI_QUIRK(0x1558, 0x5401, "ASUS", ALC880_ASUS_DIG2),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003595 SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003596 SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_UNIWILL_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003597 SND_PCI_QUIRK(0x1584, 0x9054, "Uniwlll", ALC880_F1734),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003598 SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL),
3599 SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003600 SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810),
Takashi Iwaidf99cd32008-04-25 15:25:04 +02003601 SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_MEDION_RIM),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003602 SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003603 SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003604 SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734),
Travis Place1d116042008-06-23 11:42:30 +02003605 SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FUJITSU),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003606 SND_PCI_QUIRK(0x1734, 0x10ac, "FSC", ALC880_UNIWILL),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003607 SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003608 SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003609 SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG),
3610 SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003611 SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003612 SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700),
3613 SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG), /* broken BIOS */
3614 SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG),
3615 SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003616 SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_5ST_DIG),
3617 SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003618 SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003619 SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003620 SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_3ST_DIG),
3621 SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003622 SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_5ST_DIG),
3623 SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_5ST_DIG),
3624 SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +01003625 /* default Intel */
3626 SND_PCI_QUIRK_VENDOR(0x8086, "Intel mobo", ALC880_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003627 SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG),
3628 SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003629 {}
3630};
3631
Takashi Iwai16ded522005-06-10 19:58:24 +02003632/*
Kailang Yangdf694da2005-12-05 19:42:22 +01003633 * ALC880 codec presets
Takashi Iwai16ded522005-06-10 19:58:24 +02003634 */
Takashi Iwai16ded522005-06-10 19:58:24 +02003635static struct alc_config_preset alc880_presets[] = {
3636 [ALC880_3ST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003637 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003638 .init_verbs = { alc880_volume_init_verbs,
3639 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003640 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02003641 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003642 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
3643 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003644 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003645 .input_mux = &alc880_capture_source,
3646 },
3647 [ALC880_3ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003648 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003649 .init_verbs = { alc880_volume_init_verbs,
3650 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003651 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02003652 .dac_nids = alc880_dac_nids,
3653 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003654 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
3655 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003656 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003657 .input_mux = &alc880_capture_source,
3658 },
Kailang Yangdf694da2005-12-05 19:42:22 +01003659 [ALC880_TCL_S700] = {
3660 .mixers = { alc880_tcl_s700_mixer },
3661 .init_verbs = { alc880_volume_init_verbs,
3662 alc880_pin_tcl_S700_init_verbs,
3663 alc880_gpio2_init_verbs },
3664 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3665 .dac_nids = alc880_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01003666 .adc_nids = alc880_adc_nids_alt, /* FIXME: correct? */
3667 .num_adc_nids = 1, /* single ADC */
Kailang Yangdf694da2005-12-05 19:42:22 +01003668 .hp_nid = 0x03,
3669 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3670 .channel_mode = alc880_2_jack_modes,
3671 .input_mux = &alc880_capture_source,
3672 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003673 [ALC880_5ST] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003674 .mixers = { alc880_three_stack_mixer,
3675 alc880_five_stack_mixer},
3676 .init_verbs = { alc880_volume_init_verbs,
3677 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003678 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3679 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003680 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
3681 .channel_mode = alc880_fivestack_modes,
3682 .input_mux = &alc880_capture_source,
3683 },
3684 [ALC880_5ST_DIG] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003685 .mixers = { alc880_three_stack_mixer,
3686 alc880_five_stack_mixer },
3687 .init_verbs = { alc880_volume_init_verbs,
3688 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003689 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3690 .dac_nids = alc880_dac_nids,
3691 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003692 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
3693 .channel_mode = alc880_fivestack_modes,
3694 .input_mux = &alc880_capture_source,
3695 },
Takashi Iwaib6482d42005-06-27 15:32:43 +02003696 [ALC880_6ST] = {
3697 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003698 .init_verbs = { alc880_volume_init_verbs,
3699 alc880_pin_6stack_init_verbs },
Takashi Iwaib6482d42005-06-27 15:32:43 +02003700 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
3701 .dac_nids = alc880_6st_dac_nids,
3702 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
3703 .channel_mode = alc880_sixstack_modes,
3704 .input_mux = &alc880_6stack_capture_source,
3705 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003706 [ALC880_6ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003707 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003708 .init_verbs = { alc880_volume_init_verbs,
3709 alc880_pin_6stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003710 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
3711 .dac_nids = alc880_6st_dac_nids,
3712 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003713 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
3714 .channel_mode = alc880_sixstack_modes,
3715 .input_mux = &alc880_6stack_capture_source,
3716 },
3717 [ALC880_W810] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003718 .mixers = { alc880_w810_base_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003719 .init_verbs = { alc880_volume_init_verbs,
3720 alc880_pin_w810_init_verbs,
Takashi Iwaib0af0de2005-06-21 14:49:19 +02003721 alc880_gpio2_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003722 .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids),
3723 .dac_nids = alc880_w810_dac_nids,
3724 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003725 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
3726 .channel_mode = alc880_w810_modes,
3727 .input_mux = &alc880_capture_source,
3728 },
3729 [ALC880_Z71V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003730 .mixers = { alc880_z71v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003731 .init_verbs = { alc880_volume_init_verbs,
3732 alc880_pin_z71v_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003733 .num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids),
3734 .dac_nids = alc880_z71v_dac_nids,
3735 .dig_out_nid = ALC880_DIGOUT_NID,
3736 .hp_nid = 0x03,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003737 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3738 .channel_mode = alc880_2_jack_modes,
Takashi Iwai16ded522005-06-10 19:58:24 +02003739 .input_mux = &alc880_capture_source,
3740 },
3741 [ALC880_F1734] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003742 .mixers = { alc880_f1734_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003743 .init_verbs = { alc880_volume_init_verbs,
3744 alc880_pin_f1734_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003745 .num_dacs = ARRAY_SIZE(alc880_f1734_dac_nids),
3746 .dac_nids = alc880_f1734_dac_nids,
3747 .hp_nid = 0x02,
3748 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3749 .channel_mode = alc880_2_jack_modes,
Takashi Iwai937b4162008-02-11 14:52:36 +01003750 .input_mux = &alc880_f1734_capture_source,
3751 .unsol_event = alc880_uniwill_p53_unsol_event,
3752 .init_hook = alc880_uniwill_p53_hp_automute,
Takashi Iwai16ded522005-06-10 19:58:24 +02003753 },
3754 [ALC880_ASUS] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003755 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003756 .init_verbs = { alc880_volume_init_verbs,
3757 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003758 alc880_gpio1_init_verbs },
3759 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3760 .dac_nids = alc880_asus_dac_nids,
3761 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3762 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003763 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003764 .input_mux = &alc880_capture_source,
3765 },
3766 [ALC880_ASUS_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003767 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003768 .init_verbs = { alc880_volume_init_verbs,
3769 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003770 alc880_gpio1_init_verbs },
3771 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3772 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003773 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003774 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3775 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003776 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003777 .input_mux = &alc880_capture_source,
3778 },
Kailang Yangdf694da2005-12-05 19:42:22 +01003779 [ALC880_ASUS_DIG2] = {
3780 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003781 .init_verbs = { alc880_volume_init_verbs,
3782 alc880_pin_asus_init_verbs,
Kailang Yangdf694da2005-12-05 19:42:22 +01003783 alc880_gpio2_init_verbs }, /* use GPIO2 */
3784 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3785 .dac_nids = alc880_asus_dac_nids,
3786 .dig_out_nid = ALC880_DIGOUT_NID,
3787 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3788 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003789 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01003790 .input_mux = &alc880_capture_source,
3791 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003792 [ALC880_ASUS_W1V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003793 .mixers = { alc880_asus_mixer, alc880_asus_w1v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003794 .init_verbs = { alc880_volume_init_verbs,
3795 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003796 alc880_gpio1_init_verbs },
3797 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3798 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003799 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003800 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3801 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003802 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003803 .input_mux = &alc880_capture_source,
3804 },
3805 [ALC880_UNIWILL_DIG] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01003806 .mixers = { alc880_asus_mixer },
Kailang Yangccc656c2006-10-17 12:32:26 +02003807 .init_verbs = { alc880_volume_init_verbs,
3808 alc880_pin_asus_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003809 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3810 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003811 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003812 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3813 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003814 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003815 .input_mux = &alc880_capture_source,
3816 },
Kailang Yangccc656c2006-10-17 12:32:26 +02003817 [ALC880_UNIWILL] = {
3818 .mixers = { alc880_uniwill_mixer },
3819 .init_verbs = { alc880_volume_init_verbs,
3820 alc880_uniwill_init_verbs },
3821 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3822 .dac_nids = alc880_asus_dac_nids,
3823 .dig_out_nid = ALC880_DIGOUT_NID,
3824 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
3825 .channel_mode = alc880_threestack_modes,
3826 .need_dac_fix = 1,
3827 .input_mux = &alc880_capture_source,
3828 .unsol_event = alc880_uniwill_unsol_event,
3829 .init_hook = alc880_uniwill_automute,
3830 },
3831 [ALC880_UNIWILL_P53] = {
3832 .mixers = { alc880_uniwill_p53_mixer },
3833 .init_verbs = { alc880_volume_init_verbs,
3834 alc880_uniwill_p53_init_verbs },
3835 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3836 .dac_nids = alc880_asus_dac_nids,
3837 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003838 .channel_mode = alc880_threestack_modes,
3839 .input_mux = &alc880_capture_source,
3840 .unsol_event = alc880_uniwill_p53_unsol_event,
3841 .init_hook = alc880_uniwill_p53_hp_automute,
3842 },
3843 [ALC880_FUJITSU] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01003844 .mixers = { alc880_fujitsu_mixer },
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003845 .init_verbs = { alc880_volume_init_verbs,
3846 alc880_uniwill_p53_init_verbs,
3847 alc880_beep_init_verbs },
3848 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3849 .dac_nids = alc880_dac_nids,
Takashi Iwaid53d7d92007-08-20 15:20:02 +02003850 .dig_out_nid = ALC880_DIGOUT_NID,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003851 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3852 .channel_mode = alc880_2_jack_modes,
Kailang Yangccc656c2006-10-17 12:32:26 +02003853 .input_mux = &alc880_capture_source,
3854 .unsol_event = alc880_uniwill_p53_unsol_event,
3855 .init_hook = alc880_uniwill_p53_hp_automute,
3856 },
Kailang Yangdf694da2005-12-05 19:42:22 +01003857 [ALC880_CLEVO] = {
3858 .mixers = { alc880_three_stack_mixer },
3859 .init_verbs = { alc880_volume_init_verbs,
3860 alc880_pin_clevo_init_verbs },
3861 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3862 .dac_nids = alc880_dac_nids,
3863 .hp_nid = 0x03,
3864 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
3865 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003866 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01003867 .input_mux = &alc880_capture_source,
3868 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003869 [ALC880_LG] = {
3870 .mixers = { alc880_lg_mixer },
3871 .init_verbs = { alc880_volume_init_verbs,
3872 alc880_lg_init_verbs },
3873 .num_dacs = ARRAY_SIZE(alc880_lg_dac_nids),
3874 .dac_nids = alc880_lg_dac_nids,
3875 .dig_out_nid = ALC880_DIGOUT_NID,
3876 .num_channel_mode = ARRAY_SIZE(alc880_lg_ch_modes),
3877 .channel_mode = alc880_lg_ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003878 .need_dac_fix = 1,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003879 .input_mux = &alc880_lg_capture_source,
3880 .unsol_event = alc880_lg_unsol_event,
3881 .init_hook = alc880_lg_automute,
Takashi Iwaicb53c622007-08-10 17:21:45 +02003882#ifdef CONFIG_SND_HDA_POWER_SAVE
3883 .loopbacks = alc880_lg_loopbacks,
3884#endif
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003885 },
Takashi Iwaid6815182006-03-23 16:06:23 +01003886 [ALC880_LG_LW] = {
3887 .mixers = { alc880_lg_lw_mixer },
3888 .init_verbs = { alc880_volume_init_verbs,
3889 alc880_lg_lw_init_verbs },
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003890 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwaid6815182006-03-23 16:06:23 +01003891 .dac_nids = alc880_dac_nids,
3892 .dig_out_nid = ALC880_DIGOUT_NID,
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003893 .num_channel_mode = ARRAY_SIZE(alc880_lg_lw_modes),
3894 .channel_mode = alc880_lg_lw_modes,
Takashi Iwaid6815182006-03-23 16:06:23 +01003895 .input_mux = &alc880_lg_lw_capture_source,
3896 .unsol_event = alc880_lg_lw_unsol_event,
3897 .init_hook = alc880_lg_lw_automute,
3898 },
Takashi Iwaidf99cd32008-04-25 15:25:04 +02003899 [ALC880_MEDION_RIM] = {
3900 .mixers = { alc880_medion_rim_mixer },
3901 .init_verbs = { alc880_volume_init_verbs,
3902 alc880_medion_rim_init_verbs,
3903 alc_gpio2_init_verbs },
3904 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3905 .dac_nids = alc880_dac_nids,
3906 .dig_out_nid = ALC880_DIGOUT_NID,
3907 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3908 .channel_mode = alc880_2_jack_modes,
3909 .input_mux = &alc880_medion_rim_capture_source,
3910 .unsol_event = alc880_medion_rim_unsol_event,
3911 .init_hook = alc880_medion_rim_automute,
3912 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003913#ifdef CONFIG_SND_DEBUG
3914 [ALC880_TEST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003915 .mixers = { alc880_test_mixer },
3916 .init_verbs = { alc880_test_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003917 .num_dacs = ARRAY_SIZE(alc880_test_dac_nids),
3918 .dac_nids = alc880_test_dac_nids,
3919 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003920 .num_channel_mode = ARRAY_SIZE(alc880_test_modes),
3921 .channel_mode = alc880_test_modes,
3922 .input_mux = &alc880_test_capture_source,
3923 },
3924#endif
3925};
3926
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003927/*
3928 * Automatic parse of I/O pins from the BIOS configuration
3929 */
3930
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003931enum {
3932 ALC_CTL_WIDGET_VOL,
3933 ALC_CTL_WIDGET_MUTE,
3934 ALC_CTL_BIND_MUTE,
3935};
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003936static struct snd_kcontrol_new alc880_control_templates[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003937 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
3938 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Takashi Iwai985be542005-11-02 18:26:49 +01003939 HDA_BIND_MUTE(NULL, 0, 0, 0),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003940};
3941
3942/* add dynamic controls */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003943static int add_control(struct alc_spec *spec, int type, const char *name,
3944 unsigned long val)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003945{
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003946 struct snd_kcontrol_new *knew;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003947
Takashi Iwai603c4012008-07-30 15:01:44 +02003948 snd_array_init(&spec->kctls, sizeof(*knew), 32);
3949 knew = snd_array_new(&spec->kctls);
3950 if (!knew)
3951 return -ENOMEM;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003952 *knew = alc880_control_templates[type];
Paulo Marques543537b2005-06-23 00:09:02 -07003953 knew->name = kstrdup(name, GFP_KERNEL);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003954 if (!knew->name)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003955 return -ENOMEM;
3956 knew->private_value = val;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003957 return 0;
3958}
3959
3960#define alc880_is_fixed_pin(nid) ((nid) >= 0x14 && (nid) <= 0x17)
3961#define alc880_fixed_pin_idx(nid) ((nid) - 0x14)
3962#define alc880_is_multi_pin(nid) ((nid) >= 0x18)
3963#define alc880_multi_pin_idx(nid) ((nid) - 0x18)
3964#define alc880_is_input_pin(nid) ((nid) >= 0x18)
3965#define alc880_input_pin_idx(nid) ((nid) - 0x18)
3966#define alc880_idx_to_dac(nid) ((nid) + 0x02)
3967#define alc880_dac_to_idx(nid) ((nid) - 0x02)
3968#define alc880_idx_to_mixer(nid) ((nid) + 0x0c)
3969#define alc880_idx_to_selector(nid) ((nid) + 0x10)
3970#define ALC880_PIN_CD_NID 0x1c
3971
3972/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003973static int alc880_auto_fill_dac_nids(struct alc_spec *spec,
3974 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003975{
3976 hda_nid_t nid;
3977 int assigned[4];
3978 int i, j;
3979
3980 memset(assigned, 0, sizeof(assigned));
Takashi Iwaib0af0de2005-06-21 14:49:19 +02003981 spec->multiout.dac_nids = spec->private_dac_nids;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003982
3983 /* check the pins hardwired to audio widget */
3984 for (i = 0; i < cfg->line_outs; i++) {
3985 nid = cfg->line_out_pins[i];
3986 if (alc880_is_fixed_pin(nid)) {
3987 int idx = alc880_fixed_pin_idx(nid);
Libin Yang5014f192005-11-23 15:48:36 +01003988 spec->multiout.dac_nids[i] = alc880_idx_to_dac(idx);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003989 assigned[idx] = 1;
3990 }
3991 }
3992 /* left pins can be connect to any audio widget */
3993 for (i = 0; i < cfg->line_outs; i++) {
3994 nid = cfg->line_out_pins[i];
3995 if (alc880_is_fixed_pin(nid))
3996 continue;
3997 /* search for an empty channel */
3998 for (j = 0; j < cfg->line_outs; j++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003999 if (!assigned[j]) {
4000 spec->multiout.dac_nids[i] =
4001 alc880_idx_to_dac(j);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004002 assigned[j] = 1;
4003 break;
4004 }
4005 }
4006 }
4007 spec->multiout.num_dacs = cfg->line_outs;
4008 return 0;
4009}
4010
4011/* add playback controls from the parsed DAC table */
Kailang Yangdf694da2005-12-05 19:42:22 +01004012static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
4013 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004014{
4015 char name[32];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004016 static const char *chname[4] = {
4017 "Front", "Surround", NULL /*CLFE*/, "Side"
4018 };
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004019 hda_nid_t nid;
4020 int i, err;
4021
4022 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004023 if (!spec->multiout.dac_nids[i])
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004024 continue;
4025 nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i]));
4026 if (i == 2) {
4027 /* Center/LFE */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004028 err = add_control(spec, ALC_CTL_WIDGET_VOL,
4029 "Center Playback Volume",
4030 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
4031 HDA_OUTPUT));
4032 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004033 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004034 err = add_control(spec, ALC_CTL_WIDGET_VOL,
4035 "LFE Playback Volume",
4036 HDA_COMPOSE_AMP_VAL(nid, 2, 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_BIND_MUTE,
4041 "Center Playback Switch",
4042 HDA_COMPOSE_AMP_VAL(nid, 1, 2,
4043 HDA_INPUT));
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 "LFE Playback Switch",
4048 HDA_COMPOSE_AMP_VAL(nid, 2, 2,
4049 HDA_INPUT));
4050 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004051 return err;
4052 } else {
4053 sprintf(name, "%s Playback Volume", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004054 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
4055 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
4056 HDA_OUTPUT));
4057 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004058 return err;
4059 sprintf(name, "%s Playback Switch", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004060 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
4061 HDA_COMPOSE_AMP_VAL(nid, 3, 2,
4062 HDA_INPUT));
4063 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004064 return err;
4065 }
4066 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004067 return 0;
4068}
4069
Takashi Iwai8d88bc32005-11-17 11:09:23 +01004070/* add playback controls for speaker and HP outputs */
4071static int alc880_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
4072 const char *pfx)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004073{
4074 hda_nid_t nid;
4075 int err;
Takashi Iwai8d88bc32005-11-17 11:09:23 +01004076 char name[32];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004077
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004078 if (!pin)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004079 return 0;
4080
4081 if (alc880_is_fixed_pin(pin)) {
4082 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
Takashi Iwai82bc9552006-03-21 11:24:42 +01004083 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004084 if (!spec->multiout.hp_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004085 spec->multiout.hp_nid = nid;
Takashi Iwai82bc9552006-03-21 11:24:42 +01004086 else
4087 spec->multiout.extra_out_nid[0] = nid;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004088 /* control HP volume/switch on the output mixer amp */
4089 nid = alc880_idx_to_mixer(alc880_fixed_pin_idx(pin));
Takashi Iwai8d88bc32005-11-17 11:09:23 +01004090 sprintf(name, "%s Playback Volume", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004091 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
4092 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
4093 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004094 return err;
Takashi Iwai8d88bc32005-11-17 11:09:23 +01004095 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004096 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
4097 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
4098 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004099 return err;
4100 } else if (alc880_is_multi_pin(pin)) {
4101 /* set manual connection */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004102 /* we have only a switch on HP-out PIN */
Takashi Iwai8d88bc32005-11-17 11:09:23 +01004103 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004104 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
4105 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
4106 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004107 return err;
4108 }
4109 return 0;
4110}
4111
4112/* create input playback/capture controls for the given pin */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004113static int new_analog_input(struct alc_spec *spec, hda_nid_t pin,
4114 const char *ctlname,
Kailang Yangdf694da2005-12-05 19:42:22 +01004115 int idx, hda_nid_t mix_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004116{
4117 char name[32];
Kailang Yangdf694da2005-12-05 19:42:22 +01004118 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004119
4120 sprintf(name, "%s Playback Volume", ctlname);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004121 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
4122 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
4123 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004124 return err;
4125 sprintf(name, "%s Playback Switch", ctlname);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004126 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
4127 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
4128 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004129 return err;
4130 return 0;
4131}
4132
4133/* create playback/capture controls for input pins */
Kailang Yangdf694da2005-12-05 19:42:22 +01004134static int alc880_auto_create_analog_input_ctls(struct alc_spec *spec,
4135 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004136{
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02004137 struct hda_input_mux *imux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01004138 int i, err, idx;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004139
4140 for (i = 0; i < AUTO_PIN_LAST; i++) {
4141 if (alc880_is_input_pin(cfg->input_pins[i])) {
Kailang Yangdf694da2005-12-05 19:42:22 +01004142 idx = alc880_input_pin_idx(cfg->input_pins[i]);
Takashi Iwai4a471b72005-12-07 13:56:29 +01004143 err = new_analog_input(spec, cfg->input_pins[i],
4144 auto_pin_cfg_labels[i],
Kailang Yangdf694da2005-12-05 19:42:22 +01004145 idx, 0x0b);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004146 if (err < 0)
4147 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004148 imux->items[imux->num_items].label =
4149 auto_pin_cfg_labels[i];
4150 imux->items[imux->num_items].index =
4151 alc880_input_pin_idx(cfg->input_pins[i]);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004152 imux->num_items++;
4153 }
4154 }
4155 return 0;
4156}
4157
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004158static void alc_set_pin_output(struct hda_codec *codec, hda_nid_t nid,
4159 unsigned int pin_type)
4160{
4161 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
4162 pin_type);
4163 /* unmute pin */
Takashi Iwaid260cdf2008-02-13 17:19:35 +01004164 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
4165 AMP_OUT_UNMUTE);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004166}
4167
Kailang Yangdf694da2005-12-05 19:42:22 +01004168static void alc880_auto_set_output_and_unmute(struct hda_codec *codec,
4169 hda_nid_t nid, int pin_type,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004170 int dac_idx)
4171{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004172 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004173 /* need the manual connection? */
4174 if (alc880_is_multi_pin(nid)) {
4175 struct alc_spec *spec = codec->spec;
4176 int idx = alc880_multi_pin_idx(nid);
4177 snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
4178 AC_VERB_SET_CONNECT_SEL,
4179 alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
4180 }
4181}
4182
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02004183static int get_pin_type(int line_out_type)
4184{
4185 if (line_out_type == AUTO_PIN_HP_OUT)
4186 return PIN_HP;
4187 else
4188 return PIN_OUT;
4189}
4190
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004191static void alc880_auto_init_multi_out(struct hda_codec *codec)
4192{
4193 struct alc_spec *spec = codec->spec;
4194 int i;
Kailang Yangea1fb292008-08-26 12:58:38 +02004195
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004196 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004197 for (i = 0; i < spec->autocfg.line_outs; i++) {
4198 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02004199 int pin_type = get_pin_type(spec->autocfg.line_out_type);
4200 alc880_auto_set_output_and_unmute(codec, nid, pin_type, i);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004201 }
4202}
4203
Takashi Iwai8d88bc32005-11-17 11:09:23 +01004204static void alc880_auto_init_extra_out(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004205{
4206 struct alc_spec *spec = codec->spec;
4207 hda_nid_t pin;
4208
Takashi Iwai82bc9552006-03-21 11:24:42 +01004209 pin = spec->autocfg.speaker_pins[0];
Takashi Iwai8d88bc32005-11-17 11:09:23 +01004210 if (pin) /* connect to front */
4211 alc880_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02004212 pin = spec->autocfg.hp_pins[0];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004213 if (pin) /* connect to front */
4214 alc880_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
4215}
4216
4217static void alc880_auto_init_analog_input(struct hda_codec *codec)
4218{
4219 struct alc_spec *spec = codec->spec;
4220 int i;
4221
4222 for (i = 0; i < AUTO_PIN_LAST; i++) {
4223 hda_nid_t nid = spec->autocfg.input_pins[i];
4224 if (alc880_is_input_pin(nid)) {
Takashi Iwai23f0c042009-02-26 13:03:58 +01004225 alc_set_input_pin(codec, nid, i);
Takashi Iwaie82c0252009-03-23 15:17:38 +01004226 if (nid != ALC880_PIN_CD_NID &&
4227 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004228 snd_hda_codec_write(codec, nid, 0,
4229 AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004230 AMP_OUT_MUTE);
4231 }
4232 }
4233}
4234
4235/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004236/* return 1 if successful, 0 if the proper config is not found,
4237 * or a negative error code
4238 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004239static int alc880_parse_auto_config(struct hda_codec *codec)
4240{
4241 struct alc_spec *spec = codec->spec;
Takashi Iwai6a05ac42009-02-13 11:19:09 +01004242 int i, err;
Kailang Yangdf694da2005-12-05 19:42:22 +01004243 static hda_nid_t alc880_ignore[] = { 0x1d, 0 };
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004244
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004245 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
4246 alc880_ignore);
4247 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004248 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004249 if (!spec->autocfg.line_outs)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004250 return 0; /* can't find valid BIOS pin config */
Kailang Yangdf694da2005-12-05 19:42:22 +01004251
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004252 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
4253 if (err < 0)
4254 return err;
4255 err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
4256 if (err < 0)
4257 return err;
4258 err = alc880_auto_create_extra_out(spec,
4259 spec->autocfg.speaker_pins[0],
4260 "Speaker");
4261 if (err < 0)
4262 return err;
4263 err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
4264 "Headphone");
4265 if (err < 0)
4266 return err;
4267 err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg);
4268 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004269 return err;
4270
4271 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
4272
Takashi Iwai6a05ac42009-02-13 11:19:09 +01004273 /* check multiple SPDIF-out (for recent codecs) */
4274 for (i = 0; i < spec->autocfg.dig_outs; i++) {
4275 hda_nid_t dig_nid;
4276 err = snd_hda_get_connections(codec,
4277 spec->autocfg.dig_out_pins[i],
4278 &dig_nid, 1);
4279 if (err < 0)
4280 continue;
4281 if (!i)
4282 spec->multiout.dig_out_nid = dig_nid;
4283 else {
4284 spec->multiout.slave_dig_outs = spec->slave_dig_outs;
4285 spec->slave_dig_outs[i - 1] = dig_nid;
4286 if (i == ARRAY_SIZE(spec->slave_dig_outs) - 1)
4287 break;
4288 }
4289 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004290 if (spec->autocfg.dig_in_pin)
4291 spec->dig_in_nid = ALC880_DIGIN_NID;
4292
Takashi Iwai603c4012008-07-30 15:01:44 +02004293 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +01004294 add_mixer(spec, spec->kctls.list);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004295
Takashi Iwaid88897e2008-10-31 15:01:37 +01004296 add_verb(spec, alc880_volume_init_verbs);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004297
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004298 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02004299 spec->input_mux = &spec->private_imux[0];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004300
4301 return 1;
4302}
4303
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004304/* additional initialization for auto-configuration model */
4305static void alc880_auto_init(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004306{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004307 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004308 alc880_auto_init_multi_out(codec);
Takashi Iwai8d88bc32005-11-17 11:09:23 +01004309 alc880_auto_init_extra_out(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004310 alc880_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004311 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02004312 alc_inithook(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004313}
4314
Takashi Iwaif9e336f2008-10-31 16:37:07 +01004315static void set_capture_mixer(struct alc_spec *spec)
4316{
Takashi Iwaia23b6882009-03-23 15:21:36 +01004317 static struct snd_kcontrol_new *caps[2][3] = {
4318 { alc_capture_mixer_nosrc1,
4319 alc_capture_mixer_nosrc2,
4320 alc_capture_mixer_nosrc3 },
4321 { alc_capture_mixer1,
4322 alc_capture_mixer2,
4323 alc_capture_mixer3 },
Takashi Iwaif9e336f2008-10-31 16:37:07 +01004324 };
Takashi Iwaia23b6882009-03-23 15:21:36 +01004325 if (spec->num_adc_nids > 0 && spec->num_adc_nids <= 3) {
4326 int mux;
4327 if (spec->input_mux && spec->input_mux->num_items > 1)
4328 mux = 1;
4329 else
4330 mux = 0;
4331 spec->cap_mixer = caps[mux][spec->num_adc_nids - 1];
4332 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01004333}
4334
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01004335#define set_beep_amp(spec, nid, idx, dir) \
4336 ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir))
4337
4338/*
4339 * OK, here we have finally the patch for ALC880
4340 */
4341
Linus Torvalds1da177e2005-04-16 15:20:36 -07004342static int patch_alc880(struct hda_codec *codec)
4343{
4344 struct alc_spec *spec;
4345 int board_config;
Kailang Yangdf694da2005-12-05 19:42:22 +01004346 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004347
Takashi Iwaie560d8d2005-09-09 14:21:46 +02004348 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004349 if (spec == NULL)
4350 return -ENOMEM;
4351
4352 codec->spec = spec;
4353
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004354 board_config = snd_hda_check_board_config(codec, ALC880_MODEL_LAST,
4355 alc880_models,
4356 alc880_cfg_tbl);
4357 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004358 printk(KERN_INFO "hda_codec: Unknown model for ALC880, "
4359 "trying auto-probe from BIOS...\n");
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004360 board_config = ALC880_AUTO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004361 }
4362
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004363 if (board_config == ALC880_AUTO) {
4364 /* automatic parse from the BIOS config */
4365 err = alc880_parse_auto_config(codec);
4366 if (err < 0) {
4367 alc_free(codec);
4368 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004369 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004370 printk(KERN_INFO
4371 "hda_codec: Cannot set up configuration "
4372 "from BIOS. Using 3-stack mode...\n");
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004373 board_config = ALC880_3ST;
4374 }
4375 }
4376
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09004377 err = snd_hda_attach_beep_device(codec, 0x1);
4378 if (err < 0) {
4379 alc_free(codec);
4380 return err;
4381 }
4382
Kailang Yangdf694da2005-12-05 19:42:22 +01004383 if (board_config != ALC880_AUTO)
4384 setup_preset(spec, &alc880_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004385
4386 spec->stream_name_analog = "ALC880 Analog";
4387 spec->stream_analog_playback = &alc880_pcm_analog_playback;
4388 spec->stream_analog_capture = &alc880_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01004389 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004390
4391 spec->stream_name_digital = "ALC880 Digital";
4392 spec->stream_digital_playback = &alc880_pcm_digital_playback;
4393 spec->stream_digital_capture = &alc880_pcm_digital_capture;
4394
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004395 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004396 /* check whether NID 0x07 is valid */
Takashi Iwai54d17402005-11-21 16:33:22 +01004397 unsigned int wcap = get_wcaps(codec, alc880_adc_nids[0]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004398 /* get type */
4399 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004400 if (wcap != AC_WID_AUD_IN) {
4401 spec->adc_nids = alc880_adc_nids_alt;
4402 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids_alt);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004403 } else {
4404 spec->adc_nids = alc880_adc_nids;
4405 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004406 }
4407 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01004408 set_capture_mixer(spec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01004409 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004410
Takashi Iwai2134ea42008-01-10 16:53:55 +01004411 spec->vmaster_nid = 0x0c;
4412
Linus Torvalds1da177e2005-04-16 15:20:36 -07004413 codec->patch_ops = alc_patch_ops;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004414 if (board_config == ALC880_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004415 spec->init_hook = alc880_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02004416#ifdef CONFIG_SND_HDA_POWER_SAVE
4417 if (!spec->loopback.amplist)
4418 spec->loopback.amplist = alc880_loopbacks;
4419#endif
Takashi Iwaidaead532008-11-28 12:55:36 +01004420 codec->proc_widget_hook = print_realtek_coef;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004421
4422 return 0;
4423}
4424
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004425
Linus Torvalds1da177e2005-04-16 15:20:36 -07004426/*
4427 * ALC260 support
4428 */
4429
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004430static hda_nid_t alc260_dac_nids[1] = {
4431 /* front */
4432 0x02,
4433};
4434
4435static hda_nid_t alc260_adc_nids[1] = {
4436 /* ADC0 */
4437 0x04,
4438};
4439
Kailang Yangdf694da2005-12-05 19:42:22 +01004440static hda_nid_t alc260_adc_nids_alt[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004441 /* ADC1 */
4442 0x05,
4443};
4444
Jonathan Woithed57fdac2006-02-28 11:38:35 +01004445/* NIDs used when simultaneous access to both ADCs makes sense. Note that
4446 * alc260_capture_mixer assumes ADC0 (nid 0x04) is the first ADC.
4447 */
4448static hda_nid_t alc260_dual_adc_nids[2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004449 /* ADC0, ADC1 */
4450 0x04, 0x05
4451};
4452
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004453#define ALC260_DIGOUT_NID 0x03
4454#define ALC260_DIGIN_NID 0x06
4455
4456static struct hda_input_mux alc260_capture_source = {
4457 .num_items = 4,
4458 .items = {
4459 { "Mic", 0x0 },
4460 { "Front Mic", 0x1 },
4461 { "Line", 0x2 },
4462 { "CD", 0x4 },
4463 },
4464};
4465
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01004466/* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004467 * headphone jack and the internal CD lines since these are the only pins at
4468 * which audio can appear. For flexibility, also allow the option of
4469 * recording the mixer output on the second ADC (ADC0 doesn't have a
4470 * connection to the mixer output).
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004471 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004472static struct hda_input_mux alc260_fujitsu_capture_sources[2] = {
4473 {
4474 .num_items = 3,
4475 .items = {
4476 { "Mic/Line", 0x0 },
4477 { "CD", 0x4 },
4478 { "Headphone", 0x2 },
4479 },
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004480 },
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004481 {
4482 .num_items = 4,
4483 .items = {
4484 { "Mic/Line", 0x0 },
4485 { "CD", 0x4 },
4486 { "Headphone", 0x2 },
4487 { "Mixer", 0x5 },
4488 },
4489 },
4490
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004491};
4492
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004493/* Acer TravelMate(/Extensa/Aspire) notebooks have similar configuration to
4494 * the Fujitsu S702x, but jacks are marked differently.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004495 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004496static struct hda_input_mux alc260_acer_capture_sources[2] = {
4497 {
4498 .num_items = 4,
4499 .items = {
4500 { "Mic", 0x0 },
4501 { "Line", 0x2 },
4502 { "CD", 0x4 },
4503 { "Headphone", 0x5 },
4504 },
4505 },
4506 {
4507 .num_items = 5,
4508 .items = {
4509 { "Mic", 0x0 },
4510 { "Line", 0x2 },
4511 { "CD", 0x4 },
4512 { "Headphone", 0x6 },
4513 { "Mixer", 0x5 },
4514 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004515 },
4516};
Michael Schwingencc959482009-02-22 18:58:45 +01004517
4518/* Maxdata Favorit 100XS */
4519static struct hda_input_mux alc260_favorit100_capture_sources[2] = {
4520 {
4521 .num_items = 2,
4522 .items = {
4523 { "Line/Mic", 0x0 },
4524 { "CD", 0x4 },
4525 },
4526 },
4527 {
4528 .num_items = 3,
4529 .items = {
4530 { "Line/Mic", 0x0 },
4531 { "CD", 0x4 },
4532 { "Mixer", 0x5 },
4533 },
4534 },
4535};
4536
Linus Torvalds1da177e2005-04-16 15:20:36 -07004537/*
4538 * This is just place-holder, so there's something for alc_build_pcms to look
4539 * at when it calculates the maximum number of channels. ALC260 has no mixer
4540 * element which allows changing the channel mode, so the verb list is
4541 * never used.
4542 */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01004543static struct hda_channel_mode alc260_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004544 { 2, NULL },
4545};
4546
Kailang Yangdf694da2005-12-05 19:42:22 +01004547
4548/* Mixer combinations
4549 *
4550 * basic: base_output + input + pc_beep + capture
4551 * HP: base_output + input + capture_alt
4552 * HP_3013: hp_3013 + input + capture
4553 * fujitsu: fujitsu + capture
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004554 * acer: acer + capture
Kailang Yangdf694da2005-12-05 19:42:22 +01004555 */
4556
4557static struct snd_kcontrol_new alc260_base_output_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02004558 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01004559 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01004560 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
4561 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
4562 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
4563 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
4564 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004565};
Kailang Yangdf694da2005-12-05 19:42:22 +01004566
4567static struct snd_kcontrol_new alc260_input_mixer[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004568 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4569 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
4570 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
4571 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
4572 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
4573 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
4574 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT),
4575 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004576 { } /* end */
4577};
4578
Takashi Iwaibec15c32008-01-28 18:16:30 +01004579/* update HP, line and mono out pins according to the master switch */
4580static void alc260_hp_master_update(struct hda_codec *codec,
4581 hda_nid_t hp, hda_nid_t line,
4582 hda_nid_t mono)
4583{
4584 struct alc_spec *spec = codec->spec;
4585 unsigned int val = spec->master_sw ? PIN_HP : 0;
4586 /* change HP and line-out pins */
Takashi Iwai30cde0a2008-11-07 14:49:28 +01004587 snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwaibec15c32008-01-28 18:16:30 +01004588 val);
Takashi Iwai30cde0a2008-11-07 14:49:28 +01004589 snd_hda_codec_write(codec, line, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwaibec15c32008-01-28 18:16:30 +01004590 val);
4591 /* mono (speaker) depending on the HP jack sense */
4592 val = (val && !spec->jack_present) ? PIN_OUT : 0;
Takashi Iwai30cde0a2008-11-07 14:49:28 +01004593 snd_hda_codec_write(codec, mono, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwaibec15c32008-01-28 18:16:30 +01004594 val);
4595}
4596
4597static int alc260_hp_master_sw_get(struct snd_kcontrol *kcontrol,
4598 struct snd_ctl_elem_value *ucontrol)
4599{
4600 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4601 struct alc_spec *spec = codec->spec;
4602 *ucontrol->value.integer.value = spec->master_sw;
4603 return 0;
4604}
4605
4606static int alc260_hp_master_sw_put(struct snd_kcontrol *kcontrol,
4607 struct snd_ctl_elem_value *ucontrol)
4608{
4609 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4610 struct alc_spec *spec = codec->spec;
4611 int val = !!*ucontrol->value.integer.value;
4612 hda_nid_t hp, line, mono;
4613
4614 if (val == spec->master_sw)
4615 return 0;
4616 spec->master_sw = val;
4617 hp = (kcontrol->private_value >> 16) & 0xff;
4618 line = (kcontrol->private_value >> 8) & 0xff;
4619 mono = kcontrol->private_value & 0xff;
4620 alc260_hp_master_update(codec, hp, line, mono);
4621 return 1;
4622}
4623
4624static struct snd_kcontrol_new alc260_hp_output_mixer[] = {
4625 {
4626 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4627 .name = "Master Playback Switch",
4628 .info = snd_ctl_boolean_mono_info,
4629 .get = alc260_hp_master_sw_get,
4630 .put = alc260_hp_master_sw_put,
4631 .private_value = (0x0f << 16) | (0x10 << 8) | 0x11
4632 },
4633 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4634 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
4635 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
4636 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
4637 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
4638 HDA_OUTPUT),
4639 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2, HDA_INPUT),
4640 { } /* end */
4641};
4642
4643static struct hda_verb alc260_hp_unsol_verbs[] = {
4644 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
4645 {},
4646};
4647
4648static void alc260_hp_automute(struct hda_codec *codec)
4649{
4650 struct alc_spec *spec = codec->spec;
4651 unsigned int present;
4652
4653 present = snd_hda_codec_read(codec, 0x10, 0,
4654 AC_VERB_GET_PIN_SENSE, 0);
4655 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
4656 alc260_hp_master_update(codec, 0x0f, 0x10, 0x11);
4657}
4658
4659static void alc260_hp_unsol_event(struct hda_codec *codec, unsigned int res)
4660{
4661 if ((res >> 26) == ALC880_HP_EVENT)
4662 alc260_hp_automute(codec);
4663}
4664
Kailang Yangdf694da2005-12-05 19:42:22 +01004665static struct snd_kcontrol_new alc260_hp_3013_mixer[] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01004666 {
4667 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4668 .name = "Master Playback Switch",
4669 .info = snd_ctl_boolean_mono_info,
4670 .get = alc260_hp_master_sw_get,
4671 .put = alc260_hp_master_sw_put,
Takashi Iwai30cde0a2008-11-07 14:49:28 +01004672 .private_value = (0x15 << 16) | (0x10 << 8) | 0x11
Takashi Iwaibec15c32008-01-28 18:16:30 +01004673 },
Kailang Yangdf694da2005-12-05 19:42:22 +01004674 HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT),
4675 HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT),
4676 HDA_CODEC_VOLUME("Aux-In Playback Volume", 0x07, 0x06, HDA_INPUT),
4677 HDA_CODEC_MUTE("Aux-In Playback Switch", 0x07, 0x06, HDA_INPUT),
4678 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4679 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01004680 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
4681 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02004682 { } /* end */
4683};
4684
Kailang Yang3f878302008-08-26 13:02:23 +02004685static struct hda_bind_ctls alc260_dc7600_bind_master_vol = {
4686 .ops = &snd_hda_bind_vol,
4687 .values = {
4688 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_OUTPUT),
4689 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_OUTPUT),
4690 HDA_COMPOSE_AMP_VAL(0x0a, 3, 0, HDA_OUTPUT),
4691 0
4692 },
4693};
4694
4695static struct hda_bind_ctls alc260_dc7600_bind_switch = {
4696 .ops = &snd_hda_bind_sw,
4697 .values = {
4698 HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT),
4699 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
4700 0
4701 },
4702};
4703
4704static struct snd_kcontrol_new alc260_hp_dc7600_mixer[] = {
4705 HDA_BIND_VOL("Master Playback Volume", &alc260_dc7600_bind_master_vol),
4706 HDA_BIND_SW("LineOut Playback Switch", &alc260_dc7600_bind_switch),
4707 HDA_CODEC_MUTE("Speaker Playback Switch", 0x0f, 0x0, HDA_OUTPUT),
4708 HDA_CODEC_MUTE("Headphone Playback Switch", 0x10, 0x0, HDA_OUTPUT),
4709 { } /* end */
4710};
4711
Takashi Iwaibec15c32008-01-28 18:16:30 +01004712static struct hda_verb alc260_hp_3013_unsol_verbs[] = {
4713 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
4714 {},
4715};
4716
4717static void alc260_hp_3013_automute(struct hda_codec *codec)
4718{
4719 struct alc_spec *spec = codec->spec;
4720 unsigned int present;
4721
4722 present = snd_hda_codec_read(codec, 0x15, 0,
4723 AC_VERB_GET_PIN_SENSE, 0);
4724 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
Takashi Iwai30cde0a2008-11-07 14:49:28 +01004725 alc260_hp_master_update(codec, 0x15, 0x10, 0x11);
Takashi Iwaibec15c32008-01-28 18:16:30 +01004726}
4727
4728static void alc260_hp_3013_unsol_event(struct hda_codec *codec,
4729 unsigned int res)
4730{
4731 if ((res >> 26) == ALC880_HP_EVENT)
4732 alc260_hp_3013_automute(codec);
4733}
4734
Kailang Yang3f878302008-08-26 13:02:23 +02004735static void alc260_hp_3012_automute(struct hda_codec *codec)
4736{
4737 unsigned int present, bits;
4738
4739 present = snd_hda_codec_read(codec, 0x10, 0,
4740 AC_VERB_GET_PIN_SENSE, 0) & AC_PINSENSE_PRESENCE;
4741
4742 bits = present ? 0 : PIN_OUT;
4743 snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
4744 bits);
4745 snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
4746 bits);
4747 snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
4748 bits);
4749}
4750
4751static void alc260_hp_3012_unsol_event(struct hda_codec *codec,
4752 unsigned int res)
4753{
4754 if ((res >> 26) == ALC880_HP_EVENT)
4755 alc260_hp_3012_automute(codec);
4756}
4757
4758/* Fujitsu S702x series laptops. ALC260 pin usage: Mic/Line jack = 0x12,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004759 * HP jack = 0x14, CD audio = 0x16, internal speaker = 0x10.
4760 */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01004761static struct snd_kcontrol_new alc260_fujitsu_mixer[] = {
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004762 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01004763 HDA_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004764 ALC_PIN_MODE("Headphone Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004765 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4766 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
4767 HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT),
4768 HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004769 ALC_PIN_MODE("Mic/Line Jack Mode", 0x12, ALC_PIN_DIR_IN),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01004770 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT),
4771 HDA_BIND_MUTE("Speaker Playback Switch", 0x09, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01004772 { } /* end */
4773};
4774
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004775/* Mixer for Acer TravelMate(/Extensa/Aspire) notebooks. Note that current
4776 * versions of the ALC260 don't act on requests to enable mic bias from NID
4777 * 0x0f (used to drive the headphone jack in these laptops). The ALC260
4778 * datasheet doesn't mention this restriction. At this stage it's not clear
4779 * whether this behaviour is intentional or is a hardware bug in chip
4780 * revisions available in early 2006. Therefore for now allow the
4781 * "Headphone Jack Mode" control to span all choices, but if it turns out
4782 * that the lack of mic bias for this NID is intentional we could change the
4783 * mode from ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
4784 *
4785 * In addition, Acer TravelMate(/Extensa/Aspire) notebooks in early 2006
4786 * don't appear to make the mic bias available from the "line" jack, even
4787 * though the NID used for this jack (0x14) can supply it. The theory is
4788 * that perhaps Acer have included blocking capacitors between the ALC260
4789 * and the output jack. If this turns out to be the case for all such
4790 * models the "Line Jack Mode" mode could be changed from ALC_PIN_DIR_INOUT
4791 * to ALC_PIN_DIR_INOUT_NOMICBIAS.
Jonathan Woithebd869482006-11-28 11:35:52 +01004792 *
4793 * The C20x Tablet series have a mono internal speaker which is controlled
4794 * via the chip's Mono sum widget and pin complex, so include the necessary
4795 * controls for such models. On models without a "mono speaker" the control
4796 * won't do anything.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004797 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004798static struct snd_kcontrol_new alc260_acer_mixer[] = {
4799 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4800 HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004801 ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01004802 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
Jonathan Woithebd869482006-11-28 11:35:52 +01004803 HDA_OUTPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01004804 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2,
Jonathan Woithebd869482006-11-28 11:35:52 +01004805 HDA_INPUT),
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004806 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4807 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
4808 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
4809 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
4810 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
4811 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
4812 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
4813 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004814 { } /* end */
4815};
4816
Michael Schwingencc959482009-02-22 18:58:45 +01004817/* Maxdata Favorit 100XS: one output and one input (0x12) jack
4818 */
4819static struct snd_kcontrol_new alc260_favorit100_mixer[] = {
4820 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4821 HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
4822 ALC_PIN_MODE("Output Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
4823 HDA_CODEC_VOLUME("Line/Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
4824 HDA_CODEC_MUTE("Line/Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
4825 ALC_PIN_MODE("Line/Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
4826 { } /* end */
4827};
4828
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004829/* Packard bell V7900 ALC260 pin usage: HP = 0x0f, Mic jack = 0x12,
4830 * Line In jack = 0x14, CD audio = 0x16, pc beep = 0x17.
4831 */
4832static struct snd_kcontrol_new alc260_will_mixer[] = {
4833 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4834 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
4835 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
4836 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
4837 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
4838 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
4839 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
4840 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
4841 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4842 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004843 { } /* end */
4844};
4845
4846/* Replacer 672V ALC260 pin usage: Mic jack = 0x12,
4847 * Line In jack = 0x14, ATAPI Mic = 0x13, speaker = 0x0f.
4848 */
4849static struct snd_kcontrol_new alc260_replacer_672v_mixer[] = {
4850 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4851 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
4852 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
4853 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
4854 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
4855 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x07, 0x1, HDA_INPUT),
4856 HDA_CODEC_MUTE("ATATI Mic Playback Switch", 0x07, 0x1, HDA_INPUT),
4857 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
4858 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
4859 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
4860 { } /* end */
4861};
4862
Kailang Yangdf694da2005-12-05 19:42:22 +01004863/*
4864 * initialization verbs
4865 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004866static struct hda_verb alc260_init_verbs[] = {
4867 /* Line In pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02004868 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004869 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02004870 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004871 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02004872 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004873 /* Mic2 (front panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02004874 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004875 /* LINE-2 is used for line-out in rear */
Takashi Iwai05acb862005-06-10 19:50:25 +02004876 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004877 /* select line-out */
Jonathan Woithefd56f2d2006-01-24 10:35:46 +01004878 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004879 /* LINE-OUT pin */
Takashi Iwai05acb862005-06-10 19:50:25 +02004880 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004881 /* enable HP */
Takashi Iwai05acb862005-06-10 19:50:25 +02004882 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004883 /* enable Mono */
Takashi Iwai05acb862005-06-10 19:50:25 +02004884 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4885 /* mute capture amp left and right */
Takashi Iwai16ded522005-06-10 19:58:24 +02004886 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004887 /* set connection select to line in (default select for this ADC) */
4888 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai16ded522005-06-10 19:58:24 +02004889 /* mute capture amp left and right */
4890 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4891 /* set connection select to line in (default select for this ADC) */
4892 {0x05, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai05acb862005-06-10 19:50:25 +02004893 /* set vol=0 Line-Out mixer amp left and right */
4894 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4895 /* unmute pin widget amp left and right (no gain on this amp) */
4896 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4897 /* set vol=0 HP mixer amp left and right */
4898 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4899 /* unmute pin widget amp left and right (no gain on this amp) */
4900 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4901 /* set vol=0 Mono mixer amp left and right */
4902 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4903 /* unmute pin widget amp left and right (no gain on this amp) */
4904 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4905 /* unmute LINE-2 out pin */
4906 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004907 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
4908 * Line In 2 = 0x03
4909 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02004910 /* mute analog inputs */
4911 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4912 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4913 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4914 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4915 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004916 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
Takashi Iwai05acb862005-06-10 19:50:25 +02004917 /* mute Front out path */
4918 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4919 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4920 /* mute Headphone out path */
4921 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4922 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4923 /* mute Mono out path */
4924 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4925 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004926 { }
4927};
4928
Takashi Iwai474167d2006-05-17 17:17:43 +02004929#if 0 /* should be identical with alc260_init_verbs? */
Kailang Yangdf694da2005-12-05 19:42:22 +01004930static struct hda_verb alc260_hp_init_verbs[] = {
4931 /* Headphone and output */
4932 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
4933 /* mono output */
4934 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4935 /* Mic1 (rear panel) pin widget for input and vref at 80% */
4936 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4937 /* Mic2 (front panel) pin widget for input and vref at 80% */
4938 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4939 /* Line In pin widget for input */
4940 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4941 /* Line-2 pin widget for output */
4942 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4943 /* CD pin widget for input */
4944 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4945 /* unmute amp left and right */
4946 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
4947 /* set connection select to line in (default select for this ADC) */
4948 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
4949 /* unmute Line-Out mixer amp left and right (volume = 0) */
4950 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
4951 /* mute pin widget amp left and right (no gain on this amp) */
4952 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
4953 /* unmute HP mixer amp left and right (volume = 0) */
4954 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
4955 /* mute pin widget amp left and right (no gain on this amp) */
4956 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004957 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
4958 * Line In 2 = 0x03
4959 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02004960 /* mute analog inputs */
4961 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4962 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4963 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4964 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4965 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01004966 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
4967 /* Unmute Front out path */
4968 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4969 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4970 /* Unmute Headphone out path */
4971 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4972 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4973 /* Unmute Mono out path */
4974 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4975 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4976 { }
4977};
Takashi Iwai474167d2006-05-17 17:17:43 +02004978#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01004979
4980static struct hda_verb alc260_hp_3013_init_verbs[] = {
4981 /* Line out and output */
4982 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4983 /* mono output */
4984 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4985 /* Mic1 (rear panel) pin widget for input and vref at 80% */
4986 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4987 /* Mic2 (front panel) pin widget for input and vref at 80% */
4988 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4989 /* Line In pin widget for input */
4990 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4991 /* Headphone pin widget for output */
4992 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
4993 /* CD pin widget for input */
4994 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4995 /* unmute amp left and right */
4996 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
4997 /* set connection select to line in (default select for this ADC) */
4998 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
4999 /* unmute Line-Out mixer amp left and right (volume = 0) */
5000 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
5001 /* mute pin widget amp left and right (no gain on this amp) */
5002 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
5003 /* unmute HP mixer amp left and right (volume = 0) */
5004 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
5005 /* mute pin widget amp left and right (no gain on this amp) */
5006 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005007 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
5008 * Line In 2 = 0x03
5009 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02005010 /* mute analog inputs */
5011 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5012 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5013 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5014 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5015 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01005016 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
5017 /* Unmute Front out path */
5018 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5019 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
5020 /* Unmute Headphone out path */
5021 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5022 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
5023 /* Unmute Mono out path */
5024 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5025 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
5026 { }
5027};
5028
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005029/* Initialisation sequence for ALC260 as configured in Fujitsu S702x
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005030 * laptops. ALC260 pin usage: Mic/Line jack = 0x12, HP jack = 0x14, CD
5031 * audio = 0x16, internal speaker = 0x10.
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005032 */
5033static struct hda_verb alc260_fujitsu_init_verbs[] = {
5034 /* Disable all GPIOs */
5035 {0x01, AC_VERB_SET_GPIO_MASK, 0},
5036 /* Internal speaker is connected to headphone pin */
5037 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5038 /* Headphone/Line-out jack connects to Line1 pin; make it an output */
5039 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Jonathan Woithef7ace402006-02-28 11:46:14 +01005040 /* Mic/Line-in jack is connected to mic1 pin, so make it an input */
5041 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
5042 /* Ensure all other unused pins are disabled and muted. */
5043 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5044 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005045 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01005046 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005047 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01005048 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5049 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5050 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005051
Jonathan Woithef7ace402006-02-28 11:46:14 +01005052 /* Disable digital (SPDIF) pins */
5053 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
5054 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01005055
Kailang Yangea1fb292008-08-26 12:58:38 +02005056 /* Ensure Line1 pin widget takes its input from the OUT1 sum bus
Jonathan Woithef7ace402006-02-28 11:46:14 +01005057 * when acting as an output.
5058 */
5059 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
5060
5061 /* Start with output sum widgets muted and their output gains at min */
Takashi Iwai8b33a5a2006-02-09 11:57:01 +01005062 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5063 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5064 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5065 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5066 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5067 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5068 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5069 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5070 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005071
Jonathan Woithef7ace402006-02-28 11:46:14 +01005072 /* Unmute HP pin widget amp left and right (no equiv mixer ctrl) */
5073 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5074 /* Unmute Line1 pin widget output buffer since it starts as an output.
5075 * If the pin mode is changed by the user the pin mode control will
5076 * take care of enabling the pin's input/output buffers as needed.
5077 * Therefore there's no need to enable the input buffer at this
5078 * stage.
Jonathan Woithecdcd9262006-02-28 11:36:42 +01005079 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01005080 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +02005081 /* Unmute input buffer of pin widget used for Line-in (no equiv
Jonathan Woithecdcd9262006-02-28 11:36:42 +01005082 * mixer ctrl)
5083 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01005084 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005085
Jonathan Woithef7ace402006-02-28 11:46:14 +01005086 /* Mute capture amp left and right */
5087 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +02005088 /* Set ADC connection select to match default mixer setting - line
Jonathan Woithef7ace402006-02-28 11:46:14 +01005089 * in (on mic1 pin)
5090 */
5091 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005092
Jonathan Woithef7ace402006-02-28 11:46:14 +01005093 /* Do the same for the second ADC: mute capture input amp and
5094 * set ADC connection to line in (on mic1 pin)
5095 */
5096 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5097 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01005098
Jonathan Woithef7ace402006-02-28 11:46:14 +01005099 /* Mute all inputs to mixer widget (even unconnected ones) */
5100 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
5101 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
5102 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
5103 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
5104 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
5105 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
5106 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
5107 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
Takashi Iwai4a471b72005-12-07 13:56:29 +01005108
5109 { }
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005110};
5111
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005112/* Initialisation sequence for ALC260 as configured in Acer TravelMate and
5113 * similar laptops (adapted from Fujitsu init verbs).
5114 */
5115static struct hda_verb alc260_acer_init_verbs[] = {
5116 /* On TravelMate laptops, GPIO 0 enables the internal speaker and
5117 * the headphone jack. Turn this on and rely on the standard mute
5118 * methods whenever the user wants to turn these outputs off.
5119 */
5120 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
5121 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
5122 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
5123 /* Internal speaker/Headphone jack is connected to Line-out pin */
5124 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5125 /* Internal microphone/Mic jack is connected to Mic1 pin */
5126 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
5127 /* Line In jack is connected to Line1 pin */
5128 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Jonathan Woithebd869482006-11-28 11:35:52 +01005129 /* Some Acers (eg: C20x Tablets) use Mono pin for internal speaker */
5130 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005131 /* Ensure all other unused pins are disabled and muted. */
5132 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5133 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005134 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5135 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5136 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5137 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5138 /* Disable digital (SPDIF) pins */
5139 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
5140 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
5141
Kailang Yangea1fb292008-08-26 12:58:38 +02005142 /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005143 * bus when acting as outputs.
5144 */
5145 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
5146 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
5147
5148 /* Start with output sum widgets muted and their output gains at min */
5149 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5150 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5151 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5152 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5153 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5154 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5155 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5156 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5157 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5158
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005159 /* Unmute Line-out pin widget amp left and right
5160 * (no equiv mixer ctrl)
5161 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005162 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithebd869482006-11-28 11:35:52 +01005163 /* Unmute mono pin widget amp output (no equiv mixer ctrl) */
5164 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005165 /* Unmute Mic1 and Line1 pin widget input buffers since they start as
5166 * inputs. If the pin mode is changed by the user the pin mode control
5167 * will take care of enabling the pin's input/output buffers as needed.
5168 * Therefore there's no need to enable the input buffer at this
5169 * stage.
5170 */
5171 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5172 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5173
5174 /* Mute capture amp left and right */
5175 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5176 /* Set ADC connection select to match default mixer setting - mic
5177 * (on mic1 pin)
5178 */
5179 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
5180
5181 /* Do similar with the second ADC: mute capture input amp and
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005182 * set ADC connection to mic to match ALSA's default state.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005183 */
5184 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005185 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005186
5187 /* Mute all inputs to mixer widget (even unconnected ones) */
5188 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
5189 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
5190 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
5191 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
5192 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
5193 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
5194 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
5195 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
5196
5197 { }
5198};
5199
Michael Schwingencc959482009-02-22 18:58:45 +01005200/* Initialisation sequence for Maxdata Favorit 100XS
5201 * (adapted from Acer init verbs).
5202 */
5203static struct hda_verb alc260_favorit100_init_verbs[] = {
5204 /* GPIO 0 enables the output jack.
5205 * Turn this on and rely on the standard mute
5206 * methods whenever the user wants to turn these outputs off.
5207 */
5208 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
5209 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
5210 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
5211 /* Line/Mic input jack is connected to Mic1 pin */
5212 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
5213 /* Ensure all other unused pins are disabled and muted. */
5214 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5215 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5216 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5217 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5218 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5219 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5220 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5221 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5222 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5223 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5224 /* Disable digital (SPDIF) pins */
5225 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
5226 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
5227
5228 /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
5229 * bus when acting as outputs.
5230 */
5231 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
5232 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
5233
5234 /* Start with output sum widgets muted and their output gains at min */
5235 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5236 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5237 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5238 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5239 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5240 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5241 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5242 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5243 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5244
5245 /* Unmute Line-out pin widget amp left and right
5246 * (no equiv mixer ctrl)
5247 */
5248 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5249 /* Unmute Mic1 and Line1 pin widget input buffers since they start as
5250 * inputs. If the pin mode is changed by the user the pin mode control
5251 * will take care of enabling the pin's input/output buffers as needed.
5252 * Therefore there's no need to enable the input buffer at this
5253 * stage.
5254 */
5255 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5256
5257 /* Mute capture amp left and right */
5258 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5259 /* Set ADC connection select to match default mixer setting - mic
5260 * (on mic1 pin)
5261 */
5262 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
5263
5264 /* Do similar with the second ADC: mute capture input amp and
5265 * set ADC connection to mic to match ALSA's default state.
5266 */
5267 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5268 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
5269
5270 /* Mute all inputs to mixer widget (even unconnected ones) */
5271 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
5272 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
5273 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
5274 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
5275 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
5276 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
5277 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
5278 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
5279
5280 { }
5281};
5282
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005283static struct hda_verb alc260_will_verbs[] = {
5284 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5285 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x00},
5286 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
5287 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
5288 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
5289 {0x1a, AC_VERB_SET_PROC_COEF, 0x3040},
5290 {}
5291};
5292
5293static struct hda_verb alc260_replacer_672v_verbs[] = {
5294 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
5295 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
5296 {0x1a, AC_VERB_SET_PROC_COEF, 0x3050},
5297
5298 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
5299 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
5300 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
5301
5302 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
5303 {}
5304};
5305
5306/* toggle speaker-output according to the hp-jack state */
5307static void alc260_replacer_672v_automute(struct hda_codec *codec)
5308{
5309 unsigned int present;
5310
5311 /* speaker --> GPIO Data 0, hp or spdif --> GPIO data 1 */
5312 present = snd_hda_codec_read(codec, 0x0f, 0,
5313 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
5314 if (present) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02005315 snd_hda_codec_write_cache(codec, 0x01, 0,
5316 AC_VERB_SET_GPIO_DATA, 1);
5317 snd_hda_codec_write_cache(codec, 0x0f, 0,
5318 AC_VERB_SET_PIN_WIDGET_CONTROL,
5319 PIN_HP);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005320 } else {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02005321 snd_hda_codec_write_cache(codec, 0x01, 0,
5322 AC_VERB_SET_GPIO_DATA, 0);
5323 snd_hda_codec_write_cache(codec, 0x0f, 0,
5324 AC_VERB_SET_PIN_WIDGET_CONTROL,
5325 PIN_OUT);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005326 }
5327}
5328
5329static void alc260_replacer_672v_unsol_event(struct hda_codec *codec,
5330 unsigned int res)
5331{
5332 if ((res >> 26) == ALC880_HP_EVENT)
5333 alc260_replacer_672v_automute(codec);
5334}
5335
Kailang Yang3f878302008-08-26 13:02:23 +02005336static struct hda_verb alc260_hp_dc7600_verbs[] = {
5337 {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
5338 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
5339 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5340 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5341 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5342 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5343 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
5344 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
5345 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
5346 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
5347 {}
5348};
5349
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005350/* Test configuration for debugging, modelled after the ALC880 test
5351 * configuration.
5352 */
5353#ifdef CONFIG_SND_DEBUG
5354static hda_nid_t alc260_test_dac_nids[1] = {
5355 0x02,
5356};
5357static hda_nid_t alc260_test_adc_nids[2] = {
5358 0x04, 0x05,
5359};
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005360/* For testing the ALC260, each input MUX needs its own definition since
Kailang Yangea1fb292008-08-26 12:58:38 +02005361 * the signal assignments are different. This assumes that the first ADC
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005362 * is NID 0x04.
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01005363 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005364static struct hda_input_mux alc260_test_capture_sources[2] = {
5365 {
5366 .num_items = 7,
5367 .items = {
5368 { "MIC1 pin", 0x0 },
5369 { "MIC2 pin", 0x1 },
5370 { "LINE1 pin", 0x2 },
5371 { "LINE2 pin", 0x3 },
5372 { "CD pin", 0x4 },
5373 { "LINE-OUT pin", 0x5 },
5374 { "HP-OUT pin", 0x6 },
5375 },
5376 },
5377 {
5378 .num_items = 8,
5379 .items = {
5380 { "MIC1 pin", 0x0 },
5381 { "MIC2 pin", 0x1 },
5382 { "LINE1 pin", 0x2 },
5383 { "LINE2 pin", 0x3 },
5384 { "CD pin", 0x4 },
5385 { "Mixer", 0x5 },
5386 { "LINE-OUT pin", 0x6 },
5387 { "HP-OUT pin", 0x7 },
5388 },
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005389 },
5390};
5391static struct snd_kcontrol_new alc260_test_mixer[] = {
5392 /* Output driver widgets */
5393 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
5394 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
5395 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x09, 0x0, HDA_OUTPUT),
5396 HDA_BIND_MUTE("LOUT2 Playback Switch", 0x09, 2, HDA_INPUT),
5397 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5398 HDA_BIND_MUTE("LOUT1 Playback Switch", 0x08, 2, HDA_INPUT),
5399
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005400 /* Modes for retasking pin widgets
5401 * Note: the ALC260 doesn't seem to act on requests to enable mic
5402 * bias from NIDs 0x0f and 0x10. The ALC260 datasheet doesn't
5403 * mention this restriction. At this stage it's not clear whether
5404 * this behaviour is intentional or is a hardware bug in chip
5405 * revisions available at least up until early 2006. Therefore for
5406 * now allow the "HP-OUT" and "LINE-OUT" Mode controls to span all
5407 * choices, but if it turns out that the lack of mic bias for these
5408 * NIDs is intentional we could change their modes from
5409 * ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
5410 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005411 ALC_PIN_MODE("HP-OUT pin mode", 0x10, ALC_PIN_DIR_INOUT),
5412 ALC_PIN_MODE("LINE-OUT pin mode", 0x0f, ALC_PIN_DIR_INOUT),
5413 ALC_PIN_MODE("LINE2 pin mode", 0x15, ALC_PIN_DIR_INOUT),
5414 ALC_PIN_MODE("LINE1 pin mode", 0x14, ALC_PIN_DIR_INOUT),
5415 ALC_PIN_MODE("MIC2 pin mode", 0x13, ALC_PIN_DIR_INOUT),
5416 ALC_PIN_MODE("MIC1 pin mode", 0x12, ALC_PIN_DIR_INOUT),
5417
5418 /* Loopback mixer controls */
5419 HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x07, 0x00, HDA_INPUT),
5420 HDA_CODEC_MUTE("MIC1 Playback Switch", 0x07, 0x00, HDA_INPUT),
5421 HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x07, 0x01, HDA_INPUT),
5422 HDA_CODEC_MUTE("MIC2 Playback Switch", 0x07, 0x01, HDA_INPUT),
5423 HDA_CODEC_VOLUME("LINE1 Playback Volume", 0x07, 0x02, HDA_INPUT),
5424 HDA_CODEC_MUTE("LINE1 Playback Switch", 0x07, 0x02, HDA_INPUT),
5425 HDA_CODEC_VOLUME("LINE2 Playback Volume", 0x07, 0x03, HDA_INPUT),
5426 HDA_CODEC_MUTE("LINE2 Playback Switch", 0x07, 0x03, HDA_INPUT),
5427 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
5428 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005429 HDA_CODEC_VOLUME("LINE-OUT loopback Playback Volume", 0x07, 0x06, HDA_INPUT),
5430 HDA_CODEC_MUTE("LINE-OUT loopback Playback Switch", 0x07, 0x06, HDA_INPUT),
5431 HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x07, 0x7, HDA_INPUT),
5432 HDA_CODEC_MUTE("HP-OUT loopback Playback Switch", 0x07, 0x7, HDA_INPUT),
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01005433
5434 /* Controls for GPIO pins, assuming they are configured as outputs */
5435 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
5436 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
5437 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
5438 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
5439
Jonathan Woithe92621f12006-02-28 11:47:47 +01005440 /* Switches to allow the digital IO pins to be enabled. The datasheet
5441 * is ambigious as to which NID is which; testing on laptops which
Kailang Yangea1fb292008-08-26 12:58:38 +02005442 * make this output available should provide clarification.
Jonathan Woithe92621f12006-02-28 11:47:47 +01005443 */
5444 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x03, 0x01),
5445 ALC_SPDIF_CTRL_SWITCH("SPDIF Capture Switch", 0x06, 0x01),
5446
Jonathan Woithef8225f62008-01-08 12:16:54 +01005447 /* A switch allowing EAPD to be enabled. Some laptops seem to use
5448 * this output to turn on an external amplifier.
5449 */
5450 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
5451 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
5452
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005453 { } /* end */
5454};
5455static struct hda_verb alc260_test_init_verbs[] = {
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01005456 /* Enable all GPIOs as outputs with an initial value of 0 */
5457 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f},
5458 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
5459 {0x01, AC_VERB_SET_GPIO_MASK, 0x0f},
5460
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005461 /* Enable retasking pins as output, initially without power amp */
5462 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5463 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5464 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5465 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5466 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5467 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5468
Jonathan Woithe92621f12006-02-28 11:47:47 +01005469 /* Disable digital (SPDIF) pins initially, but users can enable
5470 * them via a mixer switch. In the case of SPDIF-out, this initverb
5471 * payload also sets the generation to 0, output to be in "consumer"
5472 * PCM format, copyright asserted, no pre-emphasis and no validity
5473 * control.
5474 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005475 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
5476 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
5477
Kailang Yangea1fb292008-08-26 12:58:38 +02005478 /* Ensure mic1, mic2, line1 and line2 pin widgets take input from the
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005479 * OUT1 sum bus when acting as an output.
5480 */
5481 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
5482 {0x0c, AC_VERB_SET_CONNECT_SEL, 0},
5483 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
5484 {0x0e, AC_VERB_SET_CONNECT_SEL, 0},
5485
5486 /* Start with output sum widgets muted and their output gains at min */
5487 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5488 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5489 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5490 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5491 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5492 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5493 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5494 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5495 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5496
Jonathan Woithecdcd9262006-02-28 11:36:42 +01005497 /* Unmute retasking pin widget output buffers since the default
5498 * state appears to be output. As the pin mode is changed by the
5499 * user the pin mode control will take care of enabling the pin's
5500 * input/output buffers as needed.
5501 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005502 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5503 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5504 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5505 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5506 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5507 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5508 /* Also unmute the mono-out pin widget */
5509 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5510
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005511 /* Mute capture amp left and right */
5512 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithef7ace402006-02-28 11:46:14 +01005513 /* Set ADC connection select to match default mixer setting (mic1
5514 * pin)
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005515 */
5516 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
5517
5518 /* Do the same for the second ADC: mute capture input amp and
Jonathan Woithef7ace402006-02-28 11:46:14 +01005519 * set ADC connection to mic1 pin
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005520 */
5521 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5522 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
5523
5524 /* Mute all inputs to mixer widget (even unconnected ones) */
5525 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
5526 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
5527 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
5528 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
5529 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
5530 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
5531 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
5532 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
5533
5534 { }
5535};
5536#endif
5537
Takashi Iwai63300792008-01-24 15:31:36 +01005538#define alc260_pcm_analog_playback alc880_pcm_analog_alt_playback
5539#define alc260_pcm_analog_capture alc880_pcm_analog_capture
Linus Torvalds1da177e2005-04-16 15:20:36 -07005540
Takashi Iwaia3bcba32005-12-06 19:05:29 +01005541#define alc260_pcm_digital_playback alc880_pcm_digital_playback
5542#define alc260_pcm_digital_capture alc880_pcm_digital_capture
5543
Kailang Yangdf694da2005-12-05 19:42:22 +01005544/*
5545 * for BIOS auto-configuration
5546 */
5547
5548static int alc260_add_playback_controls(struct alc_spec *spec, hda_nid_t nid,
Takashi Iwai863b4512008-10-21 17:01:47 +02005549 const char *pfx, int *vol_bits)
Kailang Yangdf694da2005-12-05 19:42:22 +01005550{
5551 hda_nid_t nid_vol;
5552 unsigned long vol_val, sw_val;
5553 char name[32];
5554 int err;
5555
5556 if (nid >= 0x0f && nid < 0x11) {
5557 nid_vol = nid - 0x7;
5558 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
5559 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
5560 } else if (nid == 0x11) {
5561 nid_vol = nid - 0x7;
5562 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT);
5563 sw_val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
5564 } else if (nid >= 0x12 && nid <= 0x15) {
5565 nid_vol = 0x08;
5566 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
5567 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
5568 } else
5569 return 0; /* N/A */
Kailang Yangea1fb292008-08-26 12:58:38 +02005570
Takashi Iwai863b4512008-10-21 17:01:47 +02005571 if (!(*vol_bits & (1 << nid_vol))) {
5572 /* first control for the volume widget */
5573 snprintf(name, sizeof(name), "%s Playback Volume", pfx);
5574 err = add_control(spec, ALC_CTL_WIDGET_VOL, name, vol_val);
5575 if (err < 0)
5576 return err;
5577 *vol_bits |= (1 << nid_vol);
5578 }
Kailang Yangdf694da2005-12-05 19:42:22 +01005579 snprintf(name, sizeof(name), "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005580 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, sw_val);
5581 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01005582 return err;
5583 return 1;
5584}
5585
5586/* add playback controls from the parsed DAC table */
5587static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec,
5588 const struct auto_pin_cfg *cfg)
5589{
5590 hda_nid_t nid;
5591 int err;
Takashi Iwai863b4512008-10-21 17:01:47 +02005592 int vols = 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01005593
5594 spec->multiout.num_dacs = 1;
5595 spec->multiout.dac_nids = spec->private_dac_nids;
5596 spec->multiout.dac_nids[0] = 0x02;
5597
5598 nid = cfg->line_out_pins[0];
5599 if (nid) {
Takashi Iwai863b4512008-10-21 17:01:47 +02005600 err = alc260_add_playback_controls(spec, nid, "Front", &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01005601 if (err < 0)
5602 return err;
5603 }
5604
Takashi Iwai82bc9552006-03-21 11:24:42 +01005605 nid = cfg->speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01005606 if (nid) {
Takashi Iwai863b4512008-10-21 17:01:47 +02005607 err = alc260_add_playback_controls(spec, nid, "Speaker", &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01005608 if (err < 0)
5609 return err;
5610 }
5611
Takashi Iwaieb06ed82006-09-20 17:10:27 +02005612 nid = cfg->hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01005613 if (nid) {
Takashi Iwai863b4512008-10-21 17:01:47 +02005614 err = alc260_add_playback_controls(spec, nid, "Headphone",
5615 &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01005616 if (err < 0)
5617 return err;
5618 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005619 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01005620}
5621
5622/* create playback/capture controls for input pins */
5623static int alc260_auto_create_analog_input_ctls(struct alc_spec *spec,
5624 const struct auto_pin_cfg *cfg)
5625{
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02005626 struct hda_input_mux *imux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01005627 int i, err, idx;
5628
5629 for (i = 0; i < AUTO_PIN_LAST; i++) {
5630 if (cfg->input_pins[i] >= 0x12) {
5631 idx = cfg->input_pins[i] - 0x12;
Takashi Iwai4a471b72005-12-07 13:56:29 +01005632 err = new_analog_input(spec, cfg->input_pins[i],
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005633 auto_pin_cfg_labels[i], idx,
5634 0x07);
Kailang Yangdf694da2005-12-05 19:42:22 +01005635 if (err < 0)
5636 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005637 imux->items[imux->num_items].label =
5638 auto_pin_cfg_labels[i];
Kailang Yangdf694da2005-12-05 19:42:22 +01005639 imux->items[imux->num_items].index = idx;
5640 imux->num_items++;
5641 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005642 if (cfg->input_pins[i] >= 0x0f && cfg->input_pins[i] <= 0x10){
Kailang Yangdf694da2005-12-05 19:42:22 +01005643 idx = cfg->input_pins[i] - 0x09;
Takashi Iwai4a471b72005-12-07 13:56:29 +01005644 err = new_analog_input(spec, cfg->input_pins[i],
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005645 auto_pin_cfg_labels[i], idx,
5646 0x07);
Kailang Yangdf694da2005-12-05 19:42:22 +01005647 if (err < 0)
5648 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005649 imux->items[imux->num_items].label =
5650 auto_pin_cfg_labels[i];
Kailang Yangdf694da2005-12-05 19:42:22 +01005651 imux->items[imux->num_items].index = idx;
5652 imux->num_items++;
5653 }
5654 }
5655 return 0;
5656}
5657
5658static void alc260_auto_set_output_and_unmute(struct hda_codec *codec,
5659 hda_nid_t nid, int pin_type,
5660 int sel_idx)
5661{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005662 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01005663 /* need the manual connection? */
5664 if (nid >= 0x12) {
5665 int idx = nid - 0x12;
5666 snd_hda_codec_write(codec, idx + 0x0b, 0,
5667 AC_VERB_SET_CONNECT_SEL, sel_idx);
Kailang Yangdf694da2005-12-05 19:42:22 +01005668 }
5669}
5670
5671static void alc260_auto_init_multi_out(struct hda_codec *codec)
5672{
5673 struct alc_spec *spec = codec->spec;
5674 hda_nid_t nid;
5675
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005676 alc_subsystem_id(codec, 0x10, 0x15, 0x0f);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005677 nid = spec->autocfg.line_out_pins[0];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02005678 if (nid) {
5679 int pin_type = get_pin_type(spec->autocfg.line_out_type);
5680 alc260_auto_set_output_and_unmute(codec, nid, pin_type, 0);
5681 }
Kailang Yangea1fb292008-08-26 12:58:38 +02005682
Takashi Iwai82bc9552006-03-21 11:24:42 +01005683 nid = spec->autocfg.speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01005684 if (nid)
5685 alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
5686
Takashi Iwaieb06ed82006-09-20 17:10:27 +02005687 nid = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01005688 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02005689 alc260_auto_set_output_and_unmute(codec, nid, PIN_HP, 0);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005690}
Kailang Yangdf694da2005-12-05 19:42:22 +01005691
5692#define ALC260_PIN_CD_NID 0x16
5693static void alc260_auto_init_analog_input(struct hda_codec *codec)
5694{
5695 struct alc_spec *spec = codec->spec;
5696 int i;
5697
5698 for (i = 0; i < AUTO_PIN_LAST; i++) {
5699 hda_nid_t nid = spec->autocfg.input_pins[i];
5700 if (nid >= 0x12) {
Takashi Iwai23f0c042009-02-26 13:03:58 +01005701 alc_set_input_pin(codec, nid, i);
Takashi Iwaie82c0252009-03-23 15:17:38 +01005702 if (nid != ALC260_PIN_CD_NID &&
5703 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005704 snd_hda_codec_write(codec, nid, 0,
5705 AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangdf694da2005-12-05 19:42:22 +01005706 AMP_OUT_MUTE);
5707 }
5708 }
5709}
5710
5711/*
5712 * generic initialization of ADC, input mixers and output mixers
5713 */
5714static struct hda_verb alc260_volume_init_verbs[] = {
5715 /*
5716 * Unmute ADC0-1 and set the default input to mic-in
5717 */
5718 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
5719 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5720 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
5721 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +02005722
Kailang Yangdf694da2005-12-05 19:42:22 +01005723 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
5724 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005725 * Note: PASD motherboards uses the Line In 2 as the input for
5726 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01005727 */
5728 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02005729 /* mute analog inputs */
5730 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5731 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5732 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5733 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5734 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01005735
5736 /*
5737 * Set up output mixers (0x08 - 0x0a)
5738 */
5739 /* set vol=0 to output mixers */
5740 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5741 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5742 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5743 /* set up input amps for analog loopback */
5744 /* Amp Indices: DAC = 0, mixer = 1 */
5745 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5746 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5747 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5748 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5749 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5750 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +02005751
Kailang Yangdf694da2005-12-05 19:42:22 +01005752 { }
5753};
5754
5755static int alc260_parse_auto_config(struct hda_codec *codec)
5756{
5757 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01005758 int err;
5759 static hda_nid_t alc260_ignore[] = { 0x17, 0 };
5760
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005761 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
5762 alc260_ignore);
5763 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01005764 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005765 err = alc260_auto_create_multi_out_ctls(spec, &spec->autocfg);
5766 if (err < 0)
Takashi Iwai4a471b72005-12-07 13:56:29 +01005767 return err;
Takashi Iwai603c4012008-07-30 15:01:44 +02005768 if (!spec->kctls.list)
Kailang Yangdf694da2005-12-05 19:42:22 +01005769 return 0; /* can't find valid BIOS pin config */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005770 err = alc260_auto_create_analog_input_ctls(spec, &spec->autocfg);
5771 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01005772 return err;
5773
5774 spec->multiout.max_channels = 2;
5775
Takashi Iwai0852d7a2009-02-11 11:35:15 +01005776 if (spec->autocfg.dig_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +01005777 spec->multiout.dig_out_nid = ALC260_DIGOUT_NID;
Takashi Iwai603c4012008-07-30 15:01:44 +02005778 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +01005779 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +01005780
Takashi Iwaid88897e2008-10-31 15:01:37 +01005781 add_verb(spec, alc260_volume_init_verbs);
Kailang Yangdf694da2005-12-05 19:42:22 +01005782
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005783 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02005784 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01005785
Kailang Yangdf694da2005-12-05 19:42:22 +01005786 return 1;
5787}
5788
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005789/* additional initialization for auto-configuration model */
5790static void alc260_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01005791{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005792 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01005793 alc260_auto_init_multi_out(codec);
5794 alc260_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005795 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02005796 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01005797}
5798
Takashi Iwaicb53c622007-08-10 17:21:45 +02005799#ifdef CONFIG_SND_HDA_POWER_SAVE
5800static struct hda_amp_list alc260_loopbacks[] = {
5801 { 0x07, HDA_INPUT, 0 },
5802 { 0x07, HDA_INPUT, 1 },
5803 { 0x07, HDA_INPUT, 2 },
5804 { 0x07, HDA_INPUT, 3 },
5805 { 0x07, HDA_INPUT, 4 },
5806 { } /* end */
5807};
5808#endif
5809
Kailang Yangdf694da2005-12-05 19:42:22 +01005810/*
5811 * ALC260 configurations
5812 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005813static const char *alc260_models[ALC260_MODEL_LAST] = {
5814 [ALC260_BASIC] = "basic",
5815 [ALC260_HP] = "hp",
5816 [ALC260_HP_3013] = "hp-3013",
Takashi Iwai2922c9a2008-08-27 18:12:42 +02005817 [ALC260_HP_DC7600] = "hp-dc7600",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005818 [ALC260_FUJITSU_S702X] = "fujitsu",
5819 [ALC260_ACER] = "acer",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005820 [ALC260_WILL] = "will",
5821 [ALC260_REPLACER_672V] = "replacer",
Michael Schwingencc959482009-02-22 18:58:45 +01005822 [ALC260_FAVORIT100] = "favorit100",
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005823#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005824 [ALC260_TEST] = "test",
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005825#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005826 [ALC260_AUTO] = "auto",
5827};
5828
5829static struct snd_pci_quirk alc260_cfg_tbl[] = {
Jonathan Woithebd869482006-11-28 11:35:52 +01005830 SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005831 SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER),
Michael Schwingencc959482009-02-22 18:58:45 +01005832 SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FAVORIT100),
Takashi Iwai9720b712007-03-13 21:46:23 +01005833 SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013),
Takashi Iwaia8a5d062007-03-15 15:10:28 +01005834 SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_HP_3013),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005835 SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013),
Jaroslav Kysela34ec8a02008-07-10 14:49:19 +02005836 SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP_3013),
Kailang Yang3f878302008-08-26 13:02:23 +02005837 SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_DC7600),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005838 SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013),
5839 SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP),
5840 SND_PCI_QUIRK(0x103c, 0x3015, "HP", ALC260_HP),
5841 SND_PCI_QUIRK(0x103c, 0x3016, "HP", ALC260_HP),
5842 SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_BASIC),
5843 SND_PCI_QUIRK(0x104d, 0x81cc, "Sony VAIO", ALC260_BASIC),
5844 SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC),
5845 SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X),
5846 SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005847 SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_REPLACER_672V),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01005848 SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_WILL),
Takashi Iwai16ded522005-06-10 19:58:24 +02005849 {}
5850};
5851
Kailang Yangdf694da2005-12-05 19:42:22 +01005852static struct alc_config_preset alc260_presets[] = {
5853 [ALC260_BASIC] = {
5854 .mixers = { alc260_base_output_mixer,
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01005855 alc260_input_mixer },
Kailang Yangdf694da2005-12-05 19:42:22 +01005856 .init_verbs = { alc260_init_verbs },
5857 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5858 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005859 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
Kailang Yangdf694da2005-12-05 19:42:22 +01005860 .adc_nids = alc260_adc_nids,
5861 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5862 .channel_mode = alc260_modes,
5863 .input_mux = &alc260_capture_source,
5864 },
5865 [ALC260_HP] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01005866 .mixers = { alc260_hp_output_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005867 alc260_input_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01005868 .init_verbs = { alc260_init_verbs,
5869 alc260_hp_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01005870 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5871 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005872 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
5873 .adc_nids = alc260_adc_nids_alt,
Kailang Yangdf694da2005-12-05 19:42:22 +01005874 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5875 .channel_mode = alc260_modes,
5876 .input_mux = &alc260_capture_source,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005877 .unsol_event = alc260_hp_unsol_event,
5878 .init_hook = alc260_hp_automute,
Kailang Yangdf694da2005-12-05 19:42:22 +01005879 },
Kailang Yang3f878302008-08-26 13:02:23 +02005880 [ALC260_HP_DC7600] = {
5881 .mixers = { alc260_hp_dc7600_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005882 alc260_input_mixer },
Kailang Yang3f878302008-08-26 13:02:23 +02005883 .init_verbs = { alc260_init_verbs,
5884 alc260_hp_dc7600_verbs },
5885 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5886 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005887 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
5888 .adc_nids = alc260_adc_nids_alt,
Kailang Yang3f878302008-08-26 13:02:23 +02005889 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5890 .channel_mode = alc260_modes,
5891 .input_mux = &alc260_capture_source,
5892 .unsol_event = alc260_hp_3012_unsol_event,
5893 .init_hook = alc260_hp_3012_automute,
5894 },
Kailang Yangdf694da2005-12-05 19:42:22 +01005895 [ALC260_HP_3013] = {
5896 .mixers = { alc260_hp_3013_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005897 alc260_input_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01005898 .init_verbs = { alc260_hp_3013_init_verbs,
5899 alc260_hp_3013_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01005900 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5901 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005902 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
5903 .adc_nids = alc260_adc_nids_alt,
Kailang Yangdf694da2005-12-05 19:42:22 +01005904 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5905 .channel_mode = alc260_modes,
5906 .input_mux = &alc260_capture_source,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005907 .unsol_event = alc260_hp_3013_unsol_event,
5908 .init_hook = alc260_hp_3013_automute,
Kailang Yangdf694da2005-12-05 19:42:22 +01005909 },
5910 [ALC260_FUJITSU_S702X] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005911 .mixers = { alc260_fujitsu_mixer },
Kailang Yangdf694da2005-12-05 19:42:22 +01005912 .init_verbs = { alc260_fujitsu_init_verbs },
5913 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5914 .dac_nids = alc260_dac_nids,
Jonathan Woithed57fdac2006-02-28 11:38:35 +01005915 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
5916 .adc_nids = alc260_dual_adc_nids,
Kailang Yangdf694da2005-12-05 19:42:22 +01005917 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5918 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005919 .num_mux_defs = ARRAY_SIZE(alc260_fujitsu_capture_sources),
5920 .input_mux = alc260_fujitsu_capture_sources,
Kailang Yangdf694da2005-12-05 19:42:22 +01005921 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005922 [ALC260_ACER] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005923 .mixers = { alc260_acer_mixer },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005924 .init_verbs = { alc260_acer_init_verbs },
5925 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5926 .dac_nids = alc260_dac_nids,
5927 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
5928 .adc_nids = alc260_dual_adc_nids,
5929 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5930 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005931 .num_mux_defs = ARRAY_SIZE(alc260_acer_capture_sources),
5932 .input_mux = alc260_acer_capture_sources,
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005933 },
Michael Schwingencc959482009-02-22 18:58:45 +01005934 [ALC260_FAVORIT100] = {
5935 .mixers = { alc260_favorit100_mixer },
5936 .init_verbs = { alc260_favorit100_init_verbs },
5937 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5938 .dac_nids = alc260_dac_nids,
5939 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
5940 .adc_nids = alc260_dual_adc_nids,
5941 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5942 .channel_mode = alc260_modes,
5943 .num_mux_defs = ARRAY_SIZE(alc260_favorit100_capture_sources),
5944 .input_mux = alc260_favorit100_capture_sources,
5945 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005946 [ALC260_WILL] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005947 .mixers = { alc260_will_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005948 .init_verbs = { alc260_init_verbs, alc260_will_verbs },
5949 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5950 .dac_nids = alc260_dac_nids,
5951 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
5952 .adc_nids = alc260_adc_nids,
5953 .dig_out_nid = ALC260_DIGOUT_NID,
5954 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5955 .channel_mode = alc260_modes,
5956 .input_mux = &alc260_capture_source,
5957 },
5958 [ALC260_REPLACER_672V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005959 .mixers = { alc260_replacer_672v_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005960 .init_verbs = { alc260_init_verbs, alc260_replacer_672v_verbs },
5961 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5962 .dac_nids = alc260_dac_nids,
5963 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
5964 .adc_nids = alc260_adc_nids,
5965 .dig_out_nid = ALC260_DIGOUT_NID,
5966 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5967 .channel_mode = alc260_modes,
5968 .input_mux = &alc260_capture_source,
5969 .unsol_event = alc260_replacer_672v_unsol_event,
5970 .init_hook = alc260_replacer_672v_automute,
5971 },
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005972#ifdef CONFIG_SND_DEBUG
5973 [ALC260_TEST] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005974 .mixers = { alc260_test_mixer },
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005975 .init_verbs = { alc260_test_init_verbs },
5976 .num_dacs = ARRAY_SIZE(alc260_test_dac_nids),
5977 .dac_nids = alc260_test_dac_nids,
5978 .num_adc_nids = ARRAY_SIZE(alc260_test_adc_nids),
5979 .adc_nids = alc260_test_adc_nids,
5980 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5981 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005982 .num_mux_defs = ARRAY_SIZE(alc260_test_capture_sources),
5983 .input_mux = alc260_test_capture_sources,
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005984 },
5985#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01005986};
5987
Linus Torvalds1da177e2005-04-16 15:20:36 -07005988static int patch_alc260(struct hda_codec *codec)
5989{
5990 struct alc_spec *spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01005991 int err, board_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005992
Takashi Iwaie560d8d2005-09-09 14:21:46 +02005993 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005994 if (spec == NULL)
5995 return -ENOMEM;
5996
5997 codec->spec = spec;
5998
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005999 board_config = snd_hda_check_board_config(codec, ALC260_MODEL_LAST,
6000 alc260_models,
6001 alc260_cfg_tbl);
6002 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006003 snd_printd(KERN_INFO "hda_codec: Unknown model for ALC260, "
6004 "trying auto-probe from BIOS...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01006005 board_config = ALC260_AUTO;
Takashi Iwai16ded522005-06-10 19:58:24 +02006006 }
6007
Kailang Yangdf694da2005-12-05 19:42:22 +01006008 if (board_config == ALC260_AUTO) {
6009 /* automatic parse from the BIOS config */
6010 err = alc260_parse_auto_config(codec);
6011 if (err < 0) {
6012 alc_free(codec);
6013 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006014 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006015 printk(KERN_INFO
6016 "hda_codec: Cannot set up configuration "
6017 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01006018 board_config = ALC260_BASIC;
6019 }
Takashi Iwai16ded522005-06-10 19:58:24 +02006020 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006021
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09006022 err = snd_hda_attach_beep_device(codec, 0x1);
6023 if (err < 0) {
6024 alc_free(codec);
6025 return err;
6026 }
6027
Kailang Yangdf694da2005-12-05 19:42:22 +01006028 if (board_config != ALC260_AUTO)
6029 setup_preset(spec, &alc260_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006030
6031 spec->stream_name_analog = "ALC260 Analog";
6032 spec->stream_analog_playback = &alc260_pcm_analog_playback;
6033 spec->stream_analog_capture = &alc260_pcm_analog_capture;
6034
Takashi Iwaia3bcba32005-12-06 19:05:29 +01006035 spec->stream_name_digital = "ALC260 Digital";
6036 spec->stream_digital_playback = &alc260_pcm_digital_playback;
6037 spec->stream_digital_capture = &alc260_pcm_digital_capture;
6038
Takashi Iwai4ef0ef12008-11-03 17:47:49 +01006039 if (!spec->adc_nids && spec->input_mux) {
6040 /* check whether NID 0x04 is valid */
6041 unsigned int wcap = get_wcaps(codec, 0x04);
6042 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
6043 /* get type */
6044 if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
6045 spec->adc_nids = alc260_adc_nids_alt;
6046 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt);
6047 } else {
6048 spec->adc_nids = alc260_adc_nids;
6049 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids);
6050 }
6051 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006052 set_capture_mixer(spec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01006053 set_beep_amp(spec, 0x07, 0x05, HDA_INPUT);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006054
Takashi Iwai2134ea42008-01-10 16:53:55 +01006055 spec->vmaster_nid = 0x08;
6056
Linus Torvalds1da177e2005-04-16 15:20:36 -07006057 codec->patch_ops = alc_patch_ops;
Kailang Yangdf694da2005-12-05 19:42:22 +01006058 if (board_config == ALC260_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01006059 spec->init_hook = alc260_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02006060#ifdef CONFIG_SND_HDA_POWER_SAVE
6061 if (!spec->loopback.amplist)
6062 spec->loopback.amplist = alc260_loopbacks;
6063#endif
Takashi Iwaidaead532008-11-28 12:55:36 +01006064 codec->proc_widget_hook = print_realtek_coef;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006065
6066 return 0;
6067}
6068
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006069
Linus Torvalds1da177e2005-04-16 15:20:36 -07006070/*
6071 * ALC882 support
6072 *
6073 * ALC882 is almost identical with ALC880 but has cleaner and more flexible
6074 * configuration. Each pin widget can choose any input DACs and a mixer.
6075 * Each ADC is connected from a mixer of all inputs. This makes possible
6076 * 6-channel independent captures.
6077 *
6078 * In addition, an independent DAC for the multi-playback (not used in this
6079 * driver yet).
6080 */
Kailang Yangdf694da2005-12-05 19:42:22 +01006081#define ALC882_DIGOUT_NID 0x06
6082#define ALC882_DIGIN_NID 0x0a
Linus Torvalds1da177e2005-04-16 15:20:36 -07006083
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01006084static struct hda_channel_mode alc882_ch_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006085 { 8, NULL }
6086};
6087
6088static hda_nid_t alc882_dac_nids[4] = {
6089 /* front, rear, clfe, rear_surr */
6090 0x02, 0x03, 0x04, 0x05
6091};
6092
Kailang Yangdf694da2005-12-05 19:42:22 +01006093/* identical with ALC880 */
6094#define alc882_adc_nids alc880_adc_nids
6095#define alc882_adc_nids_alt alc880_adc_nids_alt
Linus Torvalds1da177e2005-04-16 15:20:36 -07006096
Takashi Iwaie1406342008-02-11 18:32:32 +01006097static hda_nid_t alc882_capsrc_nids[3] = { 0x24, 0x23, 0x22 };
6098static hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 };
6099
Linus Torvalds1da177e2005-04-16 15:20:36 -07006100/* input MUX */
6101/* FIXME: should be a matrix-type input source selection */
6102
6103static struct hda_input_mux alc882_capture_source = {
6104 .num_items = 4,
6105 .items = {
6106 { "Mic", 0x0 },
6107 { "Front Mic", 0x1 },
6108 { "Line", 0x2 },
6109 { "CD", 0x4 },
6110 },
6111};
Kailang Yangdf694da2005-12-05 19:42:22 +01006112/*
Kailang Yang272a5272007-05-14 11:00:38 +02006113 * 2ch mode
6114 */
6115static struct hda_verb alc882_3ST_ch2_init[] = {
6116 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
6117 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6118 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
6119 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6120 { } /* end */
6121};
6122
6123/*
6124 * 6ch mode
6125 */
6126static struct hda_verb alc882_3ST_ch6_init[] = {
6127 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6128 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6129 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
6130 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6131 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6132 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6133 { } /* end */
6134};
6135
6136static struct hda_channel_mode alc882_3ST_6ch_modes[2] = {
6137 { 2, alc882_3ST_ch2_init },
6138 { 6, alc882_3ST_ch6_init },
6139};
6140
6141/*
Kailang Yangdf694da2005-12-05 19:42:22 +01006142 * 6ch mode
6143 */
6144static struct hda_verb alc882_sixstack_ch6_init[] = {
6145 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
6146 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6147 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6148 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6149 { } /* end */
6150};
6151
6152/*
6153 * 8ch mode
6154 */
6155static struct hda_verb alc882_sixstack_ch8_init[] = {
6156 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6157 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6158 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6159 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6160 { } /* end */
6161};
6162
6163static struct hda_channel_mode alc882_sixstack_modes[2] = {
6164 { 6, alc882_sixstack_ch6_init },
6165 { 8, alc882_sixstack_ch8_init },
6166};
6167
Takashi Iwai87350ad2007-08-16 18:19:38 +02006168/*
6169 * macbook pro ALC885 can switch LineIn to LineOut without loosing Mic
6170 */
6171
6172/*
6173 * 2ch mode
6174 */
6175static struct hda_verb alc885_mbp_ch2_init[] = {
6176 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
6177 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6178 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6179 { } /* end */
6180};
6181
6182/*
6183 * 6ch mode
6184 */
6185static struct hda_verb alc885_mbp_ch6_init[] = {
6186 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6187 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6188 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6189 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6190 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6191 { } /* end */
6192};
6193
6194static struct hda_channel_mode alc885_mbp_6ch_modes[2] = {
6195 { 2, alc885_mbp_ch2_init },
6196 { 6, alc885_mbp_ch6_init },
6197};
6198
6199
Linus Torvalds1da177e2005-04-16 15:20:36 -07006200/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
6201 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
6202 */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01006203static struct snd_kcontrol_new alc882_base_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02006204 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01006205 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02006206 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01006207 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02006208 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
6209 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01006210 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
6211 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02006212 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01006213 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07006214 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6215 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6216 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6217 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6218 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6219 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006220 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07006221 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6222 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006223 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07006224 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07006225 { } /* end */
6226};
6227
Takashi Iwai87350ad2007-08-16 18:19:38 +02006228static struct snd_kcontrol_new alc885_mbp3_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01006229 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
6230 HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
6231 HDA_CODEC_MUTE ("Speaker Playback Switch", 0x14, 0x00, HDA_OUTPUT),
6232 HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
6233 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6234 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02006235 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
6236 HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01006237 HDA_CODEC_VOLUME("Line Boost", 0x1a, 0x00, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02006238 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT),
6239 { } /* end */
6240};
Kailang Yangbdd148a2007-05-08 15:19:08 +02006241static struct snd_kcontrol_new alc882_w2jc_mixer[] = {
6242 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6243 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6244 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6245 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6246 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6247 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6248 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6249 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
6250 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangbdd148a2007-05-08 15:19:08 +02006251 { } /* end */
6252};
6253
Kailang Yang272a5272007-05-14 11:00:38 +02006254static struct snd_kcontrol_new alc882_targa_mixer[] = {
6255 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6256 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6257 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6258 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6259 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6260 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6261 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6262 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6263 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai96fe7cc82007-09-07 10:57:44 +02006264 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02006265 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
6266 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai96fe7cc82007-09-07 10:57:44 +02006267 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02006268 { } /* end */
6269};
6270
6271/* Pin assignment: Front=0x14, HP = 0x15, Front = 0x16, ???
6272 * Front Mic=0x18, Line In = 0x1a, Line In = 0x1b, CD = 0x1c
6273 */
6274static struct snd_kcontrol_new alc882_asus_a7j_mixer[] = {
6275 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6276 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
6277 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
6278 HDA_CODEC_MUTE("Mobile Front Playback Switch", 0x16, 0x0, HDA_OUTPUT),
6279 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6280 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6281 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6282 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6283 HDA_CODEC_VOLUME("Mobile Line Playback Volume", 0x0b, 0x03, HDA_INPUT),
6284 HDA_CODEC_MUTE("Mobile Line Playback Switch", 0x0b, 0x03, HDA_INPUT),
6285 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6286 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai96fe7cc82007-09-07 10:57:44 +02006287 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02006288 { } /* end */
6289};
6290
Takashi Iwai914759b2007-09-06 14:52:04 +02006291static struct snd_kcontrol_new alc882_asus_a7m_mixer[] = {
6292 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6293 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6294 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
6295 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6296 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6297 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6298 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6299 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
6300 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
6301 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai914759b2007-09-06 14:52:04 +02006302 { } /* end */
6303};
6304
Kailang Yangdf694da2005-12-05 19:42:22 +01006305static struct snd_kcontrol_new alc882_chmode_mixer[] = {
6306 {
6307 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6308 .name = "Channel Mode",
6309 .info = alc_ch_mode_info,
6310 .get = alc_ch_mode_get,
6311 .put = alc_ch_mode_put,
6312 },
6313 { } /* end */
6314};
6315
Linus Torvalds1da177e2005-04-16 15:20:36 -07006316static struct hda_verb alc882_init_verbs[] = {
6317 /* Front mixer: unmute input/output amp left and right (volume = 0) */
Takashi Iwai05acb862005-06-10 19:50:25 +02006318 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6319 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6320 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006321 /* Rear mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02006322 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6323 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6324 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006325 /* CLFE mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02006326 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6327 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6328 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006329 /* Side mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02006330 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6331 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6332 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006333
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006334 /* Front Pin: output 0 (0x0c) */
Takashi Iwai05acb862005-06-10 19:50:25 +02006335 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02006336 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006337 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006338 /* Rear Pin: output 1 (0x0d) */
Takashi Iwai05acb862005-06-10 19:50:25 +02006339 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02006340 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006341 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006342 /* CLFE Pin: output 2 (0x0e) */
Takashi Iwai05acb862005-06-10 19:50:25 +02006343 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02006344 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006345 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006346 /* Side Pin: output 3 (0x0f) */
Takashi Iwai05acb862005-06-10 19:50:25 +02006347 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02006348 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006349 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006350 /* Mic (rear) pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02006351 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006352 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6353 /* Front Mic pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02006354 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006355 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6356 /* Line In pin: input */
Takashi Iwai05acb862005-06-10 19:50:25 +02006357 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006358 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6359 /* Line-2 In: Headphone output (output 0 - 0x0c) */
6360 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6361 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6362 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006363 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02006364 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006365
6366 /* FIXME: use matrix-type input source selection */
6367 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
6368 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
Takashi Iwai05acb862005-06-10 19:50:25 +02006369 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6370 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6371 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6372 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006373 /* Input mixer2 */
Takashi Iwai05acb862005-06-10 19:50:25 +02006374 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6375 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6376 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6377 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006378 /* Input mixer3 */
Takashi Iwai05acb862005-06-10 19:50:25 +02006379 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6380 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6381 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6382 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6383 /* ADC1: mute amp left and right */
6384 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02006385 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02006386 /* ADC2: mute amp left and right */
6387 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02006388 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02006389 /* ADC3: mute amp left and right */
6390 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02006391 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006392
6393 { }
6394};
6395
Takashi Iwai4b146cb2006-07-28 14:42:36 +02006396static struct hda_verb alc882_eapd_verbs[] = {
6397 /* change to EAPD mode */
6398 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01006399 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006400 { }
Takashi Iwai4b146cb2006-07-28 14:42:36 +02006401};
6402
Tobin Davis9102cd12006-12-15 10:02:12 +01006403/* Mac Pro test */
6404static struct snd_kcontrol_new alc882_macpro_mixer[] = {
6405 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6406 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6407 HDA_CODEC_MUTE("Headphone Playback Switch", 0x18, 0x0, HDA_OUTPUT),
6408 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
6409 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01006410 /* FIXME: this looks suspicious...
Tobin Davis9102cd12006-12-15 10:02:12 +01006411 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x02, HDA_INPUT),
6412 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01006413 */
Tobin Davis9102cd12006-12-15 10:02:12 +01006414 { } /* end */
6415};
6416
6417static struct hda_verb alc882_macpro_init_verbs[] = {
6418 /* Front mixer: unmute input/output amp left and right (volume = 0) */
6419 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6420 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6421 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6422 /* Front Pin: output 0 (0x0c) */
6423 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6424 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6425 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
6426 /* Front Mic pin: input vref at 80% */
6427 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
6428 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6429 /* Speaker: output */
6430 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6431 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6432 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x04},
6433 /* Headphone output (output 0 - 0x0c) */
6434 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6435 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6436 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
6437
6438 /* FIXME: use matrix-type input source selection */
6439 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
6440 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
6441 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6442 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6443 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6444 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6445 /* Input mixer2 */
6446 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6447 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6448 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6449 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6450 /* Input mixer3 */
6451 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6452 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6453 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6454 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6455 /* ADC1: mute amp left and right */
6456 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6457 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
6458 /* ADC2: mute amp left and right */
6459 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6460 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
6461 /* ADC3: mute amp left and right */
6462 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6463 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
6464
6465 { }
6466};
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006467
Takashi Iwai87350ad2007-08-16 18:19:38 +02006468/* Macbook Pro rev3 */
6469static struct hda_verb alc885_mbp3_init_verbs[] = {
6470 /* Front mixer: unmute input/output amp left and right (volume = 0) */
6471 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6472 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6473 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6474 /* Rear mixer */
6475 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6476 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6477 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6478 /* Front Pin: output 0 (0x0c) */
6479 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6480 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6481 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
6482 /* HP Pin: output 0 (0x0d) */
6483 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
6484 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6485 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
6486 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
6487 /* Mic (rear) pin: input vref at 80% */
6488 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
6489 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6490 /* Front Mic pin: input vref at 80% */
6491 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
6492 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6493 /* Line In pin: use output 1 when in LineOut mode */
6494 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
6495 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6496 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
6497
6498 /* FIXME: use matrix-type input source selection */
6499 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
6500 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
6501 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6502 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6503 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6504 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6505 /* Input mixer2 */
6506 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6507 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6508 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6509 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6510 /* Input mixer3 */
6511 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6512 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6513 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6514 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6515 /* ADC1: mute amp left and right */
6516 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6517 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
6518 /* ADC2: mute amp left and right */
6519 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6520 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
6521 /* ADC3: mute amp left and right */
6522 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6523 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
6524
6525 { }
6526};
6527
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006528/* iMac 24 mixer. */
6529static struct snd_kcontrol_new alc885_imac24_mixer[] = {
6530 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
6531 HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x00, HDA_INPUT),
6532 { } /* end */
6533};
6534
6535/* iMac 24 init verbs. */
6536static struct hda_verb alc885_imac24_init_verbs[] = {
6537 /* Internal speakers: output 0 (0x0c) */
6538 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6539 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6540 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
6541 /* Internal speakers: output 0 (0x0c) */
6542 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6543 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6544 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
6545 /* Headphone: output 0 (0x0c) */
6546 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6547 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6548 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
6549 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
6550 /* Front Mic: input vref at 80% */
6551 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
6552 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6553 { }
6554};
6555
6556/* Toggle speaker-output according to the hp-jack state */
6557static void alc885_imac24_automute(struct hda_codec *codec)
6558{
6559 unsigned int present;
6560
6561 present = snd_hda_codec_read(codec, 0x14, 0,
6562 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02006563 snd_hda_codec_amp_stereo(codec, 0x18, HDA_OUTPUT, 0,
6564 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
6565 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0,
6566 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006567}
6568
6569/* Processes unsolicited events. */
6570static void alc885_imac24_unsol_event(struct hda_codec *codec,
6571 unsigned int res)
6572{
6573 /* Headphone insertion or removal. */
6574 if ((res >> 26) == ALC880_HP_EVENT)
6575 alc885_imac24_automute(codec);
6576}
6577
Takashi Iwai87350ad2007-08-16 18:19:38 +02006578static void alc885_mbp3_automute(struct hda_codec *codec)
6579{
6580 unsigned int present;
6581
6582 present = snd_hda_codec_read(codec, 0x15, 0,
6583 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
6584 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
6585 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
6586 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
6587 HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE);
6588
6589}
6590static void alc885_mbp3_unsol_event(struct hda_codec *codec,
6591 unsigned int res)
6592{
6593 /* Headphone insertion or removal. */
6594 if ((res >> 26) == ALC880_HP_EVENT)
6595 alc885_mbp3_automute(codec);
6596}
6597
6598
Kailang Yang272a5272007-05-14 11:00:38 +02006599static struct hda_verb alc882_targa_verbs[] = {
6600 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6601 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6602
6603 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6604 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02006605
Kailang Yang272a5272007-05-14 11:00:38 +02006606 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
6607 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
6608 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
6609
6610 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
6611 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
6612 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
6613 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
6614 { } /* end */
6615};
6616
6617/* toggle speaker-output according to the hp-jack state */
6618static void alc882_targa_automute(struct hda_codec *codec)
6619{
6620 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02006621
Kailang Yang272a5272007-05-14 11:00:38 +02006622 present = snd_hda_codec_read(codec, 0x14, 0,
6623 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02006624 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
6625 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02006626 snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
6627 present ? 1 : 3);
Kailang Yang272a5272007-05-14 11:00:38 +02006628}
6629
6630static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res)
6631{
6632 /* Looks like the unsol event is incompatible with the standard
6633 * definition. 4bit tag is placed at 26 bit!
6634 */
6635 if (((res >> 26) == ALC880_HP_EVENT)) {
6636 alc882_targa_automute(codec);
6637 }
6638}
6639
6640static struct hda_verb alc882_asus_a7j_verbs[] = {
6641 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6642 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6643
6644 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6645 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6646 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02006647
Kailang Yang272a5272007-05-14 11:00:38 +02006648 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
6649 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
6650 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
6651
6652 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
6653 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
6654 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
6655 { } /* end */
6656};
6657
Takashi Iwai914759b2007-09-06 14:52:04 +02006658static struct hda_verb alc882_asus_a7m_verbs[] = {
6659 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6660 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6661
6662 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6663 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6664 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02006665
Takashi Iwai914759b2007-09-06 14:52:04 +02006666 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
6667 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
6668 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
6669
6670 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
6671 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
6672 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
6673 { } /* end */
6674};
6675
Tobin Davis9102cd12006-12-15 10:02:12 +01006676static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted)
6677{
6678 unsigned int gpiostate, gpiomask, gpiodir;
6679
6680 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
6681 AC_VERB_GET_GPIO_DATA, 0);
6682
6683 if (!muted)
6684 gpiostate |= (1 << pin);
6685 else
6686 gpiostate &= ~(1 << pin);
6687
6688 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
6689 AC_VERB_GET_GPIO_MASK, 0);
6690 gpiomask |= (1 << pin);
6691
6692 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
6693 AC_VERB_GET_GPIO_DIRECTION, 0);
6694 gpiodir |= (1 << pin);
6695
6696
6697 snd_hda_codec_write(codec, codec->afg, 0,
6698 AC_VERB_SET_GPIO_MASK, gpiomask);
6699 snd_hda_codec_write(codec, codec->afg, 0,
6700 AC_VERB_SET_GPIO_DIRECTION, gpiodir);
6701
6702 msleep(1);
6703
6704 snd_hda_codec_write(codec, codec->afg, 0,
6705 AC_VERB_SET_GPIO_DATA, gpiostate);
6706}
6707
Takashi Iwai7debbe52007-08-16 15:01:03 +02006708/* set up GPIO at initialization */
6709static void alc885_macpro_init_hook(struct hda_codec *codec)
6710{
6711 alc882_gpio_mute(codec, 0, 0);
6712 alc882_gpio_mute(codec, 1, 0);
6713}
6714
6715/* set up GPIO and update auto-muting at initialization */
6716static void alc885_imac24_init_hook(struct hda_codec *codec)
6717{
6718 alc885_macpro_init_hook(codec);
6719 alc885_imac24_automute(codec);
6720}
6721
Kailang Yangdf694da2005-12-05 19:42:22 +01006722/*
6723 * generic initialization of ADC, input mixers and output mixers
6724 */
6725static struct hda_verb alc882_auto_init_verbs[] = {
6726 /*
6727 * Unmute ADC0-2 and set the default input to mic-in
6728 */
6729 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
6730 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6731 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
6732 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6733 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
6734 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6735
Takashi Iwaicb53c622007-08-10 17:21:45 +02006736 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +01006737 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006738 * Note: PASD motherboards uses the Line In 2 as the input for
6739 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01006740 */
6741 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02006742 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6743 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6744 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6745 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6746 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01006747
6748 /*
6749 * Set up output mixers (0x0c - 0x0f)
6750 */
6751 /* set vol=0 to output mixers */
6752 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6753 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6754 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6755 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6756 /* set up input amps for analog loopback */
6757 /* Amp Indices: DAC = 0, mixer = 1 */
6758 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6759 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6760 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6761 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6762 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6763 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6764 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6765 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6766 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6767 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6768
6769 /* FIXME: use matrix-type input source selection */
6770 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
6771 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
6772 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6773 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
6774 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
6775 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
6776 /* Input mixer2 */
6777 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6778 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
6779 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
6780 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
6781 /* Input mixer3 */
6782 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6783 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
6784 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
6785 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
6786
6787 { }
6788};
6789
Takashi Iwaicb53c622007-08-10 17:21:45 +02006790#ifdef CONFIG_SND_HDA_POWER_SAVE
6791#define alc882_loopbacks alc880_loopbacks
6792#endif
6793
Kailang Yangdf694da2005-12-05 19:42:22 +01006794/* pcm configuration: identiacal with ALC880 */
6795#define alc882_pcm_analog_playback alc880_pcm_analog_playback
6796#define alc882_pcm_analog_capture alc880_pcm_analog_capture
6797#define alc882_pcm_digital_playback alc880_pcm_digital_playback
6798#define alc882_pcm_digital_capture alc880_pcm_digital_capture
6799
6800/*
6801 * configuration and preset
6802 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006803static const char *alc882_models[ALC882_MODEL_LAST] = {
6804 [ALC882_3ST_DIG] = "3stack-dig",
6805 [ALC882_6ST_DIG] = "6stack-dig",
6806 [ALC882_ARIMA] = "arima",
Kailang Yangbdd148a2007-05-08 15:19:08 +02006807 [ALC882_W2JC] = "w2jc",
Takashi Iwai0438a002007-09-06 14:54:11 +02006808 [ALC882_TARGA] = "targa",
6809 [ALC882_ASUS_A7J] = "asus-a7j",
6810 [ALC882_ASUS_A7M] = "asus-a7m",
Tobin Davis9102cd12006-12-15 10:02:12 +01006811 [ALC885_MACPRO] = "macpro",
Takashi Iwai87350ad2007-08-16 18:19:38 +02006812 [ALC885_MBP3] = "mbp3",
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006813 [ALC885_IMAC24] = "imac24",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006814 [ALC882_AUTO] = "auto",
6815};
6816
6817static struct snd_pci_quirk alc882_cfg_tbl[] = {
6818 SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG),
Kailang Yang272a5272007-05-14 11:00:38 +02006819 SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J),
Kailang Yangac8842a2007-09-20 12:51:39 +02006820 SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J),
Takashi Iwai914759b2007-09-06 14:52:04 +02006821 SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01006822 SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC),
Claudio Matsuokac5d9f1c2007-07-19 23:18:32 +02006823 SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG),
Tobin Davis7b9470d2006-12-28 13:56:48 +01006824 SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01006825 SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG),
Jiang zhe44447042008-01-28 12:28:24 +01006826 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01006827 SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */
6828 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG),
6829 SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA),
Kailang Yangdf694da2005-12-05 19:42:22 +01006830 {}
6831};
6832
6833static struct alc_config_preset alc882_presets[] = {
6834 [ALC882_3ST_DIG] = {
6835 .mixers = { alc882_base_mixer },
6836 .init_verbs = { alc882_init_verbs },
6837 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6838 .dac_nids = alc882_dac_nids,
6839 .dig_out_nid = ALC882_DIGOUT_NID,
Kailang Yangdf694da2005-12-05 19:42:22 +01006840 .dig_in_nid = ALC882_DIGIN_NID,
6841 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
6842 .channel_mode = alc882_ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02006843 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01006844 .input_mux = &alc882_capture_source,
6845 },
6846 [ALC882_6ST_DIG] = {
6847 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
6848 .init_verbs = { alc882_init_verbs },
6849 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6850 .dac_nids = alc882_dac_nids,
6851 .dig_out_nid = ALC882_DIGOUT_NID,
Kailang Yangdf694da2005-12-05 19:42:22 +01006852 .dig_in_nid = ALC882_DIGIN_NID,
6853 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
6854 .channel_mode = alc882_sixstack_modes,
6855 .input_mux = &alc882_capture_source,
6856 },
Takashi Iwai4b146cb2006-07-28 14:42:36 +02006857 [ALC882_ARIMA] = {
6858 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
6859 .init_verbs = { alc882_init_verbs, alc882_eapd_verbs },
6860 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6861 .dac_nids = alc882_dac_nids,
6862 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
6863 .channel_mode = alc882_sixstack_modes,
6864 .input_mux = &alc882_capture_source,
6865 },
Kailang Yangbdd148a2007-05-08 15:19:08 +02006866 [ALC882_W2JC] = {
6867 .mixers = { alc882_w2jc_mixer, alc882_chmode_mixer },
6868 .init_verbs = { alc882_init_verbs, alc882_eapd_verbs,
6869 alc880_gpio1_init_verbs },
6870 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6871 .dac_nids = alc882_dac_nids,
6872 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
6873 .channel_mode = alc880_threestack_modes,
6874 .need_dac_fix = 1,
6875 .input_mux = &alc882_capture_source,
6876 .dig_out_nid = ALC882_DIGOUT_NID,
6877 },
Takashi Iwai87350ad2007-08-16 18:19:38 +02006878 [ALC885_MBP3] = {
6879 .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer },
6880 .init_verbs = { alc885_mbp3_init_verbs,
6881 alc880_gpio1_init_verbs },
6882 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6883 .dac_nids = alc882_dac_nids,
6884 .channel_mode = alc885_mbp_6ch_modes,
6885 .num_channel_mode = ARRAY_SIZE(alc885_mbp_6ch_modes),
6886 .input_mux = &alc882_capture_source,
6887 .dig_out_nid = ALC882_DIGOUT_NID,
6888 .dig_in_nid = ALC882_DIGIN_NID,
6889 .unsol_event = alc885_mbp3_unsol_event,
6890 .init_hook = alc885_mbp3_automute,
6891 },
Tobin Davis9102cd12006-12-15 10:02:12 +01006892 [ALC885_MACPRO] = {
6893 .mixers = { alc882_macpro_mixer },
6894 .init_verbs = { alc882_macpro_init_verbs },
6895 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6896 .dac_nids = alc882_dac_nids,
6897 .dig_out_nid = ALC882_DIGOUT_NID,
6898 .dig_in_nid = ALC882_DIGIN_NID,
6899 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
6900 .channel_mode = alc882_ch_modes,
6901 .input_mux = &alc882_capture_source,
Takashi Iwai7debbe52007-08-16 15:01:03 +02006902 .init_hook = alc885_macpro_init_hook,
Tobin Davis9102cd12006-12-15 10:02:12 +01006903 },
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006904 [ALC885_IMAC24] = {
6905 .mixers = { alc885_imac24_mixer },
6906 .init_verbs = { alc885_imac24_init_verbs },
6907 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6908 .dac_nids = alc882_dac_nids,
6909 .dig_out_nid = ALC882_DIGOUT_NID,
6910 .dig_in_nid = ALC882_DIGIN_NID,
6911 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
6912 .channel_mode = alc882_ch_modes,
6913 .input_mux = &alc882_capture_source,
6914 .unsol_event = alc885_imac24_unsol_event,
Takashi Iwai7debbe52007-08-16 15:01:03 +02006915 .init_hook = alc885_imac24_init_hook,
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006916 },
Kailang Yang272a5272007-05-14 11:00:38 +02006917 [ALC882_TARGA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006918 .mixers = { alc882_targa_mixer, alc882_chmode_mixer },
Kailang Yang272a5272007-05-14 11:00:38 +02006919 .init_verbs = { alc882_init_verbs, alc882_targa_verbs},
6920 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6921 .dac_nids = alc882_dac_nids,
6922 .dig_out_nid = ALC882_DIGOUT_NID,
6923 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
6924 .adc_nids = alc882_adc_nids,
Takashi Iwaie1406342008-02-11 18:32:32 +01006925 .capsrc_nids = alc882_capsrc_nids,
Kailang Yang272a5272007-05-14 11:00:38 +02006926 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
6927 .channel_mode = alc882_3ST_6ch_modes,
6928 .need_dac_fix = 1,
6929 .input_mux = &alc882_capture_source,
6930 .unsol_event = alc882_targa_unsol_event,
6931 .init_hook = alc882_targa_automute,
6932 },
6933 [ALC882_ASUS_A7J] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006934 .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer },
Kailang Yang272a5272007-05-14 11:00:38 +02006935 .init_verbs = { alc882_init_verbs, alc882_asus_a7j_verbs},
6936 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6937 .dac_nids = alc882_dac_nids,
6938 .dig_out_nid = ALC882_DIGOUT_NID,
6939 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
6940 .adc_nids = alc882_adc_nids,
Takashi Iwaie1406342008-02-11 18:32:32 +01006941 .capsrc_nids = alc882_capsrc_nids,
Kailang Yang272a5272007-05-14 11:00:38 +02006942 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
6943 .channel_mode = alc882_3ST_6ch_modes,
6944 .need_dac_fix = 1,
6945 .input_mux = &alc882_capture_source,
Kailang Yangea1fb292008-08-26 12:58:38 +02006946 },
Takashi Iwai914759b2007-09-06 14:52:04 +02006947 [ALC882_ASUS_A7M] = {
6948 .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer },
6949 .init_verbs = { alc882_init_verbs, alc882_eapd_verbs,
6950 alc880_gpio1_init_verbs,
6951 alc882_asus_a7m_verbs },
6952 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6953 .dac_nids = alc882_dac_nids,
6954 .dig_out_nid = ALC882_DIGOUT_NID,
6955 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
6956 .channel_mode = alc880_threestack_modes,
6957 .need_dac_fix = 1,
6958 .input_mux = &alc882_capture_source,
Kailang Yangea1fb292008-08-26 12:58:38 +02006959 },
Kailang Yangdf694da2005-12-05 19:42:22 +01006960};
6961
6962
6963/*
Takashi Iwaif95474e2007-07-10 00:47:43 +02006964 * Pin config fixes
6965 */
Kailang Yangea1fb292008-08-26 12:58:38 +02006966enum {
Takashi Iwaif95474e2007-07-10 00:47:43 +02006967 PINFIX_ABIT_AW9D_MAX
6968};
6969
6970static struct alc_pincfg alc882_abit_aw9d_pinfix[] = {
6971 { 0x15, 0x01080104 }, /* side */
6972 { 0x16, 0x01011012 }, /* rear */
6973 { 0x17, 0x01016011 }, /* clfe */
6974 { }
6975};
6976
6977static const struct alc_pincfg *alc882_pin_fixes[] = {
6978 [PINFIX_ABIT_AW9D_MAX] = alc882_abit_aw9d_pinfix,
6979};
6980
6981static struct snd_pci_quirk alc882_pinfix_tbl[] = {
6982 SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
6983 {}
6984};
6985
6986/*
Kailang Yangdf694da2005-12-05 19:42:22 +01006987 * BIOS auto configuration
6988 */
6989static void alc882_auto_set_output_and_unmute(struct hda_codec *codec,
6990 hda_nid_t nid, int pin_type,
6991 int dac_idx)
6992{
6993 /* set as output */
6994 struct alc_spec *spec = codec->spec;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006995 int idx;
6996
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006997 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01006998 if (spec->multiout.dac_nids[dac_idx] == 0x25)
6999 idx = 4;
7000 else
7001 idx = spec->multiout.dac_nids[dac_idx] - 2;
Kailang Yangdf694da2005-12-05 19:42:22 +01007002 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
7003
7004}
7005
7006static void alc882_auto_init_multi_out(struct hda_codec *codec)
7007{
7008 struct alc_spec *spec = codec->spec;
7009 int i;
7010
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007011 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Kailang Yangdf694da2005-12-05 19:42:22 +01007012 for (i = 0; i <= HDA_SIDE; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007013 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02007014 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01007015 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02007016 alc882_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007017 i);
Kailang Yangdf694da2005-12-05 19:42:22 +01007018 }
7019}
7020
7021static void alc882_auto_init_hp_out(struct hda_codec *codec)
7022{
7023 struct alc_spec *spec = codec->spec;
7024 hda_nid_t pin;
7025
Takashi Iwaieb06ed82006-09-20 17:10:27 +02007026 pin = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01007027 if (pin) /* connect to front */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007028 /* use dac 0 */
7029 alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01007030 pin = spec->autocfg.speaker_pins[0];
7031 if (pin)
7032 alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Kailang Yangdf694da2005-12-05 19:42:22 +01007033}
7034
7035#define alc882_is_input_pin(nid) alc880_is_input_pin(nid)
7036#define ALC882_PIN_CD_NID ALC880_PIN_CD_NID
7037
7038static void alc882_auto_init_analog_input(struct hda_codec *codec)
7039{
7040 struct alc_spec *spec = codec->spec;
7041 int i;
7042
7043 for (i = 0; i < AUTO_PIN_LAST; i++) {
7044 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwai7194cae2008-03-06 16:58:17 +01007045 if (!nid)
7046 continue;
Takashi Iwai23f0c042009-02-26 13:03:58 +01007047 alc_set_input_pin(codec, nid, AUTO_PIN_FRONT_MIC /*i*/);
Takashi Iwai7194cae2008-03-06 16:58:17 +01007048 if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
7049 snd_hda_codec_write(codec, nid, 0,
7050 AC_VERB_SET_AMP_GAIN_MUTE,
7051 AMP_OUT_MUTE);
Kailang Yangdf694da2005-12-05 19:42:22 +01007052 }
7053}
7054
Takashi Iwaif511b012008-08-15 16:46:42 +02007055static void alc882_auto_init_input_src(struct hda_codec *codec)
7056{
7057 struct alc_spec *spec = codec->spec;
Takashi Iwaif511b012008-08-15 16:46:42 +02007058 int c;
7059
7060 for (c = 0; c < spec->num_adc_nids; c++) {
7061 hda_nid_t conn_list[HDA_MAX_NUM_INPUTS];
7062 hda_nid_t nid = spec->capsrc_nids[c];
Herton Ronaldo Krzesinskib98b7b32009-01-29 13:18:31 -02007063 unsigned int mux_idx;
7064 const struct hda_input_mux *imux;
Takashi Iwaif511b012008-08-15 16:46:42 +02007065 int conns, mute, idx, item;
7066
7067 conns = snd_hda_get_connections(codec, nid, conn_list,
7068 ARRAY_SIZE(conn_list));
7069 if (conns < 0)
7070 continue;
Herton Ronaldo Krzesinskib98b7b32009-01-29 13:18:31 -02007071 mux_idx = c >= spec->num_mux_defs ? 0 : c;
7072 imux = &spec->input_mux[mux_idx];
Takashi Iwaif511b012008-08-15 16:46:42 +02007073 for (idx = 0; idx < conns; idx++) {
7074 /* if the current connection is the selected one,
7075 * unmute it as default - otherwise mute it
7076 */
7077 mute = AMP_IN_MUTE(idx);
7078 for (item = 0; item < imux->num_items; item++) {
7079 if (imux->items[item].index == idx) {
7080 if (spec->cur_mux[c] == item)
7081 mute = AMP_IN_UNMUTE(idx);
7082 break;
7083 }
7084 }
Herton Ronaldo Krzesinskib98b7b32009-01-29 13:18:31 -02007085 /* check if we have a selector or mixer
7086 * we could check for the widget type instead, but
7087 * just check for Amp-In presence (in case of mixer
7088 * without amp-in there is something wrong, this
7089 * function shouldn't be used or capsrc nid is wrong)
7090 */
7091 if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)
7092 snd_hda_codec_write(codec, nid, 0,
7093 AC_VERB_SET_AMP_GAIN_MUTE,
7094 mute);
7095 else if (mute != AMP_IN_MUTE(idx))
7096 snd_hda_codec_write(codec, nid, 0,
7097 AC_VERB_SET_CONNECT_SEL,
7098 idx);
Takashi Iwaif511b012008-08-15 16:46:42 +02007099 }
7100 }
7101}
7102
Takashi Iwai776e1842007-08-29 15:07:11 +02007103/* add mic boosts if needed */
7104static int alc_auto_add_mic_boost(struct hda_codec *codec)
7105{
7106 struct alc_spec *spec = codec->spec;
7107 int err;
7108 hda_nid_t nid;
7109
7110 nid = spec->autocfg.input_pins[AUTO_PIN_MIC];
Takashi Iwaice22e032008-01-11 17:38:35 +01007111 if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
Takashi Iwai776e1842007-08-29 15:07:11 +02007112 err = add_control(spec, ALC_CTL_WIDGET_VOL,
7113 "Mic Boost",
7114 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
7115 if (err < 0)
7116 return err;
7117 }
7118 nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC];
Takashi Iwaice22e032008-01-11 17:38:35 +01007119 if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
Takashi Iwai776e1842007-08-29 15:07:11 +02007120 err = add_control(spec, ALC_CTL_WIDGET_VOL,
7121 "Front Mic Boost",
7122 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
7123 if (err < 0)
7124 return err;
7125 }
7126 return 0;
7127}
7128
Kailang Yangdf694da2005-12-05 19:42:22 +01007129/* almost identical with ALC880 parser... */
7130static int alc882_parse_auto_config(struct hda_codec *codec)
7131{
7132 struct alc_spec *spec = codec->spec;
7133 int err = alc880_parse_auto_config(codec);
7134
7135 if (err < 0)
7136 return err;
Takashi Iwai776e1842007-08-29 15:07:11 +02007137 else if (!err)
7138 return 0; /* no config found */
7139
7140 err = alc_auto_add_mic_boost(codec);
7141 if (err < 0)
7142 return err;
7143
7144 /* hack - override the init verbs */
7145 spec->init_verbs[0] = alc882_auto_init_verbs;
7146
7147 return 1; /* config found */
Kailang Yangdf694da2005-12-05 19:42:22 +01007148}
7149
Takashi Iwaiae6b8132006-03-03 16:47:17 +01007150/* additional initialization for auto-configuration model */
7151static void alc882_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01007152{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01007153 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01007154 alc882_auto_init_multi_out(codec);
7155 alc882_auto_init_hp_out(codec);
7156 alc882_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +02007157 alc882_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01007158 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02007159 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01007160}
7161
Takashi Iwai7943a8a2008-04-16 17:29:09 +02007162static int patch_alc883(struct hda_codec *codec); /* called in patch_alc882() */
7163
Linus Torvalds1da177e2005-04-16 15:20:36 -07007164static int patch_alc882(struct hda_codec *codec)
7165{
7166 struct alc_spec *spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01007167 int err, board_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007168
Takashi Iwaie560d8d2005-09-09 14:21:46 +02007169 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007170 if (spec == NULL)
7171 return -ENOMEM;
7172
Linus Torvalds1da177e2005-04-16 15:20:36 -07007173 codec->spec = spec;
7174
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007175 board_config = snd_hda_check_board_config(codec, ALC882_MODEL_LAST,
7176 alc882_models,
7177 alc882_cfg_tbl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007178
Kailang Yangdf694da2005-12-05 19:42:22 +01007179 if (board_config < 0 || board_config >= ALC882_MODEL_LAST) {
Tobin Davis081d17c2007-02-15 17:46:18 +01007180 /* Pick up systems that don't supply PCI SSID */
7181 switch (codec->subsystem_id) {
7182 case 0x106b0c00: /* Mac Pro */
7183 board_config = ALC885_MACPRO;
7184 break;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02007185 case 0x106b1000: /* iMac 24 */
Peter Korsgaardf3911c52008-09-27 09:13:45 +02007186 case 0x106b2800: /* AppleTV */
Mark Eggleston3077e442009-01-31 17:57:54 +01007187 case 0x106b3e00: /* iMac 24 Aluminium */
Nicola Fagnanic54728d2007-07-19 23:28:52 +02007188 board_config = ALC885_IMAC24;
7189 break;
Luke Yelavich2d466382009-02-23 13:00:33 +11007190 case 0x106b00a0: /* MacBookPro3,1 - Another revision */
Takashi Iwaic7e07572008-06-26 14:42:51 +02007191 case 0x106b00a1: /* Macbook (might be wrong - PCI SSID?) */
David Woodhouse9c95c432008-09-18 13:37:13 -07007192 case 0x106b00a4: /* MacbookPro4,1 */
Takashi Iwai87350ad2007-08-16 18:19:38 +02007193 case 0x106b2c00: /* Macbook Pro rev3 */
Takashi Iwaic7e07572008-06-26 14:42:51 +02007194 case 0x106b3600: /* Macbook 3.1 */
Luke Yelavich2a884642009-01-28 15:58:38 +11007195 case 0x106b3800: /* MacbookPro4,1 - latter revision */
Takashi Iwai87350ad2007-08-16 18:19:38 +02007196 board_config = ALC885_MBP3;
7197 break;
Tobin Davis081d17c2007-02-15 17:46:18 +01007198 default:
Takashi Iwai7943a8a2008-04-16 17:29:09 +02007199 /* ALC889A is handled better as ALC888-compatible */
Clive Messer669faba2008-09-30 15:49:13 +02007200 if (codec->revision_id == 0x100101 ||
7201 codec->revision_id == 0x100103) {
Takashi Iwai7943a8a2008-04-16 17:29:09 +02007202 alc_free(codec);
7203 return patch_alc883(codec);
7204 }
Tobin Davis081d17c2007-02-15 17:46:18 +01007205 printk(KERN_INFO "hda_codec: Unknown model for ALC882, "
7206 "trying auto-probe from BIOS...\n");
7207 board_config = ALC882_AUTO;
7208 }
Kailang Yangdf694da2005-12-05 19:42:22 +01007209 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007210
Takashi Iwaif95474e2007-07-10 00:47:43 +02007211 alc_fix_pincfg(codec, alc882_pinfix_tbl, alc882_pin_fixes);
7212
Kailang Yangdf694da2005-12-05 19:42:22 +01007213 if (board_config == ALC882_AUTO) {
7214 /* automatic parse from the BIOS config */
7215 err = alc882_parse_auto_config(codec);
7216 if (err < 0) {
7217 alc_free(codec);
7218 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007219 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007220 printk(KERN_INFO
7221 "hda_codec: Cannot set up configuration "
7222 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01007223 board_config = ALC882_3ST_DIG;
7224 }
7225 }
7226
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09007227 err = snd_hda_attach_beep_device(codec, 0x1);
7228 if (err < 0) {
7229 alc_free(codec);
7230 return err;
7231 }
7232
Kailang Yangdf694da2005-12-05 19:42:22 +01007233 if (board_config != ALC882_AUTO)
7234 setup_preset(spec, &alc882_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007235
Kailang Yang2f893282008-05-27 12:14:47 +02007236 if (codec->vendor_id == 0x10ec0885) {
7237 spec->stream_name_analog = "ALC885 Analog";
7238 spec->stream_name_digital = "ALC885 Digital";
7239 } else {
7240 spec->stream_name_analog = "ALC882 Analog";
7241 spec->stream_name_digital = "ALC882 Digital";
7242 }
7243
Kailang Yangdf694da2005-12-05 19:42:22 +01007244 spec->stream_analog_playback = &alc882_pcm_analog_playback;
7245 spec->stream_analog_capture = &alc882_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01007246 /* FIXME: setup DAC5 */
7247 /*spec->stream_analog_alt_playback = &alc880_pcm_analog_alt_playback;*/
7248 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007249
Kailang Yangdf694da2005-12-05 19:42:22 +01007250 spec->stream_digital_playback = &alc882_pcm_digital_playback;
7251 spec->stream_digital_capture = &alc882_pcm_digital_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007252
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02007253 spec->capture_style = CAPT_MIX; /* matrix-style capture */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007254 if (!spec->adc_nids && spec->input_mux) {
Kailang Yangdf694da2005-12-05 19:42:22 +01007255 /* check whether NID 0x07 is valid */
Takashi Iwai4a471b72005-12-07 13:56:29 +01007256 unsigned int wcap = get_wcaps(codec, 0x07);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007257 /* get type */
7258 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Kailang Yangdf694da2005-12-05 19:42:22 +01007259 if (wcap != AC_WID_AUD_IN) {
7260 spec->adc_nids = alc882_adc_nids_alt;
7261 spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids_alt);
Takashi Iwaie1406342008-02-11 18:32:32 +01007262 spec->capsrc_nids = alc882_capsrc_nids_alt;
Kailang Yangdf694da2005-12-05 19:42:22 +01007263 } else {
7264 spec->adc_nids = alc882_adc_nids;
7265 spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids);
Takashi Iwaie1406342008-02-11 18:32:32 +01007266 spec->capsrc_nids = alc882_capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +01007267 }
7268 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007269 set_capture_mixer(spec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01007270 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007271
Takashi Iwai2134ea42008-01-10 16:53:55 +01007272 spec->vmaster_nid = 0x0c;
7273
Linus Torvalds1da177e2005-04-16 15:20:36 -07007274 codec->patch_ops = alc_patch_ops;
Kailang Yangdf694da2005-12-05 19:42:22 +01007275 if (board_config == ALC882_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01007276 spec->init_hook = alc882_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02007277#ifdef CONFIG_SND_HDA_POWER_SAVE
7278 if (!spec->loopback.amplist)
7279 spec->loopback.amplist = alc882_loopbacks;
7280#endif
Takashi Iwaidaead532008-11-28 12:55:36 +01007281 codec->proc_widget_hook = print_realtek_coef;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007282
7283 return 0;
7284}
7285
7286/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007287 * ALC883 support
7288 *
7289 * ALC883 is almost identical with ALC880 but has cleaner and more flexible
7290 * configuration. Each pin widget can choose any input DACs and a mixer.
7291 * Each ADC is connected from a mixer of all inputs. This makes possible
7292 * 6-channel independent captures.
7293 *
7294 * In addition, an independent DAC for the multi-playback (not used in this
7295 * driver yet).
7296 */
7297#define ALC883_DIGOUT_NID 0x06
7298#define ALC883_DIGIN_NID 0x0a
7299
Wu Fengguang3ab90932008-11-17 09:51:09 +01007300#define ALC1200_DIGOUT_NID 0x10
7301
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007302static hda_nid_t alc883_dac_nids[4] = {
7303 /* front, rear, clfe, rear_surr */
Herton Ronaldo Krzesinskif32a19e2008-03-18 09:27:08 +01007304 0x02, 0x03, 0x04, 0x05
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007305};
7306
7307static hda_nid_t alc883_adc_nids[2] = {
7308 /* ADC1-2 */
7309 0x08, 0x09,
7310};
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007311
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007312static hda_nid_t alc883_adc_nids_alt[1] = {
7313 /* ADC1 */
7314 0x08,
7315};
7316
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08007317static hda_nid_t alc883_adc_nids_rev[2] = {
7318 /* ADC2-1 */
7319 0x09, 0x08
7320};
7321
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02007322#define alc889_adc_nids alc880_adc_nids
7323
Takashi Iwaie1406342008-02-11 18:32:32 +01007324static hda_nid_t alc883_capsrc_nids[2] = { 0x23, 0x22 };
7325
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08007326static hda_nid_t alc883_capsrc_nids_rev[2] = { 0x22, 0x23 };
7327
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02007328#define alc889_capsrc_nids alc882_capsrc_nids
7329
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007330/* input MUX */
7331/* FIXME: should be a matrix-type input source selection */
7332
7333static struct hda_input_mux alc883_capture_source = {
7334 .num_items = 4,
7335 .items = {
7336 { "Mic", 0x0 },
7337 { "Front Mic", 0x1 },
7338 { "Line", 0x2 },
7339 { "CD", 0x4 },
7340 },
7341};
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007342
Jiang zhe17bba1b2008-06-04 12:11:07 +02007343static struct hda_input_mux alc883_3stack_6ch_intel = {
7344 .num_items = 4,
7345 .items = {
7346 { "Mic", 0x1 },
7347 { "Front Mic", 0x0 },
7348 { "Line", 0x2 },
7349 { "CD", 0x4 },
7350 },
7351};
7352
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007353static struct hda_input_mux alc883_lenovo_101e_capture_source = {
7354 .num_items = 2,
7355 .items = {
7356 { "Mic", 0x1 },
7357 { "Line", 0x2 },
7358 },
7359};
7360
Kailang Yang272a5272007-05-14 11:00:38 +02007361static struct hda_input_mux alc883_lenovo_nb0763_capture_source = {
7362 .num_items = 4,
7363 .items = {
7364 { "Mic", 0x0 },
7365 { "iMic", 0x1 },
7366 { "Line", 0x2 },
7367 { "CD", 0x4 },
7368 },
7369};
7370
Jiang zhefb97dc62008-03-06 11:07:11 +01007371static struct hda_input_mux alc883_fujitsu_pi2515_capture_source = {
7372 .num_items = 2,
7373 .items = {
7374 { "Mic", 0x0 },
7375 { "Int Mic", 0x1 },
7376 },
7377};
7378
Kailang Yange2757d52008-08-26 13:17:46 +02007379static struct hda_input_mux alc883_lenovo_sky_capture_source = {
7380 .num_items = 3,
7381 .items = {
7382 { "Mic", 0x0 },
7383 { "Front Mic", 0x1 },
7384 { "Line", 0x4 },
7385 },
7386};
7387
7388static struct hda_input_mux alc883_asus_eee1601_capture_source = {
7389 .num_items = 2,
7390 .items = {
7391 { "Mic", 0x0 },
7392 { "Line", 0x2 },
7393 },
7394};
7395
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007396/*
7397 * 2ch mode
7398 */
7399static struct hda_channel_mode alc883_3ST_2ch_modes[1] = {
7400 { 2, NULL }
7401};
7402
7403/*
7404 * 2ch mode
7405 */
7406static struct hda_verb alc883_3ST_ch2_init[] = {
7407 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7408 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7409 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7410 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7411 { } /* end */
7412};
7413
7414/*
Tobin Davisb2011312007-09-17 12:45:11 +02007415 * 4ch mode
7416 */
7417static struct hda_verb alc883_3ST_ch4_init[] = {
7418 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7419 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7420 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7421 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7422 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7423 { } /* end */
7424};
7425
7426/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007427 * 6ch mode
7428 */
7429static struct hda_verb alc883_3ST_ch6_init[] = {
7430 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7431 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7432 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7433 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7434 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7435 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7436 { } /* end */
7437};
7438
Tobin Davisb2011312007-09-17 12:45:11 +02007439static struct hda_channel_mode alc883_3ST_6ch_modes[3] = {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007440 { 2, alc883_3ST_ch2_init },
Tobin Davisb2011312007-09-17 12:45:11 +02007441 { 4, alc883_3ST_ch4_init },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007442 { 6, alc883_3ST_ch6_init },
7443};
7444
7445/*
Jiang zhe17bba1b2008-06-04 12:11:07 +02007446 * 2ch mode
7447 */
7448static struct hda_verb alc883_3ST_ch2_intel_init[] = {
7449 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7450 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7451 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7452 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7453 { } /* end */
7454};
7455
7456/*
7457 * 4ch mode
7458 */
7459static struct hda_verb alc883_3ST_ch4_intel_init[] = {
7460 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7461 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7462 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7463 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7464 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7465 { } /* end */
7466};
7467
7468/*
7469 * 6ch mode
7470 */
7471static struct hda_verb alc883_3ST_ch6_intel_init[] = {
7472 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7473 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7474 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x02 },
7475 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7476 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7477 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7478 { } /* end */
7479};
7480
7481static struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = {
7482 { 2, alc883_3ST_ch2_intel_init },
7483 { 4, alc883_3ST_ch4_intel_init },
7484 { 6, alc883_3ST_ch6_intel_init },
7485};
7486
7487/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007488 * 6ch mode
7489 */
7490static struct hda_verb alc883_sixstack_ch6_init[] = {
7491 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
7492 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7493 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7494 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7495 { } /* end */
7496};
7497
7498/*
7499 * 8ch mode
7500 */
7501static struct hda_verb alc883_sixstack_ch8_init[] = {
7502 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7503 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7504 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7505 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7506 { } /* end */
7507};
7508
7509static struct hda_channel_mode alc883_sixstack_modes[2] = {
7510 { 6, alc883_sixstack_ch6_init },
7511 { 8, alc883_sixstack_ch8_init },
7512};
7513
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01007514static struct hda_verb alc883_medion_eapd_verbs[] = {
7515 /* eanable EAPD on medion laptop */
7516 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
7517 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
7518 { }
7519};
7520
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007521/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
7522 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
7523 */
7524
7525static struct snd_kcontrol_new alc883_base_mixer[] = {
7526 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7527 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7528 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7529 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
7530 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7531 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
7532 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7533 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
7534 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
7535 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
7536 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7537 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7538 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7539 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7540 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7541 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007542 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007543 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7544 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007545 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007546 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007547 { } /* end */
7548};
7549
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01007550static struct snd_kcontrol_new alc883_mitac_mixer[] = {
7551 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7552 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7553 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7554 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
7555 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7556 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
7557 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
7558 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7559 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7560 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7561 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7562 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
7563 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01007564 { } /* end */
7565};
7566
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007567static struct snd_kcontrol_new alc883_clevo_m720_mixer[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01007568 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7569 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
7570 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7571 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
7572 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7573 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7574 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7575 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7576 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
7577 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Jiang zhe368c7a92008-03-04 11:20:33 +01007578 { } /* end */
7579};
7580
Jiang zhefb97dc62008-03-06 11:07:11 +01007581static struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = {
7582 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7583 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
7584 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7585 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
7586 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7587 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7588 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7589 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7590 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
7591 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Jiang zhefb97dc62008-03-06 11:07:11 +01007592 { } /* end */
7593};
7594
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007595static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = {
7596 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7597 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7598 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7599 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7600 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7601 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7602 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7603 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007604 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007605 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7606 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007607 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007608 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007609 { } /* end */
7610};
7611
7612static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
7613 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7614 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7615 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7616 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
7617 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7618 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
7619 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7620 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
7621 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7622 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7623 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7624 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7625 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7626 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007627 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007628 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7629 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007630 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007631 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007632 { } /* end */
7633};
7634
Jiang zhe17bba1b2008-06-04 12:11:07 +02007635static struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = {
7636 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7637 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7638 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7639 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
7640 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
7641 HDA_OUTPUT),
7642 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
7643 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7644 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
7645 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
7646 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7647 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7648 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7649 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7650 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7651 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
7652 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
7653 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7654 HDA_CODEC_VOLUME("Front Mic Boost", 0x18, 0, HDA_INPUT),
7655 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Jiang zhe17bba1b2008-06-04 12:11:07 +02007656 { } /* end */
7657};
7658
Takashi Iwaid1d985f2006-11-23 19:27:12 +01007659static struct snd_kcontrol_new alc883_fivestack_mixer[] = {
Tobin Davisc07584c2006-10-13 12:32:16 +02007660 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02007661 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007662 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02007663 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007664 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7665 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02007666 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7667 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007668 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7669 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7670 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7671 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7672 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7673 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007674 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007675 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7676 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007677 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007678 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007679 { } /* end */
7680};
7681
Kailang Yangccc656c2006-10-17 12:32:26 +02007682static struct snd_kcontrol_new alc883_tagra_mixer[] = {
7683 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7684 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7685 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7686 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7687 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
7688 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7689 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
7690 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7691 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
7692 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7693 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7694 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7695 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7696 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007697 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02007698 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02007699 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007700};
Kailang Yangccc656c2006-10-17 12:32:26 +02007701
7702static struct snd_kcontrol_new alc883_tagra_2ch_mixer[] = {
7703 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7704 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7705 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7706 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7707 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7708 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007709 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02007710 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Jiang zhe4383fae2008-04-14 12:58:57 +02007711 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7712 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
7713 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02007714 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007715};
Kailang Yangccc656c2006-10-17 12:32:26 +02007716
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007717static struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = {
7718 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7719 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01007720 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7721 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007722 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7723 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7724 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7725 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007726 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007727};
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007728
Kailang Yang272a5272007-05-14 11:00:38 +02007729static struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = {
7730 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7731 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
7732 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7733 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7734 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7735 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7736 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7737 HDA_CODEC_VOLUME("iMic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7738 HDA_CODEC_MUTE("iMic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02007739 { } /* end */
7740};
7741
7742static struct snd_kcontrol_new alc883_medion_md2_mixer[] = {
7743 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7744 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7745 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
7746 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7747 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7748 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7749 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7750 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7751 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02007752 { } /* end */
Kailang Yangea1fb292008-08-26 12:58:38 +02007753};
Kailang Yang272a5272007-05-14 11:00:38 +02007754
Tobin Davis2880a862007-08-07 11:50:26 +02007755static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = {
Kailang Yangd1a991a2007-08-15 16:21:59 +02007756 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7757 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02007758 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02007759 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7760 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Kailang Yangd1a991a2007-08-15 16:21:59 +02007761 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7762 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7763 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02007764 { } /* end */
Kailang Yangd1a991a2007-08-15 16:21:59 +02007765};
Tobin Davis2880a862007-08-07 11:50:26 +02007766
Kailang Yange2757d52008-08-26 13:17:46 +02007767static struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = {
7768 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7769 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7770 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
7771 HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
7772 HDA_CODEC_VOLUME_MONO("Center Playback Volume",
7773 0x0d, 1, 0x0, HDA_OUTPUT),
7774 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
7775 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
7776 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
7777 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
7778 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
7779 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7780 HDA_CODEC_MUTE("iSpeaker Playback Switch", 0x1a, 0x0, HDA_OUTPUT),
7781 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7782 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7783 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7784 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7785 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7786 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7787 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7788 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7789 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
7790 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02007791 { } /* end */
7792};
7793
7794static struct hda_bind_ctls alc883_bind_cap_vol = {
7795 .ops = &snd_hda_bind_vol,
7796 .values = {
7797 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
7798 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
7799 0
7800 },
7801};
7802
7803static struct hda_bind_ctls alc883_bind_cap_switch = {
7804 .ops = &snd_hda_bind_sw,
7805 .values = {
7806 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
7807 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
7808 0
7809 },
7810};
7811
7812static struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = {
7813 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7814 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7815 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7816 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7817 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7818 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7819 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7820 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007821 { } /* end */
7822};
7823
7824static struct snd_kcontrol_new alc883_asus_eee1601_cap_mixer[] = {
Kailang Yange2757d52008-08-26 13:17:46 +02007825 HDA_BIND_VOL("Capture Volume", &alc883_bind_cap_vol),
7826 HDA_BIND_SW("Capture Switch", &alc883_bind_cap_switch),
7827 {
7828 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7829 /* .name = "Capture Source", */
7830 .name = "Input Source",
7831 .count = 1,
Takashi Iwai54cbc9a2008-10-31 15:24:04 +01007832 .info = alc_mux_enum_info,
7833 .get = alc_mux_enum_get,
7834 .put = alc_mux_enum_put,
Kailang Yange2757d52008-08-26 13:17:46 +02007835 },
7836 { } /* end */
7837};
7838
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007839static struct snd_kcontrol_new alc883_chmode_mixer[] = {
7840 {
7841 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7842 .name = "Channel Mode",
7843 .info = alc_ch_mode_info,
7844 .get = alc_ch_mode_get,
7845 .put = alc_ch_mode_put,
7846 },
7847 { } /* end */
7848};
7849
7850static struct hda_verb alc883_init_verbs[] = {
7851 /* ADC1: mute amp left and right */
Kailang Yange2757d52008-08-26 13:17:46 +02007852 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007853 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
7854 /* ADC2: mute amp left and right */
7855 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7856 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
7857 /* Front mixer: unmute input/output amp left and right (volume = 0) */
7858 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7859 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7860 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7861 /* Rear mixer */
7862 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7863 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7864 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7865 /* CLFE mixer */
7866 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7867 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7868 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7869 /* Side mixer */
7870 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7871 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7872 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7873
Takashi Iwaicb53c622007-08-10 17:21:45 +02007874 /* mute analog input loopbacks */
7875 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7876 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7877 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7878 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7879 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007880
7881 /* Front Pin: output 0 (0x0c) */
7882 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7883 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7884 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
7885 /* Rear Pin: output 1 (0x0d) */
7886 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7887 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7888 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
7889 /* CLFE Pin: output 2 (0x0e) */
7890 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7891 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7892 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
7893 /* Side Pin: output 3 (0x0f) */
7894 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7895 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7896 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
7897 /* Mic (rear) pin: input vref at 80% */
7898 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7899 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7900 /* Front Mic pin: input vref at 80% */
7901 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7902 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7903 /* Line In pin: input */
7904 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
7905 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7906 /* Line-2 In: Headphone output (output 0 - 0x0c) */
7907 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7908 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7909 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
7910 /* CD pin widget for input */
7911 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
7912
7913 /* FIXME: use matrix-type input source selection */
7914 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
7915 /* Input mixer2 */
7916 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yange2757d52008-08-26 13:17:46 +02007917 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7918 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7919 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007920 /* Input mixer3 */
7921 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yange2757d52008-08-26 13:17:46 +02007922 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7923 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7924 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007925 { }
7926};
7927
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01007928/* toggle speaker-output according to the hp-jack state */
7929static void alc883_mitac_hp_automute(struct hda_codec *codec)
7930{
7931 unsigned int present;
7932
7933 present = snd_hda_codec_read(codec, 0x15, 0,
7934 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7935 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7936 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7937 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
7938 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7939}
7940
7941/* auto-toggle front mic */
7942/*
7943static void alc883_mitac_mic_automute(struct hda_codec *codec)
7944{
7945 unsigned int present;
7946 unsigned char bits;
7947
7948 present = snd_hda_codec_read(codec, 0x18, 0,
7949 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7950 bits = present ? HDA_AMP_MUTE : 0;
7951 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
7952}
7953*/
7954
7955static void alc883_mitac_automute(struct hda_codec *codec)
7956{
7957 alc883_mitac_hp_automute(codec);
7958 /* alc883_mitac_mic_automute(codec); */
7959}
7960
7961static void alc883_mitac_unsol_event(struct hda_codec *codec,
7962 unsigned int res)
7963{
7964 switch (res >> 26) {
7965 case ALC880_HP_EVENT:
7966 alc883_mitac_hp_automute(codec);
7967 break;
7968 case ALC880_MIC_EVENT:
7969 /* alc883_mitac_mic_automute(codec); */
7970 break;
7971 }
7972}
7973
7974static struct hda_verb alc883_mitac_verbs[] = {
7975 /* HP */
7976 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7977 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7978 /* Subwoofer */
7979 {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
7980 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7981
7982 /* enable unsolicited event */
7983 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7984 /* {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, */
7985
7986 { } /* end */
7987};
7988
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007989static struct hda_verb alc883_clevo_m720_verbs[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01007990 /* HP */
7991 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7992 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7993 /* Int speaker */
7994 {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
7995 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7996
7997 /* enable unsolicited event */
7998 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007999 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Jiang zhe368c7a92008-03-04 11:20:33 +01008000
8001 { } /* end */
8002};
8003
Jiang zhefb97dc62008-03-06 11:07:11 +01008004static struct hda_verb alc883_2ch_fujitsu_pi2515_verbs[] = {
8005 /* HP */
8006 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8007 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8008 /* Subwoofer */
8009 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
8010 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8011
8012 /* enable unsolicited event */
8013 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8014
8015 { } /* end */
8016};
8017
Kailang Yangccc656c2006-10-17 12:32:26 +02008018static struct hda_verb alc883_tagra_verbs[] = {
8019 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8020 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8021
8022 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8023 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02008024
Kailang Yangccc656c2006-10-17 12:32:26 +02008025 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
8026 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
8027 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8028
8029 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008030 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
8031 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
8032 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
Kailang Yangccc656c2006-10-17 12:32:26 +02008033
8034 { } /* end */
8035};
8036
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008037static struct hda_verb alc883_lenovo_101e_verbs[] = {
8038 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8039 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT|AC_USRSP_EN},
8040 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT|AC_USRSP_EN},
8041 { } /* end */
8042};
8043
Kailang Yang272a5272007-05-14 11:00:38 +02008044static struct hda_verb alc883_lenovo_nb0763_verbs[] = {
8045 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8046 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8047 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8048 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8049 { } /* end */
8050};
8051
8052static struct hda_verb alc888_lenovo_ms7195_verbs[] = {
8053 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8054 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8055 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8056 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT | AC_USRSP_EN},
8057 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8058 { } /* end */
8059};
8060
Kailang Yang189609a2007-08-20 11:31:23 +02008061static struct hda_verb alc883_haier_w66_verbs[] = {
8062 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8063 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8064
8065 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8066
8067 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
8068 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8069 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8070 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8071 { } /* end */
8072};
8073
Kailang Yange2757d52008-08-26 13:17:46 +02008074static struct hda_verb alc888_lenovo_sky_verbs[] = {
8075 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8076 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8077 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8078 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8079 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8080 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8081 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
8082 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8083 { } /* end */
8084};
8085
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03008086static struct hda_verb alc888_6st_dell_verbs[] = {
8087 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8088 { }
8089};
8090
8091static void alc888_3st_hp_front_automute(struct hda_codec *codec)
8092{
8093 unsigned int present, bits;
8094
8095 present = snd_hda_codec_read(codec, 0x1b, 0,
8096 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
8097 bits = present ? HDA_AMP_MUTE : 0;
8098 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8099 HDA_AMP_MUTE, bits);
8100 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
8101 HDA_AMP_MUTE, bits);
8102 snd_hda_codec_amp_stereo(codec, 0x18, HDA_OUTPUT, 0,
8103 HDA_AMP_MUTE, bits);
8104}
8105
8106static void alc888_3st_hp_unsol_event(struct hda_codec *codec,
8107 unsigned int res)
8108{
8109 switch (res >> 26) {
8110 case ALC880_HP_EVENT:
8111 alc888_3st_hp_front_automute(codec);
8112 break;
8113 }
8114}
8115
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008116static struct hda_verb alc888_3st_hp_verbs[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008117 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */
Herton Ronaldo Krzesinskif32a19e2008-03-18 09:27:08 +01008118 {0x16, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Rear : output 1 (0x0d) */
8119 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* CLFE : output 2 (0x0e) */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008120 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03008121 { } /* end */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008122};
8123
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03008124/*
8125 * 2ch mode
8126 */
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008127static struct hda_verb alc888_3st_hp_2ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008128 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
8129 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
8130 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
8131 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03008132 { } /* end */
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008133};
8134
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03008135/*
8136 * 4ch mode
8137 */
8138static struct hda_verb alc888_3st_hp_4ch_init[] = {
8139 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
8140 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
8141 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8142 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
8143 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 },
8144 { } /* end */
8145};
8146
8147/*
8148 * 6ch mode
8149 */
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008150static struct hda_verb alc888_3st_hp_6ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008151 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8152 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03008153 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008154 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8155 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03008156 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 },
8157 { } /* end */
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008158};
8159
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03008160static struct hda_channel_mode alc888_3st_hp_modes[3] = {
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008161 { 2, alc888_3st_hp_2ch_init },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03008162 { 4, alc888_3st_hp_4ch_init },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008163 { 6, alc888_3st_hp_6ch_init },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008164};
8165
Kailang Yang272a5272007-05-14 11:00:38 +02008166/* toggle front-jack and RCA according to the hp-jack state */
8167static void alc888_lenovo_ms7195_front_automute(struct hda_codec *codec)
8168{
8169 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02008170
Kailang Yang272a5272007-05-14 11:00:38 +02008171 present = snd_hda_codec_read(codec, 0x1b, 0,
8172 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02008173 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8174 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
8175 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8176 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02008177}
8178
8179/* toggle RCA according to the front-jack state */
8180static void alc888_lenovo_ms7195_rca_automute(struct hda_codec *codec)
8181{
8182 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02008183
Kailang Yang272a5272007-05-14 11:00:38 +02008184 present = snd_hda_codec_read(codec, 0x14, 0,
8185 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02008186 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8187 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02008188}
Takashi Iwai47fd8302007-08-10 17:11:07 +02008189
Kailang Yang272a5272007-05-14 11:00:38 +02008190static void alc883_lenovo_ms7195_unsol_event(struct hda_codec *codec,
8191 unsigned int res)
8192{
8193 if ((res >> 26) == ALC880_HP_EVENT)
8194 alc888_lenovo_ms7195_front_automute(codec);
8195 if ((res >> 26) == ALC880_FRONT_EVENT)
8196 alc888_lenovo_ms7195_rca_automute(codec);
8197}
8198
8199static struct hda_verb alc883_medion_md2_verbs[] = {
8200 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8201 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8202
8203 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8204
8205 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8206 { } /* end */
8207};
8208
8209/* toggle speaker-output according to the hp-jack state */
8210static void alc883_medion_md2_automute(struct hda_codec *codec)
8211{
8212 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02008213
Kailang Yang272a5272007-05-14 11:00:38 +02008214 present = snd_hda_codec_read(codec, 0x14, 0,
8215 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02008216 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8217 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02008218}
8219
8220static void alc883_medion_md2_unsol_event(struct hda_codec *codec,
8221 unsigned int res)
8222{
8223 if ((res >> 26) == ALC880_HP_EVENT)
8224 alc883_medion_md2_automute(codec);
8225}
8226
Kailang Yangccc656c2006-10-17 12:32:26 +02008227/* toggle speaker-output according to the hp-jack state */
8228static void alc883_tagra_automute(struct hda_codec *codec)
8229{
8230 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008231 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02008232
8233 present = snd_hda_codec_read(codec, 0x14, 0,
8234 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02008235 bits = present ? HDA_AMP_MUTE : 0;
8236 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
8237 HDA_AMP_MUTE, bits);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02008238 snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
8239 present ? 1 : 3);
Kailang Yangccc656c2006-10-17 12:32:26 +02008240}
8241
8242static void alc883_tagra_unsol_event(struct hda_codec *codec, unsigned int res)
8243{
8244 if ((res >> 26) == ALC880_HP_EVENT)
8245 alc883_tagra_automute(codec);
8246}
8247
Jiang zhe368c7a92008-03-04 11:20:33 +01008248/* toggle speaker-output according to the hp-jack state */
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008249static void alc883_clevo_m720_hp_automute(struct hda_codec *codec)
Jiang zhe368c7a92008-03-04 11:20:33 +01008250{
8251 unsigned int present;
8252 unsigned char bits;
8253
8254 present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0)
8255 & AC_PINSENSE_PRESENCE;
8256 bits = present ? HDA_AMP_MUTE : 0;
8257 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8258 HDA_AMP_MUTE, bits);
8259}
8260
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008261static void alc883_clevo_m720_mic_automute(struct hda_codec *codec)
8262{
8263 unsigned int present;
8264
8265 present = snd_hda_codec_read(codec, 0x18, 0,
8266 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
8267 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
8268 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
8269}
8270
8271static void alc883_clevo_m720_automute(struct hda_codec *codec)
8272{
8273 alc883_clevo_m720_hp_automute(codec);
8274 alc883_clevo_m720_mic_automute(codec);
8275}
8276
8277static void alc883_clevo_m720_unsol_event(struct hda_codec *codec,
Jiang zhe368c7a92008-03-04 11:20:33 +01008278 unsigned int res)
8279{
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008280 switch (res >> 26) {
8281 case ALC880_HP_EVENT:
8282 alc883_clevo_m720_hp_automute(codec);
8283 break;
8284 case ALC880_MIC_EVENT:
8285 alc883_clevo_m720_mic_automute(codec);
8286 break;
8287 }
Jiang zhe368c7a92008-03-04 11:20:33 +01008288}
8289
Jiang zhefb97dc62008-03-06 11:07:11 +01008290/* toggle speaker-output according to the hp-jack state */
8291static void alc883_2ch_fujitsu_pi2515_automute(struct hda_codec *codec)
8292{
8293 unsigned int present;
8294 unsigned char bits;
8295
8296 present = snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0)
8297 & AC_PINSENSE_PRESENCE;
8298 bits = present ? HDA_AMP_MUTE : 0;
8299 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8300 HDA_AMP_MUTE, bits);
8301}
8302
8303static void alc883_2ch_fujitsu_pi2515_unsol_event(struct hda_codec *codec,
8304 unsigned int res)
8305{
8306 if ((res >> 26) == ALC880_HP_EVENT)
8307 alc883_2ch_fujitsu_pi2515_automute(codec);
8308}
8309
Kailang Yang189609a2007-08-20 11:31:23 +02008310static void alc883_haier_w66_automute(struct hda_codec *codec)
8311{
8312 unsigned int present;
8313 unsigned char bits;
8314
8315 present = snd_hda_codec_read(codec, 0x1b, 0,
8316 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
8317 bits = present ? 0x80 : 0;
8318 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8319 0x80, bits);
8320}
8321
8322static void alc883_haier_w66_unsol_event(struct hda_codec *codec,
8323 unsigned int res)
8324{
8325 if ((res >> 26) == ALC880_HP_EVENT)
8326 alc883_haier_w66_automute(codec);
8327}
8328
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008329static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
8330{
8331 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008332 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008333
8334 present = snd_hda_codec_read(codec, 0x14, 0,
8335 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02008336 bits = present ? HDA_AMP_MUTE : 0;
8337 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8338 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008339}
8340
8341static void alc883_lenovo_101e_all_automute(struct hda_codec *codec)
8342{
8343 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008344 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008345
8346 present = snd_hda_codec_read(codec, 0x1b, 0,
8347 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02008348 bits = present ? HDA_AMP_MUTE : 0;
8349 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8350 HDA_AMP_MUTE, bits);
8351 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8352 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008353}
8354
8355static void alc883_lenovo_101e_unsol_event(struct hda_codec *codec,
8356 unsigned int res)
8357{
8358 if ((res >> 26) == ALC880_HP_EVENT)
8359 alc883_lenovo_101e_all_automute(codec);
8360 if ((res >> 26) == ALC880_FRONT_EVENT)
8361 alc883_lenovo_101e_ispeaker_automute(codec);
8362}
8363
Takashi Iwai676a9b52007-08-16 15:23:35 +02008364/* toggle speaker-output according to the hp-jack state */
8365static void alc883_acer_aspire_automute(struct hda_codec *codec)
8366{
8367 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02008368
Takashi Iwai676a9b52007-08-16 15:23:35 +02008369 present = snd_hda_codec_read(codec, 0x14, 0,
8370 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
8371 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8372 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
8373 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
8374 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
8375}
8376
8377static void alc883_acer_aspire_unsol_event(struct hda_codec *codec,
8378 unsigned int res)
8379{
8380 if ((res >> 26) == ALC880_HP_EVENT)
8381 alc883_acer_aspire_automute(codec);
8382}
8383
Kailang Yangd1a991a2007-08-15 16:21:59 +02008384static struct hda_verb alc883_acer_eapd_verbs[] = {
8385 /* HP Pin: output 0 (0x0c) */
8386 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8387 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8388 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8389 /* Front Pin: output 0 (0x0c) */
Takashi Iwai676a9b52007-08-16 15:23:35 +02008390 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8391 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangd1a991a2007-08-15 16:21:59 +02008392 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangd1a991a2007-08-15 16:21:59 +02008393 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
8394 /* eanable EAPD on medion laptop */
8395 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
8396 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
Takashi Iwai676a9b52007-08-16 15:23:35 +02008397 /* enable unsolicited event */
8398 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yangd1a991a2007-08-15 16:21:59 +02008399 { }
8400};
8401
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008402static void alc888_6st_dell_front_automute(struct hda_codec *codec)
8403{
8404 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02008405
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008406 present = snd_hda_codec_read(codec, 0x1b, 0,
8407 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
8408 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8409 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
8410 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8411 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
8412 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
8413 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
8414 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
8415 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
8416}
8417
8418static void alc888_6st_dell_unsol_event(struct hda_codec *codec,
8419 unsigned int res)
8420{
8421 switch (res >> 26) {
8422 case ALC880_HP_EVENT:
Takashi Iwai939778a2009-02-05 15:57:55 +01008423 /* printk(KERN_DEBUG "hp_event\n"); */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008424 alc888_6st_dell_front_automute(codec);
8425 break;
8426 }
8427}
8428
Kailang Yange2757d52008-08-26 13:17:46 +02008429static void alc888_lenovo_sky_front_automute(struct hda_codec *codec)
8430{
8431 unsigned int mute;
8432 unsigned int present;
8433
8434 snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
8435 present = snd_hda_codec_read(codec, 0x1b, 0,
8436 AC_VERB_GET_PIN_SENSE, 0);
8437 present = (present & 0x80000000) != 0;
8438 if (present) {
8439 /* mute internal speaker */
8440 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8441 HDA_AMP_MUTE, HDA_AMP_MUTE);
8442 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8443 HDA_AMP_MUTE, HDA_AMP_MUTE);
8444 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
8445 HDA_AMP_MUTE, HDA_AMP_MUTE);
8446 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
8447 HDA_AMP_MUTE, HDA_AMP_MUTE);
8448 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0,
8449 HDA_AMP_MUTE, HDA_AMP_MUTE);
8450 } else {
8451 /* unmute internal speaker if necessary */
8452 mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
8453 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8454 HDA_AMP_MUTE, mute);
8455 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8456 HDA_AMP_MUTE, mute);
8457 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
8458 HDA_AMP_MUTE, mute);
8459 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
8460 HDA_AMP_MUTE, mute);
8461 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0,
8462 HDA_AMP_MUTE, mute);
8463 }
8464}
8465
8466static void alc883_lenovo_sky_unsol_event(struct hda_codec *codec,
8467 unsigned int res)
8468{
8469 if ((res >> 26) == ALC880_HP_EVENT)
8470 alc888_lenovo_sky_front_automute(codec);
8471}
8472
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008473/*
8474 * generic initialization of ADC, input mixers and output mixers
8475 */
8476static struct hda_verb alc883_auto_init_verbs[] = {
8477 /*
8478 * Unmute ADC0-2 and set the default input to mic-in
8479 */
8480 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8481 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8482 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8483 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8484
Takashi Iwaicb53c622007-08-10 17:21:45 +02008485 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008486 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008487 * Note: PASD motherboards uses the Line In 2 as the input for
8488 * front panel mic (mic 2)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008489 */
8490 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02008491 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8492 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8493 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8494 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8495 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008496
8497 /*
8498 * Set up output mixers (0x0c - 0x0f)
8499 */
8500 /* set vol=0 to output mixers */
8501 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8502 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8503 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8504 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8505 /* set up input amps for analog loopback */
8506 /* Amp Indices: DAC = 0, mixer = 1 */
8507 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8508 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8509 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8510 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8511 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8512 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8513 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8514 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8515 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8516 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8517
8518 /* FIXME: use matrix-type input source selection */
8519 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
8520 /* Input mixer1 */
8521 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8522 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8523 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008524 /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, */
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008525 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
8526 /* Input mixer2 */
8527 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8528 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8529 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008530 /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, */
Andy Shevchenkoe3cde642007-12-03 16:50:58 +01008531 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008532
8533 { }
8534};
8535
Kailang Yange2757d52008-08-26 13:17:46 +02008536static struct hda_verb alc888_asus_m90v_verbs[] = {
8537 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8538 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8539 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8540 /* enable unsolicited event */
8541 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8542 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
8543 { } /* end */
8544};
8545
8546static void alc883_nb_mic_automute(struct hda_codec *codec)
8547{
8548 unsigned int present;
8549
8550 present = snd_hda_codec_read(codec, 0x18, 0,
8551 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
8552 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
8553 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
8554 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
8555 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
8556}
8557
8558static void alc883_M90V_speaker_automute(struct hda_codec *codec)
8559{
8560 unsigned int present;
8561 unsigned char bits;
8562
8563 present = snd_hda_codec_read(codec, 0x1b, 0,
8564 AC_VERB_GET_PIN_SENSE, 0)
8565 & AC_PINSENSE_PRESENCE;
8566 bits = present ? 0 : PIN_OUT;
8567 snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
8568 bits);
8569 snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
8570 bits);
8571 snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
8572 bits);
8573}
8574
8575static void alc883_mode2_unsol_event(struct hda_codec *codec,
8576 unsigned int res)
8577{
8578 switch (res >> 26) {
8579 case ALC880_HP_EVENT:
8580 alc883_M90V_speaker_automute(codec);
8581 break;
8582 case ALC880_MIC_EVENT:
8583 alc883_nb_mic_automute(codec);
8584 break;
8585 }
8586}
8587
8588static void alc883_mode2_inithook(struct hda_codec *codec)
8589{
8590 alc883_M90V_speaker_automute(codec);
8591 alc883_nb_mic_automute(codec);
8592}
8593
8594static struct hda_verb alc888_asus_eee1601_verbs[] = {
8595 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8596 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8597 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8598 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8599 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8600 {0x20, AC_VERB_SET_COEF_INDEX, 0x0b},
8601 {0x20, AC_VERB_SET_PROC_COEF, 0x0838},
8602 /* enable unsolicited event */
8603 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8604 { } /* end */
8605};
8606
8607static void alc883_eee1601_speaker_automute(struct hda_codec *codec)
8608{
8609 unsigned int present;
8610 unsigned char bits;
8611
8612 present = snd_hda_codec_read(codec, 0x14, 0,
8613 AC_VERB_GET_PIN_SENSE, 0)
8614 & AC_PINSENSE_PRESENCE;
8615 bits = present ? 0 : PIN_OUT;
8616 snd_hda_codec_write(codec, 0x1b, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
8617 bits);
8618}
8619
8620static void alc883_eee1601_unsol_event(struct hda_codec *codec,
8621 unsigned int res)
8622{
8623 switch (res >> 26) {
8624 case ALC880_HP_EVENT:
8625 alc883_eee1601_speaker_automute(codec);
8626 break;
8627 }
8628}
8629
8630static void alc883_eee1601_inithook(struct hda_codec *codec)
8631{
8632 alc883_eee1601_speaker_automute(codec);
8633}
8634
Takashi Iwaicb53c622007-08-10 17:21:45 +02008635#ifdef CONFIG_SND_HDA_POWER_SAVE
8636#define alc883_loopbacks alc880_loopbacks
8637#endif
8638
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008639/* pcm configuration: identiacal with ALC880 */
8640#define alc883_pcm_analog_playback alc880_pcm_analog_playback
8641#define alc883_pcm_analog_capture alc880_pcm_analog_capture
Takashi Iwai63300792008-01-24 15:31:36 +01008642#define alc883_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008643#define alc883_pcm_digital_playback alc880_pcm_digital_playback
8644#define alc883_pcm_digital_capture alc880_pcm_digital_capture
8645
8646/*
8647 * configuration and preset
8648 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008649static const char *alc883_models[ALC883_MODEL_LAST] = {
8650 [ALC883_3ST_2ch_DIG] = "3stack-dig",
8651 [ALC883_3ST_6ch_DIG] = "3stack-6ch-dig",
8652 [ALC883_3ST_6ch] = "3stack-6ch",
8653 [ALC883_6ST_DIG] = "6stack-dig",
8654 [ALC883_TARGA_DIG] = "targa-dig",
8655 [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008656 [ALC883_ACER] = "acer",
Tobin Davis2880a862007-08-07 11:50:26 +02008657 [ALC883_ACER_ASPIRE] = "acer-aspire",
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08008658 [ALC888_ACER_ASPIRE_4930G] = "acer-aspire-4930g",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008659 [ALC883_MEDION] = "medion",
Kailang Yang272a5272007-05-14 11:00:38 +02008660 [ALC883_MEDION_MD2] = "medion-md2",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008661 [ALC883_LAPTOP_EAPD] = "laptop-eapd",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008662 [ALC883_LENOVO_101E_2ch] = "lenovo-101e",
Kailang Yang272a5272007-05-14 11:00:38 +02008663 [ALC883_LENOVO_NB0763] = "lenovo-nb0763",
8664 [ALC888_LENOVO_MS7195_DIG] = "lenovo-ms7195-dig",
Kailang Yange2757d52008-08-26 13:17:46 +02008665 [ALC888_LENOVO_SKY] = "lenovo-sky",
Kailang Yang189609a2007-08-20 11:31:23 +02008666 [ALC883_HAIER_W66] = "haier-w66",
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008667 [ALC888_3ST_HP] = "3stack-hp",
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008668 [ALC888_6ST_DELL] = "6stack-dell",
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008669 [ALC883_MITAC] = "mitac",
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008670 [ALC883_CLEVO_M720] = "clevo-m720",
Jiang zhefb97dc62008-03-06 11:07:11 +01008671 [ALC883_FUJITSU_PI2515] = "fujitsu-pi2515",
Vincent Petryef8ef5f2008-11-23 11:31:41 +08008672 [ALC888_FUJITSU_XA3530] = "fujitsu-xa3530",
Jiang zhe17bba1b2008-06-04 12:11:07 +02008673 [ALC883_3ST_6ch_INTEL] = "3stack-6ch-intel",
Wu Fengguang3ab90932008-11-17 09:51:09 +01008674 [ALC1200_ASUS_P5Q] = "asus-p5q",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008675 [ALC883_AUTO] = "auto",
8676};
8677
8678static struct snd_pci_quirk alc883_cfg_tbl[] = {
8679 SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC883_3ST_6ch_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008680 SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE),
Takashi Iwai69e50282008-11-03 10:07:43 +01008681 SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_ACER_ASPIRE),
Takashi Iwai9b6682f2009-03-23 22:50:52 +01008682 SND_PCI_QUIRK(0x1025, 0x010a, "Acer Ferrari 5000", ALC883_ACER_ASPIRE),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008683 SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE),
8684 SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE),
Jaroslav Kysela0b18cb12008-07-28 17:07:07 +02008685 SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_ACER_ASPIRE),
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08008686 SND_PCI_QUIRK(0x1025, 0x013e, "Acer Aspire 4930G",
8687 ALC888_ACER_ASPIRE_4930G),
Lukasz Wojnilowicza8e4f9d2009-01-08 12:00:49 +01008688 SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G",
8689 ALC888_ACER_ASPIRE_4930G),
Takashi Iwaib3bdb302009-02-18 13:16:26 +01008690 SND_PCI_QUIRK(0x1025, 0x0157, "Acer X3200", ALC883_AUTO),
Takashi Iwai94683502009-02-13 09:31:20 +01008691 SND_PCI_QUIRK(0x1025, 0x0158, "Acer AX1700-U3700A", ALC883_AUTO),
Lukasz Wojnilowicza8e4f9d2009-01-08 12:00:49 +01008692 SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G",
8693 ALC888_ACER_ASPIRE_4930G),
Juan Jesus Garcia de Soriacc374c42009-02-23 08:11:59 +01008694 SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G",
8695 ALC888_ACER_ASPIRE_4930G),
Takashi Iwaidea0a502009-02-09 17:14:52 +01008696 /* default Acer */
8697 SND_PCI_QUIRK_VENDOR(0x1025, "Acer laptop", ALC883_ACER),
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008698 SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL),
Tobin Davisfebe3372007-06-12 11:27:46 +02008699 SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008700 SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP),
8701 SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP),
Herton Ronaldo Krzesinski5d85f8d2008-03-20 12:13:46 +01008702 SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG),
Chris Bagwell06bf3e12009-01-01 10:32:08 +01008703 SND_PCI_QUIRK(0x103c, 0x2a66, "HP Acacia", ALC888_3ST_HP),
Herton Ronaldo Krzesinski7ec30f02009-03-04 14:22:52 -03008704 SND_PCI_QUIRK(0x103c, 0x2a72, "HP Educ.ar", ALC888_3ST_HP),
Kailang Yanga01c30c2008-10-15 11:14:58 +02008705 SND_PCI_QUIRK(0x1043, 0x1873, "Asus M90V", ALC888_ASUS_M90V),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008706 SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG),
Mackenzie Morgan44a678d2009-02-10 17:13:43 +01008707 SND_PCI_QUIRK(0x1043, 0x8284, "Asus Z37E", ALC883_6ST_DIG),
Wu Fengguang3ab90932008-11-17 09:51:09 +01008708 SND_PCI_QUIRK(0x1043, 0x82fe, "Asus P5Q-EM HDMI", ALC1200_ASUS_P5Q),
Kailang Yange2757d52008-08-26 13:17:46 +02008709 SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_ASUS_EEE1601),
Travis Place97ec7102008-05-23 18:31:46 +02008710 SND_PCI_QUIRK(0x105b, 0x0ce8, "Foxconn P35AX-S", ALC883_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008711 SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC883_6ST_DIG),
Luke Yelavich2de686d2009-01-16 15:08:02 +11008712 SND_PCI_QUIRK(0x1071, 0x8227, "Mitac 82801H", ALC883_MITAC),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008713 SND_PCI_QUIRK(0x1071, 0x8253, "Mitac 8252d", ALC883_MITAC),
8714 SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD),
Kailang Yange2757d52008-08-26 13:17:46 +02008715 SND_PCI_QUIRK(0x10f1, 0x2350, "TYAN-S2350", ALC888_6ST_DELL),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008716 SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch),
Tobin Davis57b14f22007-04-18 23:05:36 +02008717 SND_PCI_QUIRK(0x1458, 0xa002, "MSI", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008718 SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG),
8719 SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG),
8720 SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG),
Jiang zhe4383fae2008-04-14 12:58:57 +02008721 SND_PCI_QUIRK(0x1462, 0x2fb3, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008722 SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG),
Pascal Terjan82808232008-03-04 11:33:28 +01008723 SND_PCI_QUIRK(0x1462, 0x3783, "NEC S970", ALC883_TARGA_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008724 SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG),
8725 SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG),
8726 SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG),
8727 SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG),
8728 SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG),
8729 SND_PCI_QUIRK(0x1462, 0x3fdf, "MSI", ALC883_TARGA_DIG),
8730 SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG),
8731 SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG),
8732 SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008733 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG),
8734 SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG),
Tobin Davis799f88a2007-05-29 14:29:08 +02008735 SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG),
Takashi Iwaiee095432008-11-25 15:03:38 +01008736 SND_PCI_QUIRK(0x1462, 0x7260, "MSI 7260", ALC883_TARGA_DIG),
Herton Ronaldo Krzesinski86d34b72008-03-18 09:27:59 +01008737 SND_PCI_QUIRK(0x1462, 0x7267, "MSI", ALC883_3ST_6ch_DIG),
Leonard Norrgard2a296cb2007-01-08 11:28:22 +01008738 SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG),
Tobin Davis2dcd5222007-07-10 17:04:57 +02008739 SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008740 SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008741 SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG),
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008742 SND_PCI_QUIRK(0x1558, 0x0721, "Clevo laptop M720R", ALC883_CLEVO_M720),
8743 SND_PCI_QUIRK(0x1558, 0x0722, "Clevo laptop M720SR", ALC883_CLEVO_M720),
Takashi Iwaidea0a502009-02-09 17:14:52 +01008744 SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC883_LAPTOP_EAPD),
Daniel T Chene60623b2007-05-29 03:41:55 -04008745 SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008746 SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION),
Takashi Iwaibfb53032009-04-14 14:51:04 +02008747 SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1100, "FSC AMILO Xi/Pi25xx",
Takashi Iwaif67d8172009-02-04 23:30:19 +01008748 ALC883_FUJITSU_PI2515),
Takashi Iwaibfb53032009-04-14 14:51:04 +02008749 SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1130, "Fujitsu AMILO Xa35xx",
Vincent Petryef8ef5f2008-11-23 11:31:41 +08008750 ALC888_FUJITSU_XA3530),
Kailang Yang272a5272007-05-14 11:00:38 +02008751 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch),
Kailang Yang272a5272007-05-14 11:00:38 +02008752 SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008753 SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763),
8754 SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Kailang Yange2757d52008-08-26 13:17:46 +02008755 SND_PCI_QUIRK(0x17aa, 0x101d, "Lenovo Sky", ALC888_LENOVO_SKY),
Kailang Yang272a5272007-05-14 11:00:38 +02008756 SND_PCI_QUIRK(0x17c0, 0x4071, "MEDION MD2", ALC883_MEDION_MD2),
Takashi Iwai959973b2008-11-05 11:30:56 +01008757 SND_PCI_QUIRK(0x17c0, 0x4085, "MEDION MD96630", ALC888_LENOVO_MS7195_DIG),
Andrew Paprocki0b167bf2008-02-03 10:15:44 +01008758 SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG),
Kailang Yang189609a2007-08-20 11:31:23 +02008759 SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66),
Jiang zhe17bba1b2008-06-04 12:11:07 +02008760 SND_PCI_QUIRK(0x8086, 0x0001, "DG33BUC", ALC883_3ST_6ch_INTEL),
8761 SND_PCI_QUIRK(0x8086, 0x0002, "DG33FBC", ALC883_3ST_6ch_INTEL),
Luke Yelavich2de686d2009-01-16 15:08:02 +11008762 SND_PCI_QUIRK(0x8086, 0x2503, "82801H", ALC883_MITAC),
Wu Fengguang4b558992009-01-12 09:18:58 +08008763 SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC883_3ST_6ch_INTEL),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008764 SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008765 {}
8766};
8767
Wu Fengguangf3cd3f52009-04-02 19:44:18 +08008768static hda_nid_t alc883_slave_dig_outs[] = {
8769 ALC1200_DIGOUT_NID, 0,
8770};
8771
Wu Fengguangb25c9da2009-02-06 15:02:27 +08008772static hda_nid_t alc1200_slave_dig_outs[] = {
8773 ALC883_DIGOUT_NID, 0,
8774};
8775
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008776static struct alc_config_preset alc883_presets[] = {
8777 [ALC883_3ST_2ch_DIG] = {
8778 .mixers = { alc883_3ST_2ch_mixer },
8779 .init_verbs = { alc883_init_verbs },
8780 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8781 .dac_nids = alc883_dac_nids,
8782 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008783 .dig_in_nid = ALC883_DIGIN_NID,
8784 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8785 .channel_mode = alc883_3ST_2ch_modes,
8786 .input_mux = &alc883_capture_source,
8787 },
8788 [ALC883_3ST_6ch_DIG] = {
8789 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
8790 .init_verbs = { alc883_init_verbs },
8791 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8792 .dac_nids = alc883_dac_nids,
8793 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008794 .dig_in_nid = ALC883_DIGIN_NID,
8795 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
8796 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02008797 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008798 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008799 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008800 [ALC883_3ST_6ch] = {
8801 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
8802 .init_verbs = { alc883_init_verbs },
8803 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8804 .dac_nids = alc883_dac_nids,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008805 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
8806 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02008807 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008808 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008809 },
Jiang zhe17bba1b2008-06-04 12:11:07 +02008810 [ALC883_3ST_6ch_INTEL] = {
8811 .mixers = { alc883_3ST_6ch_intel_mixer, alc883_chmode_mixer },
8812 .init_verbs = { alc883_init_verbs },
8813 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8814 .dac_nids = alc883_dac_nids,
8815 .dig_out_nid = ALC883_DIGOUT_NID,
8816 .dig_in_nid = ALC883_DIGIN_NID,
Wu Fengguangf3cd3f52009-04-02 19:44:18 +08008817 .slave_dig_outs = alc883_slave_dig_outs,
Jiang zhe17bba1b2008-06-04 12:11:07 +02008818 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_intel_modes),
8819 .channel_mode = alc883_3ST_6ch_intel_modes,
8820 .need_dac_fix = 1,
8821 .input_mux = &alc883_3stack_6ch_intel,
8822 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008823 [ALC883_6ST_DIG] = {
8824 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
8825 .init_verbs = { alc883_init_verbs },
8826 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8827 .dac_nids = alc883_dac_nids,
8828 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008829 .dig_in_nid = ALC883_DIGIN_NID,
8830 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
8831 .channel_mode = alc883_sixstack_modes,
8832 .input_mux = &alc883_capture_source,
8833 },
Kailang Yangccc656c2006-10-17 12:32:26 +02008834 [ALC883_TARGA_DIG] = {
8835 .mixers = { alc883_tagra_mixer, alc883_chmode_mixer },
8836 .init_verbs = { alc883_init_verbs, alc883_tagra_verbs},
8837 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8838 .dac_nids = alc883_dac_nids,
8839 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +02008840 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
8841 .channel_mode = alc883_3ST_6ch_modes,
8842 .need_dac_fix = 1,
8843 .input_mux = &alc883_capture_source,
8844 .unsol_event = alc883_tagra_unsol_event,
8845 .init_hook = alc883_tagra_automute,
8846 },
8847 [ALC883_TARGA_2ch_DIG] = {
8848 .mixers = { alc883_tagra_2ch_mixer},
8849 .init_verbs = { alc883_init_verbs, alc883_tagra_verbs},
8850 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8851 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01008852 .adc_nids = alc883_adc_nids_alt,
8853 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Kailang Yangccc656c2006-10-17 12:32:26 +02008854 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +02008855 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8856 .channel_mode = alc883_3ST_2ch_modes,
8857 .input_mux = &alc883_capture_source,
8858 .unsol_event = alc883_tagra_unsol_event,
8859 .init_hook = alc883_tagra_automute,
8860 },
Vladimir Avdoninbab282b2006-08-22 13:31:58 +02008861 [ALC883_ACER] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02008862 .mixers = { alc883_base_mixer },
Vladimir Avdoninbab282b2006-08-22 13:31:58 +02008863 /* On TravelMate laptops, GPIO 0 enables the internal speaker
8864 * and the headphone jack. Turn this on and rely on the
8865 * standard mute methods whenever the user wants to turn
8866 * these outputs off.
8867 */
8868 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs },
8869 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8870 .dac_nids = alc883_dac_nids,
Vladimir Avdoninbab282b2006-08-22 13:31:58 +02008871 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8872 .channel_mode = alc883_3ST_2ch_modes,
8873 .input_mux = &alc883_capture_source,
8874 },
Tobin Davis2880a862007-08-07 11:50:26 +02008875 [ALC883_ACER_ASPIRE] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02008876 .mixers = { alc883_acer_aspire_mixer },
Kailang Yangd1a991a2007-08-15 16:21:59 +02008877 .init_verbs = { alc883_init_verbs, alc883_acer_eapd_verbs },
Tobin Davis2880a862007-08-07 11:50:26 +02008878 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8879 .dac_nids = alc883_dac_nids,
8880 .dig_out_nid = ALC883_DIGOUT_NID,
Tobin Davis2880a862007-08-07 11:50:26 +02008881 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8882 .channel_mode = alc883_3ST_2ch_modes,
8883 .input_mux = &alc883_capture_source,
Takashi Iwai676a9b52007-08-16 15:23:35 +02008884 .unsol_event = alc883_acer_aspire_unsol_event,
8885 .init_hook = alc883_acer_aspire_automute,
Kailang Yangd1a991a2007-08-15 16:21:59 +02008886 },
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08008887 [ALC888_ACER_ASPIRE_4930G] = {
Vincent Petryef8ef5f2008-11-23 11:31:41 +08008888 .mixers = { alc888_base_mixer,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08008889 alc883_chmode_mixer },
8890 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
8891 alc888_acer_aspire_4930g_verbs },
8892 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8893 .dac_nids = alc883_dac_nids,
8894 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
8895 .adc_nids = alc883_adc_nids_rev,
8896 .capsrc_nids = alc883_capsrc_nids_rev,
8897 .dig_out_nid = ALC883_DIGOUT_NID,
8898 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
8899 .channel_mode = alc883_3ST_6ch_modes,
8900 .need_dac_fix = 1,
8901 .num_mux_defs =
Vincent Petryef8ef5f2008-11-23 11:31:41 +08008902 ARRAY_SIZE(alc888_2_capture_sources),
8903 .input_mux = alc888_2_capture_sources,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08008904 .unsol_event = alc888_acer_aspire_4930g_unsol_event,
8905 .init_hook = alc888_acer_aspire_4930g_automute,
8906 },
Tobin Davisc07584c2006-10-13 12:32:16 +02008907 [ALC883_MEDION] = {
8908 .mixers = { alc883_fivestack_mixer,
8909 alc883_chmode_mixer },
8910 .init_verbs = { alc883_init_verbs,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008911 alc883_medion_eapd_verbs },
Tobin Davisc07584c2006-10-13 12:32:16 +02008912 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8913 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01008914 .adc_nids = alc883_adc_nids_alt,
8915 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Tobin Davisc07584c2006-10-13 12:32:16 +02008916 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
8917 .channel_mode = alc883_sixstack_modes,
8918 .input_mux = &alc883_capture_source,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008919 },
Kailang Yang272a5272007-05-14 11:00:38 +02008920 [ALC883_MEDION_MD2] = {
8921 .mixers = { alc883_medion_md2_mixer},
8922 .init_verbs = { alc883_init_verbs, alc883_medion_md2_verbs},
8923 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8924 .dac_nids = alc883_dac_nids,
8925 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang272a5272007-05-14 11:00:38 +02008926 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8927 .channel_mode = alc883_3ST_2ch_modes,
8928 .input_mux = &alc883_capture_source,
8929 .unsol_event = alc883_medion_md2_unsol_event,
8930 .init_hook = alc883_medion_md2_automute,
Kailang Yangea1fb292008-08-26 12:58:38 +02008931 },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008932 [ALC883_LAPTOP_EAPD] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02008933 .mixers = { alc883_base_mixer },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008934 .init_verbs = { alc883_init_verbs, alc882_eapd_verbs },
8935 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8936 .dac_nids = alc883_dac_nids,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008937 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8938 .channel_mode = alc883_3ST_2ch_modes,
8939 .input_mux = &alc883_capture_source,
8940 },
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008941 [ALC883_CLEVO_M720] = {
8942 .mixers = { alc883_clevo_m720_mixer },
8943 .init_verbs = { alc883_init_verbs, alc883_clevo_m720_verbs },
Jiang zhe368c7a92008-03-04 11:20:33 +01008944 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8945 .dac_nids = alc883_dac_nids,
8946 .dig_out_nid = ALC883_DIGOUT_NID,
8947 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8948 .channel_mode = alc883_3ST_2ch_modes,
8949 .input_mux = &alc883_capture_source,
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008950 .unsol_event = alc883_clevo_m720_unsol_event,
8951 .init_hook = alc883_clevo_m720_automute,
Jiang zhe368c7a92008-03-04 11:20:33 +01008952 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008953 [ALC883_LENOVO_101E_2ch] = {
8954 .mixers = { alc883_lenovo_101e_2ch_mixer},
8955 .init_verbs = { alc883_init_verbs, alc883_lenovo_101e_verbs},
8956 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8957 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01008958 .adc_nids = alc883_adc_nids_alt,
8959 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008960 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8961 .channel_mode = alc883_3ST_2ch_modes,
8962 .input_mux = &alc883_lenovo_101e_capture_source,
8963 .unsol_event = alc883_lenovo_101e_unsol_event,
8964 .init_hook = alc883_lenovo_101e_all_automute,
8965 },
Kailang Yang272a5272007-05-14 11:00:38 +02008966 [ALC883_LENOVO_NB0763] = {
8967 .mixers = { alc883_lenovo_nb0763_mixer },
8968 .init_verbs = { alc883_init_verbs, alc883_lenovo_nb0763_verbs},
8969 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8970 .dac_nids = alc883_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +02008971 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8972 .channel_mode = alc883_3ST_2ch_modes,
8973 .need_dac_fix = 1,
8974 .input_mux = &alc883_lenovo_nb0763_capture_source,
8975 .unsol_event = alc883_medion_md2_unsol_event,
8976 .init_hook = alc883_medion_md2_automute,
8977 },
8978 [ALC888_LENOVO_MS7195_DIG] = {
8979 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
8980 .init_verbs = { alc883_init_verbs, alc888_lenovo_ms7195_verbs},
8981 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8982 .dac_nids = alc883_dac_nids,
8983 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang272a5272007-05-14 11:00:38 +02008984 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
8985 .channel_mode = alc883_3ST_6ch_modes,
8986 .need_dac_fix = 1,
8987 .input_mux = &alc883_capture_source,
8988 .unsol_event = alc883_lenovo_ms7195_unsol_event,
8989 .init_hook = alc888_lenovo_ms7195_front_automute,
Kailang Yang189609a2007-08-20 11:31:23 +02008990 },
8991 [ALC883_HAIER_W66] = {
8992 .mixers = { alc883_tagra_2ch_mixer},
8993 .init_verbs = { alc883_init_verbs, alc883_haier_w66_verbs},
8994 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8995 .dac_nids = alc883_dac_nids,
8996 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang189609a2007-08-20 11:31:23 +02008997 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8998 .channel_mode = alc883_3ST_2ch_modes,
8999 .input_mux = &alc883_capture_source,
9000 .unsol_event = alc883_haier_w66_unsol_event,
9001 .init_hook = alc883_haier_w66_automute,
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +01009002 },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009003 [ALC888_3ST_HP] = {
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +01009004 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009005 .init_verbs = { alc883_init_verbs, alc888_3st_hp_verbs },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009006 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9007 .dac_nids = alc883_dac_nids,
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009008 .num_channel_mode = ARRAY_SIZE(alc888_3st_hp_modes),
9009 .channel_mode = alc888_3st_hp_modes,
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009010 .need_dac_fix = 1,
9011 .input_mux = &alc883_capture_source,
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009012 .unsol_event = alc888_3st_hp_unsol_event,
9013 .init_hook = alc888_3st_hp_front_automute,
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009014 },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009015 [ALC888_6ST_DELL] = {
Herton Ronaldo Krzesinskif24dbdc2008-03-20 12:14:28 +01009016 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009017 .init_verbs = { alc883_init_verbs, alc888_6st_dell_verbs },
9018 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9019 .dac_nids = alc883_dac_nids,
9020 .dig_out_nid = ALC883_DIGOUT_NID,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009021 .dig_in_nid = ALC883_DIGIN_NID,
9022 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
9023 .channel_mode = alc883_sixstack_modes,
9024 .input_mux = &alc883_capture_source,
9025 .unsol_event = alc888_6st_dell_unsol_event,
9026 .init_hook = alc888_6st_dell_front_automute,
9027 },
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009028 [ALC883_MITAC] = {
9029 .mixers = { alc883_mitac_mixer },
9030 .init_verbs = { alc883_init_verbs, alc883_mitac_verbs },
9031 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9032 .dac_nids = alc883_dac_nids,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009033 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9034 .channel_mode = alc883_3ST_2ch_modes,
9035 .input_mux = &alc883_capture_source,
9036 .unsol_event = alc883_mitac_unsol_event,
9037 .init_hook = alc883_mitac_automute,
9038 },
Jiang zhefb97dc62008-03-06 11:07:11 +01009039 [ALC883_FUJITSU_PI2515] = {
9040 .mixers = { alc883_2ch_fujitsu_pi2515_mixer },
9041 .init_verbs = { alc883_init_verbs,
9042 alc883_2ch_fujitsu_pi2515_verbs},
9043 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9044 .dac_nids = alc883_dac_nids,
9045 .dig_out_nid = ALC883_DIGOUT_NID,
9046 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9047 .channel_mode = alc883_3ST_2ch_modes,
9048 .input_mux = &alc883_fujitsu_pi2515_capture_source,
9049 .unsol_event = alc883_2ch_fujitsu_pi2515_unsol_event,
9050 .init_hook = alc883_2ch_fujitsu_pi2515_automute,
9051 },
Vincent Petryef8ef5f2008-11-23 11:31:41 +08009052 [ALC888_FUJITSU_XA3530] = {
9053 .mixers = { alc888_base_mixer, alc883_chmode_mixer },
9054 .init_verbs = { alc883_init_verbs,
9055 alc888_fujitsu_xa3530_verbs },
9056 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9057 .dac_nids = alc883_dac_nids,
9058 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
9059 .adc_nids = alc883_adc_nids_rev,
9060 .capsrc_nids = alc883_capsrc_nids_rev,
9061 .dig_out_nid = ALC883_DIGOUT_NID,
9062 .num_channel_mode = ARRAY_SIZE(alc888_4ST_8ch_intel_modes),
9063 .channel_mode = alc888_4ST_8ch_intel_modes,
9064 .num_mux_defs =
9065 ARRAY_SIZE(alc888_2_capture_sources),
9066 .input_mux = alc888_2_capture_sources,
9067 .unsol_event = alc888_fujitsu_xa3530_unsol_event,
9068 .init_hook = alc888_fujitsu_xa3530_automute,
9069 },
Kailang Yange2757d52008-08-26 13:17:46 +02009070 [ALC888_LENOVO_SKY] = {
9071 .mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer },
9072 .init_verbs = { alc883_init_verbs, alc888_lenovo_sky_verbs},
9073 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9074 .dac_nids = alc883_dac_nids,
9075 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yange2757d52008-08-26 13:17:46 +02009076 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
9077 .channel_mode = alc883_sixstack_modes,
9078 .need_dac_fix = 1,
9079 .input_mux = &alc883_lenovo_sky_capture_source,
9080 .unsol_event = alc883_lenovo_sky_unsol_event,
9081 .init_hook = alc888_lenovo_sky_front_automute,
9082 },
9083 [ALC888_ASUS_M90V] = {
9084 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
9085 .init_verbs = { alc883_init_verbs, alc888_asus_m90v_verbs },
9086 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9087 .dac_nids = alc883_dac_nids,
9088 .dig_out_nid = ALC883_DIGOUT_NID,
9089 .dig_in_nid = ALC883_DIGIN_NID,
9090 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
9091 .channel_mode = alc883_3ST_6ch_modes,
9092 .need_dac_fix = 1,
9093 .input_mux = &alc883_fujitsu_pi2515_capture_source,
9094 .unsol_event = alc883_mode2_unsol_event,
9095 .init_hook = alc883_mode2_inithook,
9096 },
9097 [ALC888_ASUS_EEE1601] = {
9098 .mixers = { alc883_asus_eee1601_mixer },
Takashi Iwaif9e336f2008-10-31 16:37:07 +01009099 .cap_mixer = alc883_asus_eee1601_cap_mixer,
Kailang Yange2757d52008-08-26 13:17:46 +02009100 .init_verbs = { alc883_init_verbs, alc888_asus_eee1601_verbs },
9101 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9102 .dac_nids = alc883_dac_nids,
9103 .dig_out_nid = ALC883_DIGOUT_NID,
9104 .dig_in_nid = ALC883_DIGIN_NID,
9105 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9106 .channel_mode = alc883_3ST_2ch_modes,
9107 .need_dac_fix = 1,
9108 .input_mux = &alc883_asus_eee1601_capture_source,
9109 .unsol_event = alc883_eee1601_unsol_event,
9110 .init_hook = alc883_eee1601_inithook,
9111 },
Wu Fengguang3ab90932008-11-17 09:51:09 +01009112 [ALC1200_ASUS_P5Q] = {
9113 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
9114 .init_verbs = { alc883_init_verbs },
9115 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9116 .dac_nids = alc883_dac_nids,
9117 .dig_out_nid = ALC1200_DIGOUT_NID,
9118 .dig_in_nid = ALC883_DIGIN_NID,
Wu Fengguangb25c9da2009-02-06 15:02:27 +08009119 .slave_dig_outs = alc1200_slave_dig_outs,
Wu Fengguang3ab90932008-11-17 09:51:09 +01009120 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
9121 .channel_mode = alc883_sixstack_modes,
9122 .input_mux = &alc883_capture_source,
9123 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009124};
9125
9126
9127/*
9128 * BIOS auto configuration
9129 */
9130static void alc883_auto_set_output_and_unmute(struct hda_codec *codec,
9131 hda_nid_t nid, int pin_type,
9132 int dac_idx)
9133{
9134 /* set as output */
9135 struct alc_spec *spec = codec->spec;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009136 int idx;
9137
Takashi Iwaif6c7e542008-02-12 18:32:23 +01009138 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009139 if (spec->multiout.dac_nids[dac_idx] == 0x25)
9140 idx = 4;
9141 else
9142 idx = spec->multiout.dac_nids[dac_idx] - 2;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009143 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
9144
9145}
9146
9147static void alc883_auto_init_multi_out(struct hda_codec *codec)
9148{
9149 struct alc_spec *spec = codec->spec;
9150 int i;
9151
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009152 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009153 for (i = 0; i <= HDA_SIDE; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009154 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02009155 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009156 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02009157 alc883_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009158 i);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009159 }
9160}
9161
9162static void alc883_auto_init_hp_out(struct hda_codec *codec)
9163{
9164 struct alc_spec *spec = codec->spec;
9165 hda_nid_t pin;
9166
Takashi Iwaieb06ed82006-09-20 17:10:27 +02009167 pin = spec->autocfg.hp_pins[0];
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009168 if (pin) /* connect to front */
9169 /* use dac 0 */
9170 alc883_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01009171 pin = spec->autocfg.speaker_pins[0];
9172 if (pin)
9173 alc883_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009174}
9175
9176#define alc883_is_input_pin(nid) alc880_is_input_pin(nid)
9177#define ALC883_PIN_CD_NID ALC880_PIN_CD_NID
9178
9179static void alc883_auto_init_analog_input(struct hda_codec *codec)
9180{
9181 struct alc_spec *spec = codec->spec;
9182 int i;
9183
9184 for (i = 0; i < AUTO_PIN_LAST; i++) {
9185 hda_nid_t nid = spec->autocfg.input_pins[i];
9186 if (alc883_is_input_pin(nid)) {
Takashi Iwai23f0c042009-02-26 13:03:58 +01009187 alc_set_input_pin(codec, nid, i);
Takashi Iwaie82c0252009-03-23 15:17:38 +01009188 if (nid != ALC883_PIN_CD_NID &&
9189 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009190 snd_hda_codec_write(codec, nid, 0,
9191 AC_VERB_SET_AMP_GAIN_MUTE,
9192 AMP_OUT_MUTE);
9193 }
9194 }
9195}
9196
Takashi Iwaif511b012008-08-15 16:46:42 +02009197#define alc883_auto_init_input_src alc882_auto_init_input_src
9198
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009199/* almost identical with ALC880 parser... */
9200static int alc883_parse_auto_config(struct hda_codec *codec)
9201{
9202 struct alc_spec *spec = codec->spec;
9203 int err = alc880_parse_auto_config(codec);
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02009204 struct auto_pin_cfg *cfg = &spec->autocfg;
9205 int i;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009206
9207 if (err < 0)
9208 return err;
Takashi Iwai776e1842007-08-29 15:07:11 +02009209 else if (!err)
9210 return 0; /* no config found */
9211
9212 err = alc_auto_add_mic_boost(codec);
9213 if (err < 0)
9214 return err;
9215
9216 /* hack - override the init verbs */
9217 spec->init_verbs[0] = alc883_auto_init_verbs;
Takashi Iwai776e1842007-08-29 15:07:11 +02009218
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02009219 /* setup input_mux for ALC889 */
9220 if (codec->vendor_id == 0x10ec0889) {
9221 /* digital-mic input pin is excluded in alc880_auto_create..()
9222 * because it's under 0x18
9223 */
9224 if (cfg->input_pins[AUTO_PIN_MIC] == 0x12 ||
9225 cfg->input_pins[AUTO_PIN_FRONT_MIC] == 0x12) {
9226 struct hda_input_mux *imux = &spec->private_imux[0];
9227 for (i = 1; i < 3; i++)
9228 memcpy(&spec->private_imux[i],
9229 &spec->private_imux[0],
9230 sizeof(spec->private_imux[0]));
9231 imux->items[imux->num_items].label = "Int DMic";
9232 imux->items[imux->num_items].index = 0x0b;
9233 imux->num_items++;
9234 spec->num_mux_defs = 3;
9235 spec->input_mux = spec->private_imux;
9236 }
9237 }
9238
Takashi Iwai776e1842007-08-29 15:07:11 +02009239 return 1; /* config found */
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009240}
9241
9242/* additional initialization for auto-configuration model */
9243static void alc883_auto_init(struct hda_codec *codec)
9244{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01009245 struct alc_spec *spec = codec->spec;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009246 alc883_auto_init_multi_out(codec);
9247 alc883_auto_init_hp_out(codec);
9248 alc883_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +02009249 alc883_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01009250 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02009251 alc_inithook(codec);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009252}
9253
9254static int patch_alc883(struct hda_codec *codec)
9255{
9256 struct alc_spec *spec;
9257 int err, board_config;
9258
9259 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
9260 if (spec == NULL)
9261 return -ENOMEM;
9262
9263 codec->spec = spec;
9264
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02009265 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
9266
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009267 board_config = snd_hda_check_board_config(codec, ALC883_MODEL_LAST,
9268 alc883_models,
9269 alc883_cfg_tbl);
9270 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009271 printk(KERN_INFO "hda_codec: Unknown model for ALC883, "
9272 "trying auto-probe from BIOS...\n");
9273 board_config = ALC883_AUTO;
9274 }
9275
9276 if (board_config == ALC883_AUTO) {
9277 /* automatic parse from the BIOS config */
9278 err = alc883_parse_auto_config(codec);
9279 if (err < 0) {
9280 alc_free(codec);
9281 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009282 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009283 printk(KERN_INFO
9284 "hda_codec: Cannot set up configuration "
9285 "from BIOS. Using base mode...\n");
9286 board_config = ALC883_3ST_2ch_DIG;
9287 }
9288 }
9289
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09009290 err = snd_hda_attach_beep_device(codec, 0x1);
9291 if (err < 0) {
9292 alc_free(codec);
9293 return err;
9294 }
9295
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009296 if (board_config != ALC883_AUTO)
9297 setup_preset(spec, &alc883_presets[board_config]);
9298
Kailang Yang2f893282008-05-27 12:14:47 +02009299 switch (codec->vendor_id) {
9300 case 0x10ec0888:
Kailang Yang44426082008-10-15 11:18:05 +02009301 if (codec->revision_id == 0x100101) {
9302 spec->stream_name_analog = "ALC1200 Analog";
9303 spec->stream_name_digital = "ALC1200 Digital";
9304 } else {
9305 spec->stream_name_analog = "ALC888 Analog";
9306 spec->stream_name_digital = "ALC888 Digital";
9307 }
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02009308 if (!spec->num_adc_nids) {
9309 spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids);
9310 spec->adc_nids = alc883_adc_nids;
9311 }
9312 if (!spec->capsrc_nids)
9313 spec->capsrc_nids = alc883_capsrc_nids;
9314 spec->capture_style = CAPT_MIX; /* matrix-style capture */
Kailang Yang2f893282008-05-27 12:14:47 +02009315 break;
9316 case 0x10ec0889:
9317 spec->stream_name_analog = "ALC889 Analog";
9318 spec->stream_name_digital = "ALC889 Digital";
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02009319 if (!spec->num_adc_nids) {
9320 spec->num_adc_nids = ARRAY_SIZE(alc889_adc_nids);
9321 spec->adc_nids = alc889_adc_nids;
9322 }
9323 if (!spec->capsrc_nids)
9324 spec->capsrc_nids = alc889_capsrc_nids;
9325 spec->capture_style = CAPT_1MUX_MIX; /* 1mux/Nmix-style
9326 capture */
Kailang Yang2f893282008-05-27 12:14:47 +02009327 break;
9328 default:
9329 spec->stream_name_analog = "ALC883 Analog";
9330 spec->stream_name_digital = "ALC883 Digital";
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02009331 if (!spec->num_adc_nids) {
9332 spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids);
9333 spec->adc_nids = alc883_adc_nids;
9334 }
9335 if (!spec->capsrc_nids)
9336 spec->capsrc_nids = alc883_capsrc_nids;
9337 spec->capture_style = CAPT_MIX; /* matrix-style capture */
Kailang Yang2f893282008-05-27 12:14:47 +02009338 break;
9339 }
9340
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009341 spec->stream_analog_playback = &alc883_pcm_analog_playback;
9342 spec->stream_analog_capture = &alc883_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01009343 spec->stream_analog_alt_capture = &alc883_pcm_analog_alt_capture;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009344
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009345 spec->stream_digital_playback = &alc883_pcm_digital_playback;
9346 spec->stream_digital_capture = &alc883_pcm_digital_capture;
9347
Takashi Iwaif9e336f2008-10-31 16:37:07 +01009348 if (!spec->cap_mixer)
9349 set_capture_mixer(spec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01009350 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009351
Takashi Iwai2134ea42008-01-10 16:53:55 +01009352 spec->vmaster_nid = 0x0c;
9353
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009354 codec->patch_ops = alc_patch_ops;
9355 if (board_config == ALC883_AUTO)
9356 spec->init_hook = alc883_auto_init;
Kailang Yangf9423e72008-05-27 12:32:25 +02009357
Takashi Iwaicb53c622007-08-10 17:21:45 +02009358#ifdef CONFIG_SND_HDA_POWER_SAVE
9359 if (!spec->loopback.amplist)
9360 spec->loopback.amplist = alc883_loopbacks;
9361#endif
Takashi Iwaidaead532008-11-28 12:55:36 +01009362 codec->proc_widget_hook = print_realtek_coef;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009363
9364 return 0;
9365}
9366
9367/*
Kailang Yangdf694da2005-12-05 19:42:22 +01009368 * ALC262 support
9369 */
9370
9371#define ALC262_DIGOUT_NID ALC880_DIGOUT_NID
9372#define ALC262_DIGIN_NID ALC880_DIGIN_NID
9373
9374#define alc262_dac_nids alc260_dac_nids
9375#define alc262_adc_nids alc882_adc_nids
9376#define alc262_adc_nids_alt alc882_adc_nids_alt
Takashi Iwai88c71a92008-02-14 17:27:17 +01009377#define alc262_capsrc_nids alc882_capsrc_nids
9378#define alc262_capsrc_nids_alt alc882_capsrc_nids_alt
Kailang Yangdf694da2005-12-05 19:42:22 +01009379
9380#define alc262_modes alc260_modes
Takashi Iwaic5f2ea02005-12-06 18:54:31 +01009381#define alc262_capture_source alc882_capture_source
Kailang Yangdf694da2005-12-05 19:42:22 +01009382
Kailang Yang4e555fe2008-08-26 13:05:55 +02009383static hda_nid_t alc262_dmic_adc_nids[1] = {
9384 /* ADC0 */
9385 0x09
9386};
9387
9388static hda_nid_t alc262_dmic_capsrc_nids[1] = { 0x22 };
9389
Kailang Yangdf694da2005-12-05 19:42:22 +01009390static struct snd_kcontrol_new alc262_base_mixer[] = {
9391 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9392 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9393 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9394 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9395 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9396 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9397 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9398 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01009399 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01009400 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
9401 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01009402 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01009403 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),
9404 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9405 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
9406 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01009407 { } /* end */
Takashi Iwai834be882006-03-01 14:16:17 +01009408};
9409
Kailang Yangccc656c2006-10-17 12:32:26 +02009410static struct snd_kcontrol_new alc262_hippo1_mixer[] = {
9411 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9412 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9413 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9414 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9415 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9416 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9417 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9418 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01009419 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009420 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
9421 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01009422 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009423 /*HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),*/
9424 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
9425 { } /* end */
9426};
9427
Takashi Iwaice875f02008-01-28 18:17:43 +01009428/* update HP, line and mono-out pins according to the master switch */
9429static void alc262_hp_master_update(struct hda_codec *codec)
9430{
9431 struct alc_spec *spec = codec->spec;
9432 int val = spec->master_sw;
9433
9434 /* HP & line-out */
9435 snd_hda_codec_write_cache(codec, 0x1b, 0,
9436 AC_VERB_SET_PIN_WIDGET_CONTROL,
9437 val ? PIN_HP : 0);
9438 snd_hda_codec_write_cache(codec, 0x15, 0,
9439 AC_VERB_SET_PIN_WIDGET_CONTROL,
9440 val ? PIN_HP : 0);
9441 /* mono (speaker) depending on the HP jack sense */
9442 val = val && !spec->jack_present;
9443 snd_hda_codec_write_cache(codec, 0x16, 0,
9444 AC_VERB_SET_PIN_WIDGET_CONTROL,
9445 val ? PIN_OUT : 0);
9446}
9447
9448static void alc262_hp_bpc_automute(struct hda_codec *codec)
9449{
9450 struct alc_spec *spec = codec->spec;
9451 unsigned int presence;
9452 presence = snd_hda_codec_read(codec, 0x1b, 0,
9453 AC_VERB_GET_PIN_SENSE, 0);
9454 spec->jack_present = !!(presence & AC_PINSENSE_PRESENCE);
9455 alc262_hp_master_update(codec);
9456}
9457
9458static void alc262_hp_bpc_unsol_event(struct hda_codec *codec, unsigned int res)
9459{
9460 if ((res >> 26) != ALC880_HP_EVENT)
9461 return;
9462 alc262_hp_bpc_automute(codec);
9463}
9464
9465static void alc262_hp_wildwest_automute(struct hda_codec *codec)
9466{
9467 struct alc_spec *spec = codec->spec;
9468 unsigned int presence;
9469 presence = snd_hda_codec_read(codec, 0x15, 0,
9470 AC_VERB_GET_PIN_SENSE, 0);
9471 spec->jack_present = !!(presence & AC_PINSENSE_PRESENCE);
9472 alc262_hp_master_update(codec);
9473}
9474
9475static void alc262_hp_wildwest_unsol_event(struct hda_codec *codec,
9476 unsigned int res)
9477{
9478 if ((res >> 26) != ALC880_HP_EVENT)
9479 return;
9480 alc262_hp_wildwest_automute(codec);
9481}
9482
9483static int alc262_hp_master_sw_get(struct snd_kcontrol *kcontrol,
9484 struct snd_ctl_elem_value *ucontrol)
9485{
9486 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
9487 struct alc_spec *spec = codec->spec;
9488 *ucontrol->value.integer.value = spec->master_sw;
9489 return 0;
9490}
9491
9492static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol,
9493 struct snd_ctl_elem_value *ucontrol)
9494{
9495 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
9496 struct alc_spec *spec = codec->spec;
9497 int val = !!*ucontrol->value.integer.value;
9498
9499 if (val == spec->master_sw)
9500 return 0;
9501 spec->master_sw = val;
9502 alc262_hp_master_update(codec);
9503 return 1;
9504}
9505
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009506static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
Takashi Iwaice875f02008-01-28 18:17:43 +01009507 {
9508 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9509 .name = "Master Playback Switch",
9510 .info = snd_ctl_boolean_mono_info,
9511 .get = alc262_hp_master_sw_get,
9512 .put = alc262_hp_master_sw_put,
9513 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009514 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9515 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9516 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +01009517 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
9518 HDA_OUTPUT),
9519 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
9520 HDA_OUTPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009521 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9522 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01009523 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009524 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
9525 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01009526 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009527 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9528 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9529 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9530 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009531 HDA_CODEC_VOLUME("AUX IN Playback Volume", 0x0b, 0x06, HDA_INPUT),
9532 HDA_CODEC_MUTE("AUX IN Playback Switch", 0x0b, 0x06, HDA_INPUT),
9533 { } /* end */
9534};
9535
Kailang Yangcd7509a2007-01-26 18:33:17 +01009536static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = {
Takashi Iwaice875f02008-01-28 18:17:43 +01009537 {
9538 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9539 .name = "Master Playback Switch",
9540 .info = snd_ctl_boolean_mono_info,
9541 .get = alc262_hp_master_sw_get,
9542 .put = alc262_hp_master_sw_put,
9543 },
Kailang Yangcd7509a2007-01-26 18:33:17 +01009544 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9545 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
9546 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
9547 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +01009548 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
9549 HDA_OUTPUT),
9550 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
9551 HDA_OUTPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +01009552 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT),
9553 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01009554 HDA_CODEC_VOLUME("Front Mic Boost", 0x1a, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +01009555 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
9556 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
9557 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9558 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +01009559 { } /* end */
9560};
9561
9562static struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = {
9563 HDA_CODEC_VOLUME("Rear Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9564 HDA_CODEC_MUTE("Rear Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01009565 HDA_CODEC_VOLUME("Rear Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +01009566 { } /* end */
9567};
9568
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009569/* mute/unmute internal speaker according to the hp jack and mute state */
9570static void alc262_hp_t5735_automute(struct hda_codec *codec, int force)
9571{
9572 struct alc_spec *spec = codec->spec;
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009573
9574 if (force || !spec->sense_updated) {
9575 unsigned int present;
9576 present = snd_hda_codec_read(codec, 0x15, 0,
9577 AC_VERB_GET_PIN_SENSE, 0);
Takashi Iwai4bb26132008-01-28 18:12:42 +01009578 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009579 spec->sense_updated = 1;
9580 }
Takashi Iwai4bb26132008-01-28 18:12:42 +01009581 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0, HDA_AMP_MUTE,
9582 spec->jack_present ? HDA_AMP_MUTE : 0);
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009583}
9584
9585static void alc262_hp_t5735_unsol_event(struct hda_codec *codec,
9586 unsigned int res)
9587{
9588 if ((res >> 26) != ALC880_HP_EVENT)
9589 return;
9590 alc262_hp_t5735_automute(codec, 1);
9591}
9592
9593static void alc262_hp_t5735_init_hook(struct hda_codec *codec)
9594{
9595 alc262_hp_t5735_automute(codec, 1);
9596}
9597
9598static struct snd_kcontrol_new alc262_hp_t5735_mixer[] = {
Takashi Iwai86cd9292008-01-28 18:09:56 +01009599 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9600 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009601 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
9602 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9603 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9604 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9605 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9606 { } /* end */
9607};
9608
9609static struct hda_verb alc262_hp_t5735_verbs[] = {
9610 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9611 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9612
9613 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9614 { }
9615};
9616
Kailang Yang8c427222008-01-10 13:03:59 +01009617static struct snd_kcontrol_new alc262_hp_rp5700_mixer[] = {
Takashi Iwaif2f48e12008-01-28 18:14:43 +01009618 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9619 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01009620 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
9621 HDA_CODEC_MUTE("Speaker Playback Switch", 0x16, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +01009622 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
9623 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
9624 { } /* end */
9625};
9626
9627static struct hda_verb alc262_hp_rp5700_verbs[] = {
9628 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9629 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9630 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9631 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9632 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
9633 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
9634 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
9635 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
9636 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
9637 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
9638 {}
9639};
9640
9641static struct hda_input_mux alc262_hp_rp5700_capture_source = {
9642 .num_items = 1,
9643 .items = {
9644 { "Line", 0x1 },
9645 },
9646};
9647
Takashi Iwai0724ea22007-08-23 00:31:43 +02009648/* bind hp and internal speaker mute (with plug check) */
9649static int alc262_sony_master_sw_put(struct snd_kcontrol *kcontrol,
9650 struct snd_ctl_elem_value *ucontrol)
9651{
9652 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
9653 long *valp = ucontrol->value.integer.value;
9654 int change;
9655
9656 /* change hp mute */
9657 change = snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0,
9658 HDA_AMP_MUTE,
9659 valp[0] ? 0 : HDA_AMP_MUTE);
9660 change |= snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0,
9661 HDA_AMP_MUTE,
9662 valp[1] ? 0 : HDA_AMP_MUTE);
9663 if (change) {
9664 /* change speaker according to HP jack state */
9665 struct alc_spec *spec = codec->spec;
9666 unsigned int mute;
9667 if (spec->jack_present)
9668 mute = HDA_AMP_MUTE;
9669 else
9670 mute = snd_hda_codec_amp_read(codec, 0x15, 0,
9671 HDA_OUTPUT, 0);
9672 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9673 HDA_AMP_MUTE, mute);
9674 }
9675 return change;
9676}
Takashi Iwai5b319542007-07-26 11:49:22 +02009677
Kailang Yang272a5272007-05-14 11:00:38 +02009678static struct snd_kcontrol_new alc262_sony_mixer[] = {
Takashi Iwai0724ea22007-08-23 00:31:43 +02009679 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9680 {
9681 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9682 .name = "Master Playback Switch",
9683 .info = snd_hda_mixer_amp_switch_info,
9684 .get = snd_hda_mixer_amp_switch_get,
9685 .put = alc262_sony_master_sw_put,
9686 .private_value = HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
9687 },
Kailang Yang272a5272007-05-14 11:00:38 +02009688 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9689 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9690 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
9691 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
9692 { } /* end */
9693};
9694
Kailang Yang83c34212007-07-05 11:43:05 +02009695static struct snd_kcontrol_new alc262_benq_t31_mixer[] = {
9696 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9697 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9698 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9699 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9700 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9701 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
9702 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
9703 { } /* end */
9704};
Kailang Yang272a5272007-05-14 11:00:38 +02009705
Tony Vroonba340e82009-02-02 19:01:30 +00009706static struct snd_kcontrol_new alc262_tyan_mixer[] = {
9707 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9708 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
9709 HDA_CODEC_VOLUME("Aux Playback Volume", 0x0b, 0x06, HDA_INPUT),
9710 HDA_CODEC_MUTE("Aux Playback Switch", 0x0b, 0x06, HDA_INPUT),
9711 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9712 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9713 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9714 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9715 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9716 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
9717 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
9718 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
9719 { } /* end */
9720};
9721
9722static struct hda_verb alc262_tyan_verbs[] = {
9723 /* Headphone automute */
9724 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
9725 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9726 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9727
9728 /* P11 AUX_IN, white 4-pin connector */
9729 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
9730 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_1, 0xe1},
9731 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_2, 0x93},
9732 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0x19},
9733
9734 {}
9735};
9736
9737/* unsolicited event for HP jack sensing */
9738static void alc262_tyan_automute(struct hda_codec *codec)
9739{
9740 unsigned int mute;
9741 unsigned int present;
9742
9743 snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
9744 present = snd_hda_codec_read(codec, 0x1b, 0,
9745 AC_VERB_GET_PIN_SENSE, 0);
9746 present = (present & 0x80000000) != 0;
9747 if (present) {
9748 /* mute line output on ATX panel */
9749 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9750 HDA_AMP_MUTE, HDA_AMP_MUTE);
9751 } else {
9752 /* unmute line output if necessary */
9753 mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
9754 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9755 HDA_AMP_MUTE, mute);
9756 }
9757}
9758
9759static void alc262_tyan_unsol_event(struct hda_codec *codec,
9760 unsigned int res)
9761{
9762 if ((res >> 26) != ALC880_HP_EVENT)
9763 return;
9764 alc262_tyan_automute(codec);
9765}
9766
Kailang Yangdf694da2005-12-05 19:42:22 +01009767#define alc262_capture_mixer alc882_capture_mixer
9768#define alc262_capture_alt_mixer alc882_capture_alt_mixer
9769
9770/*
9771 * generic initialization of ADC, input mixers and output mixers
9772 */
9773static struct hda_verb alc262_init_verbs[] = {
9774 /*
9775 * Unmute ADC0-2 and set the default input to mic-in
9776 */
9777 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
9778 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9779 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
9780 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9781 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
9782 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9783
Takashi Iwaicb53c622007-08-10 17:21:45 +02009784 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +01009785 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009786 * Note: PASD motherboards uses the Line In 2 as the input for
9787 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01009788 */
9789 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02009790 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9791 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
9792 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
9793 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
9794 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01009795
9796 /*
9797 * Set up output mixers (0x0c - 0x0e)
9798 */
9799 /* set vol=0 to output mixers */
9800 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9801 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9802 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9803 /* set up input amps for analog loopback */
9804 /* Amp Indices: DAC = 0, mixer = 1 */
9805 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9806 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9807 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9808 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9809 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9810 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9811
9812 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
9813 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
9814 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
9815 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9816 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9817 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9818
9819 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
9820 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
9821 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
9822 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
9823 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Kailang Yangea1fb292008-08-26 12:58:38 +02009824
Kailang Yangdf694da2005-12-05 19:42:22 +01009825 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
9826 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Kailang Yangea1fb292008-08-26 12:58:38 +02009827
Kailang Yangdf694da2005-12-05 19:42:22 +01009828 /* FIXME: use matrix-type input source selection */
9829 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
9830 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
9831 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9832 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
9833 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
9834 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
9835 /* Input mixer2 */
9836 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9837 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
9838 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
9839 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
9840 /* Input mixer3 */
9841 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9842 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
9843 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009844 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
Kailang Yangdf694da2005-12-05 19:42:22 +01009845
9846 { }
9847};
9848
Kailang Yang4e555fe2008-08-26 13:05:55 +02009849static struct hda_verb alc262_eapd_verbs[] = {
9850 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
9851 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
9852 { }
9853};
9854
Kailang Yangccc656c2006-10-17 12:32:26 +02009855static struct hda_verb alc262_hippo_unsol_verbs[] = {
9856 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
9857 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9858 {}
9859};
9860
9861static struct hda_verb alc262_hippo1_unsol_verbs[] = {
9862 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
9863 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
9864 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
9865
9866 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
9867 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9868 {}
9869};
9870
Kailang Yang272a5272007-05-14 11:00:38 +02009871static struct hda_verb alc262_sony_unsol_verbs[] = {
9872 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
9873 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9874 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, // Front Mic
9875
9876 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
9877 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Akio Idehara7b1e8792008-06-09 22:46:07 +09009878 {}
Kailang Yang272a5272007-05-14 11:00:38 +02009879};
9880
Kailang Yang4e555fe2008-08-26 13:05:55 +02009881static struct hda_input_mux alc262_dmic_capture_source = {
9882 .num_items = 2,
9883 .items = {
9884 { "Int DMic", 0x9 },
9885 { "Mic", 0x0 },
9886 },
9887};
9888
9889static struct snd_kcontrol_new alc262_toshiba_s06_mixer[] = {
9890 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9891 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9892 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9893 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9894 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang4e555fe2008-08-26 13:05:55 +02009895 { } /* end */
9896};
9897
9898static struct hda_verb alc262_toshiba_s06_verbs[] = {
9899 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
9900 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9901 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9902 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9903 {0x22, AC_VERB_SET_CONNECT_SEL, 0x09},
9904 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9905 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
9906 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
9907 {}
9908};
9909
9910static void alc262_dmic_automute(struct hda_codec *codec)
9911{
9912 unsigned int present;
9913
9914 present = snd_hda_codec_read(codec, 0x18, 0,
9915 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
9916 snd_hda_codec_write(codec, 0x22, 0,
9917 AC_VERB_SET_CONNECT_SEL, present ? 0x0 : 0x09);
9918}
9919
9920/* toggle speaker-output according to the hp-jack state */
9921static void alc262_toshiba_s06_speaker_automute(struct hda_codec *codec)
9922{
9923 unsigned int present;
9924 unsigned char bits;
9925
9926 present = snd_hda_codec_read(codec, 0x15, 0,
9927 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
9928 bits = present ? 0 : PIN_OUT;
9929 snd_hda_codec_write(codec, 0x14, 0,
9930 AC_VERB_SET_PIN_WIDGET_CONTROL, bits);
9931}
9932
9933
9934
9935/* unsolicited event for HP jack sensing */
9936static void alc262_toshiba_s06_unsol_event(struct hda_codec *codec,
9937 unsigned int res)
9938{
9939 if ((res >> 26) == ALC880_HP_EVENT)
9940 alc262_toshiba_s06_speaker_automute(codec);
9941 if ((res >> 26) == ALC880_MIC_EVENT)
9942 alc262_dmic_automute(codec);
9943
9944}
9945
9946static void alc262_toshiba_s06_init_hook(struct hda_codec *codec)
9947{
9948 alc262_toshiba_s06_speaker_automute(codec);
9949 alc262_dmic_automute(codec);
9950}
9951
Kailang Yangccc656c2006-10-17 12:32:26 +02009952/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwai5b319542007-07-26 11:49:22 +02009953static void alc262_hippo_automute(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02009954{
9955 struct alc_spec *spec = codec->spec;
9956 unsigned int mute;
Takashi Iwai5b319542007-07-26 11:49:22 +02009957 unsigned int present;
Kailang Yangccc656c2006-10-17 12:32:26 +02009958
Takashi Iwai5b319542007-07-26 11:49:22 +02009959 /* need to execute and sync at first */
9960 snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0);
9961 present = snd_hda_codec_read(codec, 0x15, 0,
9962 AC_VERB_GET_PIN_SENSE, 0);
9963 spec->jack_present = (present & 0x80000000) != 0;
Kailang Yangccc656c2006-10-17 12:32:26 +02009964 if (spec->jack_present) {
9965 /* mute internal speaker */
Takashi Iwai47fd8302007-08-10 17:11:07 +02009966 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9967 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yangccc656c2006-10-17 12:32:26 +02009968 } else {
9969 /* unmute internal speaker if necessary */
9970 mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0);
Takashi Iwai47fd8302007-08-10 17:11:07 +02009971 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9972 HDA_AMP_MUTE, mute);
Kailang Yangccc656c2006-10-17 12:32:26 +02009973 }
9974}
9975
9976/* unsolicited event for HP jack sensing */
9977static void alc262_hippo_unsol_event(struct hda_codec *codec,
9978 unsigned int res)
9979{
9980 if ((res >> 26) != ALC880_HP_EVENT)
9981 return;
Takashi Iwai5b319542007-07-26 11:49:22 +02009982 alc262_hippo_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02009983}
9984
Takashi Iwai5b319542007-07-26 11:49:22 +02009985static void alc262_hippo1_automute(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02009986{
Kailang Yangccc656c2006-10-17 12:32:26 +02009987 unsigned int mute;
Takashi Iwai5b319542007-07-26 11:49:22 +02009988 unsigned int present;
Kailang Yangccc656c2006-10-17 12:32:26 +02009989
Takashi Iwai5b319542007-07-26 11:49:22 +02009990 snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
9991 present = snd_hda_codec_read(codec, 0x1b, 0,
9992 AC_VERB_GET_PIN_SENSE, 0);
9993 present = (present & 0x80000000) != 0;
9994 if (present) {
Kailang Yangccc656c2006-10-17 12:32:26 +02009995 /* mute internal speaker */
Takashi Iwai47fd8302007-08-10 17:11:07 +02009996 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9997 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yangccc656c2006-10-17 12:32:26 +02009998 } else {
9999 /* unmute internal speaker if necessary */
10000 mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
Takashi Iwai47fd8302007-08-10 17:11:07 +020010001 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
10002 HDA_AMP_MUTE, mute);
Kailang Yangccc656c2006-10-17 12:32:26 +020010003 }
10004}
10005
10006/* unsolicited event for HP jack sensing */
10007static void alc262_hippo1_unsol_event(struct hda_codec *codec,
10008 unsigned int res)
10009{
10010 if ((res >> 26) != ALC880_HP_EVENT)
10011 return;
Takashi Iwai5b319542007-07-26 11:49:22 +020010012 alc262_hippo1_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +020010013}
10014
Takashi Iwai834be882006-03-01 14:16:17 +010010015/*
Pascal Terjane8f9ae22008-08-04 14:36:05 +020010016 * nec model
10017 * 0x15 = headphone
10018 * 0x16 = internal speaker
10019 * 0x18 = external mic
10020 */
10021
10022static struct snd_kcontrol_new alc262_nec_mixer[] = {
10023 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
10024 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 0, 0x0, HDA_OUTPUT),
10025
10026 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10027 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
10028 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10029
10030 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
10031 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
10032 { } /* end */
10033};
10034
10035static struct hda_verb alc262_nec_verbs[] = {
10036 /* Unmute Speaker */
10037 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10038
10039 /* Headphone */
10040 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
10041 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
10042
10043 /* External mic to headphone */
10044 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10045 /* External mic to speaker */
10046 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10047 {}
10048};
10049
10050/*
Takashi Iwai834be882006-03-01 14:16:17 +010010051 * fujitsu model
Tony Vroon5d9fab22008-03-14 17:09:18 +010010052 * 0x14 = headphone/spdif-out, 0x15 = internal speaker,
10053 * 0x1b = port replicator headphone out
Takashi Iwai834be882006-03-01 14:16:17 +010010054 */
10055
10056#define ALC_HP_EVENT 0x37
10057
10058static struct hda_verb alc262_fujitsu_unsol_verbs[] = {
10059 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
10060 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Tony Vroon5d9fab22008-03-14 17:09:18 +010010061 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
10062 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai834be882006-03-01 14:16:17 +010010063 {}
10064};
10065
Jiang zhe0e31daf2008-03-20 12:12:39 +010010066static struct hda_verb alc262_lenovo_3000_unsol_verbs[] = {
10067 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
10068 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
10069 {}
10070};
10071
Takashi Iwai834be882006-03-01 14:16:17 +010010072static struct hda_input_mux alc262_fujitsu_capture_source = {
Takashi Iwai39d3ed32007-10-12 15:03:48 +020010073 .num_items = 3,
Takashi Iwai834be882006-03-01 14:16:17 +010010074 .items = {
10075 { "Mic", 0x0 },
Takashi Iwai39d3ed32007-10-12 15:03:48 +020010076 { "Int Mic", 0x1 },
Takashi Iwai834be882006-03-01 14:16:17 +010010077 { "CD", 0x4 },
10078 },
10079};
10080
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010081static struct hda_input_mux alc262_HP_capture_source = {
10082 .num_items = 5,
10083 .items = {
10084 { "Mic", 0x0 },
zhejiangaccbe492007-08-31 12:36:05 +020010085 { "Front Mic", 0x1 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010086 { "Line", 0x2 },
10087 { "CD", 0x4 },
10088 { "AUX IN", 0x6 },
10089 },
10090};
10091
zhejiangaccbe492007-08-31 12:36:05 +020010092static struct hda_input_mux alc262_HP_D7000_capture_source = {
10093 .num_items = 4,
10094 .items = {
10095 { "Mic", 0x0 },
10096 { "Front Mic", 0x2 },
10097 { "Line", 0x1 },
10098 { "CD", 0x4 },
10099 },
10100};
10101
Takashi Iwaiebc7a402008-05-20 09:23:05 +020010102/* mute/unmute internal speaker according to the hp jacks and mute state */
Takashi Iwai834be882006-03-01 14:16:17 +010010103static void alc262_fujitsu_automute(struct hda_codec *codec, int force)
10104{
10105 struct alc_spec *spec = codec->spec;
10106 unsigned int mute;
10107
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010108 if (force || !spec->sense_updated) {
Takashi Iwaiebc7a402008-05-20 09:23:05 +020010109 unsigned int present;
Takashi Iwai834be882006-03-01 14:16:17 +010010110 /* need to execute and sync at first */
10111 snd_hda_codec_read(codec, 0x14, 0, AC_VERB_SET_PIN_SENSE, 0);
Takashi Iwaiebc7a402008-05-20 09:23:05 +020010112 /* check laptop HP jack */
10113 present = snd_hda_codec_read(codec, 0x14, 0,
10114 AC_VERB_GET_PIN_SENSE, 0);
10115 /* need to execute and sync at first */
10116 snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
10117 /* check docking HP jack */
10118 present |= snd_hda_codec_read(codec, 0x1b, 0,
10119 AC_VERB_GET_PIN_SENSE, 0);
10120 if (present & AC_PINSENSE_PRESENCE)
10121 spec->jack_present = 1;
10122 else
10123 spec->jack_present = 0;
Takashi Iwai834be882006-03-01 14:16:17 +010010124 spec->sense_updated = 1;
10125 }
Takashi Iwaiebc7a402008-05-20 09:23:05 +020010126 /* unmute internal speaker only if both HPs are unplugged and
10127 * master switch is on
10128 */
10129 if (spec->jack_present)
10130 mute = HDA_AMP_MUTE;
10131 else
Takashi Iwai834be882006-03-01 14:16:17 +010010132 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
Takashi Iwaiebc7a402008-05-20 09:23:05 +020010133 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
10134 HDA_AMP_MUTE, mute);
Takashi Iwai834be882006-03-01 14:16:17 +010010135}
10136
10137/* unsolicited event for HP jack sensing */
10138static void alc262_fujitsu_unsol_event(struct hda_codec *codec,
10139 unsigned int res)
10140{
10141 if ((res >> 26) != ALC_HP_EVENT)
10142 return;
10143 alc262_fujitsu_automute(codec, 1);
10144}
10145
Takashi Iwaiebc7a402008-05-20 09:23:05 +020010146static void alc262_fujitsu_init_hook(struct hda_codec *codec)
10147{
10148 alc262_fujitsu_automute(codec, 1);
10149}
10150
Takashi Iwai834be882006-03-01 14:16:17 +010010151/* bind volumes of both NID 0x0c and 0x0d */
Takashi Iwaicca3b372007-08-10 17:12:15 +020010152static struct hda_bind_ctls alc262_fujitsu_bind_master_vol = {
10153 .ops = &snd_hda_bind_vol,
10154 .values = {
10155 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT),
10156 HDA_COMPOSE_AMP_VAL(0x0d, 3, 0, HDA_OUTPUT),
10157 0
10158 },
10159};
Takashi Iwai834be882006-03-01 14:16:17 +010010160
Jiang zhe0e31daf2008-03-20 12:12:39 +010010161/* mute/unmute internal speaker according to the hp jack and mute state */
10162static void alc262_lenovo_3000_automute(struct hda_codec *codec, int force)
10163{
10164 struct alc_spec *spec = codec->spec;
10165 unsigned int mute;
10166
10167 if (force || !spec->sense_updated) {
10168 unsigned int present_int_hp;
10169 /* need to execute and sync at first */
10170 snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
10171 present_int_hp = snd_hda_codec_read(codec, 0x1b, 0,
10172 AC_VERB_GET_PIN_SENSE, 0);
10173 spec->jack_present = (present_int_hp & 0x80000000) != 0;
10174 spec->sense_updated = 1;
10175 }
10176 if (spec->jack_present) {
10177 /* mute internal speaker */
10178 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
10179 HDA_AMP_MUTE, HDA_AMP_MUTE);
10180 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
10181 HDA_AMP_MUTE, HDA_AMP_MUTE);
10182 } else {
10183 /* unmute internal speaker if necessary */
10184 mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
10185 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
10186 HDA_AMP_MUTE, mute);
10187 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
10188 HDA_AMP_MUTE, mute);
10189 }
10190}
10191
10192/* unsolicited event for HP jack sensing */
10193static void alc262_lenovo_3000_unsol_event(struct hda_codec *codec,
10194 unsigned int res)
10195{
10196 if ((res >> 26) != ALC_HP_EVENT)
10197 return;
10198 alc262_lenovo_3000_automute(codec, 1);
10199}
10200
Takashi Iwai834be882006-03-01 14:16:17 +010010201/* bind hp and internal speaker mute (with plug check) */
10202static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol,
10203 struct snd_ctl_elem_value *ucontrol)
10204{
10205 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
10206 long *valp = ucontrol->value.integer.value;
10207 int change;
10208
Tony Vroon5d9fab22008-03-14 17:09:18 +010010209 change = snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
10210 HDA_AMP_MUTE,
10211 valp ? 0 : HDA_AMP_MUTE);
10212 change |= snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
10213 HDA_AMP_MUTE,
10214 valp ? 0 : HDA_AMP_MUTE);
10215
Takashi Iwai82beb8f2007-08-10 17:09:26 +020010216 if (change)
10217 alc262_fujitsu_automute(codec, 0);
Takashi Iwai834be882006-03-01 14:16:17 +010010218 return change;
10219}
10220
10221static struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +020010222 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
Takashi Iwai834be882006-03-01 14:16:17 +010010223 {
10224 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10225 .name = "Master Playback Switch",
10226 .info = snd_hda_mixer_amp_switch_info,
10227 .get = snd_hda_mixer_amp_switch_get,
10228 .put = alc262_fujitsu_master_sw_put,
10229 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
10230 },
10231 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
10232 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
10233 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10234 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10235 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai39d3ed32007-10-12 15:03:48 +020010236 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
10237 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
10238 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai834be882006-03-01 14:16:17 +010010239 { } /* end */
10240};
10241
Jiang zhe0e31daf2008-03-20 12:12:39 +010010242/* bind hp and internal speaker mute (with plug check) */
10243static int alc262_lenovo_3000_master_sw_put(struct snd_kcontrol *kcontrol,
10244 struct snd_ctl_elem_value *ucontrol)
10245{
10246 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
10247 long *valp = ucontrol->value.integer.value;
10248 int change;
10249
10250 change = snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
10251 HDA_AMP_MUTE,
10252 valp ? 0 : HDA_AMP_MUTE);
10253
10254 if (change)
10255 alc262_lenovo_3000_automute(codec, 0);
10256 return change;
10257}
10258
10259static struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = {
10260 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
10261 {
10262 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10263 .name = "Master Playback Switch",
10264 .info = snd_hda_mixer_amp_switch_info,
10265 .get = snd_hda_mixer_amp_switch_get,
10266 .put = alc262_lenovo_3000_master_sw_put,
10267 .private_value = HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
10268 },
10269 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
10270 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
10271 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10272 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10273 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
10274 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
10275 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
10276 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
10277 { } /* end */
10278};
10279
Hiroshi Miura9f99a632008-08-28 16:09:06 +020010280static struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = {
10281 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
10282 {
10283 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10284 .name = "Master Playback Switch",
10285 .info = snd_hda_mixer_amp_switch_info,
10286 .get = snd_hda_mixer_amp_switch_get,
10287 .put = alc262_sony_master_sw_put,
10288 .private_value = HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
10289 },
10290 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10291 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
10292 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10293 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
10294 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
10295 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
10296 { } /* end */
10297};
10298
Takashi Iwai304dcaa2006-07-25 14:51:16 +020010299/* additional init verbs for Benq laptops */
10300static struct hda_verb alc262_EAPD_verbs[] = {
10301 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
10302 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
10303 {}
10304};
10305
Kailang Yang83c34212007-07-05 11:43:05 +020010306static struct hda_verb alc262_benq_t31_EAPD_verbs[] = {
10307 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
10308 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
10309
10310 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
10311 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
10312 {}
10313};
10314
Tobin Davisf651b502007-10-26 12:40:47 +020010315/* Samsung Q1 Ultra Vista model setup */
10316static struct snd_kcontrol_new alc262_ultra_mixer[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010317 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
10318 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +020010319 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
10320 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
10321 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010322 HDA_CODEC_VOLUME("Headphone Mic Boost", 0x15, 0, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +020010323 { } /* end */
10324};
10325
10326static struct hda_verb alc262_ultra_verbs[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010327 /* output mixer */
10328 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
10329 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10330 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10331 /* speaker */
10332 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
10333 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10334 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10335 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
10336 /* HP */
Tobin Davisf651b502007-10-26 12:40:47 +020010337 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010338 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10339 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10340 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
10341 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
10342 /* internal mic */
10343 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
10344 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10345 /* ADC, choose mic */
10346 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
10347 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
10348 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10349 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
10350 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
10351 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
10352 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
10353 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
10354 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
10355 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(8)},
Tobin Davisf651b502007-10-26 12:40:47 +020010356 {}
10357};
10358
Tobin Davisf651b502007-10-26 12:40:47 +020010359/* mute/unmute internal speaker according to the hp jack and mute state */
10360static void alc262_ultra_automute(struct hda_codec *codec)
10361{
10362 struct alc_spec *spec = codec->spec;
10363 unsigned int mute;
Tobin Davisf651b502007-10-26 12:40:47 +020010364
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010365 mute = 0;
10366 /* auto-mute only when HP is used as HP */
10367 if (!spec->cur_mux[0]) {
10368 unsigned int present;
10369 /* need to execute and sync at first */
10370 snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0);
10371 present = snd_hda_codec_read(codec, 0x15, 0,
10372 AC_VERB_GET_PIN_SENSE, 0);
10373 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
10374 if (spec->jack_present)
10375 mute = HDA_AMP_MUTE;
Tobin Davisf651b502007-10-26 12:40:47 +020010376 }
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010377 /* mute/unmute internal speaker */
10378 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
10379 HDA_AMP_MUTE, mute);
10380 /* mute/unmute HP */
10381 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
10382 HDA_AMP_MUTE, mute ? 0 : HDA_AMP_MUTE);
Tobin Davisf651b502007-10-26 12:40:47 +020010383}
10384
10385/* unsolicited event for HP jack sensing */
10386static void alc262_ultra_unsol_event(struct hda_codec *codec,
10387 unsigned int res)
10388{
10389 if ((res >> 26) != ALC880_HP_EVENT)
10390 return;
10391 alc262_ultra_automute(codec);
10392}
10393
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010394static struct hda_input_mux alc262_ultra_capture_source = {
10395 .num_items = 2,
10396 .items = {
10397 { "Mic", 0x1 },
10398 { "Headphone", 0x7 },
10399 },
10400};
10401
10402static int alc262_ultra_mux_enum_put(struct snd_kcontrol *kcontrol,
10403 struct snd_ctl_elem_value *ucontrol)
10404{
10405 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
10406 struct alc_spec *spec = codec->spec;
10407 int ret;
10408
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010010409 ret = alc_mux_enum_put(kcontrol, ucontrol);
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010410 if (!ret)
10411 return 0;
10412 /* reprogram the HP pin as mic or HP according to the input source */
10413 snd_hda_codec_write_cache(codec, 0x15, 0,
10414 AC_VERB_SET_PIN_WIDGET_CONTROL,
10415 spec->cur_mux[0] ? PIN_VREF80 : PIN_HP);
10416 alc262_ultra_automute(codec); /* mute/unmute HP */
10417 return ret;
10418}
10419
10420static struct snd_kcontrol_new alc262_ultra_capture_mixer[] = {
10421 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
10422 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
10423 {
10424 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10425 .name = "Capture Source",
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010010426 .info = alc_mux_enum_info,
10427 .get = alc_mux_enum_get,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010428 .put = alc262_ultra_mux_enum_put,
10429 },
10430 { } /* end */
10431};
10432
Kailang Yangdf694da2005-12-05 19:42:22 +010010433/* add playback controls from the parsed DAC table */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010434static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
10435 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010010436{
10437 hda_nid_t nid;
10438 int err;
10439
10440 spec->multiout.num_dacs = 1; /* only use one dac */
10441 spec->multiout.dac_nids = spec->private_dac_nids;
10442 spec->multiout.dac_nids[0] = 2;
10443
10444 nid = cfg->line_out_pins[0];
10445 if (nid) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010446 err = add_control(spec, ALC_CTL_WIDGET_VOL,
10447 "Front Playback Volume",
10448 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT));
10449 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010450 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010451 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10452 "Front Playback Switch",
10453 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
10454 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010455 return err;
10456 }
10457
Takashi Iwai82bc9552006-03-21 11:24:42 +010010458 nid = cfg->speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010010459 if (nid) {
10460 if (nid == 0x16) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010461 err = add_control(spec, ALC_CTL_WIDGET_VOL,
10462 "Speaker Playback Volume",
10463 HDA_COMPOSE_AMP_VAL(0x0e, 2, 0,
10464 HDA_OUTPUT));
10465 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010466 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010467 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10468 "Speaker Playback Switch",
10469 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
10470 HDA_OUTPUT));
10471 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010472 return err;
10473 } else {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010474 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10475 "Speaker Playback Switch",
10476 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
10477 HDA_OUTPUT));
10478 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010479 return err;
10480 }
10481 }
Takashi Iwaieb06ed82006-09-20 17:10:27 +020010482 nid = cfg->hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010010483 if (nid) {
10484 /* spec->multiout.hp_nid = 2; */
10485 if (nid == 0x16) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010486 err = add_control(spec, ALC_CTL_WIDGET_VOL,
10487 "Headphone Playback Volume",
10488 HDA_COMPOSE_AMP_VAL(0x0e, 2, 0,
10489 HDA_OUTPUT));
10490 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010491 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010492 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10493 "Headphone Playback Switch",
10494 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
10495 HDA_OUTPUT));
10496 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010497 return err;
10498 } else {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010499 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10500 "Headphone Playback Switch",
10501 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
10502 HDA_OUTPUT));
10503 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010504 return err;
10505 }
10506 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010507 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +010010508}
10509
10510/* identical with ALC880 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010511#define alc262_auto_create_analog_input_ctls \
10512 alc880_auto_create_analog_input_ctls
Kailang Yangdf694da2005-12-05 19:42:22 +010010513
10514/*
10515 * generic initialization of ADC, input mixers and output mixers
10516 */
10517static struct hda_verb alc262_volume_init_verbs[] = {
10518 /*
10519 * Unmute ADC0-2 and set the default input to mic-in
10520 */
10521 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
10522 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10523 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
10524 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10525 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
10526 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10527
Takashi Iwaicb53c622007-08-10 17:21:45 +020010528 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +010010529 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010530 * Note: PASD motherboards uses the Line In 2 as the input for
10531 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +010010532 */
10533 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020010534 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
10535 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10536 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
10537 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
10538 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +010010539
10540 /*
10541 * Set up output mixers (0x0c - 0x0f)
10542 */
10543 /* set vol=0 to output mixers */
10544 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10545 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10546 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yangea1fb292008-08-26 12:58:38 +020010547
Kailang Yangdf694da2005-12-05 19:42:22 +010010548 /* set up input amps for analog loopback */
10549 /* Amp Indices: DAC = 0, mixer = 1 */
10550 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10551 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10552 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10553 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10554 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10555 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10556
10557 /* FIXME: use matrix-type input source selection */
10558 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
10559 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
10560 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10561 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
10562 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
10563 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
10564 /* Input mixer2 */
10565 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10566 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
10567 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
10568 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
10569 /* Input mixer3 */
10570 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10571 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
10572 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
10573 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
10574
10575 { }
10576};
10577
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010578static struct hda_verb alc262_HP_BPC_init_verbs[] = {
10579 /*
10580 * Unmute ADC0-2 and set the default input to mic-in
10581 */
10582 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
10583 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10584 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
10585 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10586 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
10587 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10588
Takashi Iwaicb53c622007-08-10 17:21:45 +020010589 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010590 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010591 * Note: PASD motherboards uses the Line In 2 as the input for
10592 * front panel mic (mic 2)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010593 */
10594 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020010595 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
10596 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10597 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
10598 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
10599 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
10600 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
10601 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
Kailang Yangea1fb292008-08-26 12:58:38 +020010602
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010603 /*
10604 * Set up output mixers (0x0c - 0x0e)
10605 */
10606 /* set vol=0 to output mixers */
10607 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10608 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10609 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10610
10611 /* set up input amps for analog loopback */
10612 /* Amp Indices: DAC = 0, mixer = 1 */
10613 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10614 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10615 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10616 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10617 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10618 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10619
Takashi Iwaice875f02008-01-28 18:17:43 +010010620 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010621 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
10622 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
10623
10624 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
10625 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
10626
10627 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
10628 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
10629
10630 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10631 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
10632 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
10633 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10634 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10635
10636 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
10637 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10638 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10639 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
10640 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10641 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10642
10643
10644 /* FIXME: use matrix-type input source selection */
10645 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
10646 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
10647 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10648 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
10649 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
10650 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
10651 /* Input mixer2 */
10652 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10653 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
10654 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
10655 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
10656 /* Input mixer3 */
10657 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10658 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
10659 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
10660 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
10661
Takashi Iwaice875f02008-01-28 18:17:43 +010010662 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
10663
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010664 { }
10665};
10666
Kailang Yangcd7509a2007-01-26 18:33:17 +010010667static struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = {
10668 /*
10669 * Unmute ADC0-2 and set the default input to mic-in
10670 */
10671 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
10672 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10673 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
10674 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10675 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
10676 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10677
Takashi Iwaicb53c622007-08-10 17:21:45 +020010678 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangcd7509a2007-01-26 18:33:17 +010010679 * mixer widget
10680 * Note: PASD motherboards uses the Line In 2 as the input for front
10681 * panel mic (mic 2)
10682 */
10683 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020010684 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
10685 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10686 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
10687 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
10688 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
10689 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
10690 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
10691 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Kailang Yangcd7509a2007-01-26 18:33:17 +010010692 /*
10693 * Set up output mixers (0x0c - 0x0e)
10694 */
10695 /* set vol=0 to output mixers */
10696 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10697 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10698 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10699
10700 /* set up input amps for analog loopback */
10701 /* Amp Indices: DAC = 0, mixer = 1 */
10702 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10703 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10704 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10705 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10706 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10707 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10708
10709
10710 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP */
10711 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Mono */
10712 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* rear MIC */
10713 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* Line in */
10714 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
10715 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Line out */
10716 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD in */
10717
10718 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
10719 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
10720
10721 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
10722 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
10723
10724 /* {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, */
10725 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10726 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10727 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
10728 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10729 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10730
10731 /* FIXME: use matrix-type input source selection */
10732 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
10733 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
10734 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, /*rear MIC*/
10735 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, /*Line in*/
10736 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, /*F MIC*/
10737 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, /*Front*/
10738 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, /*CD*/
10739 /* {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
10740 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, /*HP*/
10741 /* Input mixer2 */
10742 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10743 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
10744 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
10745 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
10746 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
10747 /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
10748 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
10749 /* Input mixer3 */
10750 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10751 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
10752 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
10753 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
10754 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
10755 /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
10756 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
10757
Takashi Iwaice875f02008-01-28 18:17:43 +010010758 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
10759
Kailang Yangcd7509a2007-01-26 18:33:17 +010010760 { }
10761};
10762
Hiroshi Miura9f99a632008-08-28 16:09:06 +020010763static struct hda_verb alc262_toshiba_rx1_unsol_verbs[] = {
10764
10765 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Front Speaker */
10766 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
10767 {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
10768
10769 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* MIC jack */
10770 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
10771 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
10772 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
10773
10774 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP jack */
10775 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
10776 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
10777 {}
10778};
10779
10780
Takashi Iwaicb53c622007-08-10 17:21:45 +020010781#ifdef CONFIG_SND_HDA_POWER_SAVE
10782#define alc262_loopbacks alc880_loopbacks
10783#endif
10784
Kailang Yangdf694da2005-12-05 19:42:22 +010010785/* pcm configuration: identiacal with ALC880 */
10786#define alc262_pcm_analog_playback alc880_pcm_analog_playback
10787#define alc262_pcm_analog_capture alc880_pcm_analog_capture
10788#define alc262_pcm_digital_playback alc880_pcm_digital_playback
10789#define alc262_pcm_digital_capture alc880_pcm_digital_capture
10790
10791/*
10792 * BIOS auto configuration
10793 */
10794static int alc262_parse_auto_config(struct hda_codec *codec)
10795{
10796 struct alc_spec *spec = codec->spec;
10797 int err;
10798 static hda_nid_t alc262_ignore[] = { 0x1d, 0 };
10799
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010800 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
10801 alc262_ignore);
10802 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010803 return err;
Takashi Iwaie64f14f2009-01-20 18:32:55 +010010804 if (!spec->autocfg.line_outs) {
Takashi Iwai0852d7a2009-02-11 11:35:15 +010010805 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
Takashi Iwaie64f14f2009-01-20 18:32:55 +010010806 spec->multiout.max_channels = 2;
10807 spec->no_analog = 1;
10808 goto dig_only;
10809 }
Kailang Yangdf694da2005-12-05 19:42:22 +010010810 return 0; /* can't find valid BIOS pin config */
Takashi Iwaie64f14f2009-01-20 18:32:55 +010010811 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010812 err = alc262_auto_create_multi_out_ctls(spec, &spec->autocfg);
10813 if (err < 0)
10814 return err;
10815 err = alc262_auto_create_analog_input_ctls(spec, &spec->autocfg);
10816 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010817 return err;
10818
10819 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
10820
Takashi Iwaie64f14f2009-01-20 18:32:55 +010010821 dig_only:
Takashi Iwai0852d7a2009-02-11 11:35:15 +010010822 if (spec->autocfg.dig_outs) {
Kailang Yangdf694da2005-12-05 19:42:22 +010010823 spec->multiout.dig_out_nid = ALC262_DIGOUT_NID;
Takashi Iwai0852d7a2009-02-11 11:35:15 +010010824 spec->dig_out_type = spec->autocfg.dig_out_type[0];
Takashi Iwaie64f14f2009-01-20 18:32:55 +010010825 }
Kailang Yangdf694da2005-12-05 19:42:22 +010010826 if (spec->autocfg.dig_in_pin)
10827 spec->dig_in_nid = ALC262_DIGIN_NID;
10828
Takashi Iwai603c4012008-07-30 15:01:44 +020010829 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010010830 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +010010831
Takashi Iwaid88897e2008-10-31 15:01:37 +010010832 add_verb(spec, alc262_volume_init_verbs);
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020010833 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020010834 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010010835
Takashi Iwai776e1842007-08-29 15:07:11 +020010836 err = alc_auto_add_mic_boost(codec);
10837 if (err < 0)
10838 return err;
10839
Kailang Yangdf694da2005-12-05 19:42:22 +010010840 return 1;
10841}
10842
10843#define alc262_auto_init_multi_out alc882_auto_init_multi_out
10844#define alc262_auto_init_hp_out alc882_auto_init_hp_out
10845#define alc262_auto_init_analog_input alc882_auto_init_analog_input
Takashi Iwaif511b012008-08-15 16:46:42 +020010846#define alc262_auto_init_input_src alc882_auto_init_input_src
Kailang Yangdf694da2005-12-05 19:42:22 +010010847
10848
10849/* init callback for auto-configuration model -- overriding the default init */
Takashi Iwaiae6b8132006-03-03 16:47:17 +010010850static void alc262_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010010851{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010852 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010010853 alc262_auto_init_multi_out(codec);
10854 alc262_auto_init_hp_out(codec);
10855 alc262_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020010856 alc262_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010857 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020010858 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010010859}
10860
10861/*
10862 * configuration and preset
10863 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010864static const char *alc262_models[ALC262_MODEL_LAST] = {
10865 [ALC262_BASIC] = "basic",
10866 [ALC262_HIPPO] = "hippo",
10867 [ALC262_HIPPO_1] = "hippo_1",
10868 [ALC262_FUJITSU] = "fujitsu",
10869 [ALC262_HP_BPC] = "hp-bpc",
Kailang Yangcd7509a2007-01-26 18:33:17 +010010870 [ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000",
Takashi Iwai61dc35d2007-11-14 12:26:44 +010010871 [ALC262_HP_TC_T5735] = "hp-tc-t5735",
Kailang Yang8c427222008-01-10 13:03:59 +010010872 [ALC262_HP_RP5700] = "hp-rp5700",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010873 [ALC262_BENQ_ED8] = "benq",
Takashi Iwai0f405022007-07-06 12:24:11 +020010874 [ALC262_BENQ_T31] = "benq-t31",
10875 [ALC262_SONY_ASSAMD] = "sony-assamd",
Takashi Iwai2922c9a2008-08-27 18:12:42 +020010876 [ALC262_TOSHIBA_S06] = "toshiba-s06",
Hiroshi Miura9f99a632008-08-28 16:09:06 +020010877 [ALC262_TOSHIBA_RX1] = "toshiba-rx1",
Tobin Davisf651b502007-10-26 12:40:47 +020010878 [ALC262_ULTRA] = "ultra",
Jiang zhe0e31daf2008-03-20 12:12:39 +010010879 [ALC262_LENOVO_3000] = "lenovo-3000",
Pascal Terjane8f9ae22008-08-04 14:36:05 +020010880 [ALC262_NEC] = "nec",
Tony Vroonba340e82009-02-02 19:01:30 +000010881 [ALC262_TYAN] = "tyan",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010882 [ALC262_AUTO] = "auto",
10883};
10884
10885static struct snd_pci_quirk alc262_cfg_tbl[] = {
10886 SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO),
Pascal Terjane8f9ae22008-08-04 14:36:05 +020010887 SND_PCI_QUIRK(0x1033, 0x8895, "NEC Versa S9100", ALC262_NEC),
Takashi Iwaidea0a502009-02-09 17:14:52 +010010888 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1200, "HP xw series",
10889 ALC262_HP_BPC),
10890 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1300, "HP xw series",
10891 ALC262_HP_BPC),
Takashi Iwai53eff7e2009-02-27 17:49:44 +010010892 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1700, "HP xw series",
10893 ALC262_HP_BPC),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010894 SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010895 SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010896 SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010897 SND_PCI_QUIRK(0x103c, 0x2803, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010898 SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010899 SND_PCI_QUIRK(0x103c, 0x2805, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010900 SND_PCI_QUIRK(0x103c, 0x2806, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010901 SND_PCI_QUIRK(0x103c, 0x2807, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010902 SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC),
10903 SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC),
10904 SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC),
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010905 SND_PCI_QUIRK(0x103c, 0x302f, "HP Thin Client T5735",
10906 ALC262_HP_TC_T5735),
Kailang Yang8c427222008-01-10 13:03:59 +010010907 SND_PCI_QUIRK(0x103c, 0x2817, "HP RP5700", ALC262_HP_RP5700),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010908 SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010909 SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010910 SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD),
Takashi Iwaibd6afe32009-03-04 11:30:25 +010010911 SND_PCI_QUIRK(0x104d, 0x9016, "Sony VAIO", ALC262_AUTO), /* dig-only */
Takashi Iwaif872a912009-02-26 00:57:01 +010010912 SND_PCI_QUIRK_MASK(0x104d, 0xff00, 0x9000, "Sony VAIO",
10913 ALC262_SONY_ASSAMD),
Akio Idehara36ca6e12008-06-09 22:57:40 +090010914 SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1",
Hiroshi Miura9f99a632008-08-28 16:09:06 +020010915 ALC262_TOSHIBA_RX1),
Kailang Yang80ffe862008-10-15 11:23:27 +020010916 SND_PCI_QUIRK(0x1179, 0xff7b, "Toshiba S06", ALC262_TOSHIBA_S06),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010917 SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU),
Tony Vroon3f1eeae2008-02-25 16:44:13 +010010918 SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU),
Tony Vroonba340e82009-02-02 19:01:30 +000010919 SND_PCI_QUIRK(0x10f1, 0x2915, "Tyan Thunder n6650W", ALC262_TYAN),
Takashi Iwaidea0a502009-02-09 17:14:52 +010010920 SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc032, "Samsung Q1",
10921 ALC262_ULTRA),
Luke Yelavich3e420e72008-12-16 12:37:47 +110010922 SND_PCI_QUIRK(0x144d, 0xc510, "Samsung Q45", ALC262_HIPPO),
Jiang zhe0e31daf2008-03-20 12:12:39 +010010923 SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 y410", ALC262_LENOVO_3000),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010924 SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8),
Kailang Yang83c34212007-07-05 11:43:05 +020010925 SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010926 SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1),
Kailang Yangdf694da2005-12-05 19:42:22 +010010927 {}
10928};
10929
10930static struct alc_config_preset alc262_presets[] = {
10931 [ALC262_BASIC] = {
10932 .mixers = { alc262_base_mixer },
10933 .init_verbs = { alc262_init_verbs },
10934 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10935 .dac_nids = alc262_dac_nids,
10936 .hp_nid = 0x03,
10937 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10938 .channel_mode = alc262_modes,
Takashi Iwaia3bcba32005-12-06 19:05:29 +010010939 .input_mux = &alc262_capture_source,
Kailang Yangdf694da2005-12-05 19:42:22 +010010940 },
Kailang Yangccc656c2006-10-17 12:32:26 +020010941 [ALC262_HIPPO] = {
10942 .mixers = { alc262_base_mixer },
10943 .init_verbs = { alc262_init_verbs, alc262_hippo_unsol_verbs},
10944 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10945 .dac_nids = alc262_dac_nids,
10946 .hp_nid = 0x03,
10947 .dig_out_nid = ALC262_DIGOUT_NID,
10948 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10949 .channel_mode = alc262_modes,
10950 .input_mux = &alc262_capture_source,
10951 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +020010952 .init_hook = alc262_hippo_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020010953 },
10954 [ALC262_HIPPO_1] = {
10955 .mixers = { alc262_hippo1_mixer },
10956 .init_verbs = { alc262_init_verbs, alc262_hippo1_unsol_verbs},
10957 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10958 .dac_nids = alc262_dac_nids,
10959 .hp_nid = 0x02,
10960 .dig_out_nid = ALC262_DIGOUT_NID,
10961 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10962 .channel_mode = alc262_modes,
10963 .input_mux = &alc262_capture_source,
10964 .unsol_event = alc262_hippo1_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +020010965 .init_hook = alc262_hippo1_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020010966 },
Takashi Iwai834be882006-03-01 14:16:17 +010010967 [ALC262_FUJITSU] = {
10968 .mixers = { alc262_fujitsu_mixer },
Takashi Iwai39d3ed32007-10-12 15:03:48 +020010969 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
10970 alc262_fujitsu_unsol_verbs },
Takashi Iwai834be882006-03-01 14:16:17 +010010971 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10972 .dac_nids = alc262_dac_nids,
10973 .hp_nid = 0x03,
10974 .dig_out_nid = ALC262_DIGOUT_NID,
10975 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10976 .channel_mode = alc262_modes,
10977 .input_mux = &alc262_fujitsu_capture_source,
Takashi Iwaiae6b8132006-03-03 16:47:17 +010010978 .unsol_event = alc262_fujitsu_unsol_event,
Takashi Iwaiebc7a402008-05-20 09:23:05 +020010979 .init_hook = alc262_fujitsu_init_hook,
Takashi Iwai834be882006-03-01 14:16:17 +010010980 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010981 [ALC262_HP_BPC] = {
10982 .mixers = { alc262_HP_BPC_mixer },
10983 .init_verbs = { alc262_HP_BPC_init_verbs },
10984 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10985 .dac_nids = alc262_dac_nids,
10986 .hp_nid = 0x03,
10987 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10988 .channel_mode = alc262_modes,
10989 .input_mux = &alc262_HP_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010010990 .unsol_event = alc262_hp_bpc_unsol_event,
10991 .init_hook = alc262_hp_bpc_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010992 },
Kailang Yangcd7509a2007-01-26 18:33:17 +010010993 [ALC262_HP_BPC_D7000_WF] = {
10994 .mixers = { alc262_HP_BPC_WildWest_mixer },
10995 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
10996 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10997 .dac_nids = alc262_dac_nids,
10998 .hp_nid = 0x03,
10999 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11000 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +020011001 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010011002 .unsol_event = alc262_hp_wildwest_unsol_event,
11003 .init_hook = alc262_hp_wildwest_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011004 },
Kailang Yangcd7509a2007-01-26 18:33:17 +010011005 [ALC262_HP_BPC_D7000_WL] = {
11006 .mixers = { alc262_HP_BPC_WildWest_mixer,
11007 alc262_HP_BPC_WildWest_option_mixer },
11008 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
11009 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11010 .dac_nids = alc262_dac_nids,
11011 .hp_nid = 0x03,
11012 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11013 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +020011014 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010011015 .unsol_event = alc262_hp_wildwest_unsol_event,
11016 .init_hook = alc262_hp_wildwest_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011017 },
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011018 [ALC262_HP_TC_T5735] = {
11019 .mixers = { alc262_hp_t5735_mixer },
11020 .init_verbs = { alc262_init_verbs, alc262_hp_t5735_verbs },
11021 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11022 .dac_nids = alc262_dac_nids,
11023 .hp_nid = 0x03,
11024 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11025 .channel_mode = alc262_modes,
11026 .input_mux = &alc262_capture_source,
11027 .unsol_event = alc262_hp_t5735_unsol_event,
11028 .init_hook = alc262_hp_t5735_init_hook,
Kailang Yang8c427222008-01-10 13:03:59 +010011029 },
11030 [ALC262_HP_RP5700] = {
11031 .mixers = { alc262_hp_rp5700_mixer },
11032 .init_verbs = { alc262_init_verbs, alc262_hp_rp5700_verbs },
11033 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11034 .dac_nids = alc262_dac_nids,
11035 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11036 .channel_mode = alc262_modes,
11037 .input_mux = &alc262_hp_rp5700_capture_source,
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011038 },
Takashi Iwai304dcaa2006-07-25 14:51:16 +020011039 [ALC262_BENQ_ED8] = {
11040 .mixers = { alc262_base_mixer },
11041 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs },
11042 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11043 .dac_nids = alc262_dac_nids,
11044 .hp_nid = 0x03,
11045 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11046 .channel_mode = alc262_modes,
11047 .input_mux = &alc262_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011048 },
Kailang Yang272a5272007-05-14 11:00:38 +020011049 [ALC262_SONY_ASSAMD] = {
11050 .mixers = { alc262_sony_mixer },
11051 .init_verbs = { alc262_init_verbs, alc262_sony_unsol_verbs},
11052 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11053 .dac_nids = alc262_dac_nids,
11054 .hp_nid = 0x02,
11055 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11056 .channel_mode = alc262_modes,
11057 .input_mux = &alc262_capture_source,
11058 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +020011059 .init_hook = alc262_hippo_automute,
Kailang Yang83c34212007-07-05 11:43:05 +020011060 },
11061 [ALC262_BENQ_T31] = {
11062 .mixers = { alc262_benq_t31_mixer },
11063 .init_verbs = { alc262_init_verbs, alc262_benq_t31_EAPD_verbs, alc262_hippo_unsol_verbs },
11064 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11065 .dac_nids = alc262_dac_nids,
11066 .hp_nid = 0x03,
11067 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11068 .channel_mode = alc262_modes,
11069 .input_mux = &alc262_capture_source,
11070 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +020011071 .init_hook = alc262_hippo_automute,
Kailang Yangea1fb292008-08-26 12:58:38 +020011072 },
Tobin Davisf651b502007-10-26 12:40:47 +020011073 [ALC262_ULTRA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010011074 .mixers = { alc262_ultra_mixer },
11075 .cap_mixer = alc262_ultra_capture_mixer,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011076 .init_verbs = { alc262_ultra_verbs },
Tobin Davisf651b502007-10-26 12:40:47 +020011077 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11078 .dac_nids = alc262_dac_nids,
Tobin Davisf651b502007-10-26 12:40:47 +020011079 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11080 .channel_mode = alc262_modes,
11081 .input_mux = &alc262_ultra_capture_source,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011082 .adc_nids = alc262_adc_nids, /* ADC0 */
11083 .capsrc_nids = alc262_capsrc_nids,
11084 .num_adc_nids = 1, /* single ADC */
Tobin Davisf651b502007-10-26 12:40:47 +020011085 .unsol_event = alc262_ultra_unsol_event,
11086 .init_hook = alc262_ultra_automute,
11087 },
Jiang zhe0e31daf2008-03-20 12:12:39 +010011088 [ALC262_LENOVO_3000] = {
11089 .mixers = { alc262_lenovo_3000_mixer },
11090 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
11091 alc262_lenovo_3000_unsol_verbs },
11092 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11093 .dac_nids = alc262_dac_nids,
11094 .hp_nid = 0x03,
11095 .dig_out_nid = ALC262_DIGOUT_NID,
11096 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11097 .channel_mode = alc262_modes,
11098 .input_mux = &alc262_fujitsu_capture_source,
11099 .unsol_event = alc262_lenovo_3000_unsol_event,
11100 },
Pascal Terjane8f9ae22008-08-04 14:36:05 +020011101 [ALC262_NEC] = {
11102 .mixers = { alc262_nec_mixer },
11103 .init_verbs = { alc262_nec_verbs },
11104 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11105 .dac_nids = alc262_dac_nids,
11106 .hp_nid = 0x03,
11107 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11108 .channel_mode = alc262_modes,
11109 .input_mux = &alc262_capture_source,
11110 },
Kailang Yang4e555fe2008-08-26 13:05:55 +020011111 [ALC262_TOSHIBA_S06] = {
11112 .mixers = { alc262_toshiba_s06_mixer },
11113 .init_verbs = { alc262_init_verbs, alc262_toshiba_s06_verbs,
11114 alc262_eapd_verbs },
11115 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11116 .capsrc_nids = alc262_dmic_capsrc_nids,
11117 .dac_nids = alc262_dac_nids,
11118 .adc_nids = alc262_dmic_adc_nids, /* ADC0 */
11119 .dig_out_nid = ALC262_DIGOUT_NID,
11120 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11121 .channel_mode = alc262_modes,
11122 .input_mux = &alc262_dmic_capture_source,
11123 .unsol_event = alc262_toshiba_s06_unsol_event,
11124 .init_hook = alc262_toshiba_s06_init_hook,
11125 },
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011126 [ALC262_TOSHIBA_RX1] = {
11127 .mixers = { alc262_toshiba_rx1_mixer },
11128 .init_verbs = { alc262_init_verbs, alc262_toshiba_rx1_unsol_verbs },
11129 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11130 .dac_nids = alc262_dac_nids,
11131 .hp_nid = 0x03,
11132 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11133 .channel_mode = alc262_modes,
11134 .input_mux = &alc262_capture_source,
11135 .unsol_event = alc262_hippo_unsol_event,
11136 .init_hook = alc262_hippo_automute,
11137 },
Tony Vroonba340e82009-02-02 19:01:30 +000011138 [ALC262_TYAN] = {
11139 .mixers = { alc262_tyan_mixer },
11140 .init_verbs = { alc262_init_verbs, alc262_tyan_verbs},
11141 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11142 .dac_nids = alc262_dac_nids,
11143 .hp_nid = 0x02,
11144 .dig_out_nid = ALC262_DIGOUT_NID,
11145 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11146 .channel_mode = alc262_modes,
11147 .input_mux = &alc262_capture_source,
11148 .unsol_event = alc262_tyan_unsol_event,
11149 .init_hook = alc262_tyan_automute,
11150 },
Kailang Yangdf694da2005-12-05 19:42:22 +010011151};
11152
11153static int patch_alc262(struct hda_codec *codec)
11154{
11155 struct alc_spec *spec;
11156 int board_config;
11157 int err;
11158
Robert P. J. Daydc041e02006-12-19 14:44:15 +010011159 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010011160 if (spec == NULL)
11161 return -ENOMEM;
11162
11163 codec->spec = spec;
11164#if 0
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011165 /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is
11166 * under-run
11167 */
Kailang Yangdf694da2005-12-05 19:42:22 +010011168 {
11169 int tmp;
11170 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
11171 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
11172 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
11173 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80);
11174 }
11175#endif
11176
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020011177 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
11178
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011179 board_config = snd_hda_check_board_config(codec, ALC262_MODEL_LAST,
11180 alc262_models,
11181 alc262_cfg_tbl);
Kailang Yangcd7509a2007-01-26 18:33:17 +010011182
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011183 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011184 printk(KERN_INFO "hda_codec: Unknown model for ALC262, "
11185 "trying auto-probe from BIOS...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010011186 board_config = ALC262_AUTO;
11187 }
11188
11189 if (board_config == ALC262_AUTO) {
11190 /* automatic parse from the BIOS config */
11191 err = alc262_parse_auto_config(codec);
11192 if (err < 0) {
11193 alc_free(codec);
11194 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011195 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011196 printk(KERN_INFO
11197 "hda_codec: Cannot set up configuration "
11198 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010011199 board_config = ALC262_BASIC;
11200 }
11201 }
11202
Takashi Iwai07eba612009-02-19 08:06:35 +010011203 if (!spec->no_analog) {
11204 err = snd_hda_attach_beep_device(codec, 0x1);
11205 if (err < 0) {
11206 alc_free(codec);
11207 return err;
11208 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090011209 }
11210
Kailang Yangdf694da2005-12-05 19:42:22 +010011211 if (board_config != ALC262_AUTO)
11212 setup_preset(spec, &alc262_presets[board_config]);
11213
11214 spec->stream_name_analog = "ALC262 Analog";
11215 spec->stream_analog_playback = &alc262_pcm_analog_playback;
11216 spec->stream_analog_capture = &alc262_pcm_analog_capture;
Kailang Yangea1fb292008-08-26 12:58:38 +020011217
Kailang Yangdf694da2005-12-05 19:42:22 +010011218 spec->stream_name_digital = "ALC262 Digital";
11219 spec->stream_digital_playback = &alc262_pcm_digital_playback;
11220 spec->stream_digital_capture = &alc262_pcm_digital_capture;
11221
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020011222 spec->capture_style = CAPT_MIX;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011223 if (!spec->adc_nids && spec->input_mux) {
Kailang Yangdf694da2005-12-05 19:42:22 +010011224 /* check whether NID 0x07 is valid */
Takashi Iwai4a471b72005-12-07 13:56:29 +010011225 unsigned int wcap = get_wcaps(codec, 0x07);
11226
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011227 /* get type */
11228 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Kailang Yangdf694da2005-12-05 19:42:22 +010011229 if (wcap != AC_WID_AUD_IN) {
11230 spec->adc_nids = alc262_adc_nids_alt;
11231 spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids_alt);
Takashi Iwai88c71a92008-02-14 17:27:17 +010011232 spec->capsrc_nids = alc262_capsrc_nids_alt;
Kailang Yangdf694da2005-12-05 19:42:22 +010011233 } else {
11234 spec->adc_nids = alc262_adc_nids;
11235 spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids);
Takashi Iwai88c71a92008-02-14 17:27:17 +010011236 spec->capsrc_nids = alc262_capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +010011237 }
11238 }
Takashi Iwaie64f14f2009-01-20 18:32:55 +010011239 if (!spec->cap_mixer && !spec->no_analog)
Takashi Iwaif9e336f2008-10-31 16:37:07 +010011240 set_capture_mixer(spec);
Takashi Iwai07eba612009-02-19 08:06:35 +010011241 if (!spec->no_analog)
11242 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Kailang Yangdf694da2005-12-05 19:42:22 +010011243
Takashi Iwai2134ea42008-01-10 16:53:55 +010011244 spec->vmaster_nid = 0x0c;
11245
Kailang Yangdf694da2005-12-05 19:42:22 +010011246 codec->patch_ops = alc_patch_ops;
11247 if (board_config == ALC262_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +010011248 spec->init_hook = alc262_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020011249#ifdef CONFIG_SND_HDA_POWER_SAVE
11250 if (!spec->loopback.amplist)
11251 spec->loopback.amplist = alc262_loopbacks;
11252#endif
Takashi Iwaidaead532008-11-28 12:55:36 +010011253 codec->proc_widget_hook = print_realtek_coef;
Kailang Yangea1fb292008-08-26 12:58:38 +020011254
Kailang Yangdf694da2005-12-05 19:42:22 +010011255 return 0;
11256}
11257
Kailang Yangdf694da2005-12-05 19:42:22 +010011258/*
Kailang Yanga361d842007-06-05 12:30:55 +020011259 * ALC268 channel source setting (2 channel)
11260 */
11261#define ALC268_DIGOUT_NID ALC880_DIGOUT_NID
11262#define alc268_modes alc260_modes
Kailang Yangea1fb292008-08-26 12:58:38 +020011263
Kailang Yanga361d842007-06-05 12:30:55 +020011264static hda_nid_t alc268_dac_nids[2] = {
11265 /* front, hp */
11266 0x02, 0x03
11267};
11268
11269static hda_nid_t alc268_adc_nids[2] = {
11270 /* ADC0-1 */
11271 0x08, 0x07
11272};
11273
11274static hda_nid_t alc268_adc_nids_alt[1] = {
11275 /* ADC0 */
11276 0x08
11277};
11278
Takashi Iwaie1406342008-02-11 18:32:32 +010011279static hda_nid_t alc268_capsrc_nids[2] = { 0x23, 0x24 };
11280
Kailang Yanga361d842007-06-05 12:30:55 +020011281static struct snd_kcontrol_new alc268_base_mixer[] = {
11282 /* output mixer control */
11283 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
11284 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11285 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
11286 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai33bf17a2007-08-21 11:51:42 +020011287 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11288 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
11289 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
Kailang Yanga361d842007-06-05 12:30:55 +020011290 { }
11291};
11292
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011293/* bind Beep switches of both NID 0x0f and 0x10 */
11294static struct hda_bind_ctls alc268_bind_beep_sw = {
11295 .ops = &snd_hda_bind_sw,
11296 .values = {
11297 HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT),
11298 HDA_COMPOSE_AMP_VAL(0x10, 3, 1, HDA_INPUT),
11299 0
11300 },
11301};
11302
11303static struct snd_kcontrol_new alc268_beep_mixer[] = {
11304 HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT),
11305 HDA_BIND_SW("Beep Playback Switch", &alc268_bind_beep_sw),
11306 { }
11307};
11308
Kailang Yangd1a991a2007-08-15 16:21:59 +020011309static struct hda_verb alc268_eapd_verbs[] = {
11310 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
11311 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
11312 { }
11313};
11314
Takashi Iwaid2738092007-08-16 14:59:45 +020011315/* Toshiba specific */
11316#define alc268_toshiba_automute alc262_hippo_automute
11317
11318static struct hda_verb alc268_toshiba_verbs[] = {
11319 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
11320 { } /* end */
11321};
11322
Kailang Yang8ef355d2008-08-26 13:10:22 +020011323static struct hda_input_mux alc268_acer_lc_capture_source = {
11324 .num_items = 2,
11325 .items = {
11326 { "i-Mic", 0x6 },
11327 { "E-Mic", 0x0 },
11328 },
11329};
11330
Takashi Iwaid2738092007-08-16 14:59:45 +020011331/* Acer specific */
Takashi Iwai889c4392007-08-23 18:56:52 +020011332/* bind volumes of both NID 0x02 and 0x03 */
Takashi Iwai6bc96852007-08-17 09:02:12 +020011333static struct hda_bind_ctls alc268_acer_bind_master_vol = {
11334 .ops = &snd_hda_bind_vol,
11335 .values = {
11336 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
11337 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
11338 0
11339 },
11340};
11341
Takashi Iwai889c4392007-08-23 18:56:52 +020011342/* mute/unmute internal speaker according to the hp jack and mute state */
11343static void alc268_acer_automute(struct hda_codec *codec, int force)
11344{
11345 struct alc_spec *spec = codec->spec;
11346 unsigned int mute;
11347
11348 if (force || !spec->sense_updated) {
11349 unsigned int present;
11350 present = snd_hda_codec_read(codec, 0x14, 0,
11351 AC_VERB_GET_PIN_SENSE, 0);
11352 spec->jack_present = (present & 0x80000000) != 0;
11353 spec->sense_updated = 1;
11354 }
11355 if (spec->jack_present)
11356 mute = HDA_AMP_MUTE; /* mute internal speaker */
11357 else /* unmute internal speaker if necessary */
11358 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
11359 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
11360 HDA_AMP_MUTE, mute);
11361}
11362
11363
11364/* bind hp and internal speaker mute (with plug check) */
11365static int alc268_acer_master_sw_put(struct snd_kcontrol *kcontrol,
11366 struct snd_ctl_elem_value *ucontrol)
11367{
11368 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
11369 long *valp = ucontrol->value.integer.value;
11370 int change;
11371
11372 change = snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0,
11373 HDA_AMP_MUTE,
11374 valp[0] ? 0 : HDA_AMP_MUTE);
11375 change |= snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0,
11376 HDA_AMP_MUTE,
11377 valp[1] ? 0 : HDA_AMP_MUTE);
11378 if (change)
11379 alc268_acer_automute(codec, 0);
11380 return change;
11381}
Takashi Iwaid2738092007-08-16 14:59:45 +020011382
Kailang Yang8ef355d2008-08-26 13:10:22 +020011383static struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = {
11384 /* output mixer control */
11385 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
11386 {
11387 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11388 .name = "Master Playback Switch",
11389 .info = snd_hda_mixer_amp_switch_info,
11390 .get = snd_hda_mixer_amp_switch_get,
11391 .put = alc268_acer_master_sw_put,
11392 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
11393 },
11394 HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x18, 0, HDA_INPUT),
11395 { }
11396};
11397
Takashi Iwaid2738092007-08-16 14:59:45 +020011398static struct snd_kcontrol_new alc268_acer_mixer[] = {
11399 /* output mixer control */
11400 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
11401 {
11402 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11403 .name = "Master Playback Switch",
11404 .info = snd_hda_mixer_amp_switch_info,
11405 .get = snd_hda_mixer_amp_switch_get,
11406 .put = alc268_acer_master_sw_put,
11407 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
11408 },
Takashi Iwai33bf17a2007-08-21 11:51:42 +020011409 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11410 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
11411 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
Takashi Iwaid2738092007-08-16 14:59:45 +020011412 { }
11413};
11414
Takashi Iwaic238b4f2008-11-05 14:57:20 +010011415static struct snd_kcontrol_new alc268_acer_dmic_mixer[] = {
11416 /* output mixer control */
11417 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
11418 {
11419 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11420 .name = "Master Playback Switch",
11421 .info = snd_hda_mixer_amp_switch_info,
11422 .get = snd_hda_mixer_amp_switch_get,
11423 .put = alc268_acer_master_sw_put,
11424 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
11425 },
11426 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11427 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
11428 { }
11429};
11430
Kailang Yang8ef355d2008-08-26 13:10:22 +020011431static struct hda_verb alc268_acer_aspire_one_verbs[] = {
11432 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11433 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11434 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
11435 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
11436 {0x23, AC_VERB_SET_CONNECT_SEL, 0x06},
11437 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, 0xa017},
11438 { }
11439};
11440
Takashi Iwaid2738092007-08-16 14:59:45 +020011441static struct hda_verb alc268_acer_verbs[] = {
Takashi Iwai0ccb5412008-03-06 16:58:35 +010011442 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* internal dmic? */
11443 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaid2738092007-08-16 14:59:45 +020011444 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11445 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai0ccb5412008-03-06 16:58:35 +010011446 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
11447 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaid2738092007-08-16 14:59:45 +020011448 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
11449 { }
11450};
11451
11452/* unsolicited event for HP jack sensing */
11453static void alc268_toshiba_unsol_event(struct hda_codec *codec,
11454 unsigned int res)
11455{
Takashi Iwai889c4392007-08-23 18:56:52 +020011456 if ((res >> 26) != ALC880_HP_EVENT)
Takashi Iwaid2738092007-08-16 14:59:45 +020011457 return;
11458 alc268_toshiba_automute(codec);
11459}
11460
11461static void alc268_acer_unsol_event(struct hda_codec *codec,
11462 unsigned int res)
11463{
Takashi Iwai889c4392007-08-23 18:56:52 +020011464 if ((res >> 26) != ALC880_HP_EVENT)
Takashi Iwaid2738092007-08-16 14:59:45 +020011465 return;
11466 alc268_acer_automute(codec, 1);
11467}
11468
Takashi Iwai889c4392007-08-23 18:56:52 +020011469static void alc268_acer_init_hook(struct hda_codec *codec)
11470{
11471 alc268_acer_automute(codec, 1);
11472}
11473
Kailang Yang8ef355d2008-08-26 13:10:22 +020011474/* toggle speaker-output according to the hp-jack state */
11475static void alc268_aspire_one_speaker_automute(struct hda_codec *codec)
11476{
11477 unsigned int present;
11478 unsigned char bits;
11479
11480 present = snd_hda_codec_read(codec, 0x15, 0,
11481 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
11482 bits = present ? AMP_IN_MUTE(0) : 0;
11483 snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 0,
11484 AMP_IN_MUTE(0), bits);
11485 snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 1,
11486 AMP_IN_MUTE(0), bits);
11487}
11488
11489
11490static void alc268_acer_mic_automute(struct hda_codec *codec)
11491{
11492 unsigned int present;
11493
11494 present = snd_hda_codec_read(codec, 0x18, 0,
11495 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
11496 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_CONNECT_SEL,
11497 present ? 0x0 : 0x6);
11498}
11499
11500static void alc268_acer_lc_unsol_event(struct hda_codec *codec,
11501 unsigned int res)
11502{
11503 if ((res >> 26) == ALC880_HP_EVENT)
11504 alc268_aspire_one_speaker_automute(codec);
11505 if ((res >> 26) == ALC880_MIC_EVENT)
11506 alc268_acer_mic_automute(codec);
11507}
11508
11509static void alc268_acer_lc_init_hook(struct hda_codec *codec)
11510{
11511 alc268_aspire_one_speaker_automute(codec);
11512 alc268_acer_mic_automute(codec);
11513}
11514
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011515static struct snd_kcontrol_new alc268_dell_mixer[] = {
11516 /* output mixer control */
11517 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
11518 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11519 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
11520 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11521 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11522 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
11523 { }
11524};
11525
11526static struct hda_verb alc268_dell_verbs[] = {
11527 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11528 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11529 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
11530 { }
11531};
11532
11533/* mute/unmute internal speaker according to the hp jack and mute state */
11534static void alc268_dell_automute(struct hda_codec *codec)
11535{
11536 unsigned int present;
11537 unsigned int mute;
11538
11539 present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0);
11540 if (present & 0x80000000)
11541 mute = HDA_AMP_MUTE;
11542 else
11543 mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0);
11544 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
11545 HDA_AMP_MUTE, mute);
11546}
11547
11548static void alc268_dell_unsol_event(struct hda_codec *codec,
11549 unsigned int res)
11550{
11551 if ((res >> 26) != ALC880_HP_EVENT)
11552 return;
11553 alc268_dell_automute(codec);
11554}
11555
11556#define alc268_dell_init_hook alc268_dell_automute
11557
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020011558static struct snd_kcontrol_new alc267_quanta_il1_mixer[] = {
11559 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x2, 0x0, HDA_OUTPUT),
11560 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11561 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
11562 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11563 HDA_CODEC_VOLUME("Mic Capture Volume", 0x23, 0x0, HDA_OUTPUT),
11564 HDA_BIND_MUTE("Mic Capture Switch", 0x23, 2, HDA_OUTPUT),
11565 HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
11566 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
11567 { }
11568};
11569
11570static struct hda_verb alc267_quanta_il1_verbs[] = {
11571 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
11572 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
11573 { }
11574};
11575
11576static void alc267_quanta_il1_hp_automute(struct hda_codec *codec)
11577{
11578 unsigned int present;
11579
11580 present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0)
11581 & AC_PINSENSE_PRESENCE;
11582 snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
11583 present ? 0 : PIN_OUT);
11584}
11585
11586static void alc267_quanta_il1_mic_automute(struct hda_codec *codec)
11587{
11588 unsigned int present;
11589
11590 present = snd_hda_codec_read(codec, 0x18, 0,
11591 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
11592 snd_hda_codec_write(codec, 0x23, 0,
11593 AC_VERB_SET_CONNECT_SEL,
11594 present ? 0x00 : 0x01);
11595}
11596
11597static void alc267_quanta_il1_automute(struct hda_codec *codec)
11598{
11599 alc267_quanta_il1_hp_automute(codec);
11600 alc267_quanta_il1_mic_automute(codec);
11601}
11602
11603static void alc267_quanta_il1_unsol_event(struct hda_codec *codec,
11604 unsigned int res)
11605{
11606 switch (res >> 26) {
11607 case ALC880_HP_EVENT:
11608 alc267_quanta_il1_hp_automute(codec);
11609 break;
11610 case ALC880_MIC_EVENT:
11611 alc267_quanta_il1_mic_automute(codec);
11612 break;
11613 }
11614}
11615
Kailang Yanga361d842007-06-05 12:30:55 +020011616/*
11617 * generic initialization of ADC, input mixers and output mixers
11618 */
11619static struct hda_verb alc268_base_init_verbs[] = {
11620 /* Unmute DAC0-1 and set vol = 0 */
11621 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020011622 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020011623
11624 /*
11625 * Set up output mixers (0x0c - 0x0e)
11626 */
11627 /* set vol=0 to output mixers */
11628 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yanga361d842007-06-05 12:30:55 +020011629 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
11630
11631 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11632 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11633
11634 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
11635 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
11636 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
11637 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11638 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11639 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11640 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11641 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11642
11643 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11644 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11645 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11646 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020011647 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011648
11649 /* set PCBEEP vol = 0, mute connections */
11650 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11651 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11652 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020011653
Jiang Zhea9b3aa82007-12-20 13:13:13 +010011654 /* Unmute Selector 23h,24h and set the default input to mic-in */
Kailang Yangea1fb292008-08-26 12:58:38 +020011655
Jiang Zhea9b3aa82007-12-20 13:13:13 +010011656 {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
11657 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11658 {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
11659 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020011660
Kailang Yanga361d842007-06-05 12:30:55 +020011661 { }
11662};
11663
11664/*
11665 * generic initialization of ADC, input mixers and output mixers
11666 */
11667static struct hda_verb alc268_volume_init_verbs[] = {
11668 /* set output DAC */
Takashi Iwai4cfb91c2009-01-23 12:53:09 +010011669 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11670 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020011671
11672 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11673 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11674 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11675 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11676 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11677
Kailang Yanga361d842007-06-05 12:30:55 +020011678 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yanga361d842007-06-05 12:30:55 +020011679 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11680 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11681
11682 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020011683 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020011684
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011685 /* set PCBEEP vol = 0, mute connections */
11686 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11687 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11688 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020011689
11690 { }
11691};
11692
Kailang Yanga361d842007-06-05 12:30:55 +020011693static struct snd_kcontrol_new alc268_capture_alt_mixer[] = {
11694 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
11695 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
11696 {
11697 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11698 /* The multiple "Capture Source" controls confuse alsamixer
11699 * So call somewhat different..
Kailang Yanga361d842007-06-05 12:30:55 +020011700 */
11701 /* .name = "Capture Source", */
11702 .name = "Input Source",
11703 .count = 1,
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010011704 .info = alc_mux_enum_info,
11705 .get = alc_mux_enum_get,
11706 .put = alc_mux_enum_put,
Kailang Yanga361d842007-06-05 12:30:55 +020011707 },
11708 { } /* end */
11709};
11710
11711static struct snd_kcontrol_new alc268_capture_mixer[] = {
11712 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
11713 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
11714 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x24, 0x0, HDA_OUTPUT),
11715 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x24, 0x0, HDA_OUTPUT),
11716 {
11717 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11718 /* The multiple "Capture Source" controls confuse alsamixer
11719 * So call somewhat different..
Kailang Yanga361d842007-06-05 12:30:55 +020011720 */
11721 /* .name = "Capture Source", */
11722 .name = "Input Source",
11723 .count = 2,
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010011724 .info = alc_mux_enum_info,
11725 .get = alc_mux_enum_get,
11726 .put = alc_mux_enum_put,
Kailang Yanga361d842007-06-05 12:30:55 +020011727 },
11728 { } /* end */
11729};
11730
11731static struct hda_input_mux alc268_capture_source = {
11732 .num_items = 4,
11733 .items = {
11734 { "Mic", 0x0 },
11735 { "Front Mic", 0x1 },
11736 { "Line", 0x2 },
11737 { "CD", 0x3 },
11738 },
11739};
11740
Takashi Iwai0ccb5412008-03-06 16:58:35 +010011741static struct hda_input_mux alc268_acer_capture_source = {
11742 .num_items = 3,
11743 .items = {
11744 { "Mic", 0x0 },
Takashi Iwaic238b4f2008-11-05 14:57:20 +010011745 { "Internal Mic", 0x1 },
11746 { "Line", 0x2 },
11747 },
11748};
11749
11750static struct hda_input_mux alc268_acer_dmic_capture_source = {
11751 .num_items = 3,
11752 .items = {
11753 { "Mic", 0x0 },
Takashi Iwai0ccb5412008-03-06 16:58:35 +010011754 { "Internal Mic", 0x6 },
11755 { "Line", 0x2 },
11756 },
11757};
11758
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010011759#ifdef CONFIG_SND_DEBUG
11760static struct snd_kcontrol_new alc268_test_mixer[] = {
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010011761 /* Volume widgets */
11762 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x02, 0x0, HDA_OUTPUT),
11763 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x03, 0x0, HDA_OUTPUT),
11764 HDA_BIND_MUTE_MONO("Mono sum Playback Switch", 0x0e, 1, 2, HDA_INPUT),
11765 HDA_BIND_MUTE("LINE-OUT sum Playback Switch", 0x0f, 2, HDA_INPUT),
11766 HDA_BIND_MUTE("HP-OUT sum Playback Switch", 0x10, 2, HDA_INPUT),
11767 HDA_BIND_MUTE("LINE-OUT Playback Switch", 0x14, 2, HDA_OUTPUT),
11768 HDA_BIND_MUTE("HP-OUT Playback Switch", 0x15, 2, HDA_OUTPUT),
11769 HDA_BIND_MUTE("Mono Playback Switch", 0x16, 2, HDA_OUTPUT),
11770 HDA_CODEC_VOLUME("MIC1 Capture Volume", 0x18, 0x0, HDA_INPUT),
11771 HDA_BIND_MUTE("MIC1 Capture Switch", 0x18, 2, HDA_OUTPUT),
11772 HDA_CODEC_VOLUME("MIC2 Capture Volume", 0x19, 0x0, HDA_INPUT),
11773 HDA_CODEC_VOLUME("LINE1 Capture Volume", 0x1a, 0x0, HDA_INPUT),
11774 HDA_BIND_MUTE("LINE1 Capture Switch", 0x1a, 2, HDA_OUTPUT),
Takashi Iwaif0747ee2008-01-15 11:41:41 +010011775 /* The below appears problematic on some hardwares */
11776 /*HDA_CODEC_VOLUME("PCBEEP Playback Volume", 0x1d, 0x0, HDA_INPUT),*/
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010011777 HDA_CODEC_VOLUME("PCM-IN1 Capture Volume", 0x23, 0x0, HDA_OUTPUT),
11778 HDA_BIND_MUTE("PCM-IN1 Capture Switch", 0x23, 2, HDA_OUTPUT),
11779 HDA_CODEC_VOLUME("PCM-IN2 Capture Volume", 0x24, 0x0, HDA_OUTPUT),
11780 HDA_BIND_MUTE("PCM-IN2 Capture Switch", 0x24, 2, HDA_OUTPUT),
11781
11782 /* Modes for retasking pin widgets */
11783 ALC_PIN_MODE("LINE-OUT pin mode", 0x14, ALC_PIN_DIR_INOUT),
11784 ALC_PIN_MODE("HP-OUT pin mode", 0x15, ALC_PIN_DIR_INOUT),
11785 ALC_PIN_MODE("MIC1 pin mode", 0x18, ALC_PIN_DIR_INOUT),
11786 ALC_PIN_MODE("LINE1 pin mode", 0x1a, ALC_PIN_DIR_INOUT),
11787
11788 /* Controls for GPIO pins, assuming they are configured as outputs */
11789 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
11790 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
11791 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
11792 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
11793
11794 /* Switches to allow the digital SPDIF output pin to be enabled.
11795 * The ALC268 does not have an SPDIF input.
11796 */
11797 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x06, 0x01),
11798
11799 /* A switch allowing EAPD to be enabled. Some laptops seem to use
11800 * this output to turn on an external amplifier.
11801 */
11802 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
11803 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
11804
11805 { } /* end */
11806};
11807#endif
11808
Kailang Yanga361d842007-06-05 12:30:55 +020011809/* create input playback/capture controls for the given pin */
11810static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
11811 const char *ctlname, int idx)
11812{
11813 char name[32];
11814 int err;
11815
11816 sprintf(name, "%s Playback Volume", ctlname);
11817 if (nid == 0x14) {
11818 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
11819 HDA_COMPOSE_AMP_VAL(0x02, 3, idx,
11820 HDA_OUTPUT));
11821 if (err < 0)
11822 return err;
11823 } else if (nid == 0x15) {
11824 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
11825 HDA_COMPOSE_AMP_VAL(0x03, 3, idx,
11826 HDA_OUTPUT));
11827 if (err < 0)
11828 return err;
11829 } else
11830 return -1;
11831 sprintf(name, "%s Playback Switch", ctlname);
11832 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
11833 HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
11834 if (err < 0)
11835 return err;
11836 return 0;
11837}
11838
11839/* add playback controls from the parsed DAC table */
11840static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
11841 const struct auto_pin_cfg *cfg)
11842{
11843 hda_nid_t nid;
11844 int err;
11845
11846 spec->multiout.num_dacs = 2; /* only use one dac */
11847 spec->multiout.dac_nids = spec->private_dac_nids;
11848 spec->multiout.dac_nids[0] = 2;
11849 spec->multiout.dac_nids[1] = 3;
11850
11851 nid = cfg->line_out_pins[0];
11852 if (nid)
Kailang Yangea1fb292008-08-26 12:58:38 +020011853 alc268_new_analog_output(spec, nid, "Front", 0);
Kailang Yanga361d842007-06-05 12:30:55 +020011854
11855 nid = cfg->speaker_pins[0];
11856 if (nid == 0x1d) {
11857 err = add_control(spec, ALC_CTL_WIDGET_VOL,
11858 "Speaker Playback Volume",
11859 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
11860 if (err < 0)
11861 return err;
11862 }
11863 nid = cfg->hp_pins[0];
11864 if (nid)
11865 alc268_new_analog_output(spec, nid, "Headphone", 0);
11866
11867 nid = cfg->line_out_pins[1] | cfg->line_out_pins[2];
11868 if (nid == 0x16) {
11869 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
11870 "Mono Playback Switch",
11871 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_INPUT));
11872 if (err < 0)
11873 return err;
11874 }
Kailang Yangea1fb292008-08-26 12:58:38 +020011875 return 0;
Kailang Yanga361d842007-06-05 12:30:55 +020011876}
11877
11878/* create playback/capture controls for input pins */
11879static int alc268_auto_create_analog_input_ctls(struct alc_spec *spec,
11880 const struct auto_pin_cfg *cfg)
11881{
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020011882 struct hda_input_mux *imux = &spec->private_imux[0];
Kailang Yanga361d842007-06-05 12:30:55 +020011883 int i, idx1;
11884
11885 for (i = 0; i < AUTO_PIN_LAST; i++) {
11886 switch(cfg->input_pins[i]) {
11887 case 0x18:
11888 idx1 = 0; /* Mic 1 */
11889 break;
11890 case 0x19:
11891 idx1 = 1; /* Mic 2 */
11892 break;
11893 case 0x1a:
11894 idx1 = 2; /* Line In */
11895 break;
Kailang Yangea1fb292008-08-26 12:58:38 +020011896 case 0x1c:
Kailang Yanga361d842007-06-05 12:30:55 +020011897 idx1 = 3; /* CD */
11898 break;
Takashi Iwai7194cae2008-03-06 16:58:17 +010011899 case 0x12:
11900 case 0x13:
11901 idx1 = 6; /* digital mics */
11902 break;
Kailang Yanga361d842007-06-05 12:30:55 +020011903 default:
11904 continue;
11905 }
11906 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
11907 imux->items[imux->num_items].index = idx1;
Kailang Yangea1fb292008-08-26 12:58:38 +020011908 imux->num_items++;
Kailang Yanga361d842007-06-05 12:30:55 +020011909 }
11910 return 0;
11911}
11912
11913static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec)
11914{
11915 struct alc_spec *spec = codec->spec;
11916 hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
11917 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
11918 hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
11919 unsigned int dac_vol1, dac_vol2;
11920
11921 if (speaker_nid) {
11922 snd_hda_codec_write(codec, speaker_nid, 0,
11923 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
11924 snd_hda_codec_write(codec, 0x0f, 0,
11925 AC_VERB_SET_AMP_GAIN_MUTE,
11926 AMP_IN_UNMUTE(1));
11927 snd_hda_codec_write(codec, 0x10, 0,
11928 AC_VERB_SET_AMP_GAIN_MUTE,
11929 AMP_IN_UNMUTE(1));
11930 } else {
11931 snd_hda_codec_write(codec, 0x0f, 0,
11932 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
11933 snd_hda_codec_write(codec, 0x10, 0,
11934 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
11935 }
11936
11937 dac_vol1 = dac_vol2 = 0xb000 | 0x40; /* set max volume */
Kailang Yangea1fb292008-08-26 12:58:38 +020011938 if (line_nid == 0x14)
Kailang Yanga361d842007-06-05 12:30:55 +020011939 dac_vol2 = AMP_OUT_ZERO;
11940 else if (line_nid == 0x15)
11941 dac_vol1 = AMP_OUT_ZERO;
Kailang Yangea1fb292008-08-26 12:58:38 +020011942 if (hp_nid == 0x14)
Kailang Yanga361d842007-06-05 12:30:55 +020011943 dac_vol2 = AMP_OUT_ZERO;
11944 else if (hp_nid == 0x15)
11945 dac_vol1 = AMP_OUT_ZERO;
11946 if (line_nid != 0x16 || hp_nid != 0x16 ||
11947 spec->autocfg.line_out_pins[1] != 0x16 ||
11948 spec->autocfg.line_out_pins[2] != 0x16)
11949 dac_vol1 = dac_vol2 = AMP_OUT_ZERO;
11950
11951 snd_hda_codec_write(codec, 0x02, 0,
11952 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol1);
11953 snd_hda_codec_write(codec, 0x03, 0,
11954 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol2);
11955}
11956
11957/* pcm configuration: identiacal with ALC880 */
11958#define alc268_pcm_analog_playback alc880_pcm_analog_playback
11959#define alc268_pcm_analog_capture alc880_pcm_analog_capture
Takashi Iwai63300792008-01-24 15:31:36 +010011960#define alc268_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
Kailang Yanga361d842007-06-05 12:30:55 +020011961#define alc268_pcm_digital_playback alc880_pcm_digital_playback
11962
11963/*
11964 * BIOS auto configuration
11965 */
11966static int alc268_parse_auto_config(struct hda_codec *codec)
11967{
11968 struct alc_spec *spec = codec->spec;
11969 int err;
11970 static hda_nid_t alc268_ignore[] = { 0 };
11971
11972 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
11973 alc268_ignore);
11974 if (err < 0)
11975 return err;
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010011976 if (!spec->autocfg.line_outs) {
11977 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
11978 spec->multiout.max_channels = 2;
11979 spec->no_analog = 1;
11980 goto dig_only;
11981 }
Kailang Yanga361d842007-06-05 12:30:55 +020011982 return 0; /* can't find valid BIOS pin config */
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010011983 }
Kailang Yanga361d842007-06-05 12:30:55 +020011984 err = alc268_auto_create_multi_out_ctls(spec, &spec->autocfg);
11985 if (err < 0)
11986 return err;
11987 err = alc268_auto_create_analog_input_ctls(spec, &spec->autocfg);
11988 if (err < 0)
11989 return err;
11990
11991 spec->multiout.max_channels = 2;
11992
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010011993 dig_only:
Kailang Yanga361d842007-06-05 12:30:55 +020011994 /* digital only support output */
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010011995 if (spec->autocfg.dig_outs) {
Kailang Yanga361d842007-06-05 12:30:55 +020011996 spec->multiout.dig_out_nid = ALC268_DIGOUT_NID;
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010011997 spec->dig_out_type = spec->autocfg.dig_out_type[0];
11998 }
Takashi Iwai603c4012008-07-30 15:01:44 +020011999 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010012000 add_mixer(spec, spec->kctls.list);
Kailang Yanga361d842007-06-05 12:30:55 +020012001
Takashi Iwai892981f2009-03-02 08:04:35 +010012002 if (!spec->no_analog && spec->autocfg.speaker_pins[0] != 0x1d)
Takashi Iwaid88897e2008-10-31 15:01:37 +010012003 add_mixer(spec, alc268_beep_mixer);
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012004
Takashi Iwaid88897e2008-10-31 15:01:37 +010012005 add_verb(spec, alc268_volume_init_verbs);
Kailang Yanga361d842007-06-05 12:30:55 +020012006 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020012007 spec->input_mux = &spec->private_imux[0];
Kailang Yanga361d842007-06-05 12:30:55 +020012008
Takashi Iwai776e1842007-08-29 15:07:11 +020012009 err = alc_auto_add_mic_boost(codec);
12010 if (err < 0)
12011 return err;
12012
Kailang Yanga361d842007-06-05 12:30:55 +020012013 return 1;
12014}
12015
12016#define alc268_auto_init_multi_out alc882_auto_init_multi_out
12017#define alc268_auto_init_hp_out alc882_auto_init_hp_out
12018#define alc268_auto_init_analog_input alc882_auto_init_analog_input
12019
12020/* init callback for auto-configuration model -- overriding the default init */
12021static void alc268_auto_init(struct hda_codec *codec)
12022{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012023 struct alc_spec *spec = codec->spec;
Kailang Yanga361d842007-06-05 12:30:55 +020012024 alc268_auto_init_multi_out(codec);
12025 alc268_auto_init_hp_out(codec);
12026 alc268_auto_init_mono_speaker_out(codec);
12027 alc268_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012028 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020012029 alc_inithook(codec);
Kailang Yanga361d842007-06-05 12:30:55 +020012030}
12031
12032/*
12033 * configuration and preset
12034 */
12035static const char *alc268_models[ALC268_MODEL_LAST] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012036 [ALC267_QUANTA_IL1] = "quanta-il1",
Kailang Yanga361d842007-06-05 12:30:55 +020012037 [ALC268_3ST] = "3stack",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020012038 [ALC268_TOSHIBA] = "toshiba",
Takashi Iwaid2738092007-08-16 14:59:45 +020012039 [ALC268_ACER] = "acer",
Takashi Iwaic238b4f2008-11-05 14:57:20 +010012040 [ALC268_ACER_DMIC] = "acer-dmic",
Kailang Yang8ef355d2008-08-26 13:10:22 +020012041 [ALC268_ACER_ASPIRE_ONE] = "acer-aspire",
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012042 [ALC268_DELL] = "dell",
Mirco Tischlerf12462c2008-02-04 12:33:59 +010012043 [ALC268_ZEPTO] = "zepto",
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010012044#ifdef CONFIG_SND_DEBUG
12045 [ALC268_TEST] = "test",
12046#endif
Kailang Yanga361d842007-06-05 12:30:55 +020012047 [ALC268_AUTO] = "auto",
12048};
12049
12050static struct snd_pci_quirk alc268_cfg_tbl[] = {
Takashi Iwaia0b8f7d2008-04-22 19:39:49 +020012051 SND_PCI_QUIRK(0x1025, 0x011e, "Acer Aspire 5720z", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012052 SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER),
Andy Shevchenkodafc8352008-01-25 11:53:50 +010012053 SND_PCI_QUIRK(0x1025, 0x012e, "Acer Aspire 5310", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012054 SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER),
Andy Shevchenko29a52c22008-01-24 17:29:00 +010012055 SND_PCI_QUIRK(0x1025, 0x0136, "Acer Aspire 5315", ALC268_ACER),
Kailang Yang8ef355d2008-08-26 13:10:22 +020012056 SND_PCI_QUIRK(0x1025, 0x015b, "Acer Aspire One",
12057 ALC268_ACER_ASPIRE_ONE),
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012058 SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL),
Takashi Iwai57d13922009-01-08 15:52:09 +010012059 SND_PCI_QUIRK(0x1028, 0x02b0, "Dell Inspiron Mini9", ALC268_DELL),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012060 SND_PCI_QUIRK(0x103c, 0x30cc, "TOSHIBA", ALC268_TOSHIBA),
Adam Williamson87488952009-05-21 18:32:59 -040012061 SND_PCI_QUIRK(0x103c, 0x30f1, "HP TX25xx series", ALC268_TOSHIBA),
Kailang Yanga361d842007-06-05 12:30:55 +020012062 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST),
Kailang Yangd1a991a2007-08-15 16:21:59 +020012063 SND_PCI_QUIRK(0x1179, 0xff10, "TOSHIBA A205", ALC268_TOSHIBA),
Takashi Iwai8e7f00f2007-09-07 10:58:58 +020012064 SND_PCI_QUIRK(0x1179, 0xff50, "TOSHIBA A305", ALC268_TOSHIBA),
Travis Place2346d0c2008-09-01 08:24:00 +020012065 SND_PCI_QUIRK(0x1179, 0xff64, "TOSHIBA L305", ALC268_TOSHIBA),
Tony Vroon378bd6a2008-06-04 12:08:30 +020012066 SND_PCI_QUIRK(0x14c0, 0x0025, "COMPAL IFL90/JFL-92", ALC268_TOSHIBA),
Takashi Iwaib875bf32007-09-06 15:00:27 +020012067 SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER),
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012068 SND_PCI_QUIRK(0x152d, 0x0771, "Quanta IL1", ALC267_QUANTA_IL1),
Mirco Tischlerf12462c2008-02-04 12:33:59 +010012069 SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO),
Kailang Yanga361d842007-06-05 12:30:55 +020012070 {}
12071};
12072
12073static struct alc_config_preset alc268_presets[] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012074 [ALC267_QUANTA_IL1] = {
Takashi Iwai22971e32009-02-10 11:56:44 +010012075 .mixers = { alc267_quanta_il1_mixer, alc268_beep_mixer },
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012076 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
12077 alc267_quanta_il1_verbs },
12078 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
12079 .dac_nids = alc268_dac_nids,
12080 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
12081 .adc_nids = alc268_adc_nids_alt,
12082 .hp_nid = 0x03,
12083 .num_channel_mode = ARRAY_SIZE(alc268_modes),
12084 .channel_mode = alc268_modes,
12085 .input_mux = &alc268_capture_source,
12086 .unsol_event = alc267_quanta_il1_unsol_event,
12087 .init_hook = alc267_quanta_il1_automute,
12088 },
Kailang Yanga361d842007-06-05 12:30:55 +020012089 [ALC268_3ST] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012090 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
12091 alc268_beep_mixer },
Kailang Yanga361d842007-06-05 12:30:55 +020012092 .init_verbs = { alc268_base_init_verbs },
12093 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
12094 .dac_nids = alc268_dac_nids,
12095 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
12096 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010012097 .capsrc_nids = alc268_capsrc_nids,
Kailang Yanga361d842007-06-05 12:30:55 +020012098 .hp_nid = 0x03,
12099 .dig_out_nid = ALC268_DIGOUT_NID,
12100 .num_channel_mode = ARRAY_SIZE(alc268_modes),
12101 .channel_mode = alc268_modes,
12102 .input_mux = &alc268_capture_source,
12103 },
Kailang Yangd1a991a2007-08-15 16:21:59 +020012104 [ALC268_TOSHIBA] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012105 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
12106 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020012107 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
12108 alc268_toshiba_verbs },
Kailang Yangd1a991a2007-08-15 16:21:59 +020012109 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
12110 .dac_nids = alc268_dac_nids,
12111 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
12112 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010012113 .capsrc_nids = alc268_capsrc_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020012114 .hp_nid = 0x03,
12115 .num_channel_mode = ARRAY_SIZE(alc268_modes),
12116 .channel_mode = alc268_modes,
12117 .input_mux = &alc268_capture_source,
Takashi Iwaid2738092007-08-16 14:59:45 +020012118 .unsol_event = alc268_toshiba_unsol_event,
12119 .init_hook = alc268_toshiba_automute,
12120 },
12121 [ALC268_ACER] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012122 .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer,
12123 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020012124 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
12125 alc268_acer_verbs },
12126 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
12127 .dac_nids = alc268_dac_nids,
12128 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
12129 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010012130 .capsrc_nids = alc268_capsrc_nids,
Takashi Iwaid2738092007-08-16 14:59:45 +020012131 .hp_nid = 0x02,
12132 .num_channel_mode = ARRAY_SIZE(alc268_modes),
12133 .channel_mode = alc268_modes,
Takashi Iwai0ccb5412008-03-06 16:58:35 +010012134 .input_mux = &alc268_acer_capture_source,
Takashi Iwaid2738092007-08-16 14:59:45 +020012135 .unsol_event = alc268_acer_unsol_event,
Takashi Iwai889c4392007-08-23 18:56:52 +020012136 .init_hook = alc268_acer_init_hook,
Kailang Yangd1a991a2007-08-15 16:21:59 +020012137 },
Takashi Iwaic238b4f2008-11-05 14:57:20 +010012138 [ALC268_ACER_DMIC] = {
12139 .mixers = { alc268_acer_dmic_mixer, alc268_capture_alt_mixer,
12140 alc268_beep_mixer },
12141 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
12142 alc268_acer_verbs },
12143 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
12144 .dac_nids = alc268_dac_nids,
12145 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
12146 .adc_nids = alc268_adc_nids_alt,
12147 .capsrc_nids = alc268_capsrc_nids,
12148 .hp_nid = 0x02,
12149 .num_channel_mode = ARRAY_SIZE(alc268_modes),
12150 .channel_mode = alc268_modes,
12151 .input_mux = &alc268_acer_dmic_capture_source,
12152 .unsol_event = alc268_acer_unsol_event,
12153 .init_hook = alc268_acer_init_hook,
12154 },
Kailang Yang8ef355d2008-08-26 13:10:22 +020012155 [ALC268_ACER_ASPIRE_ONE] = {
12156 .mixers = { alc268_acer_aspire_one_mixer,
Takashi Iwai22971e32009-02-10 11:56:44 +010012157 alc268_beep_mixer,
12158 alc268_capture_alt_mixer },
Kailang Yang8ef355d2008-08-26 13:10:22 +020012159 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
12160 alc268_acer_aspire_one_verbs },
12161 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
12162 .dac_nids = alc268_dac_nids,
12163 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
12164 .adc_nids = alc268_adc_nids_alt,
12165 .capsrc_nids = alc268_capsrc_nids,
12166 .hp_nid = 0x03,
12167 .num_channel_mode = ARRAY_SIZE(alc268_modes),
12168 .channel_mode = alc268_modes,
12169 .input_mux = &alc268_acer_lc_capture_source,
12170 .unsol_event = alc268_acer_lc_unsol_event,
12171 .init_hook = alc268_acer_lc_init_hook,
12172 },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012173 [ALC268_DELL] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012174 .mixers = { alc268_dell_mixer, alc268_beep_mixer },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012175 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
12176 alc268_dell_verbs },
12177 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
12178 .dac_nids = alc268_dac_nids,
12179 .hp_nid = 0x02,
12180 .num_channel_mode = ARRAY_SIZE(alc268_modes),
12181 .channel_mode = alc268_modes,
12182 .unsol_event = alc268_dell_unsol_event,
12183 .init_hook = alc268_dell_init_hook,
12184 .input_mux = &alc268_capture_source,
12185 },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010012186 [ALC268_ZEPTO] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012187 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
12188 alc268_beep_mixer },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010012189 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
12190 alc268_toshiba_verbs },
12191 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
12192 .dac_nids = alc268_dac_nids,
12193 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
12194 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010012195 .capsrc_nids = alc268_capsrc_nids,
Mirco Tischlerf12462c2008-02-04 12:33:59 +010012196 .hp_nid = 0x03,
12197 .dig_out_nid = ALC268_DIGOUT_NID,
12198 .num_channel_mode = ARRAY_SIZE(alc268_modes),
12199 .channel_mode = alc268_modes,
12200 .input_mux = &alc268_capture_source,
12201 .unsol_event = alc268_toshiba_unsol_event,
12202 .init_hook = alc268_toshiba_automute
12203 },
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010012204#ifdef CONFIG_SND_DEBUG
12205 [ALC268_TEST] = {
12206 .mixers = { alc268_test_mixer, alc268_capture_mixer },
12207 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
12208 alc268_volume_init_verbs },
12209 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
12210 .dac_nids = alc268_dac_nids,
12211 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
12212 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010012213 .capsrc_nids = alc268_capsrc_nids,
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010012214 .hp_nid = 0x03,
12215 .dig_out_nid = ALC268_DIGOUT_NID,
12216 .num_channel_mode = ARRAY_SIZE(alc268_modes),
12217 .channel_mode = alc268_modes,
12218 .input_mux = &alc268_capture_source,
12219 },
12220#endif
Kailang Yanga361d842007-06-05 12:30:55 +020012221};
12222
12223static int patch_alc268(struct hda_codec *codec)
12224{
12225 struct alc_spec *spec;
12226 int board_config;
Takashi Iwai22971e32009-02-10 11:56:44 +010012227 int i, has_beep, err;
Kailang Yanga361d842007-06-05 12:30:55 +020012228
12229 spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
12230 if (spec == NULL)
12231 return -ENOMEM;
12232
12233 codec->spec = spec;
12234
12235 board_config = snd_hda_check_board_config(codec, ALC268_MODEL_LAST,
12236 alc268_models,
12237 alc268_cfg_tbl);
12238
12239 if (board_config < 0 || board_config >= ALC268_MODEL_LAST) {
12240 printk(KERN_INFO "hda_codec: Unknown model for ALC268, "
12241 "trying auto-probe from BIOS...\n");
12242 board_config = ALC268_AUTO;
12243 }
12244
12245 if (board_config == ALC268_AUTO) {
12246 /* automatic parse from the BIOS config */
12247 err = alc268_parse_auto_config(codec);
12248 if (err < 0) {
12249 alc_free(codec);
12250 return err;
12251 } else if (!err) {
12252 printk(KERN_INFO
12253 "hda_codec: Cannot set up configuration "
12254 "from BIOS. Using base mode...\n");
12255 board_config = ALC268_3ST;
12256 }
12257 }
12258
12259 if (board_config != ALC268_AUTO)
12260 setup_preset(spec, &alc268_presets[board_config]);
12261
Kailang Yang2f893282008-05-27 12:14:47 +020012262 if (codec->vendor_id == 0x10ec0267) {
12263 spec->stream_name_analog = "ALC267 Analog";
12264 spec->stream_name_digital = "ALC267 Digital";
12265 } else {
12266 spec->stream_name_analog = "ALC268 Analog";
12267 spec->stream_name_digital = "ALC268 Digital";
12268 }
12269
Kailang Yanga361d842007-06-05 12:30:55 +020012270 spec->stream_analog_playback = &alc268_pcm_analog_playback;
12271 spec->stream_analog_capture = &alc268_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +010012272 spec->stream_analog_alt_capture = &alc268_pcm_analog_alt_capture;
Kailang Yanga361d842007-06-05 12:30:55 +020012273
Kailang Yanga361d842007-06-05 12:30:55 +020012274 spec->stream_digital_playback = &alc268_pcm_digital_playback;
12275
Takashi Iwai22971e32009-02-10 11:56:44 +010012276 has_beep = 0;
12277 for (i = 0; i < spec->num_mixers; i++) {
12278 if (spec->mixers[i] == alc268_beep_mixer) {
12279 has_beep = 1;
12280 break;
12281 }
12282 }
12283
12284 if (has_beep) {
12285 err = snd_hda_attach_beep_device(codec, 0x1);
12286 if (err < 0) {
12287 alc_free(codec);
12288 return err;
12289 }
12290 if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
12291 /* override the amp caps for beep generator */
12292 snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012293 (0x0c << AC_AMPCAP_OFFSET_SHIFT) |
12294 (0x0c << AC_AMPCAP_NUM_STEPS_SHIFT) |
12295 (0x07 << AC_AMPCAP_STEP_SIZE_SHIFT) |
12296 (0 << AC_AMPCAP_MUTE_SHIFT));
Takashi Iwai22971e32009-02-10 11:56:44 +010012297 }
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012298
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010012299 if (!spec->no_analog && !spec->adc_nids && spec->input_mux) {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012300 /* check whether NID 0x07 is valid */
12301 unsigned int wcap = get_wcaps(codec, 0x07);
Takashi Iwai85860c02008-02-19 15:00:15 +010012302 int i;
Kailang Yanga361d842007-06-05 12:30:55 +020012303
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012304 /* get type */
12305 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Takashi Iwai67ebcb02008-02-19 15:03:57 +010012306 if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012307 spec->adc_nids = alc268_adc_nids_alt;
12308 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt);
Takashi Iwaid88897e2008-10-31 15:01:37 +010012309 add_mixer(spec, alc268_capture_alt_mixer);
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012310 } else {
12311 spec->adc_nids = alc268_adc_nids;
12312 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids);
Takashi Iwaid88897e2008-10-31 15:01:37 +010012313 add_mixer(spec, alc268_capture_mixer);
Kailang Yanga361d842007-06-05 12:30:55 +020012314 }
Takashi Iwaie1406342008-02-11 18:32:32 +010012315 spec->capsrc_nids = alc268_capsrc_nids;
Takashi Iwai85860c02008-02-19 15:00:15 +010012316 /* set default input source */
12317 for (i = 0; i < spec->num_adc_nids; i++)
12318 snd_hda_codec_write_cache(codec, alc268_capsrc_nids[i],
12319 0, AC_VERB_SET_CONNECT_SEL,
12320 spec->input_mux->items[0].index);
Kailang Yanga361d842007-06-05 12:30:55 +020012321 }
Takashi Iwai2134ea42008-01-10 16:53:55 +010012322
12323 spec->vmaster_nid = 0x02;
12324
Kailang Yanga361d842007-06-05 12:30:55 +020012325 codec->patch_ops = alc_patch_ops;
12326 if (board_config == ALC268_AUTO)
12327 spec->init_hook = alc268_auto_init;
Kailang Yangea1fb292008-08-26 12:58:38 +020012328
Takashi Iwaidaead532008-11-28 12:55:36 +010012329 codec->proc_widget_hook = print_realtek_coef;
12330
Kailang Yanga361d842007-06-05 12:30:55 +020012331 return 0;
12332}
12333
12334/*
Kailang Yangf6a92242007-12-13 16:52:54 +010012335 * ALC269 channel source setting (2 channel)
12336 */
12337#define ALC269_DIGOUT_NID ALC880_DIGOUT_NID
12338
12339#define alc269_dac_nids alc260_dac_nids
12340
12341static hda_nid_t alc269_adc_nids[1] = {
12342 /* ADC1 */
Kailang Yangf53281e2008-07-18 12:36:43 +020012343 0x08,
12344};
12345
Takashi Iwaie01bf502008-08-21 16:25:07 +020012346static hda_nid_t alc269_capsrc_nids[1] = {
12347 0x23,
12348};
12349
12350/* NOTE: ADC2 (0x07) is connected from a recording *MIXER* (0x24),
12351 * not a mux!
12352 */
12353
Kailang Yangf53281e2008-07-18 12:36:43 +020012354static struct hda_input_mux alc269_eeepc_dmic_capture_source = {
12355 .num_items = 2,
12356 .items = {
12357 { "i-Mic", 0x5 },
12358 { "e-Mic", 0x0 },
12359 },
12360};
12361
12362static struct hda_input_mux alc269_eeepc_amic_capture_source = {
12363 .num_items = 2,
12364 .items = {
12365 { "i-Mic", 0x1 },
12366 { "e-Mic", 0x0 },
12367 },
Kailang Yangf6a92242007-12-13 16:52:54 +010012368};
12369
12370#define alc269_modes alc260_modes
12371#define alc269_capture_source alc880_lg_lw_capture_source
12372
12373static struct snd_kcontrol_new alc269_base_mixer[] = {
12374 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
12375 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
12376 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
12377 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
12378 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
12379 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
12380 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12381 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
12382 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
12383 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
12384 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
12385 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
12386 { } /* end */
12387};
12388
Kailang Yang60db6b52008-08-26 13:13:00 +020012389static struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = {
12390 /* output mixer control */
12391 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
12392 {
12393 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12394 .name = "Master Playback Switch",
12395 .info = snd_hda_mixer_amp_switch_info,
12396 .get = snd_hda_mixer_amp_switch_get,
12397 .put = alc268_acer_master_sw_put,
12398 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
12399 },
12400 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
12401 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
12402 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12403 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
12404 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
12405 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yang60db6b52008-08-26 13:13:00 +020012406 { }
12407};
12408
Tony Vroon64154832008-11-06 15:08:49 +000012409static struct snd_kcontrol_new alc269_lifebook_mixer[] = {
12410 /* output mixer control */
12411 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
12412 {
12413 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12414 .name = "Master Playback Switch",
12415 .info = snd_hda_mixer_amp_switch_info,
12416 .get = snd_hda_mixer_amp_switch_get,
12417 .put = alc268_acer_master_sw_put,
12418 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
12419 },
12420 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
12421 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
12422 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12423 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
12424 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
12425 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
12426 HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x0b, 0x03, HDA_INPUT),
12427 HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x0b, 0x03, HDA_INPUT),
12428 HDA_CODEC_VOLUME("Dock Mic Boost", 0x1b, 0, HDA_INPUT),
Tony Vroon64154832008-11-06 15:08:49 +000012429 { }
12430};
12431
Kailang Yangf53281e2008-07-18 12:36:43 +020012432/* bind volumes of both NID 0x0c and 0x0d */
12433static struct hda_bind_ctls alc269_epc_bind_vol = {
12434 .ops = &snd_hda_bind_vol,
12435 .values = {
12436 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
12437 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
12438 0
12439 },
12440};
12441
12442static struct snd_kcontrol_new alc269_eeepc_mixer[] = {
12443 HDA_CODEC_MUTE("iSpeaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
12444 HDA_BIND_VOL("LineOut Playback Volume", &alc269_epc_bind_vol),
12445 HDA_CODEC_MUTE("LineOut Playback Switch", 0x15, 0x0, HDA_OUTPUT),
12446 { } /* end */
12447};
12448
Kailang Yangf6a92242007-12-13 16:52:54 +010012449/* capture mixer elements */
Kailang Yangf53281e2008-07-18 12:36:43 +020012450static struct snd_kcontrol_new alc269_epc_capture_mixer[] = {
12451 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
12452 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
Takashi Iwai26f5df22008-11-03 17:39:46 +010012453 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12454 { } /* end */
12455};
12456
12457/* FSC amilo */
12458static struct snd_kcontrol_new alc269_fujitsu_mixer[] = {
12459 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
12460 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
12461 HDA_BIND_VOL("PCM Playback Volume", &alc269_epc_bind_vol),
Kailang Yangf53281e2008-07-18 12:36:43 +020012462 { } /* end */
12463};
12464
Kailang Yang60db6b52008-08-26 13:13:00 +020012465static struct hda_verb alc269_quanta_fl1_verbs[] = {
12466 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
12467 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12468 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12469 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12470 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
12471 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12472 { }
12473};
12474
Tony Vroon64154832008-11-06 15:08:49 +000012475static struct hda_verb alc269_lifebook_verbs[] = {
12476 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
12477 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
12478 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12479 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12480 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12481 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12482 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12483 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12484 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
12485 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12486 { }
12487};
12488
Kailang Yang60db6b52008-08-26 13:13:00 +020012489/* toggle speaker-output according to the hp-jack state */
12490static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec)
12491{
12492 unsigned int present;
12493 unsigned char bits;
12494
12495 present = snd_hda_codec_read(codec, 0x15, 0,
12496 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
12497 bits = present ? AMP_IN_MUTE(0) : 0;
12498 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
12499 AMP_IN_MUTE(0), bits);
12500 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
12501 AMP_IN_MUTE(0), bits);
12502
12503 snd_hda_codec_write(codec, 0x20, 0,
12504 AC_VERB_SET_COEF_INDEX, 0x0c);
12505 snd_hda_codec_write(codec, 0x20, 0,
12506 AC_VERB_SET_PROC_COEF, 0x680);
12507
12508 snd_hda_codec_write(codec, 0x20, 0,
12509 AC_VERB_SET_COEF_INDEX, 0x0c);
12510 snd_hda_codec_write(codec, 0x20, 0,
12511 AC_VERB_SET_PROC_COEF, 0x480);
12512}
12513
Tony Vroon64154832008-11-06 15:08:49 +000012514/* toggle speaker-output according to the hp-jacks state */
12515static void alc269_lifebook_speaker_automute(struct hda_codec *codec)
12516{
12517 unsigned int present;
12518 unsigned char bits;
12519
12520 /* Check laptop headphone socket */
12521 present = snd_hda_codec_read(codec, 0x15, 0,
12522 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
12523
12524 /* Check port replicator headphone socket */
12525 present |= snd_hda_codec_read(codec, 0x1a, 0,
12526 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
12527
12528 bits = present ? AMP_IN_MUTE(0) : 0;
12529 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
12530 AMP_IN_MUTE(0), bits);
12531 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
12532 AMP_IN_MUTE(0), bits);
12533
12534 snd_hda_codec_write(codec, 0x20, 0,
12535 AC_VERB_SET_COEF_INDEX, 0x0c);
12536 snd_hda_codec_write(codec, 0x20, 0,
12537 AC_VERB_SET_PROC_COEF, 0x680);
12538
12539 snd_hda_codec_write(codec, 0x20, 0,
12540 AC_VERB_SET_COEF_INDEX, 0x0c);
12541 snd_hda_codec_write(codec, 0x20, 0,
12542 AC_VERB_SET_PROC_COEF, 0x480);
12543}
12544
Kailang Yang60db6b52008-08-26 13:13:00 +020012545static void alc269_quanta_fl1_mic_automute(struct hda_codec *codec)
12546{
12547 unsigned int present;
12548
12549 present = snd_hda_codec_read(codec, 0x18, 0,
12550 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
12551 snd_hda_codec_write(codec, 0x23, 0,
12552 AC_VERB_SET_CONNECT_SEL, present ? 0x0 : 0x1);
12553}
12554
Tony Vroon64154832008-11-06 15:08:49 +000012555static void alc269_lifebook_mic_autoswitch(struct hda_codec *codec)
12556{
12557 unsigned int present_laptop;
12558 unsigned int present_dock;
12559
12560 present_laptop = snd_hda_codec_read(codec, 0x18, 0,
12561 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
12562
12563 present_dock = snd_hda_codec_read(codec, 0x1b, 0,
12564 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
12565
12566 /* Laptop mic port overrides dock mic port, design decision */
12567 if (present_dock)
12568 snd_hda_codec_write(codec, 0x23, 0,
12569 AC_VERB_SET_CONNECT_SEL, 0x3);
12570 if (present_laptop)
12571 snd_hda_codec_write(codec, 0x23, 0,
12572 AC_VERB_SET_CONNECT_SEL, 0x0);
12573 if (!present_dock && !present_laptop)
12574 snd_hda_codec_write(codec, 0x23, 0,
12575 AC_VERB_SET_CONNECT_SEL, 0x1);
12576}
12577
Kailang Yang60db6b52008-08-26 13:13:00 +020012578static void alc269_quanta_fl1_unsol_event(struct hda_codec *codec,
12579 unsigned int res)
12580{
12581 if ((res >> 26) == ALC880_HP_EVENT)
12582 alc269_quanta_fl1_speaker_automute(codec);
12583 if ((res >> 26) == ALC880_MIC_EVENT)
12584 alc269_quanta_fl1_mic_automute(codec);
12585}
12586
Tony Vroon64154832008-11-06 15:08:49 +000012587static void alc269_lifebook_unsol_event(struct hda_codec *codec,
12588 unsigned int res)
12589{
12590 if ((res >> 26) == ALC880_HP_EVENT)
12591 alc269_lifebook_speaker_automute(codec);
12592 if ((res >> 26) == ALC880_MIC_EVENT)
12593 alc269_lifebook_mic_autoswitch(codec);
12594}
12595
Kailang Yang60db6b52008-08-26 13:13:00 +020012596static void alc269_quanta_fl1_init_hook(struct hda_codec *codec)
12597{
12598 alc269_quanta_fl1_speaker_automute(codec);
12599 alc269_quanta_fl1_mic_automute(codec);
12600}
12601
Tony Vroon64154832008-11-06 15:08:49 +000012602static void alc269_lifebook_init_hook(struct hda_codec *codec)
12603{
12604 alc269_lifebook_speaker_automute(codec);
12605 alc269_lifebook_mic_autoswitch(codec);
12606}
12607
Kailang Yang60db6b52008-08-26 13:13:00 +020012608static struct hda_verb alc269_eeepc_dmic_init_verbs[] = {
12609 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
12610 {0x23, AC_VERB_SET_CONNECT_SEL, 0x05},
12611 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
12612 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
12613 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12614 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
12615 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
12616 {}
12617};
12618
12619static struct hda_verb alc269_eeepc_amic_init_verbs[] = {
12620 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
12621 {0x23, AC_VERB_SET_CONNECT_SEL, 0x01},
12622 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
12623 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x701b | (0x00 << 8))},
12624 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
12625 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
12626 {}
12627};
12628
12629/* toggle speaker-output according to the hp-jack state */
12630static void alc269_speaker_automute(struct hda_codec *codec)
12631{
12632 unsigned int present;
12633 unsigned char bits;
12634
12635 present = snd_hda_codec_read(codec, 0x15, 0,
12636 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
12637 bits = present ? AMP_IN_MUTE(0) : 0;
12638 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
12639 AMP_IN_MUTE(0), bits);
12640 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
12641 AMP_IN_MUTE(0), bits);
12642}
12643
12644static void alc269_eeepc_dmic_automute(struct hda_codec *codec)
12645{
12646 unsigned int present;
12647
12648 present = snd_hda_codec_read(codec, 0x18, 0,
12649 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
12650 snd_hda_codec_write(codec, 0x23, 0,
12651 AC_VERB_SET_CONNECT_SEL, (present ? 0 : 5));
12652}
12653
12654static void alc269_eeepc_amic_automute(struct hda_codec *codec)
12655{
12656 unsigned int present;
12657
12658 present = snd_hda_codec_read(codec, 0x18, 0,
12659 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
12660 snd_hda_codec_write(codec, 0x24, 0, AC_VERB_SET_AMP_GAIN_MUTE,
12661 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
12662 snd_hda_codec_write(codec, 0x24, 0, AC_VERB_SET_AMP_GAIN_MUTE,
12663 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
12664}
12665
12666/* unsolicited event for HP jack sensing */
12667static void alc269_eeepc_dmic_unsol_event(struct hda_codec *codec,
12668 unsigned int res)
12669{
12670 if ((res >> 26) == ALC880_HP_EVENT)
12671 alc269_speaker_automute(codec);
12672
12673 if ((res >> 26) == ALC880_MIC_EVENT)
12674 alc269_eeepc_dmic_automute(codec);
12675}
12676
12677static void alc269_eeepc_dmic_inithook(struct hda_codec *codec)
12678{
12679 alc269_speaker_automute(codec);
12680 alc269_eeepc_dmic_automute(codec);
12681}
12682
12683/* unsolicited event for HP jack sensing */
12684static void alc269_eeepc_amic_unsol_event(struct hda_codec *codec,
12685 unsigned int res)
12686{
12687 if ((res >> 26) == ALC880_HP_EVENT)
12688 alc269_speaker_automute(codec);
12689
12690 if ((res >> 26) == ALC880_MIC_EVENT)
12691 alc269_eeepc_amic_automute(codec);
12692}
12693
12694static void alc269_eeepc_amic_inithook(struct hda_codec *codec)
12695{
12696 alc269_speaker_automute(codec);
12697 alc269_eeepc_amic_automute(codec);
12698}
12699
Kailang Yangf6a92242007-12-13 16:52:54 +010012700/*
12701 * generic initialization of ADC, input mixers and output mixers
12702 */
12703static struct hda_verb alc269_init_verbs[] = {
12704 /*
12705 * Unmute ADC0 and set the default input to mic-in
12706 */
Kailang Yang60db6b52008-08-26 13:13:00 +020012707 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangf6a92242007-12-13 16:52:54 +010012708
12709 /* Mute input amps (PCBeep, Line In, Mic 1 & Mic 2) of the
12710 * analog-loopback mixer widget
12711 * Note: PASD motherboards uses the Line In 2 as the input for
12712 * front panel mic (mic 2)
12713 */
12714 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
12715 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12716 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12717 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12718 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12719 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
12720
12721 /*
12722 * Set up output mixers (0x0c - 0x0e)
12723 */
12724 /* set vol=0 to output mixers */
12725 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12726 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12727
12728 /* set up input amps for analog loopback */
12729 /* Amp Indices: DAC = 0, mixer = 1 */
12730 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12731 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12732 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12733 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12734 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12735 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12736
12737 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12738 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12739 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12740 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
12741 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
12742 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12743 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12744
12745 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12746 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12747 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12748 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12749 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12750 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12751 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12752
12753 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
12754 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
12755
12756 /* FIXME: use matrix-type input source selection */
12757 /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
12758 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yang60db6b52008-08-26 13:13:00 +020012759 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12760 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangf6a92242007-12-13 16:52:54 +010012761 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12762 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12763
12764 /* set EAPD */
12765 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
12766 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
12767 { }
12768};
12769
12770/* add playback controls from the parsed DAC table */
12771static int alc269_auto_create_multi_out_ctls(struct alc_spec *spec,
12772 const struct auto_pin_cfg *cfg)
12773{
12774 hda_nid_t nid;
12775 int err;
12776
12777 spec->multiout.num_dacs = 1; /* only use one dac */
12778 spec->multiout.dac_nids = spec->private_dac_nids;
12779 spec->multiout.dac_nids[0] = 2;
12780
12781 nid = cfg->line_out_pins[0];
12782 if (nid) {
12783 err = add_control(spec, ALC_CTL_WIDGET_VOL,
12784 "Front Playback Volume",
12785 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT));
12786 if (err < 0)
12787 return err;
12788 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
12789 "Front Playback Switch",
12790 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
12791 if (err < 0)
12792 return err;
12793 }
12794
12795 nid = cfg->speaker_pins[0];
12796 if (nid) {
12797 if (!cfg->line_out_pins[0]) {
12798 err = add_control(spec, ALC_CTL_WIDGET_VOL,
12799 "Speaker Playback Volume",
12800 HDA_COMPOSE_AMP_VAL(0x02, 3, 0,
12801 HDA_OUTPUT));
12802 if (err < 0)
12803 return err;
12804 }
12805 if (nid == 0x16) {
12806 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
12807 "Speaker Playback Switch",
12808 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
12809 HDA_OUTPUT));
12810 if (err < 0)
12811 return err;
12812 } else {
12813 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
12814 "Speaker Playback Switch",
12815 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
12816 HDA_OUTPUT));
12817 if (err < 0)
12818 return err;
12819 }
12820 }
12821 nid = cfg->hp_pins[0];
12822 if (nid) {
12823 /* spec->multiout.hp_nid = 2; */
12824 if (!cfg->line_out_pins[0] && !cfg->speaker_pins[0]) {
12825 err = add_control(spec, ALC_CTL_WIDGET_VOL,
12826 "Headphone Playback Volume",
12827 HDA_COMPOSE_AMP_VAL(0x02, 3, 0,
12828 HDA_OUTPUT));
12829 if (err < 0)
12830 return err;
12831 }
12832 if (nid == 0x16) {
12833 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
12834 "Headphone Playback Switch",
12835 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
12836 HDA_OUTPUT));
12837 if (err < 0)
12838 return err;
12839 } else {
12840 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
12841 "Headphone Playback Switch",
12842 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
12843 HDA_OUTPUT));
12844 if (err < 0)
12845 return err;
12846 }
12847 }
12848 return 0;
12849}
12850
Takashi Iwaiee956e02008-10-31 17:16:31 +010012851static int alc269_auto_create_analog_input_ctls(struct alc_spec *spec,
12852 const struct auto_pin_cfg *cfg)
12853{
12854 int err;
12855
12856 err = alc880_auto_create_analog_input_ctls(spec, cfg);
12857 if (err < 0)
12858 return err;
12859 /* digital-mic input pin is excluded in alc880_auto_create..()
12860 * because it's under 0x18
12861 */
12862 if (cfg->input_pins[AUTO_PIN_MIC] == 0x12 ||
12863 cfg->input_pins[AUTO_PIN_FRONT_MIC] == 0x12) {
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020012864 struct hda_input_mux *imux = &spec->private_imux[0];
Takashi Iwaiee956e02008-10-31 17:16:31 +010012865 imux->items[imux->num_items].label = "Int Mic";
12866 imux->items[imux->num_items].index = 0x05;
12867 imux->num_items++;
12868 }
12869 return 0;
12870}
Kailang Yangf6a92242007-12-13 16:52:54 +010012871
12872#ifdef CONFIG_SND_HDA_POWER_SAVE
12873#define alc269_loopbacks alc880_loopbacks
12874#endif
12875
12876/* pcm configuration: identiacal with ALC880 */
12877#define alc269_pcm_analog_playback alc880_pcm_analog_playback
12878#define alc269_pcm_analog_capture alc880_pcm_analog_capture
12879#define alc269_pcm_digital_playback alc880_pcm_digital_playback
12880#define alc269_pcm_digital_capture alc880_pcm_digital_capture
12881
Takashi Iwaif03d3112009-03-05 14:18:16 +010012882static struct hda_pcm_stream alc269_44k_pcm_analog_playback = {
12883 .substreams = 1,
12884 .channels_min = 2,
12885 .channels_max = 8,
12886 .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
12887 /* NID is set in alc_build_pcms */
12888 .ops = {
12889 .open = alc880_playback_pcm_open,
12890 .prepare = alc880_playback_pcm_prepare,
12891 .cleanup = alc880_playback_pcm_cleanup
12892 },
12893};
12894
12895static struct hda_pcm_stream alc269_44k_pcm_analog_capture = {
12896 .substreams = 1,
12897 .channels_min = 2,
12898 .channels_max = 2,
12899 .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
12900 /* NID is set in alc_build_pcms */
12901};
12902
Kailang Yangf6a92242007-12-13 16:52:54 +010012903/*
12904 * BIOS auto configuration
12905 */
12906static int alc269_parse_auto_config(struct hda_codec *codec)
12907{
12908 struct alc_spec *spec = codec->spec;
Takashi Iwaicfb9fb52009-02-06 17:34:03 +010012909 int err;
Kailang Yangf6a92242007-12-13 16:52:54 +010012910 static hda_nid_t alc269_ignore[] = { 0x1d, 0 };
12911
12912 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
12913 alc269_ignore);
12914 if (err < 0)
12915 return err;
12916
12917 err = alc269_auto_create_multi_out_ctls(spec, &spec->autocfg);
12918 if (err < 0)
12919 return err;
12920 err = alc269_auto_create_analog_input_ctls(spec, &spec->autocfg);
12921 if (err < 0)
12922 return err;
12923
12924 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
12925
Takashi Iwai0852d7a2009-02-11 11:35:15 +010012926 if (spec->autocfg.dig_outs)
Kailang Yangf6a92242007-12-13 16:52:54 +010012927 spec->multiout.dig_out_nid = ALC269_DIGOUT_NID;
12928
Takashi Iwai603c4012008-07-30 15:01:44 +020012929 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010012930 add_mixer(spec, spec->kctls.list);
Kailang Yangf6a92242007-12-13 16:52:54 +010012931
Takashi Iwaid88897e2008-10-31 15:01:37 +010012932 add_verb(spec, alc269_init_verbs);
Kailang Yangf6a92242007-12-13 16:52:54 +010012933 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020012934 spec->input_mux = &spec->private_imux[0];
Takashi Iwaie01bf502008-08-21 16:25:07 +020012935 /* set default input source */
12936 snd_hda_codec_write_cache(codec, alc269_capsrc_nids[0],
12937 0, AC_VERB_SET_CONNECT_SEL,
12938 spec->input_mux->items[0].index);
Kailang Yangf6a92242007-12-13 16:52:54 +010012939
12940 err = alc_auto_add_mic_boost(codec);
12941 if (err < 0)
12942 return err;
12943
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010012944 if (!spec->cap_mixer && !spec->no_analog)
Takashi Iwaif9e336f2008-10-31 16:37:07 +010012945 set_capture_mixer(spec);
Kailang Yangf53281e2008-07-18 12:36:43 +020012946
Kailang Yangf6a92242007-12-13 16:52:54 +010012947 return 1;
12948}
12949
12950#define alc269_auto_init_multi_out alc882_auto_init_multi_out
12951#define alc269_auto_init_hp_out alc882_auto_init_hp_out
12952#define alc269_auto_init_analog_input alc882_auto_init_analog_input
12953
12954
12955/* init callback for auto-configuration model -- overriding the default init */
12956static void alc269_auto_init(struct hda_codec *codec)
12957{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012958 struct alc_spec *spec = codec->spec;
Kailang Yangf6a92242007-12-13 16:52:54 +010012959 alc269_auto_init_multi_out(codec);
12960 alc269_auto_init_hp_out(codec);
12961 alc269_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012962 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020012963 alc_inithook(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010012964}
12965
12966/*
12967 * configuration and preset
12968 */
12969static const char *alc269_models[ALC269_MODEL_LAST] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020012970 [ALC269_BASIC] = "basic",
Takashi Iwai2922c9a2008-08-27 18:12:42 +020012971 [ALC269_QUANTA_FL1] = "quanta",
12972 [ALC269_ASUS_EEEPC_P703] = "eeepc-p703",
Takashi Iwai26f5df22008-11-03 17:39:46 +010012973 [ALC269_ASUS_EEEPC_P901] = "eeepc-p901",
Tony Vroon64154832008-11-06 15:08:49 +000012974 [ALC269_FUJITSU] = "fujitsu",
12975 [ALC269_LIFEBOOK] = "lifebook"
Kailang Yangf6a92242007-12-13 16:52:54 +010012976};
12977
12978static struct snd_pci_quirk alc269_cfg_tbl[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020012979 SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_QUANTA_FL1),
Kailang Yangf53281e2008-07-18 12:36:43 +020012980 SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A",
12981 ALC269_ASUS_EEEPC_P703),
Kailang Yang622e84c2009-04-21 07:39:04 +020012982 SND_PCI_QUIRK(0x1043, 0x1883, "ASUS F81Se", ALC269_ASUS_EEEPC_P703),
12983 SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS F5Q", ALC269_ASUS_EEEPC_P703),
12984 SND_PCI_QUIRK(0x1043, 0x1723, "ASUS P80", ALC269_ASUS_EEEPC_P703),
12985 SND_PCI_QUIRK(0x1043, 0x1773, "ASUS U20A", ALC269_ASUS_EEEPC_P703),
12986 SND_PCI_QUIRK(0x1043, 0x1743, "ASUS U80", ALC269_ASUS_EEEPC_P703),
12987 SND_PCI_QUIRK(0x1043, 0x1653, "ASUS U50", ALC269_ASUS_EEEPC_P703),
Kailang Yangf53281e2008-07-18 12:36:43 +020012988 SND_PCI_QUIRK(0x1043, 0x831a, "ASUS Eeepc P901",
12989 ALC269_ASUS_EEEPC_P901),
Kailang Yang60db6b52008-08-26 13:13:00 +020012990 SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101",
12991 ALC269_ASUS_EEEPC_P901),
Kailang Yang622e84c2009-04-21 07:39:04 +020012992 SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_ASUS_EEEPC_P901),
Takashi Iwai26f5df22008-11-03 17:39:46 +010012993 SND_PCI_QUIRK(0x1734, 0x115d, "FSC Amilo", ALC269_FUJITSU),
Tony Vroon64154832008-11-06 15:08:49 +000012994 SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook ICH9M-based", ALC269_LIFEBOOK),
Kailang Yangf6a92242007-12-13 16:52:54 +010012995 {}
12996};
12997
12998static struct alc_config_preset alc269_presets[] = {
12999 [ALC269_BASIC] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010013000 .mixers = { alc269_base_mixer },
Kailang Yangf6a92242007-12-13 16:52:54 +010013001 .init_verbs = { alc269_init_verbs },
13002 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
13003 .dac_nids = alc269_dac_nids,
13004 .hp_nid = 0x03,
13005 .num_channel_mode = ARRAY_SIZE(alc269_modes),
13006 .channel_mode = alc269_modes,
13007 .input_mux = &alc269_capture_source,
13008 },
Kailang Yang60db6b52008-08-26 13:13:00 +020013009 [ALC269_QUANTA_FL1] = {
13010 .mixers = { alc269_quanta_fl1_mixer },
13011 .init_verbs = { alc269_init_verbs, alc269_quanta_fl1_verbs },
13012 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
13013 .dac_nids = alc269_dac_nids,
13014 .hp_nid = 0x03,
13015 .num_channel_mode = ARRAY_SIZE(alc269_modes),
13016 .channel_mode = alc269_modes,
13017 .input_mux = &alc269_capture_source,
13018 .unsol_event = alc269_quanta_fl1_unsol_event,
13019 .init_hook = alc269_quanta_fl1_init_hook,
13020 },
Kailang Yangf53281e2008-07-18 12:36:43 +020013021 [ALC269_ASUS_EEEPC_P703] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010013022 .mixers = { alc269_eeepc_mixer },
13023 .cap_mixer = alc269_epc_capture_mixer,
Kailang Yangf53281e2008-07-18 12:36:43 +020013024 .init_verbs = { alc269_init_verbs,
13025 alc269_eeepc_amic_init_verbs },
13026 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
13027 .dac_nids = alc269_dac_nids,
13028 .hp_nid = 0x03,
13029 .num_channel_mode = ARRAY_SIZE(alc269_modes),
13030 .channel_mode = alc269_modes,
13031 .input_mux = &alc269_eeepc_amic_capture_source,
13032 .unsol_event = alc269_eeepc_amic_unsol_event,
13033 .init_hook = alc269_eeepc_amic_inithook,
13034 },
13035 [ALC269_ASUS_EEEPC_P901] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010013036 .mixers = { alc269_eeepc_mixer },
13037 .cap_mixer = alc269_epc_capture_mixer,
Kailang Yangf53281e2008-07-18 12:36:43 +020013038 .init_verbs = { alc269_init_verbs,
13039 alc269_eeepc_dmic_init_verbs },
13040 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
13041 .dac_nids = alc269_dac_nids,
13042 .hp_nid = 0x03,
13043 .num_channel_mode = ARRAY_SIZE(alc269_modes),
13044 .channel_mode = alc269_modes,
13045 .input_mux = &alc269_eeepc_dmic_capture_source,
13046 .unsol_event = alc269_eeepc_dmic_unsol_event,
13047 .init_hook = alc269_eeepc_dmic_inithook,
13048 },
Takashi Iwai26f5df22008-11-03 17:39:46 +010013049 [ALC269_FUJITSU] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010013050 .mixers = { alc269_fujitsu_mixer },
Takashi Iwai26f5df22008-11-03 17:39:46 +010013051 .cap_mixer = alc269_epc_capture_mixer,
13052 .init_verbs = { alc269_init_verbs,
13053 alc269_eeepc_dmic_init_verbs },
13054 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
13055 .dac_nids = alc269_dac_nids,
13056 .hp_nid = 0x03,
13057 .num_channel_mode = ARRAY_SIZE(alc269_modes),
13058 .channel_mode = alc269_modes,
13059 .input_mux = &alc269_eeepc_dmic_capture_source,
13060 .unsol_event = alc269_eeepc_dmic_unsol_event,
13061 .init_hook = alc269_eeepc_dmic_inithook,
13062 },
Tony Vroon64154832008-11-06 15:08:49 +000013063 [ALC269_LIFEBOOK] = {
13064 .mixers = { alc269_lifebook_mixer },
13065 .init_verbs = { alc269_init_verbs, alc269_lifebook_verbs },
13066 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
13067 .dac_nids = alc269_dac_nids,
13068 .hp_nid = 0x03,
13069 .num_channel_mode = ARRAY_SIZE(alc269_modes),
13070 .channel_mode = alc269_modes,
13071 .input_mux = &alc269_capture_source,
13072 .unsol_event = alc269_lifebook_unsol_event,
13073 .init_hook = alc269_lifebook_init_hook,
13074 },
Kailang Yangf6a92242007-12-13 16:52:54 +010013075};
13076
13077static int patch_alc269(struct hda_codec *codec)
13078{
13079 struct alc_spec *spec;
13080 int board_config;
13081 int err;
13082
13083 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
13084 if (spec == NULL)
13085 return -ENOMEM;
13086
13087 codec->spec = spec;
13088
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020013089 alc_fix_pll_init(codec, 0x20, 0x04, 15);
13090
Kailang Yangf6a92242007-12-13 16:52:54 +010013091 board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST,
13092 alc269_models,
13093 alc269_cfg_tbl);
13094
13095 if (board_config < 0) {
13096 printk(KERN_INFO "hda_codec: Unknown model for ALC269, "
13097 "trying auto-probe from BIOS...\n");
13098 board_config = ALC269_AUTO;
13099 }
13100
13101 if (board_config == ALC269_AUTO) {
13102 /* automatic parse from the BIOS config */
13103 err = alc269_parse_auto_config(codec);
13104 if (err < 0) {
13105 alc_free(codec);
13106 return err;
13107 } else if (!err) {
13108 printk(KERN_INFO
13109 "hda_codec: Cannot set up configuration "
13110 "from BIOS. Using base mode...\n");
13111 board_config = ALC269_BASIC;
13112 }
13113 }
13114
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090013115 err = snd_hda_attach_beep_device(codec, 0x1);
13116 if (err < 0) {
13117 alc_free(codec);
13118 return err;
13119 }
13120
Kailang Yangf6a92242007-12-13 16:52:54 +010013121 if (board_config != ALC269_AUTO)
13122 setup_preset(spec, &alc269_presets[board_config]);
13123
13124 spec->stream_name_analog = "ALC269 Analog";
Takashi Iwaif03d3112009-03-05 14:18:16 +010013125 if (codec->subsystem_id == 0x17aa3bf8) {
13126 /* Due to a hardware problem on Lenovo Ideadpad, we need to
13127 * fix the sample rate of analog I/O to 44.1kHz
13128 */
13129 spec->stream_analog_playback = &alc269_44k_pcm_analog_playback;
13130 spec->stream_analog_capture = &alc269_44k_pcm_analog_capture;
13131 } else {
13132 spec->stream_analog_playback = &alc269_pcm_analog_playback;
13133 spec->stream_analog_capture = &alc269_pcm_analog_capture;
13134 }
Kailang Yangf6a92242007-12-13 16:52:54 +010013135 spec->stream_name_digital = "ALC269 Digital";
13136 spec->stream_digital_playback = &alc269_pcm_digital_playback;
13137 spec->stream_digital_capture = &alc269_pcm_digital_capture;
13138
13139 spec->adc_nids = alc269_adc_nids;
13140 spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids);
Takashi Iwaie01bf502008-08-21 16:25:07 +020013141 spec->capsrc_nids = alc269_capsrc_nids;
Takashi Iwaif9e336f2008-10-31 16:37:07 +010013142 if (!spec->cap_mixer)
13143 set_capture_mixer(spec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010013144 set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
Kailang Yangf6a92242007-12-13 16:52:54 +010013145
13146 codec->patch_ops = alc_patch_ops;
13147 if (board_config == ALC269_AUTO)
13148 spec->init_hook = alc269_auto_init;
13149#ifdef CONFIG_SND_HDA_POWER_SAVE
13150 if (!spec->loopback.amplist)
13151 spec->loopback.amplist = alc269_loopbacks;
13152#endif
Takashi Iwaidaead532008-11-28 12:55:36 +010013153 codec->proc_widget_hook = print_realtek_coef;
Kailang Yangf6a92242007-12-13 16:52:54 +010013154
13155 return 0;
13156}
13157
13158/*
Kailang Yangdf694da2005-12-05 19:42:22 +010013159 * ALC861 channel source setting (2/6 channel selection for 3-stack)
13160 */
13161
13162/*
13163 * set the path ways for 2 channel output
13164 * need to set the codec line out and mic 1 pin widgets to inputs
13165 */
13166static struct hda_verb alc861_threestack_ch2_init[] = {
13167 /* set pin widget 1Ah (line in) for input */
13168 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013169 /* set pin widget 18h (mic1/2) for input, for mic also enable
13170 * the vref
13171 */
Kailang Yangdf694da2005-12-05 19:42:22 +010013172 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13173
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013174 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
13175#if 0
13176 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
13177 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
13178#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010013179 { } /* end */
13180};
13181/*
13182 * 6ch mode
13183 * need to set the codec line out and mic 1 pin widgets to outputs
13184 */
13185static struct hda_verb alc861_threestack_ch6_init[] = {
13186 /* set pin widget 1Ah (line in) for output (Back Surround)*/
13187 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13188 /* set pin widget 18h (mic1) for output (CLFE)*/
13189 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13190
13191 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013192 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010013193
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013194 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
13195#if 0
13196 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
13197 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
13198#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010013199 { } /* end */
13200};
13201
13202static struct hda_channel_mode alc861_threestack_modes[2] = {
13203 { 2, alc861_threestack_ch2_init },
13204 { 6, alc861_threestack_ch6_init },
13205};
Takashi Iwai22309c32006-08-09 16:57:28 +020013206/* Set mic1 as input and unmute the mixer */
13207static struct hda_verb alc861_uniwill_m31_ch2_init[] = {
13208 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13209 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
13210 { } /* end */
13211};
13212/* Set mic1 as output and mute mixer */
13213static struct hda_verb alc861_uniwill_m31_ch4_init[] = {
13214 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13215 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
13216 { } /* end */
13217};
13218
13219static struct hda_channel_mode alc861_uniwill_m31_modes[2] = {
13220 { 2, alc861_uniwill_m31_ch2_init },
13221 { 4, alc861_uniwill_m31_ch4_init },
13222};
Kailang Yangdf694da2005-12-05 19:42:22 +010013223
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013224/* Set mic1 and line-in as input and unmute the mixer */
13225static struct hda_verb alc861_asus_ch2_init[] = {
13226 /* set pin widget 1Ah (line in) for input */
13227 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013228 /* set pin widget 18h (mic1/2) for input, for mic also enable
13229 * the vref
13230 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013231 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13232
13233 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
13234#if 0
13235 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
13236 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
13237#endif
13238 { } /* end */
13239};
13240/* Set mic1 nad line-in as output and mute mixer */
13241static struct hda_verb alc861_asus_ch6_init[] = {
13242 /* set pin widget 1Ah (line in) for output (Back Surround)*/
13243 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13244 /* { 0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
13245 /* set pin widget 18h (mic1) for output (CLFE)*/
13246 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13247 /* { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
13248 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
13249 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
13250
13251 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
13252#if 0
13253 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
13254 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
13255#endif
13256 { } /* end */
13257};
13258
13259static struct hda_channel_mode alc861_asus_modes[2] = {
13260 { 2, alc861_asus_ch2_init },
13261 { 6, alc861_asus_ch6_init },
13262};
13263
Kailang Yangdf694da2005-12-05 19:42:22 +010013264/* patch-ALC861 */
13265
13266static struct snd_kcontrol_new alc861_base_mixer[] = {
13267 /* output mixer control */
13268 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
13269 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
13270 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
13271 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
13272 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
13273
13274 /*Input mixer control */
13275 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
13276 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
13277 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
13278 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
13279 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
13280 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
13281 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
13282 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
13283 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
13284 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013285
Kailang Yangdf694da2005-12-05 19:42:22 +010013286 { } /* end */
13287};
13288
13289static struct snd_kcontrol_new alc861_3ST_mixer[] = {
13290 /* output mixer control */
13291 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
13292 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
13293 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
13294 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
13295 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
13296
13297 /* Input mixer control */
13298 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
13299 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
13300 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
13301 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
13302 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
13303 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
13304 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
13305 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
13306 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
13307 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013308
Kailang Yangdf694da2005-12-05 19:42:22 +010013309 {
13310 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13311 .name = "Channel Mode",
13312 .info = alc_ch_mode_info,
13313 .get = alc_ch_mode_get,
13314 .put = alc_ch_mode_put,
13315 .private_value = ARRAY_SIZE(alc861_threestack_modes),
13316 },
13317 { } /* end */
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013318};
13319
Takashi Iwaid1d985f2006-11-23 19:27:12 +010013320static struct snd_kcontrol_new alc861_toshiba_mixer[] = {
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013321 /* output mixer control */
13322 HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT),
13323 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
13324 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
Kailang Yangea1fb292008-08-26 12:58:38 +020013325
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013326 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013327};
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013328
Takashi Iwai22309c32006-08-09 16:57:28 +020013329static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = {
13330 /* output mixer control */
13331 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
13332 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
13333 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
13334 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
13335 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
13336
13337 /* Input mixer control */
13338 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
13339 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
13340 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
13341 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
13342 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
13343 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
13344 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
13345 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
13346 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
13347 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013348
Takashi Iwai22309c32006-08-09 16:57:28 +020013349 {
13350 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13351 .name = "Channel Mode",
13352 .info = alc_ch_mode_info,
13353 .get = alc_ch_mode_get,
13354 .put = alc_ch_mode_put,
13355 .private_value = ARRAY_SIZE(alc861_uniwill_m31_modes),
13356 },
13357 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013358};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013359
13360static struct snd_kcontrol_new alc861_asus_mixer[] = {
13361 /* output mixer control */
13362 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
13363 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
13364 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
13365 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
13366 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
13367
13368 /* Input mixer control */
13369 HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
13370 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT),
13371 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
13372 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
13373 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
13374 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
13375 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
13376 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
13377 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013378 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_OUTPUT),
13379
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013380 {
13381 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13382 .name = "Channel Mode",
13383 .info = alc_ch_mode_info,
13384 .get = alc_ch_mode_get,
13385 .put = alc_ch_mode_put,
13386 .private_value = ARRAY_SIZE(alc861_asus_modes),
13387 },
13388 { }
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010013389};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013390
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010013391/* additional mixer */
Takashi Iwaid1d985f2006-11-23 19:27:12 +010013392static struct snd_kcontrol_new alc861_asus_laptop_mixer[] = {
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010013393 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
13394 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010013395 { }
13396};
13397
Kailang Yangdf694da2005-12-05 19:42:22 +010013398/*
13399 * generic initialization of ADC, input mixers and output mixers
13400 */
13401static struct hda_verb alc861_base_init_verbs[] = {
13402 /*
13403 * Unmute ADC0 and set the default input to mic-in
13404 */
13405 /* port-A for surround (rear panel) */
13406 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13407 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x00 },
13408 /* port-B for mic-in (rear panel) with vref */
13409 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13410 /* port-C for line-in (rear panel) */
13411 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
13412 /* port-D for Front */
13413 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13414 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
13415 /* port-E for HP out (front panel) */
13416 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
13417 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010013418 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010013419 /* port-F for mic-in (front panel) with vref */
13420 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13421 /* port-G for CLFE (rear panel) */
13422 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13423 { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x00 },
13424 /* port-H for side (rear panel) */
13425 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13426 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x00 },
13427 /* CD-in */
13428 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
13429 /* route front mic to ADC1*/
13430 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
13431 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020013432
Kailang Yangdf694da2005-12-05 19:42:22 +010013433 /* Unmute DAC0~3 & spdif out*/
13434 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13435 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13436 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13437 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13438 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020013439
Kailang Yangdf694da2005-12-05 19:42:22 +010013440 /* Unmute Mixer 14 (mic) 1c (Line in)*/
13441 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13442 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13443 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13444 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020013445
Kailang Yangdf694da2005-12-05 19:42:22 +010013446 /* Unmute Stereo Mixer 15 */
13447 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13448 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13449 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013450 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010013451
13452 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13453 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13454 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13455 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13456 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13457 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13458 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13459 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013460 /* hp used DAC 3 (Front) */
13461 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010013462 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
13463
13464 { }
13465};
13466
13467static struct hda_verb alc861_threestack_init_verbs[] = {
13468 /*
13469 * Unmute ADC0 and set the default input to mic-in
13470 */
13471 /* port-A for surround (rear panel) */
13472 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
13473 /* port-B for mic-in (rear panel) with vref */
13474 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13475 /* port-C for line-in (rear panel) */
13476 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
13477 /* port-D for Front */
13478 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13479 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
13480 /* port-E for HP out (front panel) */
13481 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
13482 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010013483 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010013484 /* port-F for mic-in (front panel) with vref */
13485 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13486 /* port-G for CLFE (rear panel) */
13487 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
13488 /* port-H for side (rear panel) */
13489 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
13490 /* CD-in */
13491 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
13492 /* route front mic to ADC1*/
13493 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
13494 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13495 /* Unmute DAC0~3 & spdif out*/
13496 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13497 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13498 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13499 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13500 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020013501
Kailang Yangdf694da2005-12-05 19:42:22 +010013502 /* Unmute Mixer 14 (mic) 1c (Line in)*/
13503 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13504 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13505 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13506 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020013507
Kailang Yangdf694da2005-12-05 19:42:22 +010013508 /* Unmute Stereo Mixer 15 */
13509 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13510 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13511 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013512 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010013513
13514 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13515 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13516 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13517 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13518 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13519 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13520 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13521 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013522 /* hp used DAC 3 (Front) */
13523 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010013524 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
13525 { }
13526};
Takashi Iwai22309c32006-08-09 16:57:28 +020013527
13528static struct hda_verb alc861_uniwill_m31_init_verbs[] = {
13529 /*
13530 * Unmute ADC0 and set the default input to mic-in
13531 */
13532 /* port-A for surround (rear panel) */
13533 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
13534 /* port-B for mic-in (rear panel) with vref */
13535 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13536 /* port-C for line-in (rear panel) */
13537 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
13538 /* port-D for Front */
13539 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13540 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
13541 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013542 /* this has to be set to VREF80 */
13543 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Takashi Iwai22309c32006-08-09 16:57:28 +020013544 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010013545 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai22309c32006-08-09 16:57:28 +020013546 /* port-F for mic-in (front panel) with vref */
13547 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13548 /* port-G for CLFE (rear panel) */
13549 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
13550 /* port-H for side (rear panel) */
13551 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
13552 /* CD-in */
13553 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
13554 /* route front mic to ADC1*/
13555 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
13556 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13557 /* Unmute DAC0~3 & spdif out*/
13558 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13559 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13560 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13561 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13562 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020013563
Takashi Iwai22309c32006-08-09 16:57:28 +020013564 /* Unmute Mixer 14 (mic) 1c (Line in)*/
13565 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13566 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13567 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13568 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020013569
Takashi Iwai22309c32006-08-09 16:57:28 +020013570 /* Unmute Stereo Mixer 15 */
13571 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13572 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13573 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013574 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Takashi Iwai22309c32006-08-09 16:57:28 +020013575
13576 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13577 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13578 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13579 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13580 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13581 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13582 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13583 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013584 /* hp used DAC 3 (Front) */
13585 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Takashi Iwai22309c32006-08-09 16:57:28 +020013586 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
13587 { }
13588};
13589
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013590static struct hda_verb alc861_asus_init_verbs[] = {
13591 /*
13592 * Unmute ADC0 and set the default input to mic-in
13593 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013594 /* port-A for surround (rear panel)
13595 * according to codec#0 this is the HP jack
13596 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013597 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* was 0x00 */
13598 /* route front PCM to HP */
13599 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x01 },
13600 /* port-B for mic-in (rear panel) with vref */
13601 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13602 /* port-C for line-in (rear panel) */
13603 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
13604 /* port-D for Front */
13605 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13606 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
13607 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013608 /* this has to be set to VREF80 */
13609 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013610 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010013611 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013612 /* port-F for mic-in (front panel) with vref */
13613 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13614 /* port-G for CLFE (rear panel) */
13615 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13616 /* port-H for side (rear panel) */
13617 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13618 /* CD-in */
13619 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
13620 /* route front mic to ADC1*/
13621 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
13622 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13623 /* Unmute DAC0~3 & spdif out*/
13624 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13625 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13626 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13627 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13628 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13629 /* Unmute Mixer 14 (mic) 1c (Line in)*/
13630 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13631 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13632 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13633 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020013634
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013635 /* Unmute Stereo Mixer 15 */
13636 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13637 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13638 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013639 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013640
13641 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13642 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13643 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13644 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13645 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13646 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13647 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13648 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013649 /* hp used DAC 3 (Front) */
13650 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013651 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
13652 { }
13653};
13654
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010013655/* additional init verbs for ASUS laptops */
13656static struct hda_verb alc861_asus_laptop_init_verbs[] = {
13657 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x45 }, /* HP-out */
13658 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2) }, /* mute line-in */
13659 { }
13660};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013661
Kailang Yangdf694da2005-12-05 19:42:22 +010013662/*
13663 * generic initialization of ADC, input mixers and output mixers
13664 */
13665static struct hda_verb alc861_auto_init_verbs[] = {
13666 /*
13667 * Unmute ADC0 and set the default input to mic-in
13668 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013669 /* {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, */
Kailang Yangdf694da2005-12-05 19:42:22 +010013670 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020013671
Kailang Yangdf694da2005-12-05 19:42:22 +010013672 /* Unmute DAC0~3 & spdif out*/
13673 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13674 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13675 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13676 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13677 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020013678
Kailang Yangdf694da2005-12-05 19:42:22 +010013679 /* Unmute Mixer 14 (mic) 1c (Line in)*/
13680 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13681 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13682 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13683 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020013684
Kailang Yangdf694da2005-12-05 19:42:22 +010013685 /* Unmute Stereo Mixer 15 */
13686 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13687 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13688 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
13689 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c},
13690
13691 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13692 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13693 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13694 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13695 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13696 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13697 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13698 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13699
13700 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13701 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013702 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
13703 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010013704 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13705 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013706 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
13707 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010013708
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013709 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, /* set Mic 1 */
Kailang Yangdf694da2005-12-05 19:42:22 +010013710
13711 { }
13712};
13713
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013714static struct hda_verb alc861_toshiba_init_verbs[] = {
13715 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013716
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013717 { }
13718};
13719
13720/* toggle speaker-output according to the hp-jack state */
13721static void alc861_toshiba_automute(struct hda_codec *codec)
13722{
13723 unsigned int present;
13724
13725 present = snd_hda_codec_read(codec, 0x0f, 0,
13726 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020013727 snd_hda_codec_amp_stereo(codec, 0x16, HDA_INPUT, 0,
13728 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
13729 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_INPUT, 3,
13730 HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE);
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013731}
13732
13733static void alc861_toshiba_unsol_event(struct hda_codec *codec,
13734 unsigned int res)
13735{
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013736 if ((res >> 26) == ALC880_HP_EVENT)
13737 alc861_toshiba_automute(codec);
13738}
13739
Kailang Yangdf694da2005-12-05 19:42:22 +010013740/* pcm configuration: identiacal with ALC880 */
13741#define alc861_pcm_analog_playback alc880_pcm_analog_playback
13742#define alc861_pcm_analog_capture alc880_pcm_analog_capture
13743#define alc861_pcm_digital_playback alc880_pcm_digital_playback
13744#define alc861_pcm_digital_capture alc880_pcm_digital_capture
13745
13746
13747#define ALC861_DIGOUT_NID 0x07
13748
13749static struct hda_channel_mode alc861_8ch_modes[1] = {
13750 { 8, NULL }
13751};
13752
13753static hda_nid_t alc861_dac_nids[4] = {
13754 /* front, surround, clfe, side */
13755 0x03, 0x06, 0x05, 0x04
13756};
13757
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013758static hda_nid_t alc660_dac_nids[3] = {
13759 /* front, clfe, surround */
13760 0x03, 0x05, 0x06
13761};
13762
Kailang Yangdf694da2005-12-05 19:42:22 +010013763static hda_nid_t alc861_adc_nids[1] = {
13764 /* ADC0-2 */
13765 0x08,
13766};
13767
13768static struct hda_input_mux alc861_capture_source = {
13769 .num_items = 5,
13770 .items = {
13771 { "Mic", 0x0 },
13772 { "Front Mic", 0x3 },
13773 { "Line", 0x1 },
13774 { "CD", 0x4 },
13775 { "Mixer", 0x5 },
13776 },
13777};
13778
13779/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013780static int alc861_auto_fill_dac_nids(struct alc_spec *spec,
13781 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010013782{
13783 int i;
13784 hda_nid_t nid;
13785
13786 spec->multiout.dac_nids = spec->private_dac_nids;
13787 for (i = 0; i < cfg->line_outs; i++) {
13788 nid = cfg->line_out_pins[i];
13789 if (nid) {
13790 if (i >= ARRAY_SIZE(alc861_dac_nids))
13791 continue;
13792 spec->multiout.dac_nids[i] = alc861_dac_nids[i];
13793 }
13794 }
13795 spec->multiout.num_dacs = cfg->line_outs;
13796 return 0;
13797}
13798
13799/* add playback controls from the parsed DAC table */
13800static int alc861_auto_create_multi_out_ctls(struct alc_spec *spec,
13801 const struct auto_pin_cfg *cfg)
13802{
13803 char name[32];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013804 static const char *chname[4] = {
13805 "Front", "Surround", NULL /*CLFE*/, "Side"
13806 };
Kailang Yangdf694da2005-12-05 19:42:22 +010013807 hda_nid_t nid;
13808 int i, idx, err;
13809
13810 for (i = 0; i < cfg->line_outs; i++) {
13811 nid = spec->multiout.dac_nids[i];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013812 if (!nid)
Kailang Yangdf694da2005-12-05 19:42:22 +010013813 continue;
13814 if (nid == 0x05) {
13815 /* Center/LFE */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013816 err = add_control(spec, ALC_CTL_BIND_MUTE,
13817 "Center Playback Switch",
13818 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
13819 HDA_OUTPUT));
13820 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010013821 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013822 err = add_control(spec, ALC_CTL_BIND_MUTE,
13823 "LFE Playback Switch",
13824 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
13825 HDA_OUTPUT));
13826 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010013827 return err;
13828 } else {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013829 for (idx = 0; idx < ARRAY_SIZE(alc861_dac_nids) - 1;
13830 idx++)
Kailang Yangdf694da2005-12-05 19:42:22 +010013831 if (nid == alc861_dac_nids[idx])
13832 break;
13833 sprintf(name, "%s Playback Switch", chname[idx]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013834 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
13835 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
13836 HDA_OUTPUT));
13837 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010013838 return err;
13839 }
13840 }
13841 return 0;
13842}
13843
13844static int alc861_auto_create_hp_ctls(struct alc_spec *spec, hda_nid_t pin)
13845{
13846 int err;
13847 hda_nid_t nid;
13848
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013849 if (!pin)
Kailang Yangdf694da2005-12-05 19:42:22 +010013850 return 0;
13851
13852 if ((pin >= 0x0b && pin <= 0x10) || pin == 0x1f || pin == 0x20) {
13853 nid = 0x03;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013854 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
13855 "Headphone Playback Switch",
13856 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
13857 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010013858 return err;
13859 spec->multiout.hp_nid = nid;
13860 }
13861 return 0;
13862}
13863
13864/* create playback/capture controls for input pins */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013865static int alc861_auto_create_analog_input_ctls(struct alc_spec *spec,
13866 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010013867{
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020013868 struct hda_input_mux *imux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010013869 int i, err, idx, idx1;
13870
13871 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013872 switch (cfg->input_pins[i]) {
Kailang Yangdf694da2005-12-05 19:42:22 +010013873 case 0x0c:
13874 idx1 = 1;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013875 idx = 2; /* Line In */
Kailang Yangdf694da2005-12-05 19:42:22 +010013876 break;
13877 case 0x0f:
13878 idx1 = 2;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013879 idx = 2; /* Line In */
Kailang Yangdf694da2005-12-05 19:42:22 +010013880 break;
13881 case 0x0d:
13882 idx1 = 0;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013883 idx = 1; /* Mic In */
Kailang Yangdf694da2005-12-05 19:42:22 +010013884 break;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013885 case 0x10:
Kailang Yangdf694da2005-12-05 19:42:22 +010013886 idx1 = 3;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013887 idx = 1; /* Mic In */
Kailang Yangdf694da2005-12-05 19:42:22 +010013888 break;
13889 case 0x11:
13890 idx1 = 4;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013891 idx = 0; /* CD */
Kailang Yangdf694da2005-12-05 19:42:22 +010013892 break;
13893 default:
13894 continue;
13895 }
13896
Takashi Iwai4a471b72005-12-07 13:56:29 +010013897 err = new_analog_input(spec, cfg->input_pins[i],
13898 auto_pin_cfg_labels[i], idx, 0x15);
Kailang Yangdf694da2005-12-05 19:42:22 +010013899 if (err < 0)
13900 return err;
13901
Takashi Iwai4a471b72005-12-07 13:56:29 +010013902 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
Kailang Yangdf694da2005-12-05 19:42:22 +010013903 imux->items[imux->num_items].index = idx1;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013904 imux->num_items++;
Kailang Yangdf694da2005-12-05 19:42:22 +010013905 }
13906 return 0;
13907}
13908
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013909static void alc861_auto_set_output_and_unmute(struct hda_codec *codec,
13910 hda_nid_t nid,
Kailang Yangdf694da2005-12-05 19:42:22 +010013911 int pin_type, int dac_idx)
13912{
Jacek Luczak564c5be2008-05-03 18:41:23 +020013913 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
13914 pin_type);
13915 snd_hda_codec_write(codec, dac_idx, 0, AC_VERB_SET_AMP_GAIN_MUTE,
13916 AMP_OUT_UNMUTE);
Kailang Yangdf694da2005-12-05 19:42:22 +010013917}
13918
13919static void alc861_auto_init_multi_out(struct hda_codec *codec)
13920{
13921 struct alc_spec *spec = codec->spec;
13922 int i;
13923
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013924 alc_subsystem_id(codec, 0x0e, 0x0f, 0x0b);
Kailang Yangdf694da2005-12-05 19:42:22 +010013925 for (i = 0; i < spec->autocfg.line_outs; i++) {
13926 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020013927 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangdf694da2005-12-05 19:42:22 +010013928 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020013929 alc861_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013930 spec->multiout.dac_nids[i]);
Kailang Yangdf694da2005-12-05 19:42:22 +010013931 }
13932}
13933
13934static void alc861_auto_init_hp_out(struct hda_codec *codec)
13935{
13936 struct alc_spec *spec = codec->spec;
13937 hda_nid_t pin;
13938
Takashi Iwaieb06ed82006-09-20 17:10:27 +020013939 pin = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010013940 if (pin) /* connect to front */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013941 alc861_auto_set_output_and_unmute(codec, pin, PIN_HP,
13942 spec->multiout.dac_nids[0]);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013943 pin = spec->autocfg.speaker_pins[0];
13944 if (pin)
13945 alc861_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Kailang Yangdf694da2005-12-05 19:42:22 +010013946}
13947
13948static void alc861_auto_init_analog_input(struct hda_codec *codec)
13949{
13950 struct alc_spec *spec = codec->spec;
13951 int i;
13952
13953 for (i = 0; i < AUTO_PIN_LAST; i++) {
13954 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwai23f0c042009-02-26 13:03:58 +010013955 if (nid >= 0x0c && nid <= 0x11)
13956 alc_set_input_pin(codec, nid, i);
Kailang Yangdf694da2005-12-05 19:42:22 +010013957 }
13958}
13959
13960/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013961/* return 1 if successful, 0 if the proper config is not found,
13962 * or a negative error code
13963 */
Kailang Yangdf694da2005-12-05 19:42:22 +010013964static int alc861_parse_auto_config(struct hda_codec *codec)
13965{
13966 struct alc_spec *spec = codec->spec;
13967 int err;
13968 static hda_nid_t alc861_ignore[] = { 0x1d, 0 };
13969
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013970 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
13971 alc861_ignore);
13972 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010013973 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013974 if (!spec->autocfg.line_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +010013975 return 0; /* can't find valid BIOS pin config */
13976
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013977 err = alc861_auto_fill_dac_nids(spec, &spec->autocfg);
13978 if (err < 0)
13979 return err;
13980 err = alc861_auto_create_multi_out_ctls(spec, &spec->autocfg);
13981 if (err < 0)
13982 return err;
13983 err = alc861_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
13984 if (err < 0)
13985 return err;
13986 err = alc861_auto_create_analog_input_ctls(spec, &spec->autocfg);
13987 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010013988 return err;
13989
13990 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
13991
Takashi Iwai0852d7a2009-02-11 11:35:15 +010013992 if (spec->autocfg.dig_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +010013993 spec->multiout.dig_out_nid = ALC861_DIGOUT_NID;
13994
Takashi Iwai603c4012008-07-30 15:01:44 +020013995 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010013996 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +010013997
Takashi Iwaid88897e2008-10-31 15:01:37 +010013998 add_verb(spec, alc861_auto_init_verbs);
Kailang Yangdf694da2005-12-05 19:42:22 +010013999
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020014000 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020014001 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010014002
14003 spec->adc_nids = alc861_adc_nids;
14004 spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids);
Takashi Iwaif9e336f2008-10-31 16:37:07 +010014005 set_capture_mixer(spec);
Kailang Yangdf694da2005-12-05 19:42:22 +010014006
14007 return 1;
14008}
14009
Takashi Iwaiae6b8132006-03-03 16:47:17 +010014010/* additional initialization for auto-configuration model */
14011static void alc861_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010014012{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014013 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010014014 alc861_auto_init_multi_out(codec);
14015 alc861_auto_init_hp_out(codec);
14016 alc861_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014017 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020014018 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010014019}
14020
Takashi Iwaicb53c622007-08-10 17:21:45 +020014021#ifdef CONFIG_SND_HDA_POWER_SAVE
14022static struct hda_amp_list alc861_loopbacks[] = {
14023 { 0x15, HDA_INPUT, 0 },
14024 { 0x15, HDA_INPUT, 1 },
14025 { 0x15, HDA_INPUT, 2 },
14026 { 0x15, HDA_INPUT, 3 },
14027 { } /* end */
14028};
14029#endif
14030
Kailang Yangdf694da2005-12-05 19:42:22 +010014031
14032/*
14033 * configuration and preset
14034 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010014035static const char *alc861_models[ALC861_MODEL_LAST] = {
14036 [ALC861_3ST] = "3stack",
14037 [ALC660_3ST] = "3stack-660",
14038 [ALC861_3ST_DIG] = "3stack-dig",
14039 [ALC861_6ST_DIG] = "6stack-dig",
14040 [ALC861_UNIWILL_M31] = "uniwill-m31",
14041 [ALC861_TOSHIBA] = "toshiba",
14042 [ALC861_ASUS] = "asus",
14043 [ALC861_ASUS_LAPTOP] = "asus-laptop",
14044 [ALC861_AUTO] = "auto",
14045};
14046
14047static struct snd_pci_quirk alc861_cfg_tbl[] = {
Takashi Iwai687a47b2007-01-10 11:25:58 +010014048 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010014049 SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP),
14050 SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP),
14051 SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010014052 SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP),
Kailang Yang83c34212007-07-05 11:43:05 +020014053 SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS P1-AH2", ALC861_3ST_DIG),
Tobin Davisad5e7732007-01-08 10:57:32 +010014054 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA),
Takashi Iwai341d4eb2007-07-09 17:53:18 +020014055 /* FIXME: the entry below breaks Toshiba A100 (model=auto works!)
14056 * Any other models that need this preset?
14057 */
14058 /* SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), */
Claudio Matsuokaef64adb2007-07-14 00:26:16 +020014059 SND_PCI_QUIRK(0x1462, 0x7254, "HP dx2200 (MSI MS-7254)", ALC861_3ST),
14060 SND_PCI_QUIRK(0x1462, 0x7297, "HP dx2250 (MSI MS-7297)", ALC861_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010014061 SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31),
14062 SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31),
14063 SND_PCI_QUIRK(0x1584, 0x9075, "Airis Praxis N1212", ALC861_ASUS_LAPTOP),
14064 /* FIXME: the below seems conflict */
14065 /* SND_PCI_QUIRK(0x1584, 0x9075, "Uniwill", ALC861_UNIWILL_M31), */
14066 SND_PCI_QUIRK(0x1849, 0x0660, "Asrock 939SLI32", ALC660_3ST),
14067 SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST),
Kailang Yangdf694da2005-12-05 19:42:22 +010014068 {}
14069};
14070
14071static struct alc_config_preset alc861_presets[] = {
14072 [ALC861_3ST] = {
14073 .mixers = { alc861_3ST_mixer },
14074 .init_verbs = { alc861_threestack_init_verbs },
14075 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
14076 .dac_nids = alc861_dac_nids,
14077 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
14078 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020014079 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010014080 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
14081 .adc_nids = alc861_adc_nids,
14082 .input_mux = &alc861_capture_source,
14083 },
14084 [ALC861_3ST_DIG] = {
14085 .mixers = { alc861_base_mixer },
14086 .init_verbs = { alc861_threestack_init_verbs },
14087 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
14088 .dac_nids = alc861_dac_nids,
14089 .dig_out_nid = ALC861_DIGOUT_NID,
14090 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
14091 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020014092 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010014093 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
14094 .adc_nids = alc861_adc_nids,
14095 .input_mux = &alc861_capture_source,
14096 },
14097 [ALC861_6ST_DIG] = {
14098 .mixers = { alc861_base_mixer },
14099 .init_verbs = { alc861_base_init_verbs },
14100 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
14101 .dac_nids = alc861_dac_nids,
14102 .dig_out_nid = ALC861_DIGOUT_NID,
14103 .num_channel_mode = ARRAY_SIZE(alc861_8ch_modes),
14104 .channel_mode = alc861_8ch_modes,
14105 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
14106 .adc_nids = alc861_adc_nids,
14107 .input_mux = &alc861_capture_source,
14108 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014109 [ALC660_3ST] = {
14110 .mixers = { alc861_3ST_mixer },
14111 .init_verbs = { alc861_threestack_init_verbs },
14112 .num_dacs = ARRAY_SIZE(alc660_dac_nids),
14113 .dac_nids = alc660_dac_nids,
14114 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
14115 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020014116 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014117 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
14118 .adc_nids = alc861_adc_nids,
14119 .input_mux = &alc861_capture_source,
14120 },
Takashi Iwai22309c32006-08-09 16:57:28 +020014121 [ALC861_UNIWILL_M31] = {
14122 .mixers = { alc861_uniwill_m31_mixer },
14123 .init_verbs = { alc861_uniwill_m31_init_verbs },
14124 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
14125 .dac_nids = alc861_dac_nids,
14126 .dig_out_nid = ALC861_DIGOUT_NID,
14127 .num_channel_mode = ARRAY_SIZE(alc861_uniwill_m31_modes),
14128 .channel_mode = alc861_uniwill_m31_modes,
14129 .need_dac_fix = 1,
14130 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
14131 .adc_nids = alc861_adc_nids,
14132 .input_mux = &alc861_capture_source,
14133 },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020014134 [ALC861_TOSHIBA] = {
14135 .mixers = { alc861_toshiba_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014136 .init_verbs = { alc861_base_init_verbs,
14137 alc861_toshiba_init_verbs },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020014138 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
14139 .dac_nids = alc861_dac_nids,
14140 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
14141 .channel_mode = alc883_3ST_2ch_modes,
14142 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
14143 .adc_nids = alc861_adc_nids,
14144 .input_mux = &alc861_capture_source,
14145 .unsol_event = alc861_toshiba_unsol_event,
14146 .init_hook = alc861_toshiba_automute,
14147 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014148 [ALC861_ASUS] = {
14149 .mixers = { alc861_asus_mixer },
14150 .init_verbs = { alc861_asus_init_verbs },
14151 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
14152 .dac_nids = alc861_dac_nids,
14153 .dig_out_nid = ALC861_DIGOUT_NID,
14154 .num_channel_mode = ARRAY_SIZE(alc861_asus_modes),
14155 .channel_mode = alc861_asus_modes,
14156 .need_dac_fix = 1,
14157 .hp_nid = 0x06,
14158 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
14159 .adc_nids = alc861_adc_nids,
14160 .input_mux = &alc861_capture_source,
14161 },
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010014162 [ALC861_ASUS_LAPTOP] = {
14163 .mixers = { alc861_toshiba_mixer, alc861_asus_laptop_mixer },
14164 .init_verbs = { alc861_asus_init_verbs,
14165 alc861_asus_laptop_init_verbs },
14166 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
14167 .dac_nids = alc861_dac_nids,
14168 .dig_out_nid = ALC861_DIGOUT_NID,
14169 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
14170 .channel_mode = alc883_3ST_2ch_modes,
14171 .need_dac_fix = 1,
14172 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
14173 .adc_nids = alc861_adc_nids,
14174 .input_mux = &alc861_capture_source,
14175 },
14176};
Kailang Yangdf694da2005-12-05 19:42:22 +010014177
14178
14179static int patch_alc861(struct hda_codec *codec)
14180{
14181 struct alc_spec *spec;
14182 int board_config;
14183 int err;
14184
Robert P. J. Daydc041e02006-12-19 14:44:15 +010014185 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010014186 if (spec == NULL)
14187 return -ENOMEM;
14188
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014189 codec->spec = spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010014190
Takashi Iwaif5fcc132006-11-24 17:07:44 +010014191 board_config = snd_hda_check_board_config(codec, ALC861_MODEL_LAST,
14192 alc861_models,
14193 alc861_cfg_tbl);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014194
Takashi Iwaif5fcc132006-11-24 17:07:44 +010014195 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014196 printk(KERN_INFO "hda_codec: Unknown model for ALC861, "
14197 "trying auto-probe from BIOS...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010014198 board_config = ALC861_AUTO;
14199 }
14200
14201 if (board_config == ALC861_AUTO) {
14202 /* automatic parse from the BIOS config */
14203 err = alc861_parse_auto_config(codec);
14204 if (err < 0) {
14205 alc_free(codec);
14206 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014207 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014208 printk(KERN_INFO
14209 "hda_codec: Cannot set up configuration "
14210 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010014211 board_config = ALC861_3ST_DIG;
14212 }
14213 }
14214
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090014215 err = snd_hda_attach_beep_device(codec, 0x23);
14216 if (err < 0) {
14217 alc_free(codec);
14218 return err;
14219 }
14220
Kailang Yangdf694da2005-12-05 19:42:22 +010014221 if (board_config != ALC861_AUTO)
14222 setup_preset(spec, &alc861_presets[board_config]);
14223
14224 spec->stream_name_analog = "ALC861 Analog";
14225 spec->stream_analog_playback = &alc861_pcm_analog_playback;
14226 spec->stream_analog_capture = &alc861_pcm_analog_capture;
14227
14228 spec->stream_name_digital = "ALC861 Digital";
14229 spec->stream_digital_playback = &alc861_pcm_digital_playback;
14230 spec->stream_digital_capture = &alc861_pcm_digital_capture;
14231
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010014232 set_beep_amp(spec, 0x23, 0, HDA_OUTPUT);
14233
Takashi Iwai2134ea42008-01-10 16:53:55 +010014234 spec->vmaster_nid = 0x03;
14235
Kailang Yangdf694da2005-12-05 19:42:22 +010014236 codec->patch_ops = alc_patch_ops;
14237 if (board_config == ALC861_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +010014238 spec->init_hook = alc861_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020014239#ifdef CONFIG_SND_HDA_POWER_SAVE
14240 if (!spec->loopback.amplist)
14241 spec->loopback.amplist = alc861_loopbacks;
14242#endif
Takashi Iwaidaead532008-11-28 12:55:36 +010014243 codec->proc_widget_hook = print_realtek_coef;
Kailang Yangea1fb292008-08-26 12:58:38 +020014244
Kailang Yangdf694da2005-12-05 19:42:22 +010014245 return 0;
14246}
14247
14248/*
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014249 * ALC861-VD support
14250 *
14251 * Based on ALC882
14252 *
14253 * In addition, an independent DAC
14254 */
14255#define ALC861VD_DIGOUT_NID 0x06
14256
14257static hda_nid_t alc861vd_dac_nids[4] = {
14258 /* front, surr, clfe, side surr */
14259 0x02, 0x03, 0x04, 0x05
14260};
14261
14262/* dac_nids for ALC660vd are in a different order - according to
14263 * Realtek's driver.
14264 * This should probably tesult in a different mixer for 6stack models
14265 * of ALC660vd codecs, but for now there is only 3stack mixer
14266 * - and it is the same as in 861vd.
14267 * adc_nids in ALC660vd are (is) the same as in 861vd
14268 */
14269static hda_nid_t alc660vd_dac_nids[3] = {
14270 /* front, rear, clfe, rear_surr */
14271 0x02, 0x04, 0x03
14272};
14273
14274static hda_nid_t alc861vd_adc_nids[1] = {
14275 /* ADC0 */
14276 0x09,
14277};
14278
Takashi Iwaie1406342008-02-11 18:32:32 +010014279static hda_nid_t alc861vd_capsrc_nids[1] = { 0x22 };
14280
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014281/* input MUX */
14282/* FIXME: should be a matrix-type input source selection */
14283static struct hda_input_mux alc861vd_capture_source = {
14284 .num_items = 4,
14285 .items = {
14286 { "Mic", 0x0 },
14287 { "Front Mic", 0x1 },
14288 { "Line", 0x2 },
14289 { "CD", 0x4 },
14290 },
14291};
14292
Kailang Yang272a5272007-05-14 11:00:38 +020014293static struct hda_input_mux alc861vd_dallas_capture_source = {
Tobin Davisb419f342008-03-07 11:57:51 +010014294 .num_items = 2,
Kailang Yang272a5272007-05-14 11:00:38 +020014295 .items = {
Tobin Davisb419f342008-03-07 11:57:51 +010014296 { "Ext Mic", 0x0 },
14297 { "Int Mic", 0x1 },
Kailang Yang272a5272007-05-14 11:00:38 +020014298 },
14299};
14300
Kailang Yangd1a991a2007-08-15 16:21:59 +020014301static struct hda_input_mux alc861vd_hp_capture_source = {
14302 .num_items = 2,
14303 .items = {
14304 { "Front Mic", 0x0 },
14305 { "ATAPI Mic", 0x1 },
14306 },
14307};
14308
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014309/*
14310 * 2ch mode
14311 */
14312static struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = {
14313 { 2, NULL }
14314};
14315
14316/*
14317 * 6ch mode
14318 */
14319static struct hda_verb alc861vd_6stack_ch6_init[] = {
14320 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
14321 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14322 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14323 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14324 { } /* end */
14325};
14326
14327/*
14328 * 8ch mode
14329 */
14330static struct hda_verb alc861vd_6stack_ch8_init[] = {
14331 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14332 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14333 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14334 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14335 { } /* end */
14336};
14337
14338static struct hda_channel_mode alc861vd_6stack_modes[2] = {
14339 { 6, alc861vd_6stack_ch6_init },
14340 { 8, alc861vd_6stack_ch8_init },
14341};
14342
14343static struct snd_kcontrol_new alc861vd_chmode_mixer[] = {
14344 {
14345 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
14346 .name = "Channel Mode",
14347 .info = alc_ch_mode_info,
14348 .get = alc_ch_mode_get,
14349 .put = alc_ch_mode_put,
14350 },
14351 { } /* end */
14352};
14353
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014354/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
14355 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
14356 */
14357static struct snd_kcontrol_new alc861vd_6st_mixer[] = {
14358 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14359 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
14360
14361 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
14362 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
14363
14364 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0,
14365 HDA_OUTPUT),
14366 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0,
14367 HDA_OUTPUT),
14368 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
14369 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
14370
14371 HDA_CODEC_VOLUME("Side Playback Volume", 0x05, 0x0, HDA_OUTPUT),
14372 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
14373
14374 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
14375
14376 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
14377 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14378 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14379
14380 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
14381 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14382 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14383
14384 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
14385 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
14386
14387 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
14388 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
14389
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014390 { } /* end */
14391};
14392
14393static struct snd_kcontrol_new alc861vd_3st_mixer[] = {
14394 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14395 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
14396
14397 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
14398
14399 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
14400 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14401 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14402
14403 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
14404 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14405 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14406
14407 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
14408 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
14409
14410 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
14411 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
14412
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014413 { } /* end */
14414};
14415
Kailang Yangbdd148a2007-05-08 15:19:08 +020014416static struct snd_kcontrol_new alc861vd_lenovo_mixer[] = {
14417 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14418 /*HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),*/
14419 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
14420
14421 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
14422
14423 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
14424 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14425 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14426
14427 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
14428 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14429 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14430
14431 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
14432 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
14433
14434 { } /* end */
14435};
14436
Tobin Davisb419f342008-03-07 11:57:51 +010014437/* Pin assignment: Speaker=0x14, HP = 0x15,
14438 * Ext Mic=0x18, Int Mic = 0x19, CD = 0x1c, PC Beep = 0x1d
Kailang Yang272a5272007-05-14 11:00:38 +020014439 */
14440static struct snd_kcontrol_new alc861vd_dallas_mixer[] = {
Tobin Davisb419f342008-03-07 11:57:51 +010014441 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14442 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020014443 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
14444 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
Tobin Davisb419f342008-03-07 11:57:51 +010014445 HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
14446 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14447 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14448 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
14449 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14450 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020014451 { } /* end */
14452};
14453
Kailang Yangd1a991a2007-08-15 16:21:59 +020014454/* Pin assignment: Speaker=0x14, Line-out = 0x15,
14455 * Front Mic=0x18, ATAPI Mic = 0x19,
14456 */
14457static struct snd_kcontrol_new alc861vd_hp_mixer[] = {
14458 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14459 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
14460 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
14461 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
14462 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14463 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14464 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14465 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangea1fb292008-08-26 12:58:38 +020014466
Kailang Yangd1a991a2007-08-15 16:21:59 +020014467 { } /* end */
14468};
14469
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014470/*
14471 * generic initialization of ADC, input mixers and output mixers
14472 */
14473static struct hda_verb alc861vd_volume_init_verbs[] = {
14474 /*
14475 * Unmute ADC0 and set the default input to mic-in
14476 */
14477 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
14478 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14479
14480 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of
14481 * the analog-loopback mixer widget
14482 */
14483 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020014484 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14485 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
14486 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
14487 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
14488 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014489
14490 /* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yangbdd148a2007-05-08 15:19:08 +020014491 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14492 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14493 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014494 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014495
14496 /*
14497 * Set up output mixers (0x02 - 0x05)
14498 */
14499 /* set vol=0 to output mixers */
14500 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14501 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14502 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14503 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14504
14505 /* set up input amps for analog loopback */
14506 /* Amp Indices: DAC = 0, mixer = 1 */
14507 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14508 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
14509 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14510 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
14511 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14512 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
14513 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14514 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
14515
14516 { }
14517};
14518
14519/*
14520 * 3-stack pin configuration:
14521 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
14522 */
14523static struct hda_verb alc861vd_3stack_init_verbs[] = {
14524 /*
14525 * Set pin mode and muting
14526 */
14527 /* set front pin widgets 0x14 for output */
14528 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14529 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14530 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
14531
14532 /* Mic (rear) pin: input vref at 80% */
14533 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14534 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14535 /* Front Mic pin: input vref at 80% */
14536 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14537 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14538 /* Line In pin: input */
14539 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14540 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14541 /* Line-2 In: Headphone output (output 0 - 0x0c) */
14542 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14543 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14544 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
14545 /* CD pin widget for input */
14546 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14547
14548 { }
14549};
14550
14551/*
14552 * 6-stack pin configuration:
14553 */
14554static struct hda_verb alc861vd_6stack_init_verbs[] = {
14555 /*
14556 * Set pin mode and muting
14557 */
14558 /* set front pin widgets 0x14 for output */
14559 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14560 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14561 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
14562
14563 /* Rear Pin: output 1 (0x0d) */
14564 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14565 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14566 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
14567 /* CLFE Pin: output 2 (0x0e) */
14568 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14569 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14570 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
14571 /* Side Pin: output 3 (0x0f) */
14572 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14573 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14574 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
14575
14576 /* Mic (rear) pin: input vref at 80% */
14577 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14578 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14579 /* Front Mic pin: input vref at 80% */
14580 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14581 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14582 /* Line In pin: input */
14583 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14584 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14585 /* Line-2 In: Headphone output (output 0 - 0x0c) */
14586 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14587 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14588 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
14589 /* CD pin widget for input */
14590 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14591
14592 { }
14593};
14594
Kailang Yangbdd148a2007-05-08 15:19:08 +020014595static struct hda_verb alc861vd_eapd_verbs[] = {
14596 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
14597 { }
14598};
14599
Kailang Yangf9423e72008-05-27 12:32:25 +020014600static struct hda_verb alc660vd_eapd_verbs[] = {
14601 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
14602 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
14603 { }
14604};
14605
Kailang Yangbdd148a2007-05-08 15:19:08 +020014606static struct hda_verb alc861vd_lenovo_unsol_verbs[] = {
14607 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14608 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14609 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
14610 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Kailang Yangea1fb292008-08-26 12:58:38 +020014611 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
Kailang Yangbdd148a2007-05-08 15:19:08 +020014612 {}
14613};
14614
14615/* toggle speaker-output according to the hp-jack state */
14616static void alc861vd_lenovo_hp_automute(struct hda_codec *codec)
14617{
14618 unsigned int present;
14619 unsigned char bits;
14620
14621 present = snd_hda_codec_read(codec, 0x1b, 0,
14622 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020014623 bits = present ? HDA_AMP_MUTE : 0;
14624 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
14625 HDA_AMP_MUTE, bits);
Kailang Yangbdd148a2007-05-08 15:19:08 +020014626}
14627
14628static void alc861vd_lenovo_mic_automute(struct hda_codec *codec)
14629{
14630 unsigned int present;
14631 unsigned char bits;
14632
14633 present = snd_hda_codec_read(codec, 0x18, 0,
14634 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020014635 bits = present ? HDA_AMP_MUTE : 0;
14636 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
14637 HDA_AMP_MUTE, bits);
Kailang Yangbdd148a2007-05-08 15:19:08 +020014638}
14639
14640static void alc861vd_lenovo_automute(struct hda_codec *codec)
14641{
14642 alc861vd_lenovo_hp_automute(codec);
14643 alc861vd_lenovo_mic_automute(codec);
14644}
14645
14646static void alc861vd_lenovo_unsol_event(struct hda_codec *codec,
14647 unsigned int res)
14648{
14649 switch (res >> 26) {
14650 case ALC880_HP_EVENT:
14651 alc861vd_lenovo_hp_automute(codec);
14652 break;
14653 case ALC880_MIC_EVENT:
14654 alc861vd_lenovo_mic_automute(codec);
14655 break;
14656 }
14657}
14658
Kailang Yang272a5272007-05-14 11:00:38 +020014659static struct hda_verb alc861vd_dallas_verbs[] = {
14660 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14661 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14662 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14663 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14664
14665 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14666 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14667 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14668 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
14669 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14670 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
14671 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14672 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020014673
Kailang Yang272a5272007-05-14 11:00:38 +020014674 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14675 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14676 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14677 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14678 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14679 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14680 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14681 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14682
14683 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
14684 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14685 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
14686 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14687 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14688 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14689 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14690 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14691
14692 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14693 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
14694 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
14695 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
14696
14697 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020014698 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yang272a5272007-05-14 11:00:38 +020014699 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14700
14701 { } /* end */
14702};
14703
14704/* toggle speaker-output according to the hp-jack state */
14705static void alc861vd_dallas_automute(struct hda_codec *codec)
14706{
14707 unsigned int present;
14708
14709 present = snd_hda_codec_read(codec, 0x15, 0,
14710 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020014711 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
14712 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +020014713}
14714
14715static void alc861vd_dallas_unsol_event(struct hda_codec *codec, unsigned int res)
14716{
14717 if ((res >> 26) == ALC880_HP_EVENT)
14718 alc861vd_dallas_automute(codec);
14719}
14720
Takashi Iwaicb53c622007-08-10 17:21:45 +020014721#ifdef CONFIG_SND_HDA_POWER_SAVE
14722#define alc861vd_loopbacks alc880_loopbacks
14723#endif
14724
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014725/* pcm configuration: identiacal with ALC880 */
14726#define alc861vd_pcm_analog_playback alc880_pcm_analog_playback
14727#define alc861vd_pcm_analog_capture alc880_pcm_analog_capture
14728#define alc861vd_pcm_digital_playback alc880_pcm_digital_playback
14729#define alc861vd_pcm_digital_capture alc880_pcm_digital_capture
14730
14731/*
14732 * configuration and preset
14733 */
14734static const char *alc861vd_models[ALC861VD_MODEL_LAST] = {
14735 [ALC660VD_3ST] = "3stack-660",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020014736 [ALC660VD_3ST_DIG] = "3stack-660-digout",
Takashi Iwai13c94742008-11-05 08:06:08 +010014737 [ALC660VD_ASUS_V1S] = "asus-v1s",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014738 [ALC861VD_3ST] = "3stack",
14739 [ALC861VD_3ST_DIG] = "3stack-digout",
14740 [ALC861VD_6ST_DIG] = "6stack-digout",
Kailang Yangbdd148a2007-05-08 15:19:08 +020014741 [ALC861VD_LENOVO] = "lenovo",
Kailang Yang272a5272007-05-14 11:00:38 +020014742 [ALC861VD_DALLAS] = "dallas",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020014743 [ALC861VD_HP] = "hp",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014744 [ALC861VD_AUTO] = "auto",
14745};
14746
14747static struct snd_pci_quirk alc861vd_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +010014748 SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST),
14749 SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP),
Takashi Iwai07e038b2007-02-15 18:23:41 +010014750 SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014751 SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),
Takashi Iwai13c94742008-11-05 08:06:08 +010014752 SND_PCI_QUIRK(0x1043, 0x1633, "Asus V1Sn", ALC660VD_ASUS_V1S),
Mike Crash6963f842007-06-25 12:12:51 +020014753 SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014754 SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010014755 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO),
Takashi Iwai38baf5a2007-08-16 17:52:43 +020014756 /*SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS),*/ /*lenovo*/
Kailang Yang272a5272007-05-14 11:00:38 +020014757 SND_PCI_QUIRK(0x1179, 0xff01, "DALLAS", ALC861VD_DALLAS),
Takashi Iwai542d7c62007-08-16 18:57:30 +020014758 SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO),
Tobin Davisb419f342008-03-07 11:57:51 +010014759 SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_DALLAS),
Takashi Iwai39c5d412007-08-15 16:24:17 +020014760 SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +010014761 SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", ALC861VD_LENOVO),
Tobin Davis625dc0b2007-07-30 21:42:10 +020014762 SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014763 {}
14764};
14765
14766static struct alc_config_preset alc861vd_presets[] = {
14767 [ALC660VD_3ST] = {
14768 .mixers = { alc861vd_3st_mixer },
14769 .init_verbs = { alc861vd_volume_init_verbs,
14770 alc861vd_3stack_init_verbs },
14771 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
14772 .dac_nids = alc660vd_dac_nids,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014773 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14774 .channel_mode = alc861vd_3stack_2ch_modes,
14775 .input_mux = &alc861vd_capture_source,
14776 },
Mike Crash6963f842007-06-25 12:12:51 +020014777 [ALC660VD_3ST_DIG] = {
14778 .mixers = { alc861vd_3st_mixer },
14779 .init_verbs = { alc861vd_volume_init_verbs,
14780 alc861vd_3stack_init_verbs },
14781 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
14782 .dac_nids = alc660vd_dac_nids,
14783 .dig_out_nid = ALC861VD_DIGOUT_NID,
Mike Crash6963f842007-06-25 12:12:51 +020014784 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14785 .channel_mode = alc861vd_3stack_2ch_modes,
14786 .input_mux = &alc861vd_capture_source,
14787 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014788 [ALC861VD_3ST] = {
14789 .mixers = { alc861vd_3st_mixer },
14790 .init_verbs = { alc861vd_volume_init_verbs,
14791 alc861vd_3stack_init_verbs },
14792 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
14793 .dac_nids = alc861vd_dac_nids,
14794 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14795 .channel_mode = alc861vd_3stack_2ch_modes,
14796 .input_mux = &alc861vd_capture_source,
14797 },
14798 [ALC861VD_3ST_DIG] = {
14799 .mixers = { alc861vd_3st_mixer },
14800 .init_verbs = { alc861vd_volume_init_verbs,
14801 alc861vd_3stack_init_verbs },
14802 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
14803 .dac_nids = alc861vd_dac_nids,
14804 .dig_out_nid = ALC861VD_DIGOUT_NID,
14805 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14806 .channel_mode = alc861vd_3stack_2ch_modes,
14807 .input_mux = &alc861vd_capture_source,
14808 },
14809 [ALC861VD_6ST_DIG] = {
14810 .mixers = { alc861vd_6st_mixer, alc861vd_chmode_mixer },
14811 .init_verbs = { alc861vd_volume_init_verbs,
14812 alc861vd_6stack_init_verbs },
14813 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
14814 .dac_nids = alc861vd_dac_nids,
14815 .dig_out_nid = ALC861VD_DIGOUT_NID,
14816 .num_channel_mode = ARRAY_SIZE(alc861vd_6stack_modes),
14817 .channel_mode = alc861vd_6stack_modes,
14818 .input_mux = &alc861vd_capture_source,
14819 },
Kailang Yangbdd148a2007-05-08 15:19:08 +020014820 [ALC861VD_LENOVO] = {
14821 .mixers = { alc861vd_lenovo_mixer },
14822 .init_verbs = { alc861vd_volume_init_verbs,
14823 alc861vd_3stack_init_verbs,
14824 alc861vd_eapd_verbs,
14825 alc861vd_lenovo_unsol_verbs },
14826 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
14827 .dac_nids = alc660vd_dac_nids,
Kailang Yangbdd148a2007-05-08 15:19:08 +020014828 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14829 .channel_mode = alc861vd_3stack_2ch_modes,
14830 .input_mux = &alc861vd_capture_source,
14831 .unsol_event = alc861vd_lenovo_unsol_event,
14832 .init_hook = alc861vd_lenovo_automute,
14833 },
Kailang Yang272a5272007-05-14 11:00:38 +020014834 [ALC861VD_DALLAS] = {
14835 .mixers = { alc861vd_dallas_mixer },
14836 .init_verbs = { alc861vd_dallas_verbs },
14837 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
14838 .dac_nids = alc861vd_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +020014839 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14840 .channel_mode = alc861vd_3stack_2ch_modes,
14841 .input_mux = &alc861vd_dallas_capture_source,
14842 .unsol_event = alc861vd_dallas_unsol_event,
14843 .init_hook = alc861vd_dallas_automute,
Kailang Yangd1a991a2007-08-15 16:21:59 +020014844 },
14845 [ALC861VD_HP] = {
14846 .mixers = { alc861vd_hp_mixer },
14847 .init_verbs = { alc861vd_dallas_verbs, alc861vd_eapd_verbs },
14848 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
14849 .dac_nids = alc861vd_dac_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020014850 .dig_out_nid = ALC861VD_DIGOUT_NID,
Kailang Yangd1a991a2007-08-15 16:21:59 +020014851 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14852 .channel_mode = alc861vd_3stack_2ch_modes,
14853 .input_mux = &alc861vd_hp_capture_source,
14854 .unsol_event = alc861vd_dallas_unsol_event,
14855 .init_hook = alc861vd_dallas_automute,
Kailang Yangea1fb292008-08-26 12:58:38 +020014856 },
Takashi Iwai13c94742008-11-05 08:06:08 +010014857 [ALC660VD_ASUS_V1S] = {
14858 .mixers = { alc861vd_lenovo_mixer },
14859 .init_verbs = { alc861vd_volume_init_verbs,
14860 alc861vd_3stack_init_verbs,
14861 alc861vd_eapd_verbs,
14862 alc861vd_lenovo_unsol_verbs },
14863 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
14864 .dac_nids = alc660vd_dac_nids,
14865 .dig_out_nid = ALC861VD_DIGOUT_NID,
14866 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14867 .channel_mode = alc861vd_3stack_2ch_modes,
14868 .input_mux = &alc861vd_capture_source,
14869 .unsol_event = alc861vd_lenovo_unsol_event,
14870 .init_hook = alc861vd_lenovo_automute,
14871 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014872};
14873
14874/*
14875 * BIOS auto configuration
14876 */
14877static void alc861vd_auto_set_output_and_unmute(struct hda_codec *codec,
14878 hda_nid_t nid, int pin_type, int dac_idx)
14879{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014880 alc_set_pin_output(codec, nid, pin_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014881}
14882
14883static void alc861vd_auto_init_multi_out(struct hda_codec *codec)
14884{
14885 struct alc_spec *spec = codec->spec;
14886 int i;
14887
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014888 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014889 for (i = 0; i <= HDA_SIDE; i++) {
14890 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020014891 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014892 if (nid)
14893 alc861vd_auto_set_output_and_unmute(codec, nid,
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020014894 pin_type, i);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014895 }
14896}
14897
14898
14899static void alc861vd_auto_init_hp_out(struct hda_codec *codec)
14900{
14901 struct alc_spec *spec = codec->spec;
14902 hda_nid_t pin;
14903
14904 pin = spec->autocfg.hp_pins[0];
14905 if (pin) /* connect to front and use dac 0 */
14906 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014907 pin = spec->autocfg.speaker_pins[0];
14908 if (pin)
14909 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014910}
14911
14912#define alc861vd_is_input_pin(nid) alc880_is_input_pin(nid)
14913#define ALC861VD_PIN_CD_NID ALC880_PIN_CD_NID
14914
14915static void alc861vd_auto_init_analog_input(struct hda_codec *codec)
14916{
14917 struct alc_spec *spec = codec->spec;
14918 int i;
14919
14920 for (i = 0; i < AUTO_PIN_LAST; i++) {
14921 hda_nid_t nid = spec->autocfg.input_pins[i];
14922 if (alc861vd_is_input_pin(nid)) {
Takashi Iwai23f0c042009-02-26 13:03:58 +010014923 alc_set_input_pin(codec, nid, i);
Takashi Iwaie82c0252009-03-23 15:17:38 +010014924 if (nid != ALC861VD_PIN_CD_NID &&
14925 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014926 snd_hda_codec_write(codec, nid, 0,
14927 AC_VERB_SET_AMP_GAIN_MUTE,
14928 AMP_OUT_MUTE);
14929 }
14930 }
14931}
14932
Takashi Iwaif511b012008-08-15 16:46:42 +020014933#define alc861vd_auto_init_input_src alc882_auto_init_input_src
14934
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014935#define alc861vd_idx_to_mixer_vol(nid) ((nid) + 0x02)
14936#define alc861vd_idx_to_mixer_switch(nid) ((nid) + 0x0c)
14937
14938/* add playback controls from the parsed DAC table */
14939/* Based on ALC880 version. But ALC861VD has separate,
14940 * different NIDs for mute/unmute switch and volume control */
14941static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
14942 const struct auto_pin_cfg *cfg)
14943{
14944 char name[32];
14945 static const char *chname[4] = {"Front", "Surround", "CLFE", "Side"};
14946 hda_nid_t nid_v, nid_s;
14947 int i, err;
14948
14949 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014950 if (!spec->multiout.dac_nids[i])
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014951 continue;
14952 nid_v = alc861vd_idx_to_mixer_vol(
14953 alc880_dac_to_idx(
14954 spec->multiout.dac_nids[i]));
14955 nid_s = alc861vd_idx_to_mixer_switch(
14956 alc880_dac_to_idx(
14957 spec->multiout.dac_nids[i]));
14958
14959 if (i == 2) {
14960 /* Center/LFE */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014961 err = add_control(spec, ALC_CTL_WIDGET_VOL,
14962 "Center Playback Volume",
14963 HDA_COMPOSE_AMP_VAL(nid_v, 1, 0,
14964 HDA_OUTPUT));
14965 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014966 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014967 err = add_control(spec, ALC_CTL_WIDGET_VOL,
14968 "LFE Playback Volume",
14969 HDA_COMPOSE_AMP_VAL(nid_v, 2, 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_BIND_MUTE,
14974 "Center Playback Switch",
14975 HDA_COMPOSE_AMP_VAL(nid_s, 1, 2,
14976 HDA_INPUT));
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 "LFE Playback Switch",
14981 HDA_COMPOSE_AMP_VAL(nid_s, 2, 2,
14982 HDA_INPUT));
14983 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014984 return err;
14985 } else {
14986 sprintf(name, "%s Playback Volume", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014987 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
14988 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0,
14989 HDA_OUTPUT));
14990 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014991 return err;
14992 sprintf(name, "%s Playback Switch", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014993 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
Kailang Yangbdd148a2007-05-08 15:19:08 +020014994 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014995 HDA_INPUT));
14996 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014997 return err;
14998 }
14999 }
15000 return 0;
15001}
15002
15003/* add playback controls for speaker and HP outputs */
15004/* Based on ALC880 version. But ALC861VD has separate,
15005 * different NIDs for mute/unmute switch and volume control */
15006static int alc861vd_auto_create_extra_out(struct alc_spec *spec,
15007 hda_nid_t pin, const char *pfx)
15008{
15009 hda_nid_t nid_v, nid_s;
15010 int err;
15011 char name[32];
15012
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015013 if (!pin)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015014 return 0;
15015
15016 if (alc880_is_fixed_pin(pin)) {
15017 nid_v = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
15018 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015019 if (!spec->multiout.hp_nid)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015020 spec->multiout.hp_nid = nid_v;
15021 else
15022 spec->multiout.extra_out_nid[0] = nid_v;
15023 /* control HP volume/switch on the output mixer amp */
15024 nid_v = alc861vd_idx_to_mixer_vol(
15025 alc880_fixed_pin_idx(pin));
15026 nid_s = alc861vd_idx_to_mixer_switch(
15027 alc880_fixed_pin_idx(pin));
15028
15029 sprintf(name, "%s Playback Volume", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015030 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
15031 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0, HDA_OUTPUT));
15032 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015033 return err;
15034 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015035 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
15036 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2, HDA_INPUT));
15037 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015038 return err;
15039 } else if (alc880_is_multi_pin(pin)) {
15040 /* set manual connection */
15041 /* we have only a switch on HP-out PIN */
15042 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015043 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
15044 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
15045 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015046 return err;
15047 }
15048 return 0;
15049}
15050
15051/* parse the BIOS configuration and set up the alc_spec
15052 * return 1 if successful, 0 if the proper config is not found,
15053 * or a negative error code
15054 * Based on ALC880 version - had to change it to override
15055 * alc880_auto_create_extra_out and alc880_auto_create_multi_out_ctls */
15056static int alc861vd_parse_auto_config(struct hda_codec *codec)
15057{
15058 struct alc_spec *spec = codec->spec;
15059 int err;
15060 static hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
15061
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015062 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
15063 alc861vd_ignore);
15064 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015065 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015066 if (!spec->autocfg.line_outs)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015067 return 0; /* can't find valid BIOS pin config */
15068
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015069 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
15070 if (err < 0)
15071 return err;
15072 err = alc861vd_auto_create_multi_out_ctls(spec, &spec->autocfg);
15073 if (err < 0)
15074 return err;
15075 err = alc861vd_auto_create_extra_out(spec,
15076 spec->autocfg.speaker_pins[0],
15077 "Speaker");
15078 if (err < 0)
15079 return err;
15080 err = alc861vd_auto_create_extra_out(spec,
15081 spec->autocfg.hp_pins[0],
15082 "Headphone");
15083 if (err < 0)
15084 return err;
15085 err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg);
15086 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015087 return err;
15088
15089 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
15090
Takashi Iwai0852d7a2009-02-11 11:35:15 +010015091 if (spec->autocfg.dig_outs)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015092 spec->multiout.dig_out_nid = ALC861VD_DIGOUT_NID;
15093
Takashi Iwai603c4012008-07-30 15:01:44 +020015094 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010015095 add_mixer(spec, spec->kctls.list);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015096
Takashi Iwaid88897e2008-10-31 15:01:37 +010015097 add_verb(spec, alc861vd_volume_init_verbs);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015098
15099 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020015100 spec->input_mux = &spec->private_imux[0];
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015101
Takashi Iwai776e1842007-08-29 15:07:11 +020015102 err = alc_auto_add_mic_boost(codec);
15103 if (err < 0)
15104 return err;
15105
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015106 return 1;
15107}
15108
15109/* additional initialization for auto-configuration model */
15110static void alc861vd_auto_init(struct hda_codec *codec)
15111{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010015112 struct alc_spec *spec = codec->spec;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015113 alc861vd_auto_init_multi_out(codec);
15114 alc861vd_auto_init_hp_out(codec);
15115 alc861vd_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020015116 alc861vd_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010015117 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020015118 alc_inithook(codec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015119}
15120
15121static int patch_alc861vd(struct hda_codec *codec)
15122{
15123 struct alc_spec *spec;
15124 int err, board_config;
15125
15126 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
15127 if (spec == NULL)
15128 return -ENOMEM;
15129
15130 codec->spec = spec;
15131
15132 board_config = snd_hda_check_board_config(codec, ALC861VD_MODEL_LAST,
15133 alc861vd_models,
15134 alc861vd_cfg_tbl);
15135
15136 if (board_config < 0 || board_config >= ALC861VD_MODEL_LAST) {
15137 printk(KERN_INFO "hda_codec: Unknown model for ALC660VD/"
15138 "ALC861VD, trying auto-probe from BIOS...\n");
15139 board_config = ALC861VD_AUTO;
15140 }
15141
15142 if (board_config == ALC861VD_AUTO) {
15143 /* automatic parse from the BIOS config */
15144 err = alc861vd_parse_auto_config(codec);
15145 if (err < 0) {
15146 alc_free(codec);
15147 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015148 } else if (!err) {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015149 printk(KERN_INFO
15150 "hda_codec: Cannot set up configuration "
15151 "from BIOS. Using base mode...\n");
15152 board_config = ALC861VD_3ST;
15153 }
15154 }
15155
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090015156 err = snd_hda_attach_beep_device(codec, 0x23);
15157 if (err < 0) {
15158 alc_free(codec);
15159 return err;
15160 }
15161
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015162 if (board_config != ALC861VD_AUTO)
15163 setup_preset(spec, &alc861vd_presets[board_config]);
15164
Kailang Yang2f893282008-05-27 12:14:47 +020015165 if (codec->vendor_id == 0x10ec0660) {
15166 spec->stream_name_analog = "ALC660-VD Analog";
15167 spec->stream_name_digital = "ALC660-VD Digital";
Kailang Yangf9423e72008-05-27 12:32:25 +020015168 /* always turn on EAPD */
Takashi Iwaid88897e2008-10-31 15:01:37 +010015169 add_verb(spec, alc660vd_eapd_verbs);
Kailang Yang2f893282008-05-27 12:14:47 +020015170 } else {
15171 spec->stream_name_analog = "ALC861VD Analog";
15172 spec->stream_name_digital = "ALC861VD Digital";
15173 }
15174
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015175 spec->stream_analog_playback = &alc861vd_pcm_analog_playback;
15176 spec->stream_analog_capture = &alc861vd_pcm_analog_capture;
15177
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015178 spec->stream_digital_playback = &alc861vd_pcm_digital_playback;
15179 spec->stream_digital_capture = &alc861vd_pcm_digital_capture;
15180
15181 spec->adc_nids = alc861vd_adc_nids;
15182 spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids);
Takashi Iwaie1406342008-02-11 18:32:32 +010015183 spec->capsrc_nids = alc861vd_capsrc_nids;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020015184 spec->capture_style = CAPT_MIX;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015185
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015186 set_capture_mixer(spec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010015187 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015188
Takashi Iwai2134ea42008-01-10 16:53:55 +010015189 spec->vmaster_nid = 0x02;
15190
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015191 codec->patch_ops = alc_patch_ops;
15192
15193 if (board_config == ALC861VD_AUTO)
15194 spec->init_hook = alc861vd_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020015195#ifdef CONFIG_SND_HDA_POWER_SAVE
15196 if (!spec->loopback.amplist)
15197 spec->loopback.amplist = alc861vd_loopbacks;
15198#endif
Takashi Iwaidaead532008-11-28 12:55:36 +010015199 codec->proc_widget_hook = print_realtek_coef;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015200
15201 return 0;
15202}
15203
15204/*
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015205 * ALC662 support
15206 *
15207 * ALC662 is almost identical with ALC880 but has cleaner and more flexible
15208 * configuration. Each pin widget can choose any input DACs and a mixer.
15209 * Each ADC is connected from a mixer of all inputs. This makes possible
15210 * 6-channel independent captures.
15211 *
15212 * In addition, an independent DAC for the multi-playback (not used in this
15213 * driver yet).
15214 */
15215#define ALC662_DIGOUT_NID 0x06
15216#define ALC662_DIGIN_NID 0x0a
15217
15218static hda_nid_t alc662_dac_nids[4] = {
15219 /* front, rear, clfe, rear_surr */
15220 0x02, 0x03, 0x04
15221};
15222
Kailang Yang622e84c2009-04-21 07:39:04 +020015223static hda_nid_t alc272_dac_nids[2] = {
15224 0x02, 0x03
15225};
15226
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015227static hda_nid_t alc662_adc_nids[1] = {
15228 /* ADC1-2 */
15229 0x09,
15230};
Takashi Iwaie1406342008-02-11 18:32:32 +010015231
Kailang Yang622e84c2009-04-21 07:39:04 +020015232static hda_nid_t alc272_adc_nids[1] = {
15233 /* ADC1-2 */
15234 0x08,
15235};
15236
Kailang Yang77a261b2008-02-19 11:38:05 +010015237static hda_nid_t alc662_capsrc_nids[1] = { 0x22 };
Kailang Yang622e84c2009-04-21 07:39:04 +020015238static hda_nid_t alc272_capsrc_nids[1] = { 0x23 };
15239
Takashi Iwaie1406342008-02-11 18:32:32 +010015240
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015241/* input MUX */
15242/* FIXME: should be a matrix-type input source selection */
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015243static struct hda_input_mux alc662_capture_source = {
15244 .num_items = 4,
15245 .items = {
15246 { "Mic", 0x0 },
15247 { "Front Mic", 0x1 },
15248 { "Line", 0x2 },
15249 { "CD", 0x4 },
15250 },
15251};
15252
15253static struct hda_input_mux alc662_lenovo_101e_capture_source = {
15254 .num_items = 2,
15255 .items = {
15256 { "Mic", 0x1 },
15257 { "Line", 0x2 },
15258 },
15259};
Kailang Yang291702f2007-10-16 14:28:03 +020015260
15261static struct hda_input_mux alc662_eeepc_capture_source = {
15262 .num_items = 2,
15263 .items = {
15264 { "i-Mic", 0x1 },
15265 { "e-Mic", 0x0 },
15266 },
15267};
15268
Kailang Yang6dda9f42008-05-27 12:05:31 +020015269static struct hda_input_mux alc663_capture_source = {
15270 .num_items = 3,
15271 .items = {
15272 { "Mic", 0x0 },
15273 { "Front Mic", 0x1 },
15274 { "Line", 0x2 },
15275 },
15276};
15277
15278static struct hda_input_mux alc663_m51va_capture_source = {
15279 .num_items = 2,
15280 .items = {
15281 { "Ext-Mic", 0x0 },
15282 { "D-Mic", 0x9 },
15283 },
15284};
15285
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015286/*
15287 * 2ch mode
15288 */
15289static struct hda_channel_mode alc662_3ST_2ch_modes[1] = {
15290 { 2, NULL }
15291};
15292
15293/*
15294 * 2ch mode
15295 */
15296static struct hda_verb alc662_3ST_ch2_init[] = {
15297 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
15298 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
15299 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
15300 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
15301 { } /* end */
15302};
15303
15304/*
15305 * 6ch mode
15306 */
15307static struct hda_verb alc662_3ST_ch6_init[] = {
15308 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15309 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
15310 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
15311 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15312 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
15313 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
15314 { } /* end */
15315};
15316
15317static struct hda_channel_mode alc662_3ST_6ch_modes[2] = {
15318 { 2, alc662_3ST_ch2_init },
15319 { 6, alc662_3ST_ch6_init },
15320};
15321
15322/*
15323 * 2ch mode
15324 */
15325static struct hda_verb alc662_sixstack_ch6_init[] = {
15326 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15327 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15328 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15329 { } /* end */
15330};
15331
15332/*
15333 * 6ch mode
15334 */
15335static struct hda_verb alc662_sixstack_ch8_init[] = {
15336 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15337 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15338 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15339 { } /* end */
15340};
15341
15342static struct hda_channel_mode alc662_5stack_modes[2] = {
15343 { 2, alc662_sixstack_ch6_init },
15344 { 6, alc662_sixstack_ch8_init },
15345};
15346
15347/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
15348 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
15349 */
15350
15351static struct snd_kcontrol_new alc662_base_mixer[] = {
15352 /* output mixer control */
15353 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010015354 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015355 HDA_CODEC_VOLUME("Surround Playback Volume", 0x3, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010015356 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015357 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
15358 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010015359 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
15360 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015361 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
15362
15363 /*Input mixer control */
15364 HDA_CODEC_VOLUME("CD Playback Volume", 0xb, 0x4, HDA_INPUT),
15365 HDA_CODEC_MUTE("CD Playback Switch", 0xb, 0x4, HDA_INPUT),
15366 HDA_CODEC_VOLUME("Line Playback Volume", 0xb, 0x02, HDA_INPUT),
15367 HDA_CODEC_MUTE("Line Playback Switch", 0xb, 0x02, HDA_INPUT),
15368 HDA_CODEC_VOLUME("Mic Playback Volume", 0xb, 0x0, HDA_INPUT),
15369 HDA_CODEC_MUTE("Mic Playback Switch", 0xb, 0x0, HDA_INPUT),
15370 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0xb, 0x01, HDA_INPUT),
15371 HDA_CODEC_MUTE("Front Mic Playback Switch", 0xb, 0x01, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015372 { } /* end */
15373};
15374
15375static struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = {
15376 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010015377 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015378 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
15379 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
15380 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
15381 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
15382 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
15383 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15384 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15385 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15386 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015387 { } /* end */
15388};
15389
15390static struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = {
15391 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010015392 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015393 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010015394 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015395 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
15396 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010015397 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
15398 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015399 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
15400 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
15401 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
15402 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
15403 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
15404 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15405 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15406 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15407 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015408 { } /* end */
15409};
15410
15411static struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = {
15412 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15413 HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010015414 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x03, 0x0, HDA_OUTPUT),
15415 HDA_BIND_MUTE("Speaker Playback Switch", 0x03, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015416 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
15417 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
15418 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
15419 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15420 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015421 { } /* end */
15422};
15423
Kailang Yang291702f2007-10-16 14:28:03 +020015424static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = {
Takashi Iwai86cd9292008-01-28 18:09:56 +010015425 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang291702f2007-10-16 14:28:03 +020015426
Herton Ronaldo Krzesinskib4818492008-02-23 11:34:12 +010015427 HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15428 HDA_CODEC_MUTE("Line-Out Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yang291702f2007-10-16 14:28:03 +020015429
15430 HDA_CODEC_VOLUME("e-Mic Boost", 0x18, 0, HDA_INPUT),
15431 HDA_CODEC_VOLUME("e-Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15432 HDA_CODEC_MUTE("e-Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15433
15434 HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT),
15435 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15436 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
15437 { } /* end */
15438};
15439
Kailang Yang8c427222008-01-10 13:03:59 +010015440static struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = {
Takashi Iwai31bffaa2008-02-27 16:10:44 +010015441 HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15442 HDA_CODEC_MUTE("Line-Out Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010015443 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
15444 HDA_BIND_MUTE("Surround Playback Switch", 0x03, 2, HDA_INPUT),
15445 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
15446 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
15447 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x04, 1, 2, HDA_INPUT),
15448 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x04, 2, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010015449 HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010015450 HDA_BIND_MUTE("MuteCtrl Playback Switch", 0x0c, 2, HDA_INPUT),
15451 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
15452 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
15453 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15454 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15455 { } /* end */
15456};
15457
Kailang Yangf1d4e282008-08-26 14:03:29 +020015458static struct hda_bind_ctls alc663_asus_bind_master_vol = {
15459 .ops = &snd_hda_bind_vol,
15460 .values = {
15461 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
15462 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
15463 0
15464 },
15465};
15466
15467static struct hda_bind_ctls alc663_asus_one_bind_switch = {
15468 .ops = &snd_hda_bind_sw,
15469 .values = {
15470 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
15471 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
15472 0
15473 },
15474};
15475
Kailang Yang6dda9f42008-05-27 12:05:31 +020015476static struct snd_kcontrol_new alc663_m51va_mixer[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020015477 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
15478 HDA_BIND_SW("Master Playback Switch", &alc663_asus_one_bind_switch),
15479 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15480 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15481 { } /* end */
15482};
15483
15484static struct hda_bind_ctls alc663_asus_tree_bind_switch = {
15485 .ops = &snd_hda_bind_sw,
15486 .values = {
15487 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
15488 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
15489 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
15490 0
15491 },
15492};
15493
15494static struct snd_kcontrol_new alc663_two_hp_m1_mixer[] = {
15495 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
15496 HDA_BIND_SW("Master Playback Switch", &alc663_asus_tree_bind_switch),
15497 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15498 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15499 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15500 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
15501
15502 { } /* end */
15503};
15504
15505static struct hda_bind_ctls alc663_asus_four_bind_switch = {
15506 .ops = &snd_hda_bind_sw,
15507 .values = {
15508 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
15509 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
15510 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
15511 0
15512 },
15513};
15514
15515static struct snd_kcontrol_new alc663_two_hp_m2_mixer[] = {
15516 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
15517 HDA_BIND_SW("Master Playback Switch", &alc663_asus_four_bind_switch),
15518 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15519 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15520 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15521 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
15522 { } /* end */
15523};
15524
15525static struct snd_kcontrol_new alc662_1bjd_mixer[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020015526 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15527 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020015528 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
15529 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15530 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15531 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15532 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
15533 { } /* end */
15534};
15535
15536static struct hda_bind_ctls alc663_asus_two_bind_master_vol = {
15537 .ops = &snd_hda_bind_vol,
15538 .values = {
15539 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
15540 HDA_COMPOSE_AMP_VAL(0x04, 3, 0, HDA_OUTPUT),
15541 0
15542 },
15543};
15544
15545static struct hda_bind_ctls alc663_asus_two_bind_switch = {
15546 .ops = &snd_hda_bind_sw,
15547 .values = {
15548 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
15549 HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT),
15550 0
15551 },
15552};
15553
15554static struct snd_kcontrol_new alc663_asus_21jd_clfe_mixer[] = {
15555 HDA_BIND_VOL("Master Playback Volume",
15556 &alc663_asus_two_bind_master_vol),
15557 HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
15558 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020015559 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
15560 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15561 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020015562 { } /* end */
15563};
15564
15565static struct snd_kcontrol_new alc663_asus_15jd_clfe_mixer[] = {
15566 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
15567 HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
15568 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
15569 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
15570 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15571 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020015572 { } /* end */
15573};
15574
15575static struct snd_kcontrol_new alc663_g71v_mixer[] = {
15576 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15577 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
15578 HDA_CODEC_VOLUME("Front Playback Volume", 0x03, 0x0, HDA_OUTPUT),
15579 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
15580 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
15581
15582 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15583 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15584 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15585 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
15586 { } /* end */
15587};
15588
15589static struct snd_kcontrol_new alc663_g50v_mixer[] = {
15590 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15591 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
15592 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
15593
15594 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15595 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15596 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15597 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
15598 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
15599 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
15600 { } /* end */
15601};
15602
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015603static struct snd_kcontrol_new alc662_chmode_mixer[] = {
15604 {
15605 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
15606 .name = "Channel Mode",
15607 .info = alc_ch_mode_info,
15608 .get = alc_ch_mode_get,
15609 .put = alc_ch_mode_put,
15610 },
15611 { } /* end */
15612};
15613
15614static struct hda_verb alc662_init_verbs[] = {
15615 /* ADC: mute amp left and right */
15616 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15617 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
15618 /* Front mixer: unmute input/output amp left and right (volume = 0) */
15619
Takashi Iwaicb53c622007-08-10 17:21:45 +020015620 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15621 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15622 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
15623 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
15624 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015625
Kailang Yangb60dd392007-09-20 12:50:29 +020015626 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15627 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15628 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15629 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15630 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15631 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015632
15633 /* Front Pin: output 0 (0x0c) */
15634 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
15635 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15636
15637 /* Rear Pin: output 1 (0x0d) */
15638 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
15639 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15640
15641 /* CLFE Pin: output 2 (0x0e) */
15642 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
15643 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15644
15645 /* Mic (rear) pin: input vref at 80% */
15646 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
15647 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15648 /* Front Mic pin: input vref at 80% */
15649 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
15650 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15651 /* Line In pin: input */
15652 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15653 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15654 /* Line-2 In: Headphone output (output 0 - 0x0c) */
15655 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15656 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15657 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
15658 /* CD pin widget for input */
15659 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15660
15661 /* FIXME: use matrix-type input source selection */
15662 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
15663 /* Input mixer */
15664 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yang291702f2007-10-16 14:28:03 +020015665 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yang6dda9f42008-05-27 12:05:31 +020015666
15667 /* always trun on EAPD */
15668 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
15669 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
15670
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015671 { }
15672};
15673
15674static struct hda_verb alc662_sue_init_verbs[] = {
15675 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
15676 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
Kailang Yang291702f2007-10-16 14:28:03 +020015677 {}
15678};
15679
15680static struct hda_verb alc662_eeepc_sue_init_verbs[] = {
15681 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15682 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15683 {}
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015684};
15685
Kailang Yang8c427222008-01-10 13:03:59 +010015686/* Set Unsolicited Event*/
15687static struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = {
15688 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
15689 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15690 {}
15691};
15692
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015693/*
15694 * generic initialization of ADC, input mixers and output mixers
15695 */
15696static struct hda_verb alc662_auto_init_verbs[] = {
15697 /*
15698 * Unmute ADC and set the default input to mic-in
15699 */
15700 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
15701 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15702
15703 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
15704 * mixer widget
15705 * Note: PASD motherboards uses the Line In 2 as the input for front
15706 * panel mic (mic 2)
15707 */
15708 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020015709 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15710 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15711 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
15712 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
15713 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015714
15715 /*
15716 * Set up output mixers (0x0c - 0x0f)
15717 */
15718 /* set vol=0 to output mixers */
15719 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
15720 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
15721 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
15722
15723 /* set up input amps for analog loopback */
15724 /* Amp Indices: DAC = 0, mixer = 1 */
Kailang Yangb60dd392007-09-20 12:50:29 +020015725 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15726 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15727 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15728 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15729 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15730 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015731
15732
15733 /* FIXME: use matrix-type input source selection */
15734 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
15735 /* Input mixer */
15736 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangd1a991a2007-08-15 16:21:59 +020015737 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015738 { }
15739};
15740
Takashi Iwai24fb9172008-09-02 14:48:20 +020015741/* additional verbs for ALC663 */
15742static struct hda_verb alc663_auto_init_verbs[] = {
15743 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15744 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15745 { }
15746};
15747
Kailang Yang6dda9f42008-05-27 12:05:31 +020015748static struct hda_verb alc663_m51va_init_verbs[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020015749 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15750 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yang6dda9f42008-05-27 12:05:31 +020015751 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15752 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangf1d4e282008-08-26 14:03:29 +020015753 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
15754 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15755 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
Kailang Yang6dda9f42008-05-27 12:05:31 +020015756 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15757 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15758 {}
15759};
15760
Kailang Yangf1d4e282008-08-26 14:03:29 +020015761static struct hda_verb alc663_21jd_amic_init_verbs[] = {
15762 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15763 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15764 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
15765 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15766 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15767 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15768 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15769 {}
15770};
15771
15772static struct hda_verb alc662_1bjd_amic_init_verbs[] = {
15773 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15774 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15775 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15776 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
15777 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15778 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15779 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15780 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15781 {}
15782};
15783
15784static struct hda_verb alc663_15jd_amic_init_verbs[] = {
15785 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15786 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15787 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
15788 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15789 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15790 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15791 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15792 {}
15793};
15794
15795static struct hda_verb alc663_two_hp_amic_m1_init_verbs[] = {
15796 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15797 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15798 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15799 {0x21, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */
15800 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15801 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15802 {0x15, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */
15803 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15804 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15805 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15806 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15807 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15808 {}
15809};
15810
15811static struct hda_verb alc663_two_hp_amic_m2_init_verbs[] = {
15812 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15813 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15814 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15815 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
15816 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15817 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15818 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
15819 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15820 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15821 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15822 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15823 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15824 {}
15825};
15826
Kailang Yang6dda9f42008-05-27 12:05:31 +020015827static struct hda_verb alc663_g71v_init_verbs[] = {
15828 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15829 /* {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
15830 /* {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, */ /* Headphone */
15831
15832 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15833 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15834 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
15835
15836 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
15837 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_MIC_EVENT},
15838 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
15839 {}
15840};
15841
15842static struct hda_verb alc663_g50v_init_verbs[] = {
15843 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15844 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15845 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
15846
15847 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15848 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15849 {}
15850};
15851
Kailang Yangf1d4e282008-08-26 14:03:29 +020015852static struct hda_verb alc662_ecs_init_verbs[] = {
15853 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
15854 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15855 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15856 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15857 {}
15858};
15859
Kailang Yang622e84c2009-04-21 07:39:04 +020015860static struct hda_verb alc272_dell_zm1_init_verbs[] = {
15861 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15862 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15863 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15864 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15865 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15866 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15867 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
15868 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15869 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
15870 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15871 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15872 {}
15873};
15874
15875static struct hda_verb alc272_dell_init_verbs[] = {
15876 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15877 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15878 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15879 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15880 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15881 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15882 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
15883 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15884 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
15885 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15886 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15887 {}
15888};
15889
Kailang Yangf1d4e282008-08-26 14:03:29 +020015890static struct snd_kcontrol_new alc662_auto_capture_mixer[] = {
15891 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
15892 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
15893 { } /* end */
15894};
15895
Kailang Yang622e84c2009-04-21 07:39:04 +020015896static struct snd_kcontrol_new alc272_auto_capture_mixer[] = {
15897 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
15898 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
15899 { } /* end */
15900};
15901
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015902static void alc662_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
15903{
15904 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015905 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015906
15907 present = snd_hda_codec_read(codec, 0x14, 0,
15908 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020015909 bits = present ? HDA_AMP_MUTE : 0;
15910 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
15911 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015912}
15913
15914static void alc662_lenovo_101e_all_automute(struct hda_codec *codec)
15915{
15916 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015917 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015918
15919 present = snd_hda_codec_read(codec, 0x1b, 0,
15920 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020015921 bits = present ? HDA_AMP_MUTE : 0;
15922 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
15923 HDA_AMP_MUTE, bits);
15924 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
15925 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015926}
15927
15928static void alc662_lenovo_101e_unsol_event(struct hda_codec *codec,
15929 unsigned int res)
15930{
15931 if ((res >> 26) == ALC880_HP_EVENT)
15932 alc662_lenovo_101e_all_automute(codec);
15933 if ((res >> 26) == ALC880_FRONT_EVENT)
15934 alc662_lenovo_101e_ispeaker_automute(codec);
15935}
15936
Kailang Yang291702f2007-10-16 14:28:03 +020015937static void alc662_eeepc_mic_automute(struct hda_codec *codec)
15938{
15939 unsigned int present;
15940
15941 present = snd_hda_codec_read(codec, 0x18, 0,
15942 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
15943 snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
15944 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
15945 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
15946 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
15947 snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
15948 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
15949 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
15950 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
15951}
15952
15953/* unsolicited event for HP jack sensing */
15954static void alc662_eeepc_unsol_event(struct hda_codec *codec,
15955 unsigned int res)
15956{
15957 if ((res >> 26) == ALC880_HP_EVENT)
15958 alc262_hippo1_automute( codec );
15959
15960 if ((res >> 26) == ALC880_MIC_EVENT)
15961 alc662_eeepc_mic_automute(codec);
15962}
15963
15964static void alc662_eeepc_inithook(struct hda_codec *codec)
15965{
15966 alc262_hippo1_automute( codec );
15967 alc662_eeepc_mic_automute(codec);
15968}
15969
Kailang Yang8c427222008-01-10 13:03:59 +010015970static void alc662_eeepc_ep20_automute(struct hda_codec *codec)
15971{
15972 unsigned int mute;
15973 unsigned int present;
15974
15975 snd_hda_codec_read(codec, 0x14, 0, AC_VERB_SET_PIN_SENSE, 0);
15976 present = snd_hda_codec_read(codec, 0x14, 0,
15977 AC_VERB_GET_PIN_SENSE, 0);
15978 present = (present & 0x80000000) != 0;
15979 if (present) {
15980 /* mute internal speaker */
15981 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +020015982 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yang8c427222008-01-10 13:03:59 +010015983 } else {
15984 /* unmute internal speaker if necessary */
15985 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
15986 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +020015987 HDA_AMP_MUTE, mute);
Kailang Yang8c427222008-01-10 13:03:59 +010015988 }
15989}
15990
15991/* unsolicited event for HP jack sensing */
15992static void alc662_eeepc_ep20_unsol_event(struct hda_codec *codec,
15993 unsigned int res)
15994{
15995 if ((res >> 26) == ALC880_HP_EVENT)
15996 alc662_eeepc_ep20_automute(codec);
15997}
15998
15999static void alc662_eeepc_ep20_inithook(struct hda_codec *codec)
16000{
16001 alc662_eeepc_ep20_automute(codec);
16002}
16003
Kailang Yang6dda9f42008-05-27 12:05:31 +020016004static void alc663_m51va_speaker_automute(struct hda_codec *codec)
16005{
16006 unsigned int present;
16007 unsigned char bits;
16008
16009 present = snd_hda_codec_read(codec, 0x21, 0,
Kailang Yangf1d4e282008-08-26 14:03:29 +020016010 AC_VERB_GET_PIN_SENSE, 0)
16011 & AC_PINSENSE_PRESENCE;
Kailang Yang6dda9f42008-05-27 12:05:31 +020016012 bits = present ? HDA_AMP_MUTE : 0;
Kailang Yangf1d4e282008-08-26 14:03:29 +020016013 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
16014 AMP_IN_MUTE(0), bits);
16015 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
16016 AMP_IN_MUTE(0), bits);
16017}
16018
16019static void alc663_21jd_two_speaker_automute(struct hda_codec *codec)
16020{
16021 unsigned int present;
16022 unsigned char bits;
16023
16024 present = snd_hda_codec_read(codec, 0x21, 0,
16025 AC_VERB_GET_PIN_SENSE, 0)
16026 & AC_PINSENSE_PRESENCE;
16027 bits = present ? HDA_AMP_MUTE : 0;
16028 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
16029 AMP_IN_MUTE(0), bits);
16030 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
16031 AMP_IN_MUTE(0), bits);
16032 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0,
16033 AMP_IN_MUTE(0), bits);
16034 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1,
16035 AMP_IN_MUTE(0), bits);
16036}
16037
16038static void alc663_15jd_two_speaker_automute(struct hda_codec *codec)
16039{
16040 unsigned int present;
16041 unsigned char bits;
16042
16043 present = snd_hda_codec_read(codec, 0x15, 0,
16044 AC_VERB_GET_PIN_SENSE, 0)
16045 & AC_PINSENSE_PRESENCE;
16046 bits = present ? HDA_AMP_MUTE : 0;
16047 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
16048 AMP_IN_MUTE(0), bits);
16049 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
16050 AMP_IN_MUTE(0), bits);
16051 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0,
16052 AMP_IN_MUTE(0), bits);
16053 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1,
16054 AMP_IN_MUTE(0), bits);
16055}
16056
16057static void alc662_f5z_speaker_automute(struct hda_codec *codec)
16058{
16059 unsigned int present;
16060 unsigned char bits;
16061
16062 present = snd_hda_codec_read(codec, 0x1b, 0,
16063 AC_VERB_GET_PIN_SENSE, 0)
16064 & AC_PINSENSE_PRESENCE;
16065 bits = present ? 0 : PIN_OUT;
16066 snd_hda_codec_write(codec, 0x14, 0,
16067 AC_VERB_SET_PIN_WIDGET_CONTROL, bits);
16068}
16069
16070static void alc663_two_hp_m1_speaker_automute(struct hda_codec *codec)
16071{
16072 unsigned int present1, present2;
16073
16074 present1 = snd_hda_codec_read(codec, 0x21, 0,
16075 AC_VERB_GET_PIN_SENSE, 0)
16076 & AC_PINSENSE_PRESENCE;
16077 present2 = snd_hda_codec_read(codec, 0x15, 0,
16078 AC_VERB_GET_PIN_SENSE, 0)
16079 & AC_PINSENSE_PRESENCE;
16080
16081 if (present1 || present2) {
16082 snd_hda_codec_write_cache(codec, 0x14, 0,
16083 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
16084 } else {
16085 snd_hda_codec_write_cache(codec, 0x14, 0,
16086 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
16087 }
16088}
16089
16090static void alc663_two_hp_m2_speaker_automute(struct hda_codec *codec)
16091{
16092 unsigned int present1, present2;
16093
16094 present1 = snd_hda_codec_read(codec, 0x1b, 0,
16095 AC_VERB_GET_PIN_SENSE, 0)
16096 & AC_PINSENSE_PRESENCE;
16097 present2 = snd_hda_codec_read(codec, 0x15, 0,
16098 AC_VERB_GET_PIN_SENSE, 0)
16099 & AC_PINSENSE_PRESENCE;
16100
16101 if (present1 || present2) {
16102 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
16103 AMP_IN_MUTE(0), AMP_IN_MUTE(0));
16104 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
16105 AMP_IN_MUTE(0), AMP_IN_MUTE(0));
16106 } else {
16107 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
16108 AMP_IN_MUTE(0), 0);
16109 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
16110 AMP_IN_MUTE(0), 0);
16111 }
Kailang Yang6dda9f42008-05-27 12:05:31 +020016112}
16113
16114static void alc663_m51va_mic_automute(struct hda_codec *codec)
16115{
16116 unsigned int present;
16117
16118 present = snd_hda_codec_read(codec, 0x18, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +020016119 AC_VERB_GET_PIN_SENSE, 0)
16120 & AC_PINSENSE_PRESENCE;
Kailang Yang6dda9f42008-05-27 12:05:31 +020016121 snd_hda_codec_write_cache(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangea1fb292008-08-26 12:58:38 +020016122 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
Kailang Yang6dda9f42008-05-27 12:05:31 +020016123 snd_hda_codec_write_cache(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangea1fb292008-08-26 12:58:38 +020016124 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
Kailang Yang6dda9f42008-05-27 12:05:31 +020016125 snd_hda_codec_write_cache(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangea1fb292008-08-26 12:58:38 +020016126 0x7000 | (0x09 << 8) | (present ? 0x80 : 0));
Kailang Yang6dda9f42008-05-27 12:05:31 +020016127 snd_hda_codec_write_cache(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangea1fb292008-08-26 12:58:38 +020016128 0x7000 | (0x09 << 8) | (present ? 0x80 : 0));
Kailang Yang6dda9f42008-05-27 12:05:31 +020016129}
16130
16131static void alc663_m51va_unsol_event(struct hda_codec *codec,
16132 unsigned int res)
16133{
16134 switch (res >> 26) {
16135 case ALC880_HP_EVENT:
16136 alc663_m51va_speaker_automute(codec);
16137 break;
16138 case ALC880_MIC_EVENT:
16139 alc663_m51va_mic_automute(codec);
16140 break;
16141 }
16142}
16143
16144static void alc663_m51va_inithook(struct hda_codec *codec)
16145{
16146 alc663_m51va_speaker_automute(codec);
16147 alc663_m51va_mic_automute(codec);
16148}
16149
Kailang Yangf1d4e282008-08-26 14:03:29 +020016150/* ***************** Mode1 ******************************/
16151static void alc663_mode1_unsol_event(struct hda_codec *codec,
16152 unsigned int res)
16153{
16154 switch (res >> 26) {
16155 case ALC880_HP_EVENT:
16156 alc663_m51va_speaker_automute(codec);
16157 break;
16158 case ALC880_MIC_EVENT:
16159 alc662_eeepc_mic_automute(codec);
16160 break;
16161 }
16162}
16163
16164static void alc663_mode1_inithook(struct hda_codec *codec)
16165{
16166 alc663_m51va_speaker_automute(codec);
16167 alc662_eeepc_mic_automute(codec);
16168}
16169/* ***************** Mode2 ******************************/
16170static void alc662_mode2_unsol_event(struct hda_codec *codec,
16171 unsigned int res)
16172{
16173 switch (res >> 26) {
16174 case ALC880_HP_EVENT:
16175 alc662_f5z_speaker_automute(codec);
16176 break;
16177 case ALC880_MIC_EVENT:
16178 alc662_eeepc_mic_automute(codec);
16179 break;
16180 }
16181}
16182
16183static void alc662_mode2_inithook(struct hda_codec *codec)
16184{
16185 alc662_f5z_speaker_automute(codec);
16186 alc662_eeepc_mic_automute(codec);
16187}
16188/* ***************** Mode3 ******************************/
16189static void alc663_mode3_unsol_event(struct hda_codec *codec,
16190 unsigned int res)
16191{
16192 switch (res >> 26) {
16193 case ALC880_HP_EVENT:
16194 alc663_two_hp_m1_speaker_automute(codec);
16195 break;
16196 case ALC880_MIC_EVENT:
16197 alc662_eeepc_mic_automute(codec);
16198 break;
16199 }
16200}
16201
16202static void alc663_mode3_inithook(struct hda_codec *codec)
16203{
16204 alc663_two_hp_m1_speaker_automute(codec);
16205 alc662_eeepc_mic_automute(codec);
16206}
16207/* ***************** Mode4 ******************************/
16208static void alc663_mode4_unsol_event(struct hda_codec *codec,
16209 unsigned int res)
16210{
16211 switch (res >> 26) {
16212 case ALC880_HP_EVENT:
16213 alc663_21jd_two_speaker_automute(codec);
16214 break;
16215 case ALC880_MIC_EVENT:
16216 alc662_eeepc_mic_automute(codec);
16217 break;
16218 }
16219}
16220
16221static void alc663_mode4_inithook(struct hda_codec *codec)
16222{
16223 alc663_21jd_two_speaker_automute(codec);
16224 alc662_eeepc_mic_automute(codec);
16225}
16226/* ***************** Mode5 ******************************/
16227static void alc663_mode5_unsol_event(struct hda_codec *codec,
16228 unsigned int res)
16229{
16230 switch (res >> 26) {
16231 case ALC880_HP_EVENT:
16232 alc663_15jd_two_speaker_automute(codec);
16233 break;
16234 case ALC880_MIC_EVENT:
16235 alc662_eeepc_mic_automute(codec);
16236 break;
16237 }
16238}
16239
16240static void alc663_mode5_inithook(struct hda_codec *codec)
16241{
16242 alc663_15jd_two_speaker_automute(codec);
16243 alc662_eeepc_mic_automute(codec);
16244}
16245/* ***************** Mode6 ******************************/
16246static void alc663_mode6_unsol_event(struct hda_codec *codec,
16247 unsigned int res)
16248{
16249 switch (res >> 26) {
16250 case ALC880_HP_EVENT:
16251 alc663_two_hp_m2_speaker_automute(codec);
16252 break;
16253 case ALC880_MIC_EVENT:
16254 alc662_eeepc_mic_automute(codec);
16255 break;
16256 }
16257}
16258
16259static void alc663_mode6_inithook(struct hda_codec *codec)
16260{
16261 alc663_two_hp_m2_speaker_automute(codec);
16262 alc662_eeepc_mic_automute(codec);
16263}
16264
Kailang Yang6dda9f42008-05-27 12:05:31 +020016265static void alc663_g71v_hp_automute(struct hda_codec *codec)
16266{
16267 unsigned int present;
16268 unsigned char bits;
16269
16270 present = snd_hda_codec_read(codec, 0x21, 0,
16271 AC_VERB_GET_PIN_SENSE, 0)
16272 & AC_PINSENSE_PRESENCE;
16273 bits = present ? HDA_AMP_MUTE : 0;
16274 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
16275 HDA_AMP_MUTE, bits);
16276 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
16277 HDA_AMP_MUTE, bits);
16278}
16279
16280static void alc663_g71v_front_automute(struct hda_codec *codec)
16281{
16282 unsigned int present;
16283 unsigned char bits;
16284
16285 present = snd_hda_codec_read(codec, 0x15, 0,
16286 AC_VERB_GET_PIN_SENSE, 0)
16287 & AC_PINSENSE_PRESENCE;
16288 bits = present ? HDA_AMP_MUTE : 0;
16289 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
16290 HDA_AMP_MUTE, bits);
16291}
16292
16293static void alc663_g71v_unsol_event(struct hda_codec *codec,
16294 unsigned int res)
16295{
16296 switch (res >> 26) {
16297 case ALC880_HP_EVENT:
16298 alc663_g71v_hp_automute(codec);
16299 break;
16300 case ALC880_FRONT_EVENT:
16301 alc663_g71v_front_automute(codec);
16302 break;
16303 case ALC880_MIC_EVENT:
16304 alc662_eeepc_mic_automute(codec);
16305 break;
16306 }
16307}
16308
16309static void alc663_g71v_inithook(struct hda_codec *codec)
16310{
16311 alc663_g71v_front_automute(codec);
16312 alc663_g71v_hp_automute(codec);
16313 alc662_eeepc_mic_automute(codec);
16314}
16315
16316static void alc663_g50v_unsol_event(struct hda_codec *codec,
16317 unsigned int res)
16318{
16319 switch (res >> 26) {
16320 case ALC880_HP_EVENT:
16321 alc663_m51va_speaker_automute(codec);
16322 break;
16323 case ALC880_MIC_EVENT:
16324 alc662_eeepc_mic_automute(codec);
16325 break;
16326 }
16327}
16328
16329static void alc663_g50v_inithook(struct hda_codec *codec)
16330{
16331 alc663_m51va_speaker_automute(codec);
16332 alc662_eeepc_mic_automute(codec);
16333}
16334
Kailang Yangf1d4e282008-08-26 14:03:29 +020016335/* bind hp and internal speaker mute (with plug check) */
16336static int alc662_ecs_master_sw_put(struct snd_kcontrol *kcontrol,
16337 struct snd_ctl_elem_value *ucontrol)
16338{
16339 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
16340 long *valp = ucontrol->value.integer.value;
16341 int change;
16342
16343 change = snd_hda_codec_amp_update(codec, 0x1b, 0, HDA_OUTPUT, 0,
16344 HDA_AMP_MUTE,
16345 valp[0] ? 0 : HDA_AMP_MUTE);
16346 change |= snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0,
16347 HDA_AMP_MUTE,
16348 valp[1] ? 0 : HDA_AMP_MUTE);
16349 if (change)
16350 alc262_hippo1_automute(codec);
16351 return change;
16352}
16353
16354static struct snd_kcontrol_new alc662_ecs_mixer[] = {
16355 HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16356 {
16357 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
16358 .name = "Master Playback Switch",
16359 .info = snd_hda_mixer_amp_switch_info,
16360 .get = snd_hda_mixer_amp_switch_get,
16361 .put = alc662_ecs_master_sw_put,
16362 .private_value = HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
16363 },
16364
16365 HDA_CODEC_VOLUME("e-Mic/LineIn Boost", 0x18, 0, HDA_INPUT),
16366 HDA_CODEC_VOLUME("e-Mic/LineIn Playback Volume", 0x0b, 0x0, HDA_INPUT),
16367 HDA_CODEC_MUTE("e-Mic/LineIn Playback Switch", 0x0b, 0x0, HDA_INPUT),
16368
16369 HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT),
16370 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16371 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16372 { } /* end */
16373};
16374
Takashi Iwaicb53c622007-08-10 17:21:45 +020016375#ifdef CONFIG_SND_HDA_POWER_SAVE
16376#define alc662_loopbacks alc880_loopbacks
16377#endif
16378
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016379
16380/* pcm configuration: identiacal with ALC880 */
16381#define alc662_pcm_analog_playback alc880_pcm_analog_playback
16382#define alc662_pcm_analog_capture alc880_pcm_analog_capture
16383#define alc662_pcm_digital_playback alc880_pcm_digital_playback
16384#define alc662_pcm_digital_capture alc880_pcm_digital_capture
16385
16386/*
16387 * configuration and preset
16388 */
16389static const char *alc662_models[ALC662_MODEL_LAST] = {
16390 [ALC662_3ST_2ch_DIG] = "3stack-dig",
16391 [ALC662_3ST_6ch_DIG] = "3stack-6ch-dig",
16392 [ALC662_3ST_6ch] = "3stack-6ch",
16393 [ALC662_5ST_DIG] = "6stack-dig",
16394 [ALC662_LENOVO_101E] = "lenovo-101e",
Takashi Iwaib995d762007-10-17 10:41:06 +020016395 [ALC662_ASUS_EEEPC_P701] = "eeepc-p701",
Kailang Yang8c427222008-01-10 13:03:59 +010016396 [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20",
Kailang Yangf1d4e282008-08-26 14:03:29 +020016397 [ALC662_ECS] = "ecs",
Kailang Yang6dda9f42008-05-27 12:05:31 +020016398 [ALC663_ASUS_M51VA] = "m51va",
16399 [ALC663_ASUS_G71V] = "g71v",
16400 [ALC663_ASUS_H13] = "h13",
16401 [ALC663_ASUS_G50V] = "g50v",
Kailang Yangf1d4e282008-08-26 14:03:29 +020016402 [ALC663_ASUS_MODE1] = "asus-mode1",
16403 [ALC662_ASUS_MODE2] = "asus-mode2",
16404 [ALC663_ASUS_MODE3] = "asus-mode3",
16405 [ALC663_ASUS_MODE4] = "asus-mode4",
16406 [ALC663_ASUS_MODE5] = "asus-mode5",
16407 [ALC663_ASUS_MODE6] = "asus-mode6",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016408 [ALC662_AUTO] = "auto",
16409};
16410
16411static struct snd_pci_quirk alc662_cfg_tbl[] = {
Takashi Iwaidea0a502009-02-09 17:14:52 +010016412 SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_ECS),
Kailang Yang622e84c2009-04-21 07:39:04 +020016413 SND_PCI_QUIRK(0x1028, 0x02d6, "DELL", ALC272_DELL),
16414 SND_PCI_QUIRK(0x1028, 0x02f4, "DELL ZM1", ALC272_DELL_ZM1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016415 SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC663_ASUS_MODE1),
16416 SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC663_ASUS_MODE3),
16417 SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC663_ASUS_MODE3),
16418 SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC663_ASUS_MODE1),
16419 SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_ASUS_MODE2),
16420 SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC663_ASUS_MODE1),
16421 SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_ASUS_MODE2),
16422 SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_ASUS_MODE2),
16423 SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_ASUS_MODE2),
16424 SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC663_ASUS_MODE6),
16425 SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC663_ASUS_MODE6),
16426 SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020016427 SND_PCI_QUIRK(0x1043, 0x17b3, "ASUS F70SL", ALC663_ASUS_MODE3),
16428 SND_PCI_QUIRK(0x1043, 0x17c3, "ASUS UX20", ALC663_ASUS_M51VA),
16429 SND_PCI_QUIRK(0x1043, 0x17f3, "ASUS X58LE", ALC662_ASUS_MODE2),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016430 SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_ASUS_MODE2),
16431 SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC663_ASUS_MODE5),
16432 SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC663_ASUS_MODE6),
16433 SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020016434 SND_PCI_QUIRK(0x1043, 0x1853, "ASUS F50Z", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016435 SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_ASUS_MODE2),
16436 SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yang6dda9f42008-05-27 12:05:31 +020016437 SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M51VA", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016438 /*SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M50Vr", ALC663_ASUS_MODE1),*/
16439 SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC663_ASUS_MODE3),
16440 SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC663_ASUS_MODE3),
Kailang Yang622e84c2009-04-21 07:39:04 +020016441 SND_PCI_QUIRK(0x1043, 0x18b3, "ASUS N80Vc", ALC663_ASUS_MODE1),
16442 SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS N81Te", ALC663_ASUS_MODE1),
16443 SND_PCI_QUIRK(0x1043, 0x18f3, "ASUS N505Tp", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016444 SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC663_ASUS_MODE1),
16445 SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_ASUS_MODE2),
16446 SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020016447 SND_PCI_QUIRK(0x1043, 0x1943, "ASUS Vx3V", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016448 SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC663_ASUS_MODE1),
16449 SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC663_ASUS_MODE3),
Kailang Yang622e84c2009-04-21 07:39:04 +020016450 SND_PCI_QUIRK(0x1043, 0x1983, "ASUS N5051A", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016451 SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC663_ASUS_MODE1),
Kailang Yang80ffe862008-10-15 11:23:27 +020016452 SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS G50V", ALC663_ASUS_G50V),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016453 /*SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS NB", ALC663_ASUS_MODE1),*/
16454 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC663_ASUS_MODE1),
16455 SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020016456 SND_PCI_QUIRK(0x1043, 0x19d3, "ASUS NB", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016457 SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC663_ASUS_MODE1),
16458 SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC663_ASUS_MODE4),
Herton Ronaldo Krzesinski3da23ca2008-03-14 12:52:59 +010016459 SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG),
Kailang Yang291702f2007-10-16 14:28:03 +020016460 SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701),
Kailang Yang8c427222008-01-10 13:03:59 +010016461 SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016462 SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS),
Herton Ronaldo Krzesinski95fe5f22008-09-26 23:48:45 -030016463 SND_PCI_QUIRK(0x105b, 0x0d47, "Foxconn 45CMX/45GMX/45CMX-K",
16464 ALC662_3ST_6ch_DIG),
Herton Ronaldo Krzesinskicb559742008-09-26 23:47:45 -030016465 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L",
16466 ALC662_3ST_6ch_DIG),
Vedran Miletic19c009a2008-09-29 20:29:25 +020016467 SND_PCI_QUIRK(0x1565, 0x820f, "Biostar TA780G M2+", ALC662_3ST_6ch_DIG),
Takashi Iwai5bd37292009-04-21 18:36:30 +020016468 SND_PCI_QUIRK(0x1631, 0xc10c, "PB RS65", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016469 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E),
Takashi Iwai238713d2008-10-05 10:57:39 +020016470 SND_PCI_QUIRK(0x1849, 0x3662, "ASROCK K10N78FullHD-hSLI R3.0",
Vedran Miletic19c009a2008-09-29 20:29:25 +020016471 ALC662_3ST_6ch_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016472 SND_PCI_QUIRK_MASK(0x1854, 0xf000, 0x2000, "ASUS H13-200x",
16473 ALC663_ASUS_H13),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016474 {}
16475};
16476
16477static struct alc_config_preset alc662_presets[] = {
16478 [ALC662_3ST_2ch_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016479 .mixers = { alc662_3ST_2ch_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016480 .init_verbs = { alc662_init_verbs },
16481 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16482 .dac_nids = alc662_dac_nids,
16483 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016484 .dig_in_nid = ALC662_DIGIN_NID,
16485 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16486 .channel_mode = alc662_3ST_2ch_modes,
16487 .input_mux = &alc662_capture_source,
16488 },
16489 [ALC662_3ST_6ch_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016490 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016491 .init_verbs = { alc662_init_verbs },
16492 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16493 .dac_nids = alc662_dac_nids,
16494 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016495 .dig_in_nid = ALC662_DIGIN_NID,
16496 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
16497 .channel_mode = alc662_3ST_6ch_modes,
16498 .need_dac_fix = 1,
16499 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016500 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016501 [ALC662_3ST_6ch] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016502 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016503 .init_verbs = { alc662_init_verbs },
16504 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16505 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016506 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
16507 .channel_mode = alc662_3ST_6ch_modes,
16508 .need_dac_fix = 1,
16509 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016510 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016511 [ALC662_5ST_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016512 .mixers = { alc662_base_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016513 .init_verbs = { alc662_init_verbs },
16514 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16515 .dac_nids = alc662_dac_nids,
16516 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016517 .dig_in_nid = ALC662_DIGIN_NID,
16518 .num_channel_mode = ARRAY_SIZE(alc662_5stack_modes),
16519 .channel_mode = alc662_5stack_modes,
16520 .input_mux = &alc662_capture_source,
16521 },
16522 [ALC662_LENOVO_101E] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016523 .mixers = { alc662_lenovo_101e_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016524 .init_verbs = { alc662_init_verbs, alc662_sue_init_verbs },
16525 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16526 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016527 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16528 .channel_mode = alc662_3ST_2ch_modes,
16529 .input_mux = &alc662_lenovo_101e_capture_source,
16530 .unsol_event = alc662_lenovo_101e_unsol_event,
16531 .init_hook = alc662_lenovo_101e_all_automute,
16532 },
Kailang Yang291702f2007-10-16 14:28:03 +020016533 [ALC662_ASUS_EEEPC_P701] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016534 .mixers = { alc662_eeepc_p701_mixer },
Kailang Yang291702f2007-10-16 14:28:03 +020016535 .init_verbs = { alc662_init_verbs,
16536 alc662_eeepc_sue_init_verbs },
16537 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16538 .dac_nids = alc662_dac_nids,
Kailang Yang291702f2007-10-16 14:28:03 +020016539 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16540 .channel_mode = alc662_3ST_2ch_modes,
16541 .input_mux = &alc662_eeepc_capture_source,
16542 .unsol_event = alc662_eeepc_unsol_event,
16543 .init_hook = alc662_eeepc_inithook,
16544 },
Kailang Yang8c427222008-01-10 13:03:59 +010016545 [ALC662_ASUS_EEEPC_EP20] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016546 .mixers = { alc662_eeepc_ep20_mixer,
Kailang Yang8c427222008-01-10 13:03:59 +010016547 alc662_chmode_mixer },
16548 .init_verbs = { alc662_init_verbs,
16549 alc662_eeepc_ep20_sue_init_verbs },
16550 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16551 .dac_nids = alc662_dac_nids,
Kailang Yang8c427222008-01-10 13:03:59 +010016552 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
16553 .channel_mode = alc662_3ST_6ch_modes,
16554 .input_mux = &alc662_lenovo_101e_capture_source,
16555 .unsol_event = alc662_eeepc_ep20_unsol_event,
16556 .init_hook = alc662_eeepc_ep20_inithook,
16557 },
Kailang Yangf1d4e282008-08-26 14:03:29 +020016558 [ALC662_ECS] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016559 .mixers = { alc662_ecs_mixer },
Kailang Yangf1d4e282008-08-26 14:03:29 +020016560 .init_verbs = { alc662_init_verbs,
16561 alc662_ecs_init_verbs },
16562 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16563 .dac_nids = alc662_dac_nids,
16564 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16565 .channel_mode = alc662_3ST_2ch_modes,
16566 .input_mux = &alc662_eeepc_capture_source,
16567 .unsol_event = alc662_eeepc_unsol_event,
16568 .init_hook = alc662_eeepc_inithook,
16569 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020016570 [ALC663_ASUS_M51VA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016571 .mixers = { alc663_m51va_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020016572 .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
16573 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16574 .dac_nids = alc662_dac_nids,
16575 .dig_out_nid = ALC662_DIGOUT_NID,
16576 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16577 .channel_mode = alc662_3ST_2ch_modes,
16578 .input_mux = &alc663_m51va_capture_source,
16579 .unsol_event = alc663_m51va_unsol_event,
16580 .init_hook = alc663_m51va_inithook,
16581 },
16582 [ALC663_ASUS_G71V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016583 .mixers = { alc663_g71v_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020016584 .init_verbs = { alc662_init_verbs, alc663_g71v_init_verbs },
16585 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16586 .dac_nids = alc662_dac_nids,
16587 .dig_out_nid = ALC662_DIGOUT_NID,
16588 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16589 .channel_mode = alc662_3ST_2ch_modes,
16590 .input_mux = &alc662_eeepc_capture_source,
16591 .unsol_event = alc663_g71v_unsol_event,
16592 .init_hook = alc663_g71v_inithook,
16593 },
16594 [ALC663_ASUS_H13] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016595 .mixers = { alc663_m51va_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020016596 .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
16597 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16598 .dac_nids = alc662_dac_nids,
16599 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16600 .channel_mode = alc662_3ST_2ch_modes,
16601 .input_mux = &alc663_m51va_capture_source,
16602 .unsol_event = alc663_m51va_unsol_event,
16603 .init_hook = alc663_m51va_inithook,
16604 },
16605 [ALC663_ASUS_G50V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016606 .mixers = { alc663_g50v_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020016607 .init_verbs = { alc662_init_verbs, alc663_g50v_init_verbs },
16608 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16609 .dac_nids = alc662_dac_nids,
16610 .dig_out_nid = ALC662_DIGOUT_NID,
16611 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
16612 .channel_mode = alc662_3ST_6ch_modes,
16613 .input_mux = &alc663_capture_source,
16614 .unsol_event = alc663_g50v_unsol_event,
16615 .init_hook = alc663_g50v_inithook,
16616 },
Kailang Yangf1d4e282008-08-26 14:03:29 +020016617 [ALC663_ASUS_MODE1] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016618 .mixers = { alc663_m51va_mixer },
16619 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020016620 .init_verbs = { alc662_init_verbs,
16621 alc663_21jd_amic_init_verbs },
16622 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16623 .hp_nid = 0x03,
16624 .dac_nids = alc662_dac_nids,
16625 .dig_out_nid = ALC662_DIGOUT_NID,
16626 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16627 .channel_mode = alc662_3ST_2ch_modes,
16628 .input_mux = &alc662_eeepc_capture_source,
16629 .unsol_event = alc663_mode1_unsol_event,
16630 .init_hook = alc663_mode1_inithook,
16631 },
16632 [ALC662_ASUS_MODE2] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016633 .mixers = { alc662_1bjd_mixer },
16634 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020016635 .init_verbs = { alc662_init_verbs,
16636 alc662_1bjd_amic_init_verbs },
16637 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16638 .dac_nids = alc662_dac_nids,
16639 .dig_out_nid = ALC662_DIGOUT_NID,
16640 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16641 .channel_mode = alc662_3ST_2ch_modes,
16642 .input_mux = &alc662_eeepc_capture_source,
16643 .unsol_event = alc662_mode2_unsol_event,
16644 .init_hook = alc662_mode2_inithook,
16645 },
16646 [ALC663_ASUS_MODE3] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016647 .mixers = { alc663_two_hp_m1_mixer },
16648 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020016649 .init_verbs = { alc662_init_verbs,
16650 alc663_two_hp_amic_m1_init_verbs },
16651 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16652 .hp_nid = 0x03,
16653 .dac_nids = alc662_dac_nids,
16654 .dig_out_nid = ALC662_DIGOUT_NID,
16655 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16656 .channel_mode = alc662_3ST_2ch_modes,
16657 .input_mux = &alc662_eeepc_capture_source,
16658 .unsol_event = alc663_mode3_unsol_event,
16659 .init_hook = alc663_mode3_inithook,
16660 },
16661 [ALC663_ASUS_MODE4] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016662 .mixers = { alc663_asus_21jd_clfe_mixer },
16663 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020016664 .init_verbs = { alc662_init_verbs,
16665 alc663_21jd_amic_init_verbs},
16666 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16667 .hp_nid = 0x03,
16668 .dac_nids = alc662_dac_nids,
16669 .dig_out_nid = ALC662_DIGOUT_NID,
16670 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16671 .channel_mode = alc662_3ST_2ch_modes,
16672 .input_mux = &alc662_eeepc_capture_source,
16673 .unsol_event = alc663_mode4_unsol_event,
16674 .init_hook = alc663_mode4_inithook,
16675 },
16676 [ALC663_ASUS_MODE5] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016677 .mixers = { alc663_asus_15jd_clfe_mixer },
16678 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020016679 .init_verbs = { alc662_init_verbs,
16680 alc663_15jd_amic_init_verbs },
16681 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16682 .hp_nid = 0x03,
16683 .dac_nids = alc662_dac_nids,
16684 .dig_out_nid = ALC662_DIGOUT_NID,
16685 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16686 .channel_mode = alc662_3ST_2ch_modes,
16687 .input_mux = &alc662_eeepc_capture_source,
16688 .unsol_event = alc663_mode5_unsol_event,
16689 .init_hook = alc663_mode5_inithook,
16690 },
16691 [ALC663_ASUS_MODE6] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016692 .mixers = { alc663_two_hp_m2_mixer },
16693 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020016694 .init_verbs = { alc662_init_verbs,
16695 alc663_two_hp_amic_m2_init_verbs },
16696 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16697 .hp_nid = 0x03,
16698 .dac_nids = alc662_dac_nids,
16699 .dig_out_nid = ALC662_DIGOUT_NID,
16700 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16701 .channel_mode = alc662_3ST_2ch_modes,
16702 .input_mux = &alc662_eeepc_capture_source,
16703 .unsol_event = alc663_mode6_unsol_event,
16704 .init_hook = alc663_mode6_inithook,
16705 },
Kailang Yang622e84c2009-04-21 07:39:04 +020016706 [ALC272_DELL] = {
16707 .mixers = { alc663_m51va_mixer },
16708 .cap_mixer = alc272_auto_capture_mixer,
16709 .init_verbs = { alc662_init_verbs, alc272_dell_init_verbs },
16710 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
16711 .dac_nids = alc662_dac_nids,
16712 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16713 .adc_nids = alc272_adc_nids,
16714 .num_adc_nids = ARRAY_SIZE(alc272_adc_nids),
16715 .capsrc_nids = alc272_capsrc_nids,
16716 .channel_mode = alc662_3ST_2ch_modes,
16717 .input_mux = &alc663_m51va_capture_source,
16718 .unsol_event = alc663_m51va_unsol_event,
16719 .init_hook = alc663_m51va_inithook,
16720 },
16721 [ALC272_DELL_ZM1] = {
16722 .mixers = { alc663_m51va_mixer },
16723 .cap_mixer = alc662_auto_capture_mixer,
16724 .init_verbs = { alc662_init_verbs, alc272_dell_zm1_init_verbs },
16725 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
16726 .dac_nids = alc662_dac_nids,
16727 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16728 .adc_nids = alc662_adc_nids,
16729 .num_adc_nids = ARRAY_SIZE(alc662_adc_nids),
16730 .capsrc_nids = alc662_capsrc_nids,
16731 .channel_mode = alc662_3ST_2ch_modes,
16732 .input_mux = &alc663_m51va_capture_source,
16733 .unsol_event = alc663_m51va_unsol_event,
16734 .init_hook = alc663_m51va_inithook,
16735 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016736};
16737
16738
16739/*
16740 * BIOS auto configuration
16741 */
16742
16743/* add playback controls from the parsed DAC table */
16744static int alc662_auto_create_multi_out_ctls(struct alc_spec *spec,
16745 const struct auto_pin_cfg *cfg)
16746{
16747 char name[32];
16748 static const char *chname[4] = {
16749 "Front", "Surround", NULL /*CLFE*/, "Side"
16750 };
16751 hda_nid_t nid;
16752 int i, err;
16753
16754 for (i = 0; i < cfg->line_outs; i++) {
16755 if (!spec->multiout.dac_nids[i])
16756 continue;
Kailang Yangb60dd392007-09-20 12:50:29 +020016757 nid = alc880_idx_to_dac(i);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016758 if (i == 2) {
16759 /* Center/LFE */
16760 err = add_control(spec, ALC_CTL_WIDGET_VOL,
16761 "Center Playback Volume",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016762 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
16763 HDA_OUTPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016764 if (err < 0)
16765 return err;
16766 err = add_control(spec, ALC_CTL_WIDGET_VOL,
16767 "LFE Playback Volume",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016768 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
16769 HDA_OUTPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016770 if (err < 0)
16771 return err;
Herton Ronaldo Krzesinskib69ce012008-09-18 16:41:49 -030016772 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016773 "Center Playback Switch",
Herton Ronaldo Krzesinskib69ce012008-09-18 16:41:49 -030016774 HDA_COMPOSE_AMP_VAL(0x0e, 1, 0,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016775 HDA_INPUT));
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 "LFE Playback Switch",
Herton Ronaldo Krzesinskib69ce012008-09-18 16:41:49 -030016780 HDA_COMPOSE_AMP_VAL(0x0e, 2, 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;
16784 } else {
16785 sprintf(name, "%s Playback Volume", chname[i]);
16786 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016787 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
16788 HDA_OUTPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016789 if (err < 0)
16790 return err;
16791 sprintf(name, "%s Playback Switch", chname[i]);
Herton Ronaldo Krzesinskib69ce012008-09-18 16:41:49 -030016792 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
16793 HDA_COMPOSE_AMP_VAL(alc880_idx_to_mixer(i),
16794 3, 0, HDA_INPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016795 if (err < 0)
16796 return err;
16797 }
16798 }
16799 return 0;
16800}
16801
16802/* add playback controls for speaker and HP outputs */
16803static int alc662_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
16804 const char *pfx)
16805{
16806 hda_nid_t nid;
16807 int err;
16808 char name[32];
16809
16810 if (!pin)
16811 return 0;
16812
Takashi Iwai24fb9172008-09-02 14:48:20 +020016813 if (pin == 0x17) {
16814 /* ALC663 has a mono output pin on 0x17 */
16815 sprintf(name, "%s Playback Switch", pfx);
16816 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
16817 HDA_COMPOSE_AMP_VAL(pin, 2, 0, HDA_OUTPUT));
16818 return err;
16819 }
16820
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016821 if (alc880_is_fixed_pin(pin)) {
16822 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
Takashi Iwai939778a2009-02-05 15:57:55 +010016823 /* printk(KERN_DEBUG "DAC nid=%x\n",nid); */
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016824 /* specify the DAC as the extra output */
16825 if (!spec->multiout.hp_nid)
16826 spec->multiout.hp_nid = nid;
16827 else
16828 spec->multiout.extra_out_nid[0] = nid;
16829 /* control HP volume/switch on the output mixer amp */
16830 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
16831 sprintf(name, "%s Playback Volume", pfx);
16832 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
16833 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
16834 if (err < 0)
16835 return err;
16836 sprintf(name, "%s Playback Switch", pfx);
16837 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
16838 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
16839 if (err < 0)
16840 return err;
16841 } else if (alc880_is_multi_pin(pin)) {
16842 /* set manual connection */
16843 /* we have only a switch on HP-out PIN */
16844 sprintf(name, "%s Playback Switch", pfx);
16845 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
16846 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
16847 if (err < 0)
16848 return err;
16849 }
16850 return 0;
16851}
16852
Takashi Iwai2d864c42009-03-20 12:52:47 +010016853/* return the index of the src widget from the connection list of the nid.
16854 * return -1 if not found
16855 */
16856static int alc662_input_pin_idx(struct hda_codec *codec, hda_nid_t nid,
16857 hda_nid_t src)
16858{
16859 hda_nid_t conn_list[HDA_MAX_CONNECTIONS];
16860 int i, conns;
16861
16862 conns = snd_hda_get_connections(codec, nid, conn_list,
16863 ARRAY_SIZE(conn_list));
16864 if (conns < 0)
16865 return -1;
16866 for (i = 0; i < conns; i++)
16867 if (conn_list[i] == src)
16868 return i;
16869 return -1;
16870}
16871
16872static int alc662_is_input_pin(struct hda_codec *codec, hda_nid_t nid)
16873{
Takashi Iwai1327a322009-03-23 13:07:47 +010016874 unsigned int pincap = snd_hda_query_pin_caps(codec, nid);
Takashi Iwai2d864c42009-03-20 12:52:47 +010016875 return (pincap & AC_PINCAP_IN) != 0;
16876}
16877
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016878/* create playback/capture controls for input pins */
Takashi Iwai2d864c42009-03-20 12:52:47 +010016879static int alc662_auto_create_analog_input_ctls(struct hda_codec *codec,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016880 const struct auto_pin_cfg *cfg)
16881{
Takashi Iwai2d864c42009-03-20 12:52:47 +010016882 struct alc_spec *spec = codec->spec;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020016883 struct hda_input_mux *imux = &spec->private_imux[0];
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016884 int i, err, idx;
16885
16886 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwai2d864c42009-03-20 12:52:47 +010016887 if (alc662_is_input_pin(codec, cfg->input_pins[i])) {
16888 idx = alc662_input_pin_idx(codec, 0x0b,
16889 cfg->input_pins[i]);
16890 if (idx >= 0) {
16891 err = new_analog_input(spec, cfg->input_pins[i],
16892 auto_pin_cfg_labels[i],
16893 idx, 0x0b);
16894 if (err < 0)
16895 return err;
16896 }
16897 idx = alc662_input_pin_idx(codec, 0x22,
16898 cfg->input_pins[i]);
16899 if (idx >= 0) {
16900 imux->items[imux->num_items].label =
16901 auto_pin_cfg_labels[i];
16902 imux->items[imux->num_items].index = idx;
16903 imux->num_items++;
16904 }
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016905 }
16906 }
16907 return 0;
16908}
16909
16910static void alc662_auto_set_output_and_unmute(struct hda_codec *codec,
16911 hda_nid_t nid, int pin_type,
16912 int dac_idx)
16913{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016914 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016915 /* need the manual connection? */
16916 if (alc880_is_multi_pin(nid)) {
16917 struct alc_spec *spec = codec->spec;
16918 int idx = alc880_multi_pin_idx(nid);
16919 snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
16920 AC_VERB_SET_CONNECT_SEL,
16921 alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
16922 }
16923}
16924
16925static void alc662_auto_init_multi_out(struct hda_codec *codec)
16926{
16927 struct alc_spec *spec = codec->spec;
16928 int i;
16929
Kailang Yang8c427222008-01-10 13:03:59 +010016930 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016931 for (i = 0; i <= HDA_SIDE; i++) {
16932 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020016933 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016934 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020016935 alc662_auto_set_output_and_unmute(codec, nid, pin_type,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016936 i);
16937 }
16938}
16939
16940static void alc662_auto_init_hp_out(struct hda_codec *codec)
16941{
16942 struct alc_spec *spec = codec->spec;
16943 hda_nid_t pin;
16944
16945 pin = spec->autocfg.hp_pins[0];
16946 if (pin) /* connect to front */
16947 /* use dac 0 */
16948 alc662_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016949 pin = spec->autocfg.speaker_pins[0];
16950 if (pin)
16951 alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016952}
16953
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016954#define ALC662_PIN_CD_NID ALC880_PIN_CD_NID
16955
16956static void alc662_auto_init_analog_input(struct hda_codec *codec)
16957{
16958 struct alc_spec *spec = codec->spec;
16959 int i;
16960
16961 for (i = 0; i < AUTO_PIN_LAST; i++) {
16962 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwai2d864c42009-03-20 12:52:47 +010016963 if (alc662_is_input_pin(codec, nid)) {
Takashi Iwai23f0c042009-02-26 13:03:58 +010016964 alc_set_input_pin(codec, nid, i);
Takashi Iwai52ca15b2009-03-23 12:51:55 +010016965 if (nid != ALC662_PIN_CD_NID &&
Takashi Iwaie82c0252009-03-23 15:17:38 +010016966 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016967 snd_hda_codec_write(codec, nid, 0,
16968 AC_VERB_SET_AMP_GAIN_MUTE,
16969 AMP_OUT_MUTE);
16970 }
16971 }
16972}
16973
Takashi Iwaif511b012008-08-15 16:46:42 +020016974#define alc662_auto_init_input_src alc882_auto_init_input_src
16975
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016976static int alc662_parse_auto_config(struct hda_codec *codec)
16977{
16978 struct alc_spec *spec = codec->spec;
16979 int err;
16980 static hda_nid_t alc662_ignore[] = { 0x1d, 0 };
16981
16982 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
16983 alc662_ignore);
16984 if (err < 0)
16985 return err;
16986 if (!spec->autocfg.line_outs)
16987 return 0; /* can't find valid BIOS pin config */
16988
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016989 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
16990 if (err < 0)
16991 return err;
16992 err = alc662_auto_create_multi_out_ctls(spec, &spec->autocfg);
16993 if (err < 0)
16994 return err;
16995 err = alc662_auto_create_extra_out(spec,
16996 spec->autocfg.speaker_pins[0],
16997 "Speaker");
16998 if (err < 0)
16999 return err;
17000 err = alc662_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
17001 "Headphone");
17002 if (err < 0)
17003 return err;
Takashi Iwai2d864c42009-03-20 12:52:47 +010017004 err = alc662_auto_create_analog_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017005 if (err < 0)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017006 return err;
17007
17008 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
17009
Takashi Iwai0852d7a2009-02-11 11:35:15 +010017010 if (spec->autocfg.dig_outs)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017011 spec->multiout.dig_out_nid = ALC880_DIGOUT_NID;
17012
Takashi Iwai603c4012008-07-30 15:01:44 +020017013 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010017014 add_mixer(spec, spec->kctls.list);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017015
17016 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020017017 spec->input_mux = &spec->private_imux[0];
Kailang Yangea1fb292008-08-26 12:58:38 +020017018
Takashi Iwaid88897e2008-10-31 15:01:37 +010017019 add_verb(spec, alc662_auto_init_verbs);
Takashi Iwai24fb9172008-09-02 14:48:20 +020017020 if (codec->vendor_id == 0x10ec0663)
Takashi Iwaid88897e2008-10-31 15:01:37 +010017021 add_verb(spec, alc663_auto_init_verbs);
Takashi Iwaiee979a142008-09-02 15:42:20 +020017022
17023 err = alc_auto_add_mic_boost(codec);
17024 if (err < 0)
17025 return err;
17026
Takashi Iwai8c872862007-06-19 12:11:16 +020017027 return 1;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017028}
17029
17030/* additional initialization for auto-configuration model */
17031static void alc662_auto_init(struct hda_codec *codec)
17032{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010017033 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017034 alc662_auto_init_multi_out(codec);
17035 alc662_auto_init_hp_out(codec);
17036 alc662_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020017037 alc662_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010017038 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020017039 alc_inithook(codec);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017040}
17041
17042static int patch_alc662(struct hda_codec *codec)
17043{
17044 struct alc_spec *spec;
17045 int err, board_config;
17046
17047 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
17048 if (!spec)
17049 return -ENOMEM;
17050
17051 codec->spec = spec;
17052
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020017053 alc_fix_pll_init(codec, 0x20, 0x04, 15);
17054
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017055 board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST,
17056 alc662_models,
17057 alc662_cfg_tbl);
17058 if (board_config < 0) {
17059 printk(KERN_INFO "hda_codec: Unknown model for ALC662, "
17060 "trying auto-probe from BIOS...\n");
17061 board_config = ALC662_AUTO;
17062 }
17063
17064 if (board_config == ALC662_AUTO) {
17065 /* automatic parse from the BIOS config */
17066 err = alc662_parse_auto_config(codec);
17067 if (err < 0) {
17068 alc_free(codec);
17069 return err;
Takashi Iwai8c872862007-06-19 12:11:16 +020017070 } else if (!err) {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017071 printk(KERN_INFO
17072 "hda_codec: Cannot set up configuration "
17073 "from BIOS. Using base mode...\n");
17074 board_config = ALC662_3ST_2ch_DIG;
17075 }
17076 }
17077
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090017078 err = snd_hda_attach_beep_device(codec, 0x1);
17079 if (err < 0) {
17080 alc_free(codec);
17081 return err;
17082 }
17083
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017084 if (board_config != ALC662_AUTO)
17085 setup_preset(spec, &alc662_presets[board_config]);
17086
Kailang Yang6dda9f42008-05-27 12:05:31 +020017087 if (codec->vendor_id == 0x10ec0663) {
17088 spec->stream_name_analog = "ALC663 Analog";
17089 spec->stream_name_digital = "ALC663 Digital";
Kailang Yang01afd412008-10-15 11:22:09 +020017090 } else if (codec->vendor_id == 0x10ec0272) {
17091 spec->stream_name_analog = "ALC272 Analog";
17092 spec->stream_name_digital = "ALC272 Digital";
Kailang Yang6dda9f42008-05-27 12:05:31 +020017093 } else {
17094 spec->stream_name_analog = "ALC662 Analog";
17095 spec->stream_name_digital = "ALC662 Digital";
17096 }
17097
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017098 spec->stream_analog_playback = &alc662_pcm_analog_playback;
17099 spec->stream_analog_capture = &alc662_pcm_analog_capture;
17100
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017101 spec->stream_digital_playback = &alc662_pcm_digital_playback;
17102 spec->stream_digital_capture = &alc662_pcm_digital_capture;
17103
Takashi Iwaie1406342008-02-11 18:32:32 +010017104 spec->adc_nids = alc662_adc_nids;
17105 spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids);
17106 spec->capsrc_nids = alc662_capsrc_nids;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020017107 spec->capture_style = CAPT_MIX;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017108
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017109 if (!spec->cap_mixer)
17110 set_capture_mixer(spec);
Takashi Iwaib9591442009-03-16 15:25:00 +010017111 if (codec->vendor_id == 0x10ec0662)
17112 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
17113 else
17114 set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017115
Takashi Iwai2134ea42008-01-10 16:53:55 +010017116 spec->vmaster_nid = 0x02;
17117
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017118 codec->patch_ops = alc_patch_ops;
17119 if (board_config == ALC662_AUTO)
17120 spec->init_hook = alc662_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020017121#ifdef CONFIG_SND_HDA_POWER_SAVE
17122 if (!spec->loopback.amplist)
17123 spec->loopback.amplist = alc662_loopbacks;
17124#endif
Takashi Iwaidaead532008-11-28 12:55:36 +010017125 codec->proc_widget_hook = print_realtek_coef;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017126
17127 return 0;
17128}
17129
17130/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070017131 * patch entries
17132 */
Takashi Iwai1289e9e2008-11-27 15:47:11 +010017133static struct hda_codec_preset snd_hda_preset_realtek[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070017134 { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
Kailang Yangdf694da2005-12-05 19:42:22 +010017135 { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
Kailang Yangf6a92242007-12-13 16:52:54 +010017136 { .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 },
Kailang Yanga361d842007-06-05 12:30:55 +020017137 { .id = 0x10ec0268, .name = "ALC268", .patch = patch_alc268 },
Kailang Yangf6a92242007-12-13 16:52:54 +010017138 { .id = 0x10ec0269, .name = "ALC269", .patch = patch_alc269 },
Kailang Yang01afd412008-10-15 11:22:09 +020017139 { .id = 0x10ec0272, .name = "ALC272", .patch = patch_alc662 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017140 { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017141 .patch = patch_alc861 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017142 { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
17143 { .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 },
17144 { .id = 0x10ec0862, .name = "ALC861-VD", .patch = patch_alc861vd },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017145 { .id = 0x10ec0662, .rev = 0x100002, .name = "ALC662 rev2",
17146 .patch = patch_alc883 },
17147 { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1",
17148 .patch = patch_alc662 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020017149 { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017150 { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070017151 { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020017152 { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc883 },
Clive Messer669faba2008-09-30 15:49:13 +020017153 { .id = 0x10ec0885, .rev = 0x100101, .name = "ALC889A",
17154 .patch = patch_alc882 }, /* should be patch_alc883() in future */
Takashi Iwaicb308f92008-04-16 14:13:29 +020017155 { .id = 0x10ec0885, .rev = 0x100103, .name = "ALC889A",
Takashi Iwai7943a8a2008-04-16 17:29:09 +020017156 .patch = patch_alc882 }, /* should be patch_alc883() in future */
Kailang Yangdf694da2005-12-05 19:42:22 +010017157 { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
Kailang Yanga385a522008-10-15 11:20:21 +020017158 { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc883 },
Kailang Yang44426082008-10-15 11:18:05 +020017159 { .id = 0x10ec0888, .rev = 0x100101, .name = "ALC1200",
17160 .patch = patch_alc883 },
Wu Fengguang3fea2cb2008-12-26 12:20:43 +080017161 { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc883 },
Kailang Yangf6a92242007-12-13 16:52:54 +010017162 { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc883 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070017163 {} /* terminator */
17164};
Takashi Iwai1289e9e2008-11-27 15:47:11 +010017165
17166MODULE_ALIAS("snd-hda-codec-id:10ec*");
17167
17168MODULE_LICENSE("GPL");
17169MODULE_DESCRIPTION("Realtek HD-audio codec");
17170
17171static struct hda_codec_preset_list realtek_list = {
17172 .preset = snd_hda_preset_realtek,
17173 .owner = THIS_MODULE,
17174};
17175
17176static int __init patch_realtek_init(void)
17177{
17178 return snd_hda_add_codec_preset(&realtek_list);
17179}
17180
17181static void __exit patch_realtek_exit(void)
17182{
17183 snd_hda_delete_codec_preset(&realtek_list);
17184}
17185
17186module_init(patch_realtek_init)
17187module_exit(patch_realtek_exit)