blob: 04e153a77dbcc886caa1a580b4b4afc241c22a79 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Universal Interface for Intel High Definition Audio Codec
3 *
4 * HD audio interface patch for ALC 260/880/882 codecs
5 *
Kailang Yangdf694da2005-12-05 19:42:22 +01006 * Copyright (c) 2004 Kailang Yang <kailang@realtek.com.tw>
7 * PeiSen Hou <pshou@realtek.com.tw>
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 * Takashi Iwai <tiwai@suse.de>
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01009 * Jonathan Woithe <jwoithe@physics.adelaide.edu.au>
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 *
11 * This driver is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This driver is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <linux/init.h>
27#include <linux/delay.h>
28#include <linux/slab.h>
29#include <linux/pci.h>
30#include <sound/core.h>
31#include "hda_codec.h"
32#include "hda_local.h"
Harvey Harrison3c9a3202008-02-29 11:59:26 +010033#include "hda_patch.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070034
Kailang Yangccc656c2006-10-17 12:32:26 +020035#define ALC880_FRONT_EVENT 0x01
36#define ALC880_DCVOL_EVENT 0x02
37#define ALC880_HP_EVENT 0x04
38#define ALC880_MIC_EVENT 0x08
Linus Torvalds1da177e2005-04-16 15:20:36 -070039
40/* ALC880 board config type */
41enum {
Linus Torvalds1da177e2005-04-16 15:20:36 -070042 ALC880_3ST,
43 ALC880_3ST_DIG,
44 ALC880_5ST,
45 ALC880_5ST_DIG,
46 ALC880_W810,
Takashi Iwaidfc0ff62005-05-12 14:31:49 +020047 ALC880_Z71V,
Takashi Iwaib6482d42005-06-27 15:32:43 +020048 ALC880_6ST,
Takashi Iwai16ded522005-06-10 19:58:24 +020049 ALC880_6ST_DIG,
50 ALC880_F1734,
51 ALC880_ASUS,
52 ALC880_ASUS_DIG,
53 ALC880_ASUS_W1V,
Kailang Yangdf694da2005-12-05 19:42:22 +010054 ALC880_ASUS_DIG2,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +010055 ALC880_FUJITSU,
Takashi Iwai16ded522005-06-10 19:58:24 +020056 ALC880_UNIWILL_DIG,
Kailang Yangccc656c2006-10-17 12:32:26 +020057 ALC880_UNIWILL,
58 ALC880_UNIWILL_P53,
Kailang Yangdf694da2005-12-05 19:42:22 +010059 ALC880_CLEVO,
60 ALC880_TCL_S700,
Takashi Iwaiae6b8132006-03-03 16:47:17 +010061 ALC880_LG,
Takashi Iwaid6815182006-03-23 16:06:23 +010062 ALC880_LG_LW,
Takashi Iwaidf99cd32008-04-25 15:25:04 +020063 ALC880_MEDION_RIM,
Takashi Iwaie9edcee2005-06-13 14:16:38 +020064#ifdef CONFIG_SND_DEBUG
65 ALC880_TEST,
66#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010067 ALC880_AUTO,
Takashi Iwai16ded522005-06-10 19:58:24 +020068 ALC880_MODEL_LAST /* last tag */
69};
70
71/* ALC260 models */
72enum {
73 ALC260_BASIC,
74 ALC260_HP,
Kailang Yang3f878302008-08-26 13:02:23 +020075 ALC260_HP_DC7600,
Kailang Yangdf694da2005-12-05 19:42:22 +010076 ALC260_HP_3013,
77 ALC260_FUJITSU_S702X,
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +010078 ALC260_ACER,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020079 ALC260_WILL,
80 ALC260_REPLACER_672V,
Jonathan Woithe7cf51e482006-02-09 12:01:26 +010081#ifdef CONFIG_SND_DEBUG
82 ALC260_TEST,
83#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010084 ALC260_AUTO,
Takashi Iwai16ded522005-06-10 19:58:24 +020085 ALC260_MODEL_LAST /* last tag */
Linus Torvalds1da177e2005-04-16 15:20:36 -070086};
87
Kailang Yangdf694da2005-12-05 19:42:22 +010088/* ALC262 models */
89enum {
90 ALC262_BASIC,
Kailang Yangccc656c2006-10-17 12:32:26 +020091 ALC262_HIPPO,
92 ALC262_HIPPO_1,
Takashi Iwai834be882006-03-01 14:16:17 +010093 ALC262_FUJITSU,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020094 ALC262_HP_BPC,
Kailang Yangcd7509a2007-01-26 18:33:17 +010095 ALC262_HP_BPC_D7000_WL,
96 ALC262_HP_BPC_D7000_WF,
Kailang Yang66d2a9d2007-11-14 12:06:21 +010097 ALC262_HP_TC_T5735,
Kailang Yang8c427222008-01-10 13:03:59 +010098 ALC262_HP_RP5700,
Takashi Iwai304dcaa2006-07-25 14:51:16 +020099 ALC262_BENQ_ED8,
Kailang Yang272a5272007-05-14 11:00:38 +0200100 ALC262_SONY_ASSAMD,
Kailang Yang83c34212007-07-05 11:43:05 +0200101 ALC262_BENQ_T31,
Tobin Davisf651b502007-10-26 12:40:47 +0200102 ALC262_ULTRA,
Jiang zhe0e31daf2008-03-20 12:12:39 +0100103 ALC262_LENOVO_3000,
Pascal Terjane8f9ae22008-08-04 14:36:05 +0200104 ALC262_NEC,
Kailang Yang4e555fe2008-08-26 13:05:55 +0200105 ALC262_TOSHIBA_S06,
Hiroshi Miura9f99a632008-08-28 16:09:06 +0200106 ALC262_TOSHIBA_RX1,
Kailang Yangdf694da2005-12-05 19:42:22 +0100107 ALC262_AUTO,
108 ALC262_MODEL_LAST /* last tag */
109};
110
Kailang Yanga361d842007-06-05 12:30:55 +0200111/* ALC268 models */
112enum {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +0200113 ALC267_QUANTA_IL1,
Kailang Yanga361d842007-06-05 12:30:55 +0200114 ALC268_3ST,
Kailang Yangd1a991a2007-08-15 16:21:59 +0200115 ALC268_TOSHIBA,
Takashi Iwaid2738092007-08-16 14:59:45 +0200116 ALC268_ACER,
Takashi Iwaic238b4f2008-11-05 14:57:20 +0100117 ALC268_ACER_DMIC,
Kailang Yang8ef355d2008-08-26 13:10:22 +0200118 ALC268_ACER_ASPIRE_ONE,
Takashi Iwai3866f0b2008-01-15 12:37:42 +0100119 ALC268_DELL,
Mirco Tischlerf12462c2008-02-04 12:33:59 +0100120 ALC268_ZEPTO,
Jonathan Woithe86c53bd2008-01-08 12:33:19 +0100121#ifdef CONFIG_SND_DEBUG
122 ALC268_TEST,
123#endif
Kailang Yanga361d842007-06-05 12:30:55 +0200124 ALC268_AUTO,
125 ALC268_MODEL_LAST /* last tag */
126};
127
Kailang Yangf6a92242007-12-13 16:52:54 +0100128/* ALC269 models */
129enum {
130 ALC269_BASIC,
Kailang Yang60db6b52008-08-26 13:13:00 +0200131 ALC269_QUANTA_FL1,
Kailang Yangf53281e2008-07-18 12:36:43 +0200132 ALC269_ASUS_EEEPC_P703,
133 ALC269_ASUS_EEEPC_P901,
Takashi Iwai26f5df22008-11-03 17:39:46 +0100134 ALC269_FUJITSU,
Tony Vroon64154832008-11-06 15:08:49 +0000135 ALC269_LIFEBOOK,
Kailang Yangf6a92242007-12-13 16:52:54 +0100136 ALC269_AUTO,
137 ALC269_MODEL_LAST /* last tag */
138};
139
Kailang Yangdf694da2005-12-05 19:42:22 +0100140/* ALC861 models */
141enum {
142 ALC861_3ST,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200143 ALC660_3ST,
Kailang Yangdf694da2005-12-05 19:42:22 +0100144 ALC861_3ST_DIG,
145 ALC861_6ST_DIG,
Takashi Iwai22309c32006-08-09 16:57:28 +0200146 ALC861_UNIWILL_M31,
Tobin Davisa53d1ae2006-10-17 12:00:28 +0200147 ALC861_TOSHIBA,
Mariusz Domanski7cdbff92006-10-23 13:42:56 +0200148 ALC861_ASUS,
Takashi Iwai56bb0ca2006-11-22 11:52:52 +0100149 ALC861_ASUS_LAPTOP,
Kailang Yangdf694da2005-12-05 19:42:22 +0100150 ALC861_AUTO,
151 ALC861_MODEL_LAST,
152};
153
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100154/* ALC861-VD models */
155enum {
156 ALC660VD_3ST,
Mike Crash6963f842007-06-25 12:12:51 +0200157 ALC660VD_3ST_DIG,
Takashi Iwai13c94742008-11-05 08:06:08 +0100158 ALC660VD_ASUS_V1S,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100159 ALC861VD_3ST,
160 ALC861VD_3ST_DIG,
161 ALC861VD_6ST_DIG,
Kailang Yangbdd148a2007-05-08 15:19:08 +0200162 ALC861VD_LENOVO,
Kailang Yang272a5272007-05-14 11:00:38 +0200163 ALC861VD_DALLAS,
Kailang Yangd1a991a2007-08-15 16:21:59 +0200164 ALC861VD_HP,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100165 ALC861VD_AUTO,
166 ALC861VD_MODEL_LAST,
167};
168
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200169/* ALC662 models */
170enum {
171 ALC662_3ST_2ch_DIG,
172 ALC662_3ST_6ch_DIG,
173 ALC662_3ST_6ch,
174 ALC662_5ST_DIG,
175 ALC662_LENOVO_101E,
Kailang Yang291702f2007-10-16 14:28:03 +0200176 ALC662_ASUS_EEEPC_P701,
Kailang Yang8c427222008-01-10 13:03:59 +0100177 ALC662_ASUS_EEEPC_EP20,
Kailang Yang6dda9f42008-05-27 12:05:31 +0200178 ALC663_ASUS_M51VA,
179 ALC663_ASUS_G71V,
180 ALC663_ASUS_H13,
181 ALC663_ASUS_G50V,
Kailang Yangf1d4e282008-08-26 14:03:29 +0200182 ALC662_ECS,
183 ALC663_ASUS_MODE1,
184 ALC662_ASUS_MODE2,
185 ALC663_ASUS_MODE3,
186 ALC663_ASUS_MODE4,
187 ALC663_ASUS_MODE5,
188 ALC663_ASUS_MODE6,
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200189 ALC662_AUTO,
190 ALC662_MODEL_LAST,
191};
192
Kailang Yangdf694da2005-12-05 19:42:22 +0100193/* ALC882 models */
194enum {
195 ALC882_3ST_DIG,
196 ALC882_6ST_DIG,
Takashi Iwai4b146cb2006-07-28 14:42:36 +0200197 ALC882_ARIMA,
Kailang Yangbdd148a2007-05-08 15:19:08 +0200198 ALC882_W2JC,
Kailang Yang272a5272007-05-14 11:00:38 +0200199 ALC882_TARGA,
200 ALC882_ASUS_A7J,
Takashi Iwai914759b2007-09-06 14:52:04 +0200201 ALC882_ASUS_A7M,
Tobin Davis9102cd12006-12-15 10:02:12 +0100202 ALC885_MACPRO,
Takashi Iwai87350ad2007-08-16 18:19:38 +0200203 ALC885_MBP3,
Nicola Fagnanic54728d2007-07-19 23:28:52 +0200204 ALC885_IMAC24,
Kailang Yang272a5272007-05-14 11:00:38 +0200205 ALC882_AUTO,
Kailang Yangdf694da2005-12-05 19:42:22 +0100206 ALC882_MODEL_LAST,
207};
208
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200209/* ALC883 models */
210enum {
211 ALC883_3ST_2ch_DIG,
212 ALC883_3ST_6ch_DIG,
213 ALC883_3ST_6ch,
214 ALC883_6ST_DIG,
Kailang Yangccc656c2006-10-17 12:32:26 +0200215 ALC883_TARGA_DIG,
216 ALC883_TARGA_2ch_DIG,
Vladimir Avdoninbab282b92006-08-22 13:31:58 +0200217 ALC883_ACER,
Tobin Davis2880a862007-08-07 11:50:26 +0200218 ALC883_ACER_ASPIRE,
Tobin Davisc07584c2006-10-13 12:32:16 +0200219 ALC883_MEDION,
Kailang Yangea1fb292008-08-26 12:58:38 +0200220 ALC883_MEDION_MD2,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +0100221 ALC883_LAPTOP_EAPD,
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200222 ALC883_LENOVO_101E_2ch,
Kailang Yang272a5272007-05-14 11:00:38 +0200223 ALC883_LENOVO_NB0763,
Kailang Yang189609a2007-08-20 11:31:23 +0200224 ALC888_LENOVO_MS7195_DIG,
Kailang Yange2757d52008-08-26 13:17:46 +0200225 ALC888_LENOVO_SKY,
Kailang Yangea1fb292008-08-26 12:58:38 +0200226 ALC883_HAIER_W66,
Claudio Matsuoka4723c022007-07-13 14:36:19 +0200227 ALC888_3ST_HP,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +0100228 ALC888_6ST_DELL,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +0100229 ALC883_MITAC,
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +0100230 ALC883_CLEVO_M720,
Jiang zhefb97dc62008-03-06 11:07:11 +0100231 ALC883_FUJITSU_PI2515,
Jiang zhe17bba1b2008-06-04 12:11:07 +0200232 ALC883_3ST_6ch_INTEL,
Kailang Yange2757d52008-08-26 13:17:46 +0200233 ALC888_ASUS_M90V,
234 ALC888_ASUS_EEE1601,
Wu Fengguang3ab90932008-11-17 09:51:09 +0100235 ALC1200_ASUS_P5Q,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200236 ALC883_AUTO,
237 ALC883_MODEL_LAST,
238};
239
Kailang Yangdf694da2005-12-05 19:42:22 +0100240/* for GPIO Poll */
241#define GPIO_MASK 0x03
242
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243struct alc_spec {
244 /* codec parameterization */
Kailang Yangdf694da2005-12-05 19:42:22 +0100245 struct snd_kcontrol_new *mixers[5]; /* mixer arrays */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 unsigned int num_mixers;
Takashi Iwaif9e336f2008-10-31 16:37:07 +0100247 struct snd_kcontrol_new *cap_mixer; /* capture mixer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248
Kailang Yangdf694da2005-12-05 19:42:22 +0100249 const struct hda_verb *init_verbs[5]; /* initialization verbs
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200250 * don't forget NULL
251 * termination!
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200252 */
253 unsigned int num_init_verbs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254
Takashi Iwai16ded522005-06-10 19:58:24 +0200255 char *stream_name_analog; /* analog PCM stream */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 struct hda_pcm_stream *stream_analog_playback;
257 struct hda_pcm_stream *stream_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +0100258 struct hda_pcm_stream *stream_analog_alt_playback;
259 struct hda_pcm_stream *stream_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200261 char *stream_name_digital; /* digital PCM stream */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 struct hda_pcm_stream *stream_digital_playback;
263 struct hda_pcm_stream *stream_digital_capture;
264
265 /* playback */
Takashi Iwai16ded522005-06-10 19:58:24 +0200266 struct hda_multi_out multiout; /* playback set-up
267 * max_channels, dacs must be set
268 * dig_out_nid and hp_nid are optional
269 */
Takashi Iwai63300792008-01-24 15:31:36 +0100270 hda_nid_t alt_dac_nid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271
272 /* capture */
273 unsigned int num_adc_nids;
274 hda_nid_t *adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100275 hda_nid_t *capsrc_nids;
Takashi Iwai16ded522005-06-10 19:58:24 +0200276 hda_nid_t dig_in_nid; /* digital-in NID; optional */
Takashi Iwai54cbc9a2008-10-31 15:24:04 +0100277 unsigned char is_mix_capture; /* matrix-style capture (non-mux) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278
279 /* capture source */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200280 unsigned int num_mux_defs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 const struct hda_input_mux *input_mux;
282 unsigned int cur_mux[3];
283
284 /* channel model */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100285 const struct hda_channel_mode *channel_mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286 int num_channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200287 int need_dac_fix;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288
289 /* PCM information */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100290 struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */
Takashi Iwai41e41f12005-06-08 14:48:49 +0200291
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200292 /* dynamic controls, init_verbs and input_mux */
293 struct auto_pin_cfg autocfg;
Takashi Iwai603c4012008-07-30 15:01:44 +0200294 struct snd_array kctls;
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200295 struct hda_input_mux private_imux;
Takashi Iwai41923e42007-10-22 17:20:10 +0200296 hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
Takashi Iwai834be882006-03-01 14:16:17 +0100297
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100298 /* hooks */
299 void (*init_hook)(struct hda_codec *codec);
300 void (*unsol_event)(struct hda_codec *codec, unsigned int res);
301
Takashi Iwai834be882006-03-01 14:16:17 +0100302 /* for pin sensing */
303 unsigned int sense_updated: 1;
304 unsigned int jack_present: 1;
Takashi Iwaibec15c32008-01-28 18:16:30 +0100305 unsigned int master_sw: 1;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200306
Takashi Iwai2134ea42008-01-10 16:53:55 +0100307 /* for virtual master */
308 hda_nid_t vmaster_nid;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200309#ifdef CONFIG_SND_HDA_POWER_SAVE
310 struct hda_loopback_check loopback;
311#endif
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +0200312
313 /* for PLL fix */
314 hda_nid_t pll_nid;
315 unsigned int pll_coef_idx, pll_coef_bit;
Takashi Iwaie044c392008-10-27 16:56:24 +0100316
317#ifdef SND_HDA_NEEDS_RESUME
318#define ALC_MAX_PINS 16
319 unsigned int num_pins;
320 hda_nid_t pin_nids[ALC_MAX_PINS];
321 unsigned int pin_cfgs[ALC_MAX_PINS];
322#endif
Kailang Yangdf694da2005-12-05 19:42:22 +0100323};
324
325/*
326 * configuration template - to be copied to the spec instance
327 */
328struct alc_config_preset {
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200329 struct snd_kcontrol_new *mixers[5]; /* should be identical size
330 * with spec
331 */
Takashi Iwaif9e336f2008-10-31 16:37:07 +0100332 struct snd_kcontrol_new *cap_mixer; /* capture mixer */
Kailang Yangdf694da2005-12-05 19:42:22 +0100333 const struct hda_verb *init_verbs[5];
334 unsigned int num_dacs;
335 hda_nid_t *dac_nids;
336 hda_nid_t dig_out_nid; /* optional */
337 hda_nid_t hp_nid; /* optional */
338 unsigned int num_adc_nids;
339 hda_nid_t *adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100340 hda_nid_t *capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +0100341 hda_nid_t dig_in_nid;
342 unsigned int num_channel_mode;
343 const struct hda_channel_mode *channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200344 int need_dac_fix;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200345 unsigned int num_mux_defs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100346 const struct hda_input_mux *input_mux;
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100347 void (*unsol_event)(struct hda_codec *, unsigned int);
348 void (*init_hook)(struct hda_codec *);
Takashi Iwaicb53c622007-08-10 17:21:45 +0200349#ifdef CONFIG_SND_HDA_POWER_SAVE
350 struct hda_amp_list *loopbacks;
351#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352};
353
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354
355/*
356 * input MUX handling
357 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200358static int alc_mux_enum_info(struct snd_kcontrol *kcontrol,
359 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360{
361 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
362 struct alc_spec *spec = codec->spec;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200363 unsigned int mux_idx = snd_ctl_get_ioffidx(kcontrol, &uinfo->id);
364 if (mux_idx >= spec->num_mux_defs)
365 mux_idx = 0;
366 return snd_hda_input_mux_info(&spec->input_mux[mux_idx], uinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367}
368
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200369static int alc_mux_enum_get(struct snd_kcontrol *kcontrol,
370 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371{
372 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
373 struct alc_spec *spec = codec->spec;
374 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
375
376 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
377 return 0;
378}
379
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200380static int alc_mux_enum_put(struct snd_kcontrol *kcontrol,
381 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382{
383 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
384 struct alc_spec *spec = codec->spec;
Takashi Iwai54cbc9a2008-10-31 15:24:04 +0100385 const struct hda_input_mux *imux = spec->input_mux;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Takashi Iwaie1406342008-02-11 18:32:32 +0100387 hda_nid_t nid = spec->capsrc_nids ?
388 spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389
Takashi Iwai54cbc9a2008-10-31 15:24:04 +0100390 if (spec->is_mix_capture) {
391 /* Matrix-mixer style (e.g. ALC882) */
392 unsigned int *cur_val = &spec->cur_mux[adc_idx];
393 unsigned int i, idx;
394
395 idx = ucontrol->value.enumerated.item[0];
396 if (idx >= imux->num_items)
397 idx = imux->num_items - 1;
398 if (*cur_val == idx)
399 return 0;
400 for (i = 0; i < imux->num_items; i++) {
401 unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE;
402 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT,
403 imux->items[i].index,
404 HDA_AMP_MUTE, v);
405 }
406 *cur_val = idx;
407 return 1;
408 } else {
409 /* MUX style (e.g. ALC880) */
410 unsigned int mux_idx;
411 mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx;
412 return snd_hda_input_mux_put(codec, &spec->input_mux[mux_idx],
413 ucontrol, nid,
414 &spec->cur_mux[adc_idx]);
415 }
416}
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200417
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418/*
419 * channel mode setting
420 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200421static int alc_ch_mode_info(struct snd_kcontrol *kcontrol,
422 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423{
424 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
425 struct alc_spec *spec = codec->spec;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100426 return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode,
427 spec->num_channel_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428}
429
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200430static int alc_ch_mode_get(struct snd_kcontrol *kcontrol,
431 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432{
433 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
434 struct alc_spec *spec = codec->spec;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100435 return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200436 spec->num_channel_mode,
437 spec->multiout.max_channels);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438}
439
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200440static int alc_ch_mode_put(struct snd_kcontrol *kcontrol,
441 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442{
443 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
444 struct alc_spec *spec = codec->spec;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200445 int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
446 spec->num_channel_mode,
447 &spec->multiout.max_channels);
Takashi Iwaibd2033f2006-10-10 19:49:31 +0200448 if (err >= 0 && spec->need_dac_fix)
Takashi Iwai4e195a72006-07-28 14:47:34 +0200449 spec->multiout.num_dacs = spec->multiout.max_channels / 2;
450 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451}
452
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453/*
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100454 * Control the mode of pin widget settings via the mixer. "pc" is used
Kailang Yangea1fb292008-08-26 12:58:38 +0200455 * instead of "%" to avoid consequences of accidently treating the % as
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100456 * being part of a format specifier. Maximum allowed length of a value is
457 * 63 characters plus NULL terminator.
Jonathan Woithe7cf51e482006-02-09 12:01:26 +0100458 *
459 * Note: some retasking pin complexes seem to ignore requests for input
460 * states other than HiZ (eg: PIN_VREFxx) and revert to HiZ if any of these
461 * are requested. Therefore order this list so that this behaviour will not
462 * cause problems when mixer clients move through the enum sequentially.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200463 * NIDs 0x0f and 0x10 have been observed to have this behaviour as of
464 * March 2006.
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200465 */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100466static char *alc_pin_mode_names[] = {
Jonathan Woithe7cf51e482006-02-09 12:01:26 +0100467 "Mic 50pc bias", "Mic 80pc bias",
468 "Line in", "Line out", "Headphone out",
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100469};
470static unsigned char alc_pin_mode_values[] = {
Jonathan Woithe7cf51e482006-02-09 12:01:26 +0100471 PIN_VREF50, PIN_VREF80, PIN_IN, PIN_OUT, PIN_HP,
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100472};
473/* The control can present all 5 options, or it can limit the options based
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200474 * in the pin being assumed to be exclusively an input or an output pin. In
475 * addition, "input" pins may or may not process the mic bias option
476 * depending on actual widget capability (NIDs 0x0f and 0x10 don't seem to
477 * accept requests for bias as of chip versions up to March 2006) and/or
478 * wiring in the computer.
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100479 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200480#define ALC_PIN_DIR_IN 0x00
481#define ALC_PIN_DIR_OUT 0x01
482#define ALC_PIN_DIR_INOUT 0x02
483#define ALC_PIN_DIR_IN_NOMICBIAS 0x03
484#define ALC_PIN_DIR_INOUT_NOMICBIAS 0x04
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100485
Kailang Yangea1fb292008-08-26 12:58:38 +0200486/* Info about the pin modes supported by the different pin direction modes.
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100487 * For each direction the minimum and maximum values are given.
488 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200489static signed char alc_pin_mode_dir_info[5][2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100490 { 0, 2 }, /* ALC_PIN_DIR_IN */
491 { 3, 4 }, /* ALC_PIN_DIR_OUT */
492 { 0, 4 }, /* ALC_PIN_DIR_INOUT */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200493 { 2, 2 }, /* ALC_PIN_DIR_IN_NOMICBIAS */
494 { 2, 4 }, /* ALC_PIN_DIR_INOUT_NOMICBIAS */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100495};
496#define alc_pin_mode_min(_dir) (alc_pin_mode_dir_info[_dir][0])
497#define alc_pin_mode_max(_dir) (alc_pin_mode_dir_info[_dir][1])
498#define alc_pin_mode_n_items(_dir) \
499 (alc_pin_mode_max(_dir)-alc_pin_mode_min(_dir)+1)
500
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200501static int alc_pin_mode_info(struct snd_kcontrol *kcontrol,
502 struct snd_ctl_elem_info *uinfo)
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200503{
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100504 unsigned int item_num = uinfo->value.enumerated.item;
505 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
506
507 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200508 uinfo->count = 1;
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100509 uinfo->value.enumerated.items = alc_pin_mode_n_items(dir);
510
511 if (item_num<alc_pin_mode_min(dir) || item_num>alc_pin_mode_max(dir))
512 item_num = alc_pin_mode_min(dir);
513 strcpy(uinfo->value.enumerated.name, alc_pin_mode_names[item_num]);
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200514 return 0;
515}
516
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200517static int alc_pin_mode_get(struct snd_kcontrol *kcontrol,
518 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200519{
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100520 unsigned int i;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200521 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
522 hda_nid_t nid = kcontrol->private_value & 0xffff;
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100523 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200524 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200525 unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
526 AC_VERB_GET_PIN_WIDGET_CONTROL,
527 0x00);
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200528
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100529 /* Find enumerated value for current pinctl setting */
530 i = alc_pin_mode_min(dir);
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200531 while (alc_pin_mode_values[i] != pinctl && i <= alc_pin_mode_max(dir))
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100532 i++;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200533 *valp = i <= alc_pin_mode_max(dir) ? i: alc_pin_mode_min(dir);
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100534 return 0;
535}
536
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200537static int alc_pin_mode_put(struct snd_kcontrol *kcontrol,
538 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100539{
540 signed int change;
541 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
542 hda_nid_t nid = kcontrol->private_value & 0xffff;
543 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
544 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200545 unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
546 AC_VERB_GET_PIN_WIDGET_CONTROL,
547 0x00);
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100548
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200549 if (val < alc_pin_mode_min(dir) || val > alc_pin_mode_max(dir))
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100550 val = alc_pin_mode_min(dir);
551
552 change = pinctl != alc_pin_mode_values[val];
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100553 if (change) {
554 /* Set pin mode to that requested */
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200555 snd_hda_codec_write_cache(codec, nid, 0,
556 AC_VERB_SET_PIN_WIDGET_CONTROL,
557 alc_pin_mode_values[val]);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100558
Kailang Yangea1fb292008-08-26 12:58:38 +0200559 /* Also enable the retasking pin's input/output as required
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100560 * for the requested pin mode. Enum values of 2 or less are
561 * input modes.
562 *
563 * Dynamically switching the input/output buffers probably
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200564 * reduces noise slightly (particularly on input) so we'll
565 * do it. However, having both input and output buffers
566 * enabled simultaneously doesn't seem to be problematic if
567 * this turns out to be necessary in the future.
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100568 */
569 if (val <= 2) {
Takashi Iwai47fd8302007-08-10 17:11:07 +0200570 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
571 HDA_AMP_MUTE, HDA_AMP_MUTE);
572 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
573 HDA_AMP_MUTE, 0);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100574 } else {
Takashi Iwai47fd8302007-08-10 17:11:07 +0200575 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
576 HDA_AMP_MUTE, HDA_AMP_MUTE);
577 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
578 HDA_AMP_MUTE, 0);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100579 }
580 }
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200581 return change;
582}
583
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100584#define ALC_PIN_MODE(xname, nid, dir) \
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200585 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100586 .info = alc_pin_mode_info, \
587 .get = alc_pin_mode_get, \
588 .put = alc_pin_mode_put, \
589 .private_value = nid | (dir<<16) }
Kailang Yangdf694da2005-12-05 19:42:22 +0100590
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100591/* A switch control for ALC260 GPIO pins. Multiple GPIOs can be ganged
592 * together using a mask with more than one bit set. This control is
593 * currently used only by the ALC260 test model. At this stage they are not
594 * needed for any "production" models.
595 */
596#ifdef CONFIG_SND_DEBUG
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200597#define alc_gpio_data_info snd_ctl_boolean_mono_info
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200598
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200599static int alc_gpio_data_get(struct snd_kcontrol *kcontrol,
600 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100601{
602 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
603 hda_nid_t nid = kcontrol->private_value & 0xffff;
604 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
605 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200606 unsigned int val = snd_hda_codec_read(codec, nid, 0,
607 AC_VERB_GET_GPIO_DATA, 0x00);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100608
609 *valp = (val & mask) != 0;
610 return 0;
611}
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200612static int alc_gpio_data_put(struct snd_kcontrol *kcontrol,
613 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100614{
615 signed int change;
616 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
617 hda_nid_t nid = kcontrol->private_value & 0xffff;
618 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
619 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200620 unsigned int gpio_data = snd_hda_codec_read(codec, nid, 0,
621 AC_VERB_GET_GPIO_DATA,
622 0x00);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100623
624 /* Set/unset the masked GPIO bit(s) as needed */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200625 change = (val == 0 ? 0 : mask) != (gpio_data & mask);
626 if (val == 0)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100627 gpio_data &= ~mask;
628 else
629 gpio_data |= mask;
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200630 snd_hda_codec_write_cache(codec, nid, 0,
631 AC_VERB_SET_GPIO_DATA, gpio_data);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100632
633 return change;
634}
635#define ALC_GPIO_DATA_SWITCH(xname, nid, mask) \
636 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
637 .info = alc_gpio_data_info, \
638 .get = alc_gpio_data_get, \
639 .put = alc_gpio_data_put, \
640 .private_value = nid | (mask<<16) }
641#endif /* CONFIG_SND_DEBUG */
642
Jonathan Woithe92621f12006-02-28 11:47:47 +0100643/* A switch control to allow the enabling of the digital IO pins on the
644 * ALC260. This is incredibly simplistic; the intention of this control is
645 * to provide something in the test model allowing digital outputs to be
646 * identified if present. If models are found which can utilise these
647 * outputs a more complete mixer control can be devised for those models if
648 * necessary.
649 */
650#ifdef CONFIG_SND_DEBUG
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200651#define alc_spdif_ctrl_info snd_ctl_boolean_mono_info
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200652
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200653static int alc_spdif_ctrl_get(struct snd_kcontrol *kcontrol,
654 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe92621f12006-02-28 11:47:47 +0100655{
656 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
657 hda_nid_t nid = kcontrol->private_value & 0xffff;
658 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
659 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200660 unsigned int val = snd_hda_codec_read(codec, nid, 0,
Andrew Paprocki3982d172007-12-19 12:13:44 +0100661 AC_VERB_GET_DIGI_CONVERT_1, 0x00);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100662
663 *valp = (val & mask) != 0;
664 return 0;
665}
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200666static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol,
667 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe92621f12006-02-28 11:47:47 +0100668{
669 signed int change;
670 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
671 hda_nid_t nid = kcontrol->private_value & 0xffff;
672 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
673 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200674 unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
Andrew Paprocki3982d172007-12-19 12:13:44 +0100675 AC_VERB_GET_DIGI_CONVERT_1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200676 0x00);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100677
678 /* Set/unset the masked control bit(s) as needed */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200679 change = (val == 0 ? 0 : mask) != (ctrl_data & mask);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100680 if (val==0)
681 ctrl_data &= ~mask;
682 else
683 ctrl_data |= mask;
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200684 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
685 ctrl_data);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100686
687 return change;
688}
689#define ALC_SPDIF_CTRL_SWITCH(xname, nid, mask) \
690 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
691 .info = alc_spdif_ctrl_info, \
692 .get = alc_spdif_ctrl_get, \
693 .put = alc_spdif_ctrl_put, \
694 .private_value = nid | (mask<<16) }
695#endif /* CONFIG_SND_DEBUG */
696
Jonathan Woithef8225f62008-01-08 12:16:54 +0100697/* A switch control to allow the enabling EAPD digital outputs on the ALC26x.
698 * Again, this is only used in the ALC26x test models to help identify when
699 * the EAPD line must be asserted for features to work.
700 */
701#ifdef CONFIG_SND_DEBUG
702#define alc_eapd_ctrl_info snd_ctl_boolean_mono_info
703
704static int alc_eapd_ctrl_get(struct snd_kcontrol *kcontrol,
705 struct snd_ctl_elem_value *ucontrol)
706{
707 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
708 hda_nid_t nid = kcontrol->private_value & 0xffff;
709 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
710 long *valp = ucontrol->value.integer.value;
711 unsigned int val = snd_hda_codec_read(codec, nid, 0,
712 AC_VERB_GET_EAPD_BTLENABLE, 0x00);
713
714 *valp = (val & mask) != 0;
715 return 0;
716}
717
718static int alc_eapd_ctrl_put(struct snd_kcontrol *kcontrol,
719 struct snd_ctl_elem_value *ucontrol)
720{
721 int change;
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 val = *ucontrol->value.integer.value;
726 unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
727 AC_VERB_GET_EAPD_BTLENABLE,
728 0x00);
729
730 /* Set/unset the masked control bit(s) as needed */
731 change = (!val ? 0 : mask) != (ctrl_data & mask);
732 if (!val)
733 ctrl_data &= ~mask;
734 else
735 ctrl_data |= mask;
736 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
737 ctrl_data);
738
739 return change;
740}
741
742#define ALC_EAPD_CTRL_SWITCH(xname, nid, mask) \
743 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
744 .info = alc_eapd_ctrl_info, \
745 .get = alc_eapd_ctrl_get, \
746 .put = alc_eapd_ctrl_put, \
747 .private_value = nid | (mask<<16) }
748#endif /* CONFIG_SND_DEBUG */
749
Kailang Yangdf694da2005-12-05 19:42:22 +0100750/*
Takashi Iwaid88897e2008-10-31 15:01:37 +0100751 */
752static void add_mixer(struct alc_spec *spec, struct snd_kcontrol_new *mix)
753{
754 if (snd_BUG_ON(spec->num_mixers >= ARRAY_SIZE(spec->mixers)))
755 return;
756 spec->mixers[spec->num_mixers++] = mix;
757}
758
759static void add_verb(struct alc_spec *spec, const struct hda_verb *verb)
760{
761 if (snd_BUG_ON(spec->num_init_verbs >= ARRAY_SIZE(spec->init_verbs)))
762 return;
763 spec->init_verbs[spec->num_init_verbs++] = verb;
764}
765
766/*
Kailang Yangdf694da2005-12-05 19:42:22 +0100767 * set up from the preset table
768 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200769static void setup_preset(struct alc_spec *spec,
770 const struct alc_config_preset *preset)
Kailang Yangdf694da2005-12-05 19:42:22 +0100771{
772 int i;
773
774 for (i = 0; i < ARRAY_SIZE(preset->mixers) && preset->mixers[i]; i++)
Takashi Iwaid88897e2008-10-31 15:01:37 +0100775 add_mixer(spec, preset->mixers[i]);
Takashi Iwaif9e336f2008-10-31 16:37:07 +0100776 spec->cap_mixer = preset->cap_mixer;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200777 for (i = 0; i < ARRAY_SIZE(preset->init_verbs) && preset->init_verbs[i];
778 i++)
Takashi Iwaid88897e2008-10-31 15:01:37 +0100779 add_verb(spec, preset->init_verbs[i]);
Kailang Yangea1fb292008-08-26 12:58:38 +0200780
Kailang Yangdf694da2005-12-05 19:42:22 +0100781 spec->channel_mode = preset->channel_mode;
782 spec->num_channel_mode = preset->num_channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200783 spec->need_dac_fix = preset->need_dac_fix;
Kailang Yangdf694da2005-12-05 19:42:22 +0100784
785 spec->multiout.max_channels = spec->channel_mode[0].channels;
786
787 spec->multiout.num_dacs = preset->num_dacs;
788 spec->multiout.dac_nids = preset->dac_nids;
789 spec->multiout.dig_out_nid = preset->dig_out_nid;
790 spec->multiout.hp_nid = preset->hp_nid;
Kailang Yangea1fb292008-08-26 12:58:38 +0200791
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200792 spec->num_mux_defs = preset->num_mux_defs;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200793 if (!spec->num_mux_defs)
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200794 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +0100795 spec->input_mux = preset->input_mux;
796
797 spec->num_adc_nids = preset->num_adc_nids;
798 spec->adc_nids = preset->adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100799 spec->capsrc_nids = preset->capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +0100800 spec->dig_in_nid = preset->dig_in_nid;
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100801
802 spec->unsol_event = preset->unsol_event;
803 spec->init_hook = preset->init_hook;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200804#ifdef CONFIG_SND_HDA_POWER_SAVE
805 spec->loopback.amplist = preset->loopbacks;
806#endif
Kailang Yangdf694da2005-12-05 19:42:22 +0100807}
808
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200809/* Enable GPIO mask and set output */
810static struct hda_verb alc_gpio1_init_verbs[] = {
811 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
812 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
813 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
814 { }
815};
816
817static struct hda_verb alc_gpio2_init_verbs[] = {
818 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
819 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
820 {0x01, AC_VERB_SET_GPIO_DATA, 0x02},
821 { }
822};
823
Kailang Yangbdd148a2007-05-08 15:19:08 +0200824static struct hda_verb alc_gpio3_init_verbs[] = {
825 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
826 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
827 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
828 { }
829};
830
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +0200831/*
832 * Fix hardware PLL issue
833 * On some codecs, the analog PLL gating control must be off while
834 * the default value is 1.
835 */
836static void alc_fix_pll(struct hda_codec *codec)
837{
838 struct alc_spec *spec = codec->spec;
839 unsigned int val;
840
841 if (!spec->pll_nid)
842 return;
843 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
844 spec->pll_coef_idx);
845 val = snd_hda_codec_read(codec, spec->pll_nid, 0,
846 AC_VERB_GET_PROC_COEF, 0);
847 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
848 spec->pll_coef_idx);
849 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_PROC_COEF,
850 val & ~(1 << spec->pll_coef_bit));
851}
852
853static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
854 unsigned int coef_idx, unsigned int coef_bit)
855{
856 struct alc_spec *spec = codec->spec;
857 spec->pll_nid = nid;
858 spec->pll_coef_idx = coef_idx;
859 spec->pll_coef_bit = coef_bit;
860 alc_fix_pll(codec);
861}
862
Kailang Yangc9b58002007-10-16 14:30:01 +0200863static void alc_sku_automute(struct hda_codec *codec)
864{
865 struct alc_spec *spec = codec->spec;
Kailang Yangc9b58002007-10-16 14:30:01 +0200866 unsigned int present;
867 unsigned int hp_nid = spec->autocfg.hp_pins[0];
868 unsigned int sp_nid = spec->autocfg.speaker_pins[0];
869
870 /* need to execute and sync at first */
871 snd_hda_codec_read(codec, hp_nid, 0, AC_VERB_SET_PIN_SENSE, 0);
872 present = snd_hda_codec_read(codec, hp_nid, 0,
873 AC_VERB_GET_PIN_SENSE, 0);
874 spec->jack_present = (present & 0x80000000) != 0;
Takashi Iwaif6c7e542008-02-12 18:32:23 +0100875 snd_hda_codec_write(codec, sp_nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
876 spec->jack_present ? 0 : PIN_OUT);
Kailang Yangc9b58002007-10-16 14:30:01 +0200877}
878
Takashi Iwai4605b712008-10-31 14:18:24 +0100879#if 0 /* it's broken in some acses -- temporarily disabled */
Kailang Yang7fb0d782008-10-15 11:12:35 +0200880static void alc_mic_automute(struct hda_codec *codec)
881{
882 struct alc_spec *spec = codec->spec;
883 unsigned int present;
884 unsigned int mic_nid = spec->autocfg.input_pins[AUTO_PIN_MIC];
885 unsigned int fmic_nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC];
886 unsigned int mix_nid = spec->capsrc_nids[0];
887 unsigned int capsrc_idx_mic, capsrc_idx_fmic;
888
889 capsrc_idx_mic = mic_nid - 0x18;
890 capsrc_idx_fmic = fmic_nid - 0x18;
891 present = snd_hda_codec_read(codec, mic_nid, 0,
892 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
893 snd_hda_codec_write(codec, mix_nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
894 0x7000 | (capsrc_idx_mic << 8) | (present ? 0 : 0x80));
895 snd_hda_codec_write(codec, mix_nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
896 0x7000 | (capsrc_idx_fmic << 8) | (present ? 0x80 : 0));
897 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, capsrc_idx_fmic,
898 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
899}
Takashi Iwai4605b712008-10-31 14:18:24 +0100900#else
901#define alc_mic_automute(codec) /* NOP */
902#endif /* disabled */
Kailang Yang7fb0d782008-10-15 11:12:35 +0200903
Kailang Yangc9b58002007-10-16 14:30:01 +0200904/* unsolicited event for HP jack sensing */
905static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res)
906{
907 if (codec->vendor_id == 0x10ec0880)
908 res >>= 28;
909 else
910 res >>= 26;
Kailang Yang7fb0d782008-10-15 11:12:35 +0200911 if (res == ALC880_HP_EVENT)
912 alc_sku_automute(codec);
Kailang Yangc9b58002007-10-16 14:30:01 +0200913
Kailang Yang7fb0d782008-10-15 11:12:35 +0200914 if (res == ALC880_MIC_EVENT)
915 alc_mic_automute(codec);
916}
917
918static void alc_inithook(struct hda_codec *codec)
919{
Kailang Yangc9b58002007-10-16 14:30:01 +0200920 alc_sku_automute(codec);
Kailang Yang7fb0d782008-10-15 11:12:35 +0200921 alc_mic_automute(codec);
Kailang Yangc9b58002007-10-16 14:30:01 +0200922}
923
Kailang Yangf9423e72008-05-27 12:32:25 +0200924/* additional initialization for ALC888 variants */
925static void alc888_coef_init(struct hda_codec *codec)
926{
927 unsigned int tmp;
928
929 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0);
930 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
931 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
932 if ((tmp & 0xf0) == 2)
933 /* alc888S-VC */
934 snd_hda_codec_read(codec, 0x20, 0,
935 AC_VERB_SET_PROC_COEF, 0x830);
936 else
937 /* alc888-VB */
938 snd_hda_codec_read(codec, 0x20, 0,
939 AC_VERB_SET_PROC_COEF, 0x3030);
940}
941
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200942/* 32-bit subsystem ID for BIOS loading in HD Audio codec.
943 * 31 ~ 16 : Manufacture ID
944 * 15 ~ 8 : SKU ID
945 * 7 ~ 0 : Assembly ID
946 * port-A --> pin 39/41, port-E --> pin 14/15, port-D --> pin 35/36
947 */
948static void alc_subsystem_id(struct hda_codec *codec,
949 unsigned int porta, unsigned int porte,
950 unsigned int portd)
951{
Kailang Yangc9b58002007-10-16 14:30:01 +0200952 unsigned int ass, tmp, i;
953 unsigned nid;
954 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200955
Kailang Yangc9b58002007-10-16 14:30:01 +0200956 ass = codec->subsystem_id & 0xffff;
957 if ((ass != codec->bus->pci->subsystem_device) && (ass & 1))
958 goto do_sku;
959
Kailang Yangea1fb292008-08-26 12:58:38 +0200960 /*
Kailang Yangc9b58002007-10-16 14:30:01 +0200961 * 31~30 : port conetcivity
962 * 29~21 : reserve
963 * 20 : PCBEEP input
964 * 19~16 : Check sum (15:1)
965 * 15~1 : Custom
966 * 0 : override
967 */
968 nid = 0x1d;
969 if (codec->vendor_id == 0x10ec0260)
970 nid = 0x17;
971 ass = snd_hda_codec_read(codec, nid, 0,
972 AC_VERB_GET_CONFIG_DEFAULT, 0);
973 if (!(ass & 1) && !(ass & 0x100000))
974 return;
975 if ((ass >> 30) != 1) /* no physical connection */
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200976 return;
977
Kailang Yangc9b58002007-10-16 14:30:01 +0200978 /* check sum */
979 tmp = 0;
980 for (i = 1; i < 16; i++) {
Kailang Yang8c427222008-01-10 13:03:59 +0100981 if ((ass >> i) & 1)
Kailang Yangc9b58002007-10-16 14:30:01 +0200982 tmp++;
983 }
984 if (((ass >> 16) & 0xf) != tmp)
985 return;
986do_sku:
987 /*
988 * 0 : override
989 * 1 : Swap Jack
990 * 2 : 0 --> Desktop, 1 --> Laptop
991 * 3~5 : External Amplifier control
992 * 7~6 : Reserved
993 */
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200994 tmp = (ass & 0x38) >> 3; /* external Amp control */
995 switch (tmp) {
996 case 1:
997 snd_hda_sequence_write(codec, alc_gpio1_init_verbs);
998 break;
999 case 3:
1000 snd_hda_sequence_write(codec, alc_gpio2_init_verbs);
1001 break;
Kailang Yangbdd148a2007-05-08 15:19:08 +02001002 case 7:
1003 snd_hda_sequence_write(codec, alc_gpio3_init_verbs);
1004 break;
Kailang Yangc9b58002007-10-16 14:30:01 +02001005 case 5: /* set EAPD output high */
Kailang Yangbdd148a2007-05-08 15:19:08 +02001006 switch (codec->vendor_id) {
Kailang Yangc9b58002007-10-16 14:30:01 +02001007 case 0x10ec0260:
1008 snd_hda_codec_write(codec, 0x0f, 0,
1009 AC_VERB_SET_EAPD_BTLENABLE, 2);
1010 snd_hda_codec_write(codec, 0x10, 0,
1011 AC_VERB_SET_EAPD_BTLENABLE, 2);
1012 break;
1013 case 0x10ec0262:
Kailang Yangbdd148a2007-05-08 15:19:08 +02001014 case 0x10ec0267:
1015 case 0x10ec0268:
Kailang Yangc9b58002007-10-16 14:30:01 +02001016 case 0x10ec0269:
Kailang Yangf9423e72008-05-27 12:32:25 +02001017 case 0x10ec0660:
1018 case 0x10ec0662:
1019 case 0x10ec0663:
Kailang Yangc9b58002007-10-16 14:30:01 +02001020 case 0x10ec0862:
Takashi Iwai20a3a052008-05-23 17:52:53 +02001021 case 0x10ec0889:
Kailang Yangbdd148a2007-05-08 15:19:08 +02001022 snd_hda_codec_write(codec, 0x14, 0,
1023 AC_VERB_SET_EAPD_BTLENABLE, 2);
1024 snd_hda_codec_write(codec, 0x15, 0,
1025 AC_VERB_SET_EAPD_BTLENABLE, 2);
Kailang Yangc9b58002007-10-16 14:30:01 +02001026 break;
Kailang Yangbdd148a2007-05-08 15:19:08 +02001027 }
Kailang Yangc9b58002007-10-16 14:30:01 +02001028 switch (codec->vendor_id) {
1029 case 0x10ec0260:
1030 snd_hda_codec_write(codec, 0x1a, 0,
1031 AC_VERB_SET_COEF_INDEX, 7);
1032 tmp = snd_hda_codec_read(codec, 0x1a, 0,
1033 AC_VERB_GET_PROC_COEF, 0);
1034 snd_hda_codec_write(codec, 0x1a, 0,
1035 AC_VERB_SET_COEF_INDEX, 7);
1036 snd_hda_codec_write(codec, 0x1a, 0,
1037 AC_VERB_SET_PROC_COEF,
1038 tmp | 0x2010);
1039 break;
1040 case 0x10ec0262:
1041 case 0x10ec0880:
1042 case 0x10ec0882:
1043 case 0x10ec0883:
1044 case 0x10ec0885:
Takashi Iwai20a3a052008-05-23 17:52:53 +02001045 case 0x10ec0889:
Kailang Yangc9b58002007-10-16 14:30:01 +02001046 snd_hda_codec_write(codec, 0x20, 0,
1047 AC_VERB_SET_COEF_INDEX, 7);
1048 tmp = snd_hda_codec_read(codec, 0x20, 0,
1049 AC_VERB_GET_PROC_COEF, 0);
1050 snd_hda_codec_write(codec, 0x20, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +02001051 AC_VERB_SET_COEF_INDEX, 7);
Kailang Yangc9b58002007-10-16 14:30:01 +02001052 snd_hda_codec_write(codec, 0x20, 0,
1053 AC_VERB_SET_PROC_COEF,
1054 tmp | 0x2010);
1055 break;
Kailang Yangf9423e72008-05-27 12:32:25 +02001056 case 0x10ec0888:
Takashi Iwai1082c742008-08-22 15:24:22 +02001057 /*alc888_coef_init(codec);*/ /* called in alc_init() */
Kailang Yangf9423e72008-05-27 12:32:25 +02001058 break;
Kailang Yangc9b58002007-10-16 14:30:01 +02001059 case 0x10ec0267:
1060 case 0x10ec0268:
1061 snd_hda_codec_write(codec, 0x20, 0,
1062 AC_VERB_SET_COEF_INDEX, 7);
1063 tmp = snd_hda_codec_read(codec, 0x20, 0,
1064 AC_VERB_GET_PROC_COEF, 0);
1065 snd_hda_codec_write(codec, 0x20, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +02001066 AC_VERB_SET_COEF_INDEX, 7);
Kailang Yangc9b58002007-10-16 14:30:01 +02001067 snd_hda_codec_write(codec, 0x20, 0,
1068 AC_VERB_SET_PROC_COEF,
1069 tmp | 0x3000);
1070 break;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001071 }
Kailang Yangc9b58002007-10-16 14:30:01 +02001072 default:
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001073 break;
1074 }
Kailang Yangea1fb292008-08-26 12:58:38 +02001075
Kailang Yang8c427222008-01-10 13:03:59 +01001076 /* is laptop or Desktop and enable the function "Mute internal speaker
Kailang Yangc9b58002007-10-16 14:30:01 +02001077 * when the external headphone out jack is plugged"
1078 */
Kailang Yang8c427222008-01-10 13:03:59 +01001079 if (!(ass & 0x8000))
Kailang Yangc9b58002007-10-16 14:30:01 +02001080 return;
1081 /*
1082 * 10~8 : Jack location
1083 * 12~11: Headphone out -> 00: PortA, 01: PortE, 02: PortD, 03: Resvered
1084 * 14~13: Resvered
1085 * 15 : 1 --> enable the function "Mute internal speaker
1086 * when the external headphone out jack is plugged"
1087 */
1088 if (!spec->autocfg.speaker_pins[0]) {
Kailang Yang8c427222008-01-10 13:03:59 +01001089 if (spec->autocfg.line_out_pins[0])
Kailang Yangc9b58002007-10-16 14:30:01 +02001090 spec->autocfg.speaker_pins[0] =
Kailang Yang8c427222008-01-10 13:03:59 +01001091 spec->autocfg.line_out_pins[0];
Kailang Yangc9b58002007-10-16 14:30:01 +02001092 else
1093 return;
1094 }
1095
1096 if (!spec->autocfg.hp_pins[0]) {
1097 tmp = (ass >> 11) & 0x3; /* HP to chassis */
1098 if (tmp == 0)
1099 spec->autocfg.hp_pins[0] = porta;
1100 else if (tmp == 1)
1101 spec->autocfg.hp_pins[0] = porte;
1102 else if (tmp == 2)
1103 spec->autocfg.hp_pins[0] = portd;
1104 else
1105 return;
1106 }
Kailang Yang7fb0d782008-10-15 11:12:35 +02001107 if (spec->autocfg.hp_pins[0])
1108 snd_hda_codec_write(codec, spec->autocfg.hp_pins[0], 0,
1109 AC_VERB_SET_UNSOLICITED_ENABLE,
1110 AC_USRSP_EN | ALC880_HP_EVENT);
Kailang Yangc9b58002007-10-16 14:30:01 +02001111
Takashi Iwai4605b712008-10-31 14:18:24 +01001112#if 0 /* it's broken in some acses -- temporarily disabled */
Kailang Yang7fb0d782008-10-15 11:12:35 +02001113 if (spec->autocfg.input_pins[AUTO_PIN_MIC] &&
1114 spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC])
1115 snd_hda_codec_write(codec,
1116 spec->autocfg.input_pins[AUTO_PIN_MIC], 0,
1117 AC_VERB_SET_UNSOLICITED_ENABLE,
1118 AC_USRSP_EN | ALC880_MIC_EVENT);
Takashi Iwai4605b712008-10-31 14:18:24 +01001119#endif /* disabled */
Kailang Yangea1fb292008-08-26 12:58:38 +02001120
Kailang Yangc9b58002007-10-16 14:30:01 +02001121 spec->unsol_event = alc_sku_unsol_event;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001122}
1123
Takashi Iwai41e41f12005-06-08 14:48:49 +02001124/*
Takashi Iwaif95474e2007-07-10 00:47:43 +02001125 * Fix-up pin default configurations
1126 */
1127
1128struct alc_pincfg {
1129 hda_nid_t nid;
1130 u32 val;
1131};
1132
1133static void alc_fix_pincfg(struct hda_codec *codec,
1134 const struct snd_pci_quirk *quirk,
1135 const struct alc_pincfg **pinfix)
1136{
1137 const struct alc_pincfg *cfg;
1138
1139 quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk);
1140 if (!quirk)
1141 return;
1142
1143 cfg = pinfix[quirk->value];
1144 for (; cfg->nid; cfg++) {
1145 int i;
1146 u32 val = cfg->val;
1147 for (i = 0; i < 4; i++) {
1148 snd_hda_codec_write(codec, cfg->nid, 0,
1149 AC_VERB_SET_CONFIG_DEFAULT_BYTES_0 + i,
1150 val & 0xff);
1151 val >>= 8;
1152 }
1153 }
1154}
1155
1156/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001157 * ALC880 3-stack model
1158 *
1159 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0e)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001160 * Pin assignment: Front = 0x14, Line-In/Surr = 0x1a, Mic/CLFE = 0x18,
1161 * F-Mic = 0x1b, HP = 0x19
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162 */
1163
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001164static hda_nid_t alc880_dac_nids[4] = {
1165 /* front, rear, clfe, rear_surr */
1166 0x02, 0x05, 0x04, 0x03
1167};
1168
1169static hda_nid_t alc880_adc_nids[3] = {
1170 /* ADC0-2 */
1171 0x07, 0x08, 0x09,
1172};
1173
1174/* The datasheet says the node 0x07 is connected from inputs,
1175 * but it shows zero connection in the real implementation on some devices.
Kailang Yangdf694da2005-12-05 19:42:22 +01001176 * Note: this is a 915GAV bug, fixed on 915GLV
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001178static hda_nid_t alc880_adc_nids_alt[2] = {
1179 /* ADC1-2 */
1180 0x08, 0x09,
1181};
1182
1183#define ALC880_DIGOUT_NID 0x06
1184#define ALC880_DIGIN_NID 0x0a
1185
1186static struct hda_input_mux alc880_capture_source = {
1187 .num_items = 4,
1188 .items = {
1189 { "Mic", 0x0 },
1190 { "Front Mic", 0x3 },
1191 { "Line", 0x2 },
1192 { "CD", 0x4 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193 },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001194};
1195
1196/* channel source setting (2/6 channel selection for 3-stack) */
1197/* 2ch mode */
1198static struct hda_verb alc880_threestack_ch2_init[] = {
1199 /* set line-in to input, mute it */
1200 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
1201 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1202 /* set mic-in to input vref 80%, mute it */
1203 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1204 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205 { } /* end */
1206};
1207
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001208/* 6ch mode */
1209static struct hda_verb alc880_threestack_ch6_init[] = {
1210 /* set line-in to output, unmute it */
1211 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1212 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1213 /* set mic-in to output, unmute it */
1214 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1215 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1216 { } /* end */
1217};
1218
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001219static struct hda_channel_mode alc880_threestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001220 { 2, alc880_threestack_ch2_init },
1221 { 6, alc880_threestack_ch6_init },
1222};
1223
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001224static struct snd_kcontrol_new alc880_three_stack_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02001225 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001226 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02001227 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001228 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02001229 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1230 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001231 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1232 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1234 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1235 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1236 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1237 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1238 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1239 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
1240 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
1241 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
1242 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243 HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001244 {
1245 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1246 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01001247 .info = alc_ch_mode_info,
1248 .get = alc_ch_mode_get,
1249 .put = alc_ch_mode_put,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001250 },
1251 { } /* end */
1252};
1253
1254/* capture mixer elements */
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001255static int alc_cap_vol_info(struct snd_kcontrol *kcontrol,
1256 struct snd_ctl_elem_info *uinfo)
1257{
1258 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1259 struct alc_spec *spec = codec->spec;
1260 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001261
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001262 mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */
1263 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0,
1264 HDA_INPUT);
1265 err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo);
1266 mutex_unlock(&codec->spdif_mutex); /* reuse spdif_mutex */
1267 return err;
1268}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001270static int alc_cap_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
1271 unsigned int size, unsigned int __user *tlv)
1272{
1273 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1274 struct alc_spec *spec = codec->spec;
1275 int err;
1276
1277 mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */
1278 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0,
1279 HDA_INPUT);
1280 err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv);
1281 mutex_unlock(&codec->spdif_mutex); /* reuse spdif_mutex */
1282 return err;
1283}
1284
1285typedef int (*getput_call_t)(struct snd_kcontrol *kcontrol,
1286 struct snd_ctl_elem_value *ucontrol);
1287
1288static int alc_cap_getput_caller(struct snd_kcontrol *kcontrol,
1289 struct snd_ctl_elem_value *ucontrol,
1290 getput_call_t func)
1291{
1292 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1293 struct alc_spec *spec = codec->spec;
1294 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1295 int err;
1296
1297 mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */
1298 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[adc_idx],
1299 3, 0, HDA_INPUT);
1300 err = func(kcontrol, ucontrol);
1301 mutex_unlock(&codec->spdif_mutex); /* reuse spdif_mutex */
1302 return err;
1303}
1304
1305static int alc_cap_vol_get(struct snd_kcontrol *kcontrol,
1306 struct snd_ctl_elem_value *ucontrol)
1307{
1308 return alc_cap_getput_caller(kcontrol, ucontrol,
1309 snd_hda_mixer_amp_volume_get);
1310}
1311
1312static int alc_cap_vol_put(struct snd_kcontrol *kcontrol,
1313 struct snd_ctl_elem_value *ucontrol)
1314{
1315 return alc_cap_getput_caller(kcontrol, ucontrol,
1316 snd_hda_mixer_amp_volume_put);
1317}
1318
1319/* capture mixer elements */
1320#define alc_cap_sw_info snd_ctl_boolean_stereo_info
1321
1322static int alc_cap_sw_get(struct snd_kcontrol *kcontrol,
1323 struct snd_ctl_elem_value *ucontrol)
1324{
1325 return alc_cap_getput_caller(kcontrol, ucontrol,
1326 snd_hda_mixer_amp_switch_get);
1327}
1328
1329static int alc_cap_sw_put(struct snd_kcontrol *kcontrol,
1330 struct snd_ctl_elem_value *ucontrol)
1331{
1332 return alc_cap_getput_caller(kcontrol, ucontrol,
1333 snd_hda_mixer_amp_switch_put);
1334}
1335
1336#define DEFINE_CAPMIX(num) \
1337static struct snd_kcontrol_new alc_capture_mixer ## num[] = { \
1338 { \
1339 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
1340 .name = "Capture Switch", \
1341 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
1342 .count = num, \
1343 .info = alc_cap_sw_info, \
1344 .get = alc_cap_sw_get, \
1345 .put = alc_cap_sw_put, \
1346 }, \
1347 { \
1348 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
1349 .name = "Capture Volume", \
1350 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | \
1351 SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
1352 SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK), \
1353 .count = num, \
1354 .info = alc_cap_vol_info, \
1355 .get = alc_cap_vol_get, \
1356 .put = alc_cap_vol_put, \
1357 .tlv = { .c = alc_cap_vol_tlv }, \
1358 }, \
Takashi Iwai3c3e9892008-10-31 17:48:56 +01001359 { \
1360 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
1361 /* .name = "Capture Source", */ \
1362 .name = "Input Source", \
1363 .count = num, \
1364 .info = alc_mux_enum_info, \
1365 .get = alc_mux_enum_get, \
1366 .put = alc_mux_enum_put, \
1367 }, \
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001368 { } /* end */ \
1369}
1370
1371/* up to three ADCs */
1372DEFINE_CAPMIX(1);
1373DEFINE_CAPMIX(2);
1374DEFINE_CAPMIX(3);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001375
1376
1377/*
1378 * ALC880 5-stack model
1379 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001380 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0d),
1381 * Side = 0x02 (0xd)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001382 * Pin assignment: Front = 0x14, Surr = 0x17, CLFE = 0x16
1383 * Line-In/Side = 0x1a, Mic = 0x18, F-Mic = 0x1b, HP = 0x19
1384 */
1385
1386/* additional mixers to alc880_three_stack_mixer */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001387static struct snd_kcontrol_new alc880_five_stack_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001388 HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001389 HDA_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390 { } /* end */
1391};
1392
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001393/* channel source setting (6/8 channel selection for 5-stack) */
1394/* 6ch mode */
1395static struct hda_verb alc880_fivestack_ch6_init[] = {
1396 /* set line-in to input, mute it */
1397 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
1398 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02001399 { } /* end */
1400};
1401
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001402/* 8ch mode */
1403static struct hda_verb alc880_fivestack_ch8_init[] = {
1404 /* set line-in to output, unmute it */
1405 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1406 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1407 { } /* end */
1408};
1409
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001410static struct hda_channel_mode alc880_fivestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001411 { 6, alc880_fivestack_ch6_init },
1412 { 8, alc880_fivestack_ch8_init },
1413};
1414
1415
1416/*
1417 * ALC880 6-stack model
1418 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001419 * DAC: Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e),
1420 * Side = 0x05 (0x0f)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001421 * Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, Side = 0x17,
1422 * Mic = 0x18, F-Mic = 0x19, Line = 0x1a, HP = 0x1b
1423 */
1424
1425static hda_nid_t alc880_6st_dac_nids[4] = {
1426 /* front, rear, clfe, rear_surr */
1427 0x02, 0x03, 0x04, 0x05
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02001428};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001429
1430static struct hda_input_mux alc880_6stack_capture_source = {
1431 .num_items = 4,
1432 .items = {
1433 { "Mic", 0x0 },
1434 { "Front Mic", 0x1 },
1435 { "Line", 0x2 },
1436 { "CD", 0x4 },
1437 },
1438};
1439
1440/* fixed 8-channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001441static struct hda_channel_mode alc880_sixstack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001442 { 8, NULL },
1443};
1444
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001445static struct snd_kcontrol_new alc880_six_stack_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001446 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001447 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001448 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001449 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001450 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1451 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001452 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1453 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001454 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001455 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001456 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1457 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1458 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1459 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1460 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1461 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1462 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1463 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
1464 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
1465 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001466 {
1467 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1468 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01001469 .info = alc_ch_mode_info,
1470 .get = alc_ch_mode_get,
1471 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02001472 },
1473 { } /* end */
1474};
1475
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001476
1477/*
1478 * ALC880 W810 model
1479 *
1480 * W810 has rear IO for:
1481 * Front (DAC 02)
1482 * Surround (DAC 03)
1483 * Center/LFE (DAC 04)
1484 * Digital out (06)
1485 *
1486 * The system also has a pair of internal speakers, and a headphone jack.
1487 * These are both connected to Line2 on the codec, hence to DAC 02.
Kailang Yangea1fb292008-08-26 12:58:38 +02001488 *
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001489 * There is a variable resistor to control the speaker or headphone
1490 * volume. This is a hardware-only device without a software API.
1491 *
1492 * Plugging headphones in will disable the internal speakers. This is
1493 * implemented in hardware, not via the driver using jack sense. In
1494 * a similar fashion, plugging into the rear socket marked "front" will
1495 * disable both the speakers and headphones.
1496 *
1497 * For input, there's a microphone jack, and an "audio in" jack.
1498 * These may not do anything useful with this driver yet, because I
1499 * haven't setup any initialization verbs for these yet...
1500 */
1501
1502static hda_nid_t alc880_w810_dac_nids[3] = {
1503 /* front, rear/surround, clfe */
1504 0x02, 0x03, 0x04
1505};
1506
1507/* fixed 6 channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001508static struct hda_channel_mode alc880_w810_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001509 { 6, NULL }
1510};
1511
1512/* Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, HP = 0x1b */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001513static struct snd_kcontrol_new alc880_w810_base_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001514 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001515 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001516 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001517 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001518 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1519 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001520 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1521 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001522 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
1523 { } /* end */
1524};
1525
1526
1527/*
1528 * Z710V model
1529 *
1530 * DAC: Front = 0x02 (0x0c), HP = 0x03 (0x0d)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001531 * Pin assignment: Front = 0x14, HP = 0x15, Mic = 0x18, Mic2 = 0x19(?),
1532 * Line = 0x1a
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001533 */
1534
1535static hda_nid_t alc880_z71v_dac_nids[1] = {
1536 0x02
1537};
1538#define ALC880_Z71V_HP_DAC 0x03
1539
1540/* fixed 2 channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001541static struct hda_channel_mode alc880_2_jack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001542 { 2, NULL }
1543};
1544
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001545static struct snd_kcontrol_new alc880_z71v_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001546 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001547 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001548 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001549 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001550 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1551 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1552 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1553 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1554 { } /* end */
1555};
1556
1557
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001558/*
1559 * ALC880 F1734 model
1560 *
1561 * DAC: HP = 0x02 (0x0c), Front = 0x03 (0x0d)
1562 * Pin assignment: HP = 0x14, Front = 0x15, Mic = 0x18
1563 */
1564
1565static hda_nid_t alc880_f1734_dac_nids[1] = {
1566 0x03
1567};
1568#define ALC880_F1734_HP_DAC 0x02
1569
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001570static struct snd_kcontrol_new alc880_f1734_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001571 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001572 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01001573 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1574 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001575 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1576 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Takashi Iwai937b4162008-02-11 14:52:36 +01001577 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1578 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001579 { } /* end */
1580};
1581
Takashi Iwai937b4162008-02-11 14:52:36 +01001582static struct hda_input_mux alc880_f1734_capture_source = {
1583 .num_items = 2,
1584 .items = {
1585 { "Mic", 0x1 },
1586 { "CD", 0x4 },
1587 },
1588};
1589
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001590
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001591/*
1592 * ALC880 ASUS model
1593 *
1594 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
1595 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
1596 * Mic = 0x18, Line = 0x1a
1597 */
1598
1599#define alc880_asus_dac_nids alc880_w810_dac_nids /* identical with w810 */
1600#define alc880_asus_modes alc880_threestack_modes /* 2/6 channel mode */
1601
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001602static struct snd_kcontrol_new alc880_asus_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001603 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001604 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001605 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001606 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001607 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1608 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001609 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1610 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001611 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1612 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1613 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1614 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1615 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1616 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001617 {
1618 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1619 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01001620 .info = alc_ch_mode_info,
1621 .get = alc_ch_mode_get,
1622 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02001623 },
1624 { } /* end */
1625};
1626
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001627/*
1628 * ALC880 ASUS W1V model
1629 *
1630 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
1631 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
1632 * Mic = 0x18, Line = 0x1a, Line2 = 0x1b
1633 */
1634
1635/* additional mixers to alc880_asus_mixer */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001636static struct snd_kcontrol_new alc880_asus_w1v_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001637 HDA_CODEC_VOLUME("Line2 Playback Volume", 0x0b, 0x03, HDA_INPUT),
1638 HDA_CODEC_MUTE("Line2 Playback Switch", 0x0b, 0x03, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001639 { } /* end */
1640};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001641
Takashi Iwai3c10a9d2005-08-23 20:02:27 +02001642/* additional mixers to alc880_asus_mixer */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001643static struct snd_kcontrol_new alc880_pcbeep_mixer[] = {
Takashi Iwai3c10a9d2005-08-23 20:02:27 +02001644 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
1645 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
1646 { } /* end */
1647};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001648
Kailang Yangdf694da2005-12-05 19:42:22 +01001649/* TCL S700 */
1650static struct snd_kcontrol_new alc880_tcl_s700_mixer[] = {
1651 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1652 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
1653 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
1654 HDA_CODEC_VOLUME("CD Playback Volume", 0x0B, 0x04, HDA_INPUT),
1655 HDA_CODEC_MUTE("CD Playback Switch", 0x0B, 0x04, HDA_INPUT),
1656 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0B, 0x0, HDA_INPUT),
1657 HDA_CODEC_MUTE("Mic Playback Switch", 0x0B, 0x0, HDA_INPUT),
1658 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
1659 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01001660 { } /* end */
1661};
1662
Kailang Yangccc656c2006-10-17 12:32:26 +02001663/* Uniwill */
1664static struct snd_kcontrol_new alc880_uniwill_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01001665 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1666 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
1667 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1668 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02001669 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1670 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
1671 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1672 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
1673 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1674 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1675 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1676 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1677 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1678 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1679 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1680 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
1681 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
1682 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
1683 {
1684 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1685 .name = "Channel Mode",
1686 .info = alc_ch_mode_info,
1687 .get = alc_ch_mode_get,
1688 .put = alc_ch_mode_put,
1689 },
1690 { } /* end */
1691};
1692
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01001693static struct snd_kcontrol_new alc880_fujitsu_mixer[] = {
1694 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1695 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
1696 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1697 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
1698 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1699 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1700 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1701 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1702 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1703 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
1704 { } /* end */
1705};
1706
Kailang Yangccc656c2006-10-17 12:32:26 +02001707static struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01001708 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1709 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
1710 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1711 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02001712 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1713 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1714 { } /* end */
1715};
1716
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717/*
Takashi Iwai2134ea42008-01-10 16:53:55 +01001718 * virtual master controls
1719 */
1720
1721/*
1722 * slave controls for virtual master
1723 */
1724static const char *alc_slave_vols[] = {
1725 "Front Playback Volume",
1726 "Surround Playback Volume",
1727 "Center Playback Volume",
1728 "LFE Playback Volume",
1729 "Side Playback Volume",
1730 "Headphone Playback Volume",
1731 "Speaker Playback Volume",
1732 "Mono Playback Volume",
Takashi Iwai2134ea42008-01-10 16:53:55 +01001733 "Line-Out Playback Volume",
Takashi Iwai26f5df22008-11-03 17:39:46 +01001734 "PCM Playback Volume",
Takashi Iwai2134ea42008-01-10 16:53:55 +01001735 NULL,
1736};
1737
1738static const char *alc_slave_sws[] = {
1739 "Front Playback Switch",
1740 "Surround Playback Switch",
1741 "Center Playback Switch",
1742 "LFE Playback Switch",
1743 "Side Playback Switch",
1744 "Headphone Playback Switch",
1745 "Speaker Playback Switch",
1746 "Mono Playback Switch",
Takashi Iwaiedb54a52008-01-29 12:47:02 +01001747 "IEC958 Playback Switch",
Takashi Iwai2134ea42008-01-10 16:53:55 +01001748 NULL,
1749};
1750
1751/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001752 * build control elements
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753 */
Takashi Iwai603c4012008-07-30 15:01:44 +02001754
1755static void alc_free_kctls(struct hda_codec *codec);
1756
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757static int alc_build_controls(struct hda_codec *codec)
1758{
1759 struct alc_spec *spec = codec->spec;
1760 int err;
1761 int i;
1762
1763 for (i = 0; i < spec->num_mixers; i++) {
1764 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
1765 if (err < 0)
1766 return err;
1767 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001768 if (spec->cap_mixer) {
1769 err = snd_hda_add_new_ctls(codec, spec->cap_mixer);
1770 if (err < 0)
1771 return err;
1772 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773 if (spec->multiout.dig_out_nid) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001774 err = snd_hda_create_spdif_out_ctls(codec,
1775 spec->multiout.dig_out_nid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776 if (err < 0)
1777 return err;
Takashi Iwai9a081602008-02-12 18:37:26 +01001778 err = snd_hda_create_spdif_share_sw(codec,
1779 &spec->multiout);
1780 if (err < 0)
1781 return err;
1782 spec->multiout.share_spdif = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783 }
1784 if (spec->dig_in_nid) {
1785 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
1786 if (err < 0)
1787 return err;
1788 }
Takashi Iwai2134ea42008-01-10 16:53:55 +01001789
1790 /* if we have no master control, let's create it */
1791 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001792 unsigned int vmaster_tlv[4];
Takashi Iwai2134ea42008-01-10 16:53:55 +01001793 snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001794 HDA_OUTPUT, vmaster_tlv);
Takashi Iwai2134ea42008-01-10 16:53:55 +01001795 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001796 vmaster_tlv, alc_slave_vols);
Takashi Iwai2134ea42008-01-10 16:53:55 +01001797 if (err < 0)
1798 return err;
1799 }
1800 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
1801 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
1802 NULL, alc_slave_sws);
1803 if (err < 0)
1804 return err;
1805 }
1806
Takashi Iwai603c4012008-07-30 15:01:44 +02001807 alc_free_kctls(codec); /* no longer needed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808 return 0;
1809}
1810
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001811
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812/*
1813 * initialize the codec volumes, etc
1814 */
1815
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001816/*
1817 * generic initialization of ADC, input mixers and output mixers
1818 */
1819static struct hda_verb alc880_volume_init_verbs[] = {
1820 /*
1821 * Unmute ADC0-2 and set the default input to mic-in
1822 */
Takashi Iwai71fe7b82005-05-25 18:11:40 +02001823 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001824 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02001825 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001826 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02001827 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001828 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001830 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
1831 * mixer widget
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001832 * Note: PASD motherboards uses the Line In 2 as the input for front
1833 * panel mic (mic 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001835 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02001836 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1837 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
1838 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
1839 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
1840 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
1841 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
1842 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001844 /*
1845 * Set up output mixers (0x0c - 0x0f)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001847 /* set vol=0 to output mixers */
1848 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1849 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1850 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1851 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1852 /* set up input amps for analog loopback */
1853 /* Amp Indices: DAC = 0, mixer = 1 */
Takashi Iwai05acb862005-06-10 19:50:25 +02001854 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1855 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02001856 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1857 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02001858 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1859 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02001860 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1861 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862
1863 { }
1864};
1865
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001866/*
1867 * 3-stack pin configuration:
1868 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
1869 */
1870static struct hda_verb alc880_pin_3stack_init_verbs[] = {
1871 /*
1872 * preset connection lists of input pins
1873 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
1874 */
1875 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
1876 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1877 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
1878
1879 /*
1880 * Set pin mode and muting
1881 */
1882 /* set front pin widgets 0x14 for output */
1883 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1884 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1885 /* Mic1 (rear panel) pin widget for input and vref at 80% */
1886 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1887 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1888 /* Mic2 (as headphone out) for HP output */
1889 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1890 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1891 /* Line In pin widget for input */
1892 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1893 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1894 /* Line2 (as front mic) pin widget for input and vref at 80% */
1895 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1896 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1897 /* CD pin widget for input */
1898 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1899
1900 { }
1901};
1902
1903/*
1904 * 5-stack pin configuration:
1905 * front = 0x14, surround = 0x17, clfe = 0x16, mic = 0x18, HP = 0x19,
1906 * line-in/side = 0x1a, f-mic = 0x1b
1907 */
1908static struct hda_verb alc880_pin_5stack_init_verbs[] = {
1909 /*
1910 * preset connection lists of input pins
1911 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
1912 */
1913 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1914 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/side */
1915
1916 /*
1917 * Set pin mode and muting
1918 */
1919 /* set pin widgets 0x14-0x17 for output */
Takashi Iwai05acb862005-06-10 19:50:25 +02001920 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1921 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1922 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1923 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001924 /* unmute pins for output (no gain on this amp) */
1925 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1926 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1927 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1928 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1929
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02001931 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001932 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1933 /* Mic2 (as headphone out) for HP output */
1934 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02001935 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001936 /* Line In pin widget for input */
1937 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1938 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1939 /* Line2 (as front mic) pin widget for input and vref at 80% */
1940 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1941 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1942 /* CD pin widget for input */
1943 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944
1945 { }
1946};
1947
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001948/*
1949 * W810 pin configuration:
1950 * front = 0x14, surround = 0x15, clfe = 0x16, HP = 0x1b
1951 */
1952static struct hda_verb alc880_pin_w810_init_verbs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953 /* hphone/speaker input selector: front DAC */
1954 {0x13, AC_VERB_SET_CONNECT_SEL, 0x0},
1955
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001956 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1957 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1958 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1959 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1960 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1961 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1962
1963 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02001964 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965
Linus Torvalds1da177e2005-04-16 15:20:36 -07001966 { }
1967};
1968
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001969/*
1970 * Z71V pin configuration:
1971 * Speaker-out = 0x14, HP = 0x15, Mic = 0x18, Line-in = 0x1a, Mic2 = 0x1b (?)
1972 */
1973static struct hda_verb alc880_pin_z71v_init_verbs[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02001974 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001975 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai05acb862005-06-10 19:50:25 +02001976 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001977 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02001978
Takashi Iwai16ded522005-06-10 19:58:24 +02001979 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001980 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02001981 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001982 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02001983
1984 { }
1985};
1986
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001987/*
1988 * 6-stack pin configuration:
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001989 * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18,
1990 * f-mic = 0x19, line = 0x1a, HP = 0x1b
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001991 */
1992static struct hda_verb alc880_pin_6stack_init_verbs[] = {
1993 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1994
Takashi Iwai16ded522005-06-10 19:58:24 +02001995 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001996 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001997 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001998 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001999 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002000 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002001 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002002 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2003
Takashi Iwai16ded522005-06-10 19:58:24 +02002004 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002005 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002006 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002007 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002008 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002009 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002010 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai16ded522005-06-10 19:58:24 +02002011 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002012 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangea1fb292008-08-26 12:58:38 +02002013
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002014 { }
2015};
Takashi Iwai16ded522005-06-10 19:58:24 +02002016
Kailang Yangccc656c2006-10-17 12:32:26 +02002017/*
2018 * Uniwill pin configuration:
2019 * HP = 0x14, InternalSpeaker = 0x15, mic = 0x18, internal mic = 0x19,
2020 * line = 0x1a
2021 */
2022static struct hda_verb alc880_uniwill_init_verbs[] = {
2023 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2024
2025 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2026 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2027 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2028 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2029 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2030 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2031 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2032 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2033 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2034 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2035 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2036 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2037 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2038 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2039
2040 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2041 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2042 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2043 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2044 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2045 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2046 /* {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, */
2047 /* {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
2048 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2049
2050 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
2051 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
2052
2053 { }
2054};
2055
2056/*
2057* Uniwill P53
Kailang Yangea1fb292008-08-26 12:58:38 +02002058* HP = 0x14, InternalSpeaker = 0x15, mic = 0x19,
Kailang Yangccc656c2006-10-17 12:32:26 +02002059 */
2060static struct hda_verb alc880_uniwill_p53_init_verbs[] = {
2061 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2062
2063 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2064 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2065 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2066 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2067 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2068 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2069 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2070 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2071 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2072 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2073 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2074 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2075
2076 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2077 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2078 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2079 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2080 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2081 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2082
2083 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
2084 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_DCVOL_EVENT},
2085
2086 { }
2087};
2088
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01002089static struct hda_verb alc880_beep_init_verbs[] = {
2090 { 0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) },
2091 { }
2092};
2093
Kailang Yangccc656c2006-10-17 12:32:26 +02002094/* toggle speaker-output according to the hp-jack state */
Takashi Iwai458a4fa2007-05-05 12:18:40 +02002095static void alc880_uniwill_hp_automute(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02002096{
2097 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002098 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02002099
2100 present = snd_hda_codec_read(codec, 0x14, 0,
2101 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02002102 bits = present ? HDA_AMP_MUTE : 0;
2103 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
2104 HDA_AMP_MUTE, bits);
2105 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
2106 HDA_AMP_MUTE, bits);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02002107}
2108
2109/* auto-toggle front mic */
2110static void alc880_uniwill_mic_automute(struct hda_codec *codec)
2111{
2112 unsigned int present;
2113 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02002114
2115 present = snd_hda_codec_read(codec, 0x18, 0,
2116 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02002117 bits = present ? HDA_AMP_MUTE : 0;
2118 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02002119}
2120
2121static void alc880_uniwill_automute(struct hda_codec *codec)
2122{
2123 alc880_uniwill_hp_automute(codec);
2124 alc880_uniwill_mic_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02002125}
2126
2127static void alc880_uniwill_unsol_event(struct hda_codec *codec,
2128 unsigned int res)
2129{
2130 /* Looks like the unsol event is incompatible with the standard
2131 * definition. 4bit tag is placed at 28 bit!
2132 */
Takashi Iwai458a4fa2007-05-05 12:18:40 +02002133 switch (res >> 28) {
2134 case ALC880_HP_EVENT:
2135 alc880_uniwill_hp_automute(codec);
2136 break;
2137 case ALC880_MIC_EVENT:
2138 alc880_uniwill_mic_automute(codec);
2139 break;
2140 }
Kailang Yangccc656c2006-10-17 12:32:26 +02002141}
2142
2143static void alc880_uniwill_p53_hp_automute(struct hda_codec *codec)
2144{
2145 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002146 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02002147
2148 present = snd_hda_codec_read(codec, 0x14, 0,
2149 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02002150 bits = present ? HDA_AMP_MUTE : 0;
Jiang zhe64654c22008-04-14 13:26:21 +02002151 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, HDA_AMP_MUTE, bits);
Kailang Yangccc656c2006-10-17 12:32:26 +02002152}
2153
2154static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec)
2155{
2156 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02002157
Kailang Yangccc656c2006-10-17 12:32:26 +02002158 present = snd_hda_codec_read(codec, 0x21, 0,
Takashi Iwai47fd8302007-08-10 17:11:07 +02002159 AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
2160 present &= HDA_AMP_VOLMASK;
2161 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0,
2162 HDA_AMP_VOLMASK, present);
2163 snd_hda_codec_amp_stereo(codec, 0x0d, HDA_OUTPUT, 0,
2164 HDA_AMP_VOLMASK, present);
Kailang Yangccc656c2006-10-17 12:32:26 +02002165}
Takashi Iwai47fd8302007-08-10 17:11:07 +02002166
Kailang Yangccc656c2006-10-17 12:32:26 +02002167static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec,
2168 unsigned int res)
2169{
2170 /* Looks like the unsol event is incompatible with the standard
2171 * definition. 4bit tag is placed at 28 bit!
2172 */
2173 if ((res >> 28) == ALC880_HP_EVENT)
2174 alc880_uniwill_p53_hp_automute(codec);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002175 if ((res >> 28) == ALC880_DCVOL_EVENT)
Kailang Yangccc656c2006-10-17 12:32:26 +02002176 alc880_uniwill_p53_dcvol_automute(codec);
2177}
2178
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002179/*
2180 * F1734 pin configuration:
2181 * HP = 0x14, speaker-out = 0x15, mic = 0x18
2182 */
2183static struct hda_verb alc880_pin_f1734_init_verbs[] = {
Michael Gruberee7a9c72008-03-10 11:30:59 +01002184 {0x07, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002185 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
2186 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
2187 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
2188 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
2189
2190 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2191 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2192 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2193 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2194
2195 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2196 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Michael Gruberee7a9c72008-03-10 11:30:59 +01002197 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002198 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2199 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2200 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2201 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2202 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2203 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02002204
Takashi Iwai937b4162008-02-11 14:52:36 +01002205 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
2206 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_DCVOL_EVENT},
2207
Takashi Iwai16ded522005-06-10 19:58:24 +02002208 { }
2209};
2210
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002211/*
2212 * ASUS pin configuration:
2213 * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a
2214 */
2215static struct hda_verb alc880_pin_asus_init_verbs[] = {
2216 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
2217 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
2218 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
2219 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
2220
2221 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2222 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2223 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2224 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2225 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2226 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2227 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2228 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2229
2230 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2231 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2232 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2233 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2234 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2235 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2236 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2237 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2238 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangea1fb292008-08-26 12:58:38 +02002239
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002240 { }
2241};
2242
2243/* Enable GPIO mask and set output */
Kailang Yangbc9f98a2007-04-12 13:06:07 +02002244#define alc880_gpio1_init_verbs alc_gpio1_init_verbs
2245#define alc880_gpio2_init_verbs alc_gpio2_init_verbs
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002246
Kailang Yangdf694da2005-12-05 19:42:22 +01002247/* Clevo m520g init */
2248static struct hda_verb alc880_pin_clevo_init_verbs[] = {
2249 /* headphone output */
2250 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
2251 /* line-out */
2252 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2253 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2254 /* Line-in */
2255 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2256 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2257 /* CD */
2258 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2259 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2260 /* Mic1 (rear panel) */
2261 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2262 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2263 /* Mic2 (front panel) */
2264 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2265 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2266 /* headphone */
2267 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2268 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2269 /* change to EAPD mode */
2270 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
2271 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
2272
2273 { }
2274};
2275
2276static struct hda_verb alc880_pin_tcl_S700_init_verbs[] = {
Takashi Iwai4b146cb2006-07-28 14:42:36 +02002277 /* change to EAPD mode */
2278 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
2279 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
2280
Kailang Yangdf694da2005-12-05 19:42:22 +01002281 /* Headphone output */
2282 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2283 /* Front output*/
2284 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2285 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
2286
2287 /* Line In pin widget for input */
2288 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2289 /* CD pin widget for input */
2290 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2291 /* Mic1 (rear panel) pin widget for input and vref at 80% */
2292 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2293
2294 /* change to EAPD mode */
2295 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
2296 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
2297
2298 { }
2299};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002300
2301/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002302 * LG m1 express dual
2303 *
2304 * Pin assignment:
2305 * Rear Line-In/Out (blue): 0x14
2306 * Build-in Mic-In: 0x15
2307 * Speaker-out: 0x17
2308 * HP-Out (green): 0x1b
2309 * Mic-In/Out (red): 0x19
2310 * SPDIF-Out: 0x1e
2311 */
2312
2313/* To make 5.1 output working (green=Front, blue=Surr, red=CLFE) */
2314static hda_nid_t alc880_lg_dac_nids[3] = {
2315 0x05, 0x02, 0x03
2316};
2317
2318/* seems analog CD is not working */
2319static struct hda_input_mux alc880_lg_capture_source = {
2320 .num_items = 3,
2321 .items = {
2322 { "Mic", 0x1 },
2323 { "Line", 0x5 },
2324 { "Internal Mic", 0x6 },
2325 },
2326};
2327
2328/* 2,4,6 channel modes */
2329static struct hda_verb alc880_lg_ch2_init[] = {
2330 /* set line-in and mic-in to input */
2331 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2332 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2333 { }
2334};
2335
2336static struct hda_verb alc880_lg_ch4_init[] = {
2337 /* set line-in to out and mic-in to input */
2338 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
2339 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2340 { }
2341};
2342
2343static struct hda_verb alc880_lg_ch6_init[] = {
2344 /* set line-in and mic-in to output */
2345 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
2346 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
2347 { }
2348};
2349
2350static struct hda_channel_mode alc880_lg_ch_modes[3] = {
2351 { 2, alc880_lg_ch2_init },
2352 { 4, alc880_lg_ch4_init },
2353 { 6, alc880_lg_ch6_init },
2354};
2355
2356static struct snd_kcontrol_new alc880_lg_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01002357 HDA_CODEC_VOLUME("Front Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
2358 HDA_BIND_MUTE("Front Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002359 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2360 HDA_BIND_MUTE("Surround Playback Switch", 0x0c, 2, HDA_INPUT),
2361 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
2362 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
2363 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
2364 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
2365 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2366 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
2367 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x06, HDA_INPUT),
2368 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x06, HDA_INPUT),
2369 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x07, HDA_INPUT),
2370 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x07, HDA_INPUT),
2371 {
2372 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2373 .name = "Channel Mode",
2374 .info = alc_ch_mode_info,
2375 .get = alc_ch_mode_get,
2376 .put = alc_ch_mode_put,
2377 },
2378 { } /* end */
2379};
2380
2381static struct hda_verb alc880_lg_init_verbs[] = {
2382 /* set capture source to mic-in */
2383 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2384 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2385 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2386 /* mute all amp mixer inputs */
2387 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02002388 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
2389 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002390 /* line-in to input */
2391 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2392 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2393 /* built-in mic */
2394 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2395 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2396 /* speaker-out */
2397 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2398 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2399 /* mic-in to input */
2400 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
2401 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2402 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2403 /* HP-out */
2404 {0x13, AC_VERB_SET_CONNECT_SEL, 0x03},
2405 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2406 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2407 /* jack sense */
2408 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | 0x1},
2409 { }
2410};
2411
2412/* toggle speaker-output according to the hp-jack state */
2413static void alc880_lg_automute(struct hda_codec *codec)
2414{
2415 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002416 unsigned char bits;
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002417
2418 present = snd_hda_codec_read(codec, 0x1b, 0,
2419 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02002420 bits = present ? HDA_AMP_MUTE : 0;
2421 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
2422 HDA_AMP_MUTE, bits);
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002423}
2424
2425static void alc880_lg_unsol_event(struct hda_codec *codec, unsigned int res)
2426{
2427 /* Looks like the unsol event is incompatible with the standard
2428 * definition. 4bit tag is placed at 28 bit!
2429 */
2430 if ((res >> 28) == 0x01)
2431 alc880_lg_automute(codec);
2432}
2433
2434/*
Takashi Iwaid6815182006-03-23 16:06:23 +01002435 * LG LW20
2436 *
2437 * Pin assignment:
2438 * Speaker-out: 0x14
2439 * Mic-In: 0x18
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02002440 * Built-in Mic-In: 0x19
2441 * Line-In: 0x1b
2442 * HP-Out: 0x1a
Takashi Iwaid6815182006-03-23 16:06:23 +01002443 * SPDIF-Out: 0x1e
2444 */
2445
Takashi Iwaid6815182006-03-23 16:06:23 +01002446static struct hda_input_mux alc880_lg_lw_capture_source = {
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02002447 .num_items = 3,
Takashi Iwaid6815182006-03-23 16:06:23 +01002448 .items = {
2449 { "Mic", 0x0 },
2450 { "Internal Mic", 0x1 },
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02002451 { "Line In", 0x2 },
Takashi Iwaid6815182006-03-23 16:06:23 +01002452 },
2453};
2454
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002455#define alc880_lg_lw_modes alc880_threestack_modes
2456
Takashi Iwaid6815182006-03-23 16:06:23 +01002457static struct snd_kcontrol_new alc880_lg_lw_mixer[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002458 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2459 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
2460 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
2461 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
2462 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2463 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
2464 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2465 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
2466 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2467 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaid6815182006-03-23 16:06:23 +01002468 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2469 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2470 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
2471 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002472 {
2473 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2474 .name = "Channel Mode",
2475 .info = alc_ch_mode_info,
2476 .get = alc_ch_mode_get,
2477 .put = alc_ch_mode_put,
2478 },
Takashi Iwaid6815182006-03-23 16:06:23 +01002479 { } /* end */
2480};
2481
2482static struct hda_verb alc880_lg_lw_init_verbs[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002483 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2484 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
2485 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
2486
Takashi Iwaid6815182006-03-23 16:06:23 +01002487 /* set capture source to mic-in */
2488 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2489 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2490 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02002491 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaid6815182006-03-23 16:06:23 +01002492 /* speaker-out */
2493 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2494 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2495 /* HP-out */
Takashi Iwaid6815182006-03-23 16:06:23 +01002496 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2497 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2498 /* mic-in to input */
2499 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2500 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2501 /* built-in mic */
2502 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2503 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2504 /* jack sense */
2505 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | 0x1},
2506 { }
2507};
2508
2509/* toggle speaker-output according to the hp-jack state */
2510static void alc880_lg_lw_automute(struct hda_codec *codec)
2511{
2512 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002513 unsigned char bits;
Takashi Iwaid6815182006-03-23 16:06:23 +01002514
2515 present = snd_hda_codec_read(codec, 0x1b, 0,
2516 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02002517 bits = present ? HDA_AMP_MUTE : 0;
2518 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
2519 HDA_AMP_MUTE, bits);
Takashi Iwaid6815182006-03-23 16:06:23 +01002520}
2521
2522static void alc880_lg_lw_unsol_event(struct hda_codec *codec, unsigned int res)
2523{
2524 /* Looks like the unsol event is incompatible with the standard
2525 * definition. 4bit tag is placed at 28 bit!
2526 */
2527 if ((res >> 28) == 0x01)
2528 alc880_lg_lw_automute(codec);
2529}
2530
Takashi Iwaidf99cd32008-04-25 15:25:04 +02002531static struct snd_kcontrol_new alc880_medion_rim_mixer[] = {
2532 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2533 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
2534 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2535 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2536 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2537 HDA_CODEC_MUTE("Internal Playback Switch", 0x0b, 0x1, HDA_INPUT),
2538 { } /* end */
2539};
2540
2541static struct hda_input_mux alc880_medion_rim_capture_source = {
2542 .num_items = 2,
2543 .items = {
2544 { "Mic", 0x0 },
2545 { "Internal Mic", 0x1 },
2546 },
2547};
2548
2549static struct hda_verb alc880_medion_rim_init_verbs[] = {
2550 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2551
2552 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2553 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2554
2555 /* Mic1 (rear panel) pin widget for input and vref at 80% */
2556 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2557 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2558 /* Mic2 (as headphone out) for HP output */
2559 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2560 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2561 /* Internal Speaker */
2562 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2563 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2564
2565 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
2566 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
2567
2568 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
2569 { }
2570};
2571
2572/* toggle speaker-output according to the hp-jack state */
2573static void alc880_medion_rim_automute(struct hda_codec *codec)
2574{
2575 unsigned int present;
2576 unsigned char bits;
2577
2578 present = snd_hda_codec_read(codec, 0x14, 0,
2579 AC_VERB_GET_PIN_SENSE, 0)
2580 & AC_PINSENSE_PRESENCE;
2581 bits = present ? HDA_AMP_MUTE : 0;
2582 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
2583 HDA_AMP_MUTE, bits);
2584 if (present)
2585 snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0);
2586 else
2587 snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 2);
2588}
2589
2590static void alc880_medion_rim_unsol_event(struct hda_codec *codec,
2591 unsigned int res)
2592{
2593 /* Looks like the unsol event is incompatible with the standard
2594 * definition. 4bit tag is placed at 28 bit!
2595 */
2596 if ((res >> 28) == ALC880_HP_EVENT)
2597 alc880_medion_rim_automute(codec);
2598}
2599
Takashi Iwaicb53c622007-08-10 17:21:45 +02002600#ifdef CONFIG_SND_HDA_POWER_SAVE
2601static struct hda_amp_list alc880_loopbacks[] = {
2602 { 0x0b, HDA_INPUT, 0 },
2603 { 0x0b, HDA_INPUT, 1 },
2604 { 0x0b, HDA_INPUT, 2 },
2605 { 0x0b, HDA_INPUT, 3 },
2606 { 0x0b, HDA_INPUT, 4 },
2607 { } /* end */
2608};
2609
2610static struct hda_amp_list alc880_lg_loopbacks[] = {
2611 { 0x0b, HDA_INPUT, 1 },
2612 { 0x0b, HDA_INPUT, 6 },
2613 { 0x0b, HDA_INPUT, 7 },
2614 { } /* end */
2615};
2616#endif
2617
Takashi Iwaid6815182006-03-23 16:06:23 +01002618/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002619 * Common callbacks
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002620 */
Takashi Iwai16ded522005-06-10 19:58:24 +02002621
Linus Torvalds1da177e2005-04-16 15:20:36 -07002622static int alc_init(struct hda_codec *codec)
2623{
2624 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002625 unsigned int i;
2626
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02002627 alc_fix_pll(codec);
Takashi Iwai1082c742008-08-22 15:24:22 +02002628 if (codec->vendor_id == 0x10ec0888)
2629 alc888_coef_init(codec);
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02002630
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002631 for (i = 0; i < spec->num_init_verbs; i++)
2632 snd_hda_sequence_write(codec, spec->init_verbs[i]);
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002633
2634 if (spec->init_hook)
2635 spec->init_hook(codec);
2636
Linus Torvalds1da177e2005-04-16 15:20:36 -07002637 return 0;
2638}
2639
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002640static void alc_unsol_event(struct hda_codec *codec, unsigned int res)
2641{
2642 struct alc_spec *spec = codec->spec;
2643
2644 if (spec->unsol_event)
2645 spec->unsol_event(codec, res);
2646}
2647
Takashi Iwaicb53c622007-08-10 17:21:45 +02002648#ifdef CONFIG_SND_HDA_POWER_SAVE
2649static int alc_check_power_status(struct hda_codec *codec, hda_nid_t nid)
2650{
2651 struct alc_spec *spec = codec->spec;
2652 return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
2653}
2654#endif
2655
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656/*
2657 * Analog playback callbacks
2658 */
2659static int alc880_playback_pcm_open(struct hda_pcm_stream *hinfo,
2660 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002661 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002662{
2663 struct alc_spec *spec = codec->spec;
Takashi Iwai9a081602008-02-12 18:37:26 +01002664 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
2665 hinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002666}
2667
2668static int alc880_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
2669 struct hda_codec *codec,
2670 unsigned int stream_tag,
2671 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002672 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002673{
2674 struct alc_spec *spec = codec->spec;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002675 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
2676 stream_tag, format, substream);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677}
2678
2679static int alc880_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
2680 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002681 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002682{
2683 struct alc_spec *spec = codec->spec;
2684 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
2685}
2686
2687/*
2688 * Digital out
2689 */
2690static int alc880_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
2691 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002692 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693{
2694 struct alc_spec *spec = codec->spec;
2695 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
2696}
2697
Takashi Iwai6b97eb42007-04-05 14:51:48 +02002698static int alc880_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
2699 struct hda_codec *codec,
2700 unsigned int stream_tag,
2701 unsigned int format,
2702 struct snd_pcm_substream *substream)
2703{
2704 struct alc_spec *spec = codec->spec;
2705 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
2706 stream_tag, format, substream);
2707}
2708
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709static int alc880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
2710 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002711 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002712{
2713 struct alc_spec *spec = codec->spec;
2714 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
2715}
2716
2717/*
2718 * Analog capture
2719 */
Takashi Iwai63300792008-01-24 15:31:36 +01002720static int alc880_alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002721 struct hda_codec *codec,
2722 unsigned int stream_tag,
2723 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002724 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725{
2726 struct alc_spec *spec = codec->spec;
2727
Takashi Iwai63300792008-01-24 15:31:36 +01002728 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1],
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729 stream_tag, 0, format);
2730 return 0;
2731}
2732
Takashi Iwai63300792008-01-24 15:31:36 +01002733static int alc880_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002735 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002736{
2737 struct alc_spec *spec = codec->spec;
2738
Takashi Iwai888afa12008-03-18 09:57:50 +01002739 snd_hda_codec_cleanup_stream(codec,
2740 spec->adc_nids[substream->number + 1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002741 return 0;
2742}
2743
2744
2745/*
2746 */
2747static struct hda_pcm_stream alc880_pcm_analog_playback = {
2748 .substreams = 1,
2749 .channels_min = 2,
2750 .channels_max = 8,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002751 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002752 .ops = {
2753 .open = alc880_playback_pcm_open,
2754 .prepare = alc880_playback_pcm_prepare,
2755 .cleanup = alc880_playback_pcm_cleanup
2756 },
2757};
2758
2759static struct hda_pcm_stream alc880_pcm_analog_capture = {
Takashi Iwai63300792008-01-24 15:31:36 +01002760 .substreams = 1,
2761 .channels_min = 2,
2762 .channels_max = 2,
2763 /* NID is set in alc_build_pcms */
2764};
2765
2766static struct hda_pcm_stream alc880_pcm_analog_alt_playback = {
2767 .substreams = 1,
2768 .channels_min = 2,
2769 .channels_max = 2,
2770 /* NID is set in alc_build_pcms */
2771};
2772
2773static struct hda_pcm_stream alc880_pcm_analog_alt_capture = {
2774 .substreams = 2, /* can be overridden */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002775 .channels_min = 2,
2776 .channels_max = 2,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002777 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002778 .ops = {
Takashi Iwai63300792008-01-24 15:31:36 +01002779 .prepare = alc880_alt_capture_pcm_prepare,
2780 .cleanup = alc880_alt_capture_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781 },
2782};
2783
2784static struct hda_pcm_stream alc880_pcm_digital_playback = {
2785 .substreams = 1,
2786 .channels_min = 2,
2787 .channels_max = 2,
2788 /* NID is set in alc_build_pcms */
2789 .ops = {
2790 .open = alc880_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02002791 .close = alc880_dig_playback_pcm_close,
2792 .prepare = alc880_dig_playback_pcm_prepare
Linus Torvalds1da177e2005-04-16 15:20:36 -07002793 },
2794};
2795
2796static struct hda_pcm_stream alc880_pcm_digital_capture = {
2797 .substreams = 1,
2798 .channels_min = 2,
2799 .channels_max = 2,
2800 /* NID is set in alc_build_pcms */
2801};
2802
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01002803/* Used by alc_build_pcms to flag that a PCM has no playback stream */
Takashi Iwai63300792008-01-24 15:31:36 +01002804static struct hda_pcm_stream alc_pcm_null_stream = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01002805 .substreams = 0,
2806 .channels_min = 0,
2807 .channels_max = 0,
2808};
2809
Linus Torvalds1da177e2005-04-16 15:20:36 -07002810static int alc_build_pcms(struct hda_codec *codec)
2811{
2812 struct alc_spec *spec = codec->spec;
2813 struct hda_pcm *info = spec->pcm_rec;
2814 int i;
2815
2816 codec->num_pcms = 1;
2817 codec->pcm_info = info;
2818
2819 info->name = spec->stream_name_analog;
Takashi Iwai4a471b72005-12-07 13:56:29 +01002820 if (spec->stream_analog_playback) {
Takashi Iwaida3cec32008-08-08 17:12:14 +02002821 if (snd_BUG_ON(!spec->multiout.dac_nids))
2822 return -EINVAL;
Takashi Iwai4a471b72005-12-07 13:56:29 +01002823 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
2824 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
2825 }
2826 if (spec->stream_analog_capture) {
Takashi Iwaida3cec32008-08-08 17:12:14 +02002827 if (snd_BUG_ON(!spec->adc_nids))
2828 return -EINVAL;
Takashi Iwai4a471b72005-12-07 13:56:29 +01002829 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
2830 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
2831 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832
Takashi Iwai4a471b72005-12-07 13:56:29 +01002833 if (spec->channel_mode) {
2834 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0;
2835 for (i = 0; i < spec->num_channel_mode; i++) {
2836 if (spec->channel_mode[i].channels > info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max) {
2837 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->channel_mode[i].channels;
2838 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002839 }
2840 }
2841
Takashi Iwaie08a0072006-09-07 17:52:14 +02002842 /* SPDIF for stream index #1 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002843 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
Takashi Iwaie08a0072006-09-07 17:52:14 +02002844 codec->num_pcms = 2;
Takashi Iwaic06134d2006-10-11 18:49:13 +02002845 info = spec->pcm_rec + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002846 info->name = spec->stream_name_digital;
Takashi Iwai7ba72ba2008-02-06 14:03:20 +01002847 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Takashi Iwai4a471b72005-12-07 13:56:29 +01002848 if (spec->multiout.dig_out_nid &&
2849 spec->stream_digital_playback) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002850 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_digital_playback);
2851 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
2852 }
Takashi Iwai4a471b72005-12-07 13:56:29 +01002853 if (spec->dig_in_nid &&
2854 spec->stream_digital_capture) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002855 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_digital_capture);
2856 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
2857 }
Takashi Iwai963f8032008-08-11 10:04:40 +02002858 /* FIXME: do we need this for all Realtek codec models? */
2859 codec->spdif_status_reset = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002860 }
2861
Takashi Iwaie08a0072006-09-07 17:52:14 +02002862 /* If the use of more than one ADC is requested for the current
2863 * model, configure a second analog capture-only PCM.
2864 */
2865 /* Additional Analaog capture for index #2 */
Takashi Iwai63300792008-01-24 15:31:36 +01002866 if ((spec->alt_dac_nid && spec->stream_analog_alt_playback) ||
2867 (spec->num_adc_nids > 1 && spec->stream_analog_alt_capture)) {
Takashi Iwaie08a0072006-09-07 17:52:14 +02002868 codec->num_pcms = 3;
Takashi Iwaic06134d2006-10-11 18:49:13 +02002869 info = spec->pcm_rec + 2;
Takashi Iwaie08a0072006-09-07 17:52:14 +02002870 info->name = spec->stream_name_analog;
Takashi Iwai63300792008-01-24 15:31:36 +01002871 if (spec->alt_dac_nid) {
2872 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
2873 *spec->stream_analog_alt_playback;
2874 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
2875 spec->alt_dac_nid;
2876 } else {
2877 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
2878 alc_pcm_null_stream;
2879 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
2880 }
2881 if (spec->num_adc_nids > 1) {
2882 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
2883 *spec->stream_analog_alt_capture;
2884 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
2885 spec->adc_nids[1];
2886 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams =
2887 spec->num_adc_nids - 1;
2888 } else {
2889 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
2890 alc_pcm_null_stream;
2891 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0;
Takashi Iwaie08a0072006-09-07 17:52:14 +02002892 }
2893 }
2894
Linus Torvalds1da177e2005-04-16 15:20:36 -07002895 return 0;
2896}
2897
Takashi Iwai603c4012008-07-30 15:01:44 +02002898static void alc_free_kctls(struct hda_codec *codec)
2899{
2900 struct alc_spec *spec = codec->spec;
2901
2902 if (spec->kctls.list) {
2903 struct snd_kcontrol_new *kctl = spec->kctls.list;
2904 int i;
2905 for (i = 0; i < spec->kctls.used; i++)
2906 kfree(kctl[i].name);
2907 }
2908 snd_array_free(&spec->kctls);
2909}
2910
Linus Torvalds1da177e2005-04-16 15:20:36 -07002911static void alc_free(struct hda_codec *codec)
2912{
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002913 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002914
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002915 if (!spec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002916 return;
2917
Takashi Iwai603c4012008-07-30 15:01:44 +02002918 alc_free_kctls(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002919 kfree(spec);
Takashi Iwai7943a8a2008-04-16 17:29:09 +02002920 codec->spec = NULL; /* to be sure */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002921}
2922
Takashi Iwaie044c392008-10-27 16:56:24 +01002923#ifdef SND_HDA_NEEDS_RESUME
2924static void store_pin_configs(struct hda_codec *codec)
2925{
2926 struct alc_spec *spec = codec->spec;
2927 hda_nid_t nid, end_nid;
2928
2929 end_nid = codec->start_nid + codec->num_nodes;
2930 for (nid = codec->start_nid; nid < end_nid; nid++) {
2931 unsigned int wid_caps = get_wcaps(codec, nid);
2932 unsigned int wid_type =
2933 (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
2934 if (wid_type != AC_WID_PIN)
2935 continue;
2936 if (spec->num_pins >= ARRAY_SIZE(spec->pin_nids))
2937 break;
2938 spec->pin_nids[spec->num_pins] = nid;
2939 spec->pin_cfgs[spec->num_pins] =
2940 snd_hda_codec_read(codec, nid, 0,
2941 AC_VERB_GET_CONFIG_DEFAULT, 0);
2942 spec->num_pins++;
2943 }
2944}
2945
2946static void resume_pin_configs(struct hda_codec *codec)
2947{
2948 struct alc_spec *spec = codec->spec;
2949 int i;
2950
2951 for (i = 0; i < spec->num_pins; i++) {
2952 hda_nid_t pin_nid = spec->pin_nids[i];
2953 unsigned int pin_config = spec->pin_cfgs[i];
2954 snd_hda_codec_write(codec, pin_nid, 0,
2955 AC_VERB_SET_CONFIG_DEFAULT_BYTES_0,
2956 pin_config & 0x000000ff);
2957 snd_hda_codec_write(codec, pin_nid, 0,
2958 AC_VERB_SET_CONFIG_DEFAULT_BYTES_1,
2959 (pin_config & 0x0000ff00) >> 8);
2960 snd_hda_codec_write(codec, pin_nid, 0,
2961 AC_VERB_SET_CONFIG_DEFAULT_BYTES_2,
2962 (pin_config & 0x00ff0000) >> 16);
2963 snd_hda_codec_write(codec, pin_nid, 0,
2964 AC_VERB_SET_CONFIG_DEFAULT_BYTES_3,
2965 pin_config >> 24);
2966 }
2967}
2968
2969static int alc_resume(struct hda_codec *codec)
2970{
2971 resume_pin_configs(codec);
2972 codec->patch_ops.init(codec);
2973 snd_hda_codec_resume_amp(codec);
2974 snd_hda_codec_resume_cache(codec);
2975 return 0;
2976}
2977#else
2978#define store_pin_configs(codec)
2979#endif
2980
Linus Torvalds1da177e2005-04-16 15:20:36 -07002981/*
2982 */
2983static struct hda_codec_ops alc_patch_ops = {
2984 .build_controls = alc_build_controls,
2985 .build_pcms = alc_build_pcms,
2986 .init = alc_init,
2987 .free = alc_free,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002988 .unsol_event = alc_unsol_event,
Takashi Iwaie044c392008-10-27 16:56:24 +01002989#ifdef SND_HDA_NEEDS_RESUME
2990 .resume = alc_resume,
2991#endif
Takashi Iwaicb53c622007-08-10 17:21:45 +02002992#ifdef CONFIG_SND_HDA_POWER_SAVE
2993 .check_power_status = alc_check_power_status,
2994#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002995};
2996
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002997
2998/*
2999 * Test configuration for debugging
3000 *
3001 * Almost all inputs/outputs are enabled. I/O pins can be configured via
3002 * enum controls.
3003 */
3004#ifdef CONFIG_SND_DEBUG
3005static hda_nid_t alc880_test_dac_nids[4] = {
3006 0x02, 0x03, 0x04, 0x05
3007};
3008
3009static struct hda_input_mux alc880_test_capture_source = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003010 .num_items = 7,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003011 .items = {
3012 { "In-1", 0x0 },
3013 { "In-2", 0x1 },
3014 { "In-3", 0x2 },
3015 { "In-4", 0x3 },
3016 { "CD", 0x4 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003017 { "Front", 0x5 },
3018 { "Surround", 0x6 },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003019 },
3020};
3021
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01003022static struct hda_channel_mode alc880_test_modes[4] = {
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003023 { 2, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02003024 { 4, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003025 { 6, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02003026 { 8, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003027};
3028
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003029static int alc_test_pin_ctl_info(struct snd_kcontrol *kcontrol,
3030 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003031{
3032 static char *texts[] = {
3033 "N/A", "Line Out", "HP Out",
3034 "In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%"
3035 };
3036 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
3037 uinfo->count = 1;
3038 uinfo->value.enumerated.items = 8;
3039 if (uinfo->value.enumerated.item >= 8)
3040 uinfo->value.enumerated.item = 7;
3041 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
3042 return 0;
3043}
3044
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003045static int alc_test_pin_ctl_get(struct snd_kcontrol *kcontrol,
3046 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003047{
3048 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3049 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
3050 unsigned int pin_ctl, item = 0;
3051
3052 pin_ctl = snd_hda_codec_read(codec, nid, 0,
3053 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
3054 if (pin_ctl & AC_PINCTL_OUT_EN) {
3055 if (pin_ctl & AC_PINCTL_HP_EN)
3056 item = 2;
3057 else
3058 item = 1;
3059 } else if (pin_ctl & AC_PINCTL_IN_EN) {
3060 switch (pin_ctl & AC_PINCTL_VREFEN) {
3061 case AC_PINCTL_VREF_HIZ: item = 3; break;
3062 case AC_PINCTL_VREF_50: item = 4; break;
3063 case AC_PINCTL_VREF_GRD: item = 5; break;
3064 case AC_PINCTL_VREF_80: item = 6; break;
3065 case AC_PINCTL_VREF_100: item = 7; break;
3066 }
3067 }
3068 ucontrol->value.enumerated.item[0] = item;
3069 return 0;
3070}
3071
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003072static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol,
3073 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003074{
3075 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3076 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
3077 static unsigned int ctls[] = {
3078 0, AC_PINCTL_OUT_EN, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN,
3079 AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ,
3080 AC_PINCTL_IN_EN | AC_PINCTL_VREF_50,
3081 AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD,
3082 AC_PINCTL_IN_EN | AC_PINCTL_VREF_80,
3083 AC_PINCTL_IN_EN | AC_PINCTL_VREF_100,
3084 };
3085 unsigned int old_ctl, new_ctl;
3086
3087 old_ctl = snd_hda_codec_read(codec, nid, 0,
3088 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
3089 new_ctl = ctls[ucontrol->value.enumerated.item[0]];
3090 if (old_ctl != new_ctl) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003091 int val;
3092 snd_hda_codec_write_cache(codec, nid, 0,
3093 AC_VERB_SET_PIN_WIDGET_CONTROL,
3094 new_ctl);
Takashi Iwai47fd8302007-08-10 17:11:07 +02003095 val = ucontrol->value.enumerated.item[0] >= 3 ?
3096 HDA_AMP_MUTE : 0;
3097 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
3098 HDA_AMP_MUTE, val);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003099 return 1;
3100 }
3101 return 0;
3102}
3103
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003104static int alc_test_pin_src_info(struct snd_kcontrol *kcontrol,
3105 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003106{
3107 static char *texts[] = {
3108 "Front", "Surround", "CLFE", "Side"
3109 };
3110 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
3111 uinfo->count = 1;
3112 uinfo->value.enumerated.items = 4;
3113 if (uinfo->value.enumerated.item >= 4)
3114 uinfo->value.enumerated.item = 3;
3115 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
3116 return 0;
3117}
3118
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003119static int alc_test_pin_src_get(struct snd_kcontrol *kcontrol,
3120 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003121{
3122 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3123 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
3124 unsigned int sel;
3125
3126 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0);
3127 ucontrol->value.enumerated.item[0] = sel & 3;
3128 return 0;
3129}
3130
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003131static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol,
3132 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003133{
3134 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3135 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
3136 unsigned int sel;
3137
3138 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3;
3139 if (ucontrol->value.enumerated.item[0] != sel) {
3140 sel = ucontrol->value.enumerated.item[0] & 3;
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003141 snd_hda_codec_write_cache(codec, nid, 0,
3142 AC_VERB_SET_CONNECT_SEL, sel);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003143 return 1;
3144 }
3145 return 0;
3146}
3147
3148#define PIN_CTL_TEST(xname,nid) { \
3149 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
3150 .name = xname, \
3151 .info = alc_test_pin_ctl_info, \
3152 .get = alc_test_pin_ctl_get, \
3153 .put = alc_test_pin_ctl_put, \
3154 .private_value = nid \
3155 }
3156
3157#define PIN_SRC_TEST(xname,nid) { \
3158 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
3159 .name = xname, \
3160 .info = alc_test_pin_src_info, \
3161 .get = alc_test_pin_src_get, \
3162 .put = alc_test_pin_src_put, \
3163 .private_value = nid \
3164 }
3165
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003166static struct snd_kcontrol_new alc880_test_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02003167 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3168 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
3169 HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
3170 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003171 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
3172 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
3173 HDA_BIND_MUTE("CLFE Playback Switch", 0x0e, 2, HDA_INPUT),
3174 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003175 PIN_CTL_TEST("Front Pin Mode", 0x14),
3176 PIN_CTL_TEST("Surround Pin Mode", 0x15),
3177 PIN_CTL_TEST("CLFE Pin Mode", 0x16),
3178 PIN_CTL_TEST("Side Pin Mode", 0x17),
3179 PIN_CTL_TEST("In-1 Pin Mode", 0x18),
3180 PIN_CTL_TEST("In-2 Pin Mode", 0x19),
3181 PIN_CTL_TEST("In-3 Pin Mode", 0x1a),
3182 PIN_CTL_TEST("In-4 Pin Mode", 0x1b),
3183 PIN_SRC_TEST("In-1 Pin Source", 0x18),
3184 PIN_SRC_TEST("In-2 Pin Source", 0x19),
3185 PIN_SRC_TEST("In-3 Pin Source", 0x1a),
3186 PIN_SRC_TEST("In-4 Pin Source", 0x1b),
3187 HDA_CODEC_VOLUME("In-1 Playback Volume", 0x0b, 0x0, HDA_INPUT),
3188 HDA_CODEC_MUTE("In-1 Playback Switch", 0x0b, 0x0, HDA_INPUT),
3189 HDA_CODEC_VOLUME("In-2 Playback Volume", 0x0b, 0x1, HDA_INPUT),
3190 HDA_CODEC_MUTE("In-2 Playback Switch", 0x0b, 0x1, HDA_INPUT),
3191 HDA_CODEC_VOLUME("In-3 Playback Volume", 0x0b, 0x2, HDA_INPUT),
3192 HDA_CODEC_MUTE("In-3 Playback Switch", 0x0b, 0x2, HDA_INPUT),
3193 HDA_CODEC_VOLUME("In-4 Playback Volume", 0x0b, 0x3, HDA_INPUT),
3194 HDA_CODEC_MUTE("In-4 Playback Switch", 0x0b, 0x3, HDA_INPUT),
3195 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x4, HDA_INPUT),
3196 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x4, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003197 {
3198 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3199 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01003200 .info = alc_ch_mode_info,
3201 .get = alc_ch_mode_get,
3202 .put = alc_ch_mode_put,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003203 },
3204 { } /* end */
3205};
3206
3207static struct hda_verb alc880_test_init_verbs[] = {
3208 /* Unmute inputs of 0x0c - 0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02003209 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3210 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3211 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3212 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3213 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3214 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3215 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3216 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003217 /* Vol output for 0x0c-0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02003218 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3219 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3220 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3221 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003222 /* Set output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02003223 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3224 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3225 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3226 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003227 /* Unmute output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02003228 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3229 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3230 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3231 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003232 /* Set input pins 0x18-0x1c */
Takashi Iwai16ded522005-06-10 19:58:24 +02003233 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3234 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwai05acb862005-06-10 19:50:25 +02003235 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3236 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3237 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003238 /* Mute input pins 0x18-0x1b */
Takashi Iwai05acb862005-06-10 19:50:25 +02003239 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3240 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3241 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3242 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003243 /* ADC set up */
Takashi Iwai05acb862005-06-10 19:50:25 +02003244 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003245 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02003246 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003247 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02003248 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003249 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02003250 /* Analog input/passthru */
3251 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3252 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
3253 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
3254 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
3255 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003256 { }
3257};
3258#endif
3259
Linus Torvalds1da177e2005-04-16 15:20:36 -07003260/*
3261 */
3262
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003263static const char *alc880_models[ALC880_MODEL_LAST] = {
3264 [ALC880_3ST] = "3stack",
3265 [ALC880_TCL_S700] = "tcl",
3266 [ALC880_3ST_DIG] = "3stack-digout",
3267 [ALC880_CLEVO] = "clevo",
3268 [ALC880_5ST] = "5stack",
3269 [ALC880_5ST_DIG] = "5stack-digout",
3270 [ALC880_W810] = "w810",
3271 [ALC880_Z71V] = "z71v",
3272 [ALC880_6ST] = "6stack",
3273 [ALC880_6ST_DIG] = "6stack-digout",
3274 [ALC880_ASUS] = "asus",
3275 [ALC880_ASUS_W1V] = "asus-w1v",
3276 [ALC880_ASUS_DIG] = "asus-dig",
3277 [ALC880_ASUS_DIG2] = "asus-dig2",
3278 [ALC880_UNIWILL_DIG] = "uniwill",
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003279 [ALC880_UNIWILL_P53] = "uniwill-p53",
3280 [ALC880_FUJITSU] = "fujitsu",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003281 [ALC880_F1734] = "F1734",
3282 [ALC880_LG] = "lg",
3283 [ALC880_LG_LW] = "lg-lw",
Takashi Iwaidf99cd32008-04-25 15:25:04 +02003284 [ALC880_MEDION_RIM] = "medion",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003285#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003286 [ALC880_TEST] = "test",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003287#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003288 [ALC880_AUTO] = "auto",
3289};
3290
3291static struct snd_pci_quirk alc880_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003292 SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003293 SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG),
3294 SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST),
3295 SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_3ST_DIG),
3296 SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_6ST_DIG),
3297 SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_6ST_DIG),
3298 SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_6ST_DIG),
3299 SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_3ST_DIG),
3300 SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003301 SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_6ST_DIG),
3302 SND_PCI_QUIRK(0x103c, 0x2a09, "HP", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003303 SND_PCI_QUIRK(0x1043, 0x10b3, "ASUS W1V", ALC880_ASUS_W1V),
3304 SND_PCI_QUIRK(0x1043, 0x10c2, "ASUS W6A", ALC880_ASUS_DIG),
3305 SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS Wxx", ALC880_ASUS_DIG),
3306 SND_PCI_QUIRK(0x1043, 0x1113, "ASUS", ALC880_ASUS_DIG),
3307 SND_PCI_QUIRK(0x1043, 0x1123, "ASUS", ALC880_ASUS_DIG),
3308 SND_PCI_QUIRK(0x1043, 0x1173, "ASUS", ALC880_ASUS_DIG),
3309 SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_Z71V),
3310 /* SND_PCI_QUIRK(0x1043, 0x1964, "ASUS", ALC880_ASUS_DIG), */
3311 SND_PCI_QUIRK(0x1043, 0x1973, "ASUS", ALC880_ASUS_DIG),
3312 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS", ALC880_ASUS_DIG),
Travis Place186c3112008-05-20 11:54:41 +02003313 SND_PCI_QUIRK(0x1043, 0x814e, "ASUS P5GD1 w/SPDIF", ALC880_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003314 SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG),
3315 SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST),
3316 SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003317 SND_PCI_QUIRK(0x1043, 0, "ASUS", ALC880_ASUS), /* default ASUS */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003318 SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003319 SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST),
3320 SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003321 SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_5ST),
3322 SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003323 SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_6ST_DIG),
3324 SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_6ST_DIG),
3325 SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_6ST_DIG),
3326 SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003327 SND_PCI_QUIRK(0x1558, 0x0520, "Clevo m520G", ALC880_CLEVO),
3328 SND_PCI_QUIRK(0x1558, 0x0660, "Clevo m655n", ALC880_CLEVO),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003329 SND_PCI_QUIRK(0x1558, 0x5401, "ASUS", ALC880_ASUS_DIG2),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003330 SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003331 SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_UNIWILL_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003332 SND_PCI_QUIRK(0x1584, 0x9054, "Uniwlll", ALC880_F1734),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003333 SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL),
3334 SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003335 SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810),
Takashi Iwaidf99cd32008-04-25 15:25:04 +02003336 SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_MEDION_RIM),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003337 SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003338 SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003339 SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734),
Travis Place1d116042008-06-23 11:42:30 +02003340 SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FUJITSU),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003341 SND_PCI_QUIRK(0x1734, 0x10ac, "FSC", ALC880_UNIWILL),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003342 SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003343 SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003344 SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG),
3345 SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003346 SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003347 SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700),
3348 SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG), /* broken BIOS */
3349 SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG),
3350 SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003351 SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_5ST_DIG),
3352 SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003353 SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003354 SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003355 SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_3ST_DIG),
3356 SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003357 SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_5ST_DIG),
3358 SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_5ST_DIG),
3359 SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003360 SND_PCI_QUIRK(0x8086, 0, "Intel mobo", ALC880_3ST), /* default Intel */
3361 SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG),
3362 SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003363 {}
3364};
3365
Takashi Iwai16ded522005-06-10 19:58:24 +02003366/*
Kailang Yangdf694da2005-12-05 19:42:22 +01003367 * ALC880 codec presets
Takashi Iwai16ded522005-06-10 19:58:24 +02003368 */
Takashi Iwai16ded522005-06-10 19:58:24 +02003369static struct alc_config_preset alc880_presets[] = {
3370 [ALC880_3ST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003371 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003372 .init_verbs = { alc880_volume_init_verbs,
3373 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003374 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02003375 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003376 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
3377 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003378 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003379 .input_mux = &alc880_capture_source,
3380 },
3381 [ALC880_3ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003382 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003383 .init_verbs = { alc880_volume_init_verbs,
3384 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003385 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02003386 .dac_nids = alc880_dac_nids,
3387 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003388 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
3389 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003390 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003391 .input_mux = &alc880_capture_source,
3392 },
Kailang Yangdf694da2005-12-05 19:42:22 +01003393 [ALC880_TCL_S700] = {
3394 .mixers = { alc880_tcl_s700_mixer },
3395 .init_verbs = { alc880_volume_init_verbs,
3396 alc880_pin_tcl_S700_init_verbs,
3397 alc880_gpio2_init_verbs },
3398 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3399 .dac_nids = alc880_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01003400 .adc_nids = alc880_adc_nids_alt, /* FIXME: correct? */
3401 .num_adc_nids = 1, /* single ADC */
Kailang Yangdf694da2005-12-05 19:42:22 +01003402 .hp_nid = 0x03,
3403 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3404 .channel_mode = alc880_2_jack_modes,
3405 .input_mux = &alc880_capture_source,
3406 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003407 [ALC880_5ST] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003408 .mixers = { alc880_three_stack_mixer,
3409 alc880_five_stack_mixer},
3410 .init_verbs = { alc880_volume_init_verbs,
3411 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003412 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3413 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003414 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
3415 .channel_mode = alc880_fivestack_modes,
3416 .input_mux = &alc880_capture_source,
3417 },
3418 [ALC880_5ST_DIG] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003419 .mixers = { alc880_three_stack_mixer,
3420 alc880_five_stack_mixer },
3421 .init_verbs = { alc880_volume_init_verbs,
3422 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003423 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3424 .dac_nids = alc880_dac_nids,
3425 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003426 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
3427 .channel_mode = alc880_fivestack_modes,
3428 .input_mux = &alc880_capture_source,
3429 },
Takashi Iwaib6482d42005-06-27 15:32:43 +02003430 [ALC880_6ST] = {
3431 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003432 .init_verbs = { alc880_volume_init_verbs,
3433 alc880_pin_6stack_init_verbs },
Takashi Iwaib6482d42005-06-27 15:32:43 +02003434 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
3435 .dac_nids = alc880_6st_dac_nids,
3436 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
3437 .channel_mode = alc880_sixstack_modes,
3438 .input_mux = &alc880_6stack_capture_source,
3439 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003440 [ALC880_6ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003441 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003442 .init_verbs = { alc880_volume_init_verbs,
3443 alc880_pin_6stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003444 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
3445 .dac_nids = alc880_6st_dac_nids,
3446 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003447 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
3448 .channel_mode = alc880_sixstack_modes,
3449 .input_mux = &alc880_6stack_capture_source,
3450 },
3451 [ALC880_W810] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003452 .mixers = { alc880_w810_base_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003453 .init_verbs = { alc880_volume_init_verbs,
3454 alc880_pin_w810_init_verbs,
Takashi Iwaib0af0de2005-06-21 14:49:19 +02003455 alc880_gpio2_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003456 .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids),
3457 .dac_nids = alc880_w810_dac_nids,
3458 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003459 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
3460 .channel_mode = alc880_w810_modes,
3461 .input_mux = &alc880_capture_source,
3462 },
3463 [ALC880_Z71V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003464 .mixers = { alc880_z71v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003465 .init_verbs = { alc880_volume_init_verbs,
3466 alc880_pin_z71v_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003467 .num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids),
3468 .dac_nids = alc880_z71v_dac_nids,
3469 .dig_out_nid = ALC880_DIGOUT_NID,
3470 .hp_nid = 0x03,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003471 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3472 .channel_mode = alc880_2_jack_modes,
Takashi Iwai16ded522005-06-10 19:58:24 +02003473 .input_mux = &alc880_capture_source,
3474 },
3475 [ALC880_F1734] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003476 .mixers = { alc880_f1734_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003477 .init_verbs = { alc880_volume_init_verbs,
3478 alc880_pin_f1734_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003479 .num_dacs = ARRAY_SIZE(alc880_f1734_dac_nids),
3480 .dac_nids = alc880_f1734_dac_nids,
3481 .hp_nid = 0x02,
3482 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3483 .channel_mode = alc880_2_jack_modes,
Takashi Iwai937b4162008-02-11 14:52:36 +01003484 .input_mux = &alc880_f1734_capture_source,
3485 .unsol_event = alc880_uniwill_p53_unsol_event,
3486 .init_hook = alc880_uniwill_p53_hp_automute,
Takashi Iwai16ded522005-06-10 19:58:24 +02003487 },
3488 [ALC880_ASUS] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003489 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003490 .init_verbs = { alc880_volume_init_verbs,
3491 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003492 alc880_gpio1_init_verbs },
3493 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3494 .dac_nids = alc880_asus_dac_nids,
3495 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3496 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003497 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003498 .input_mux = &alc880_capture_source,
3499 },
3500 [ALC880_ASUS_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003501 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003502 .init_verbs = { alc880_volume_init_verbs,
3503 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003504 alc880_gpio1_init_verbs },
3505 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3506 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003507 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003508 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3509 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003510 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003511 .input_mux = &alc880_capture_source,
3512 },
Kailang Yangdf694da2005-12-05 19:42:22 +01003513 [ALC880_ASUS_DIG2] = {
3514 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003515 .init_verbs = { alc880_volume_init_verbs,
3516 alc880_pin_asus_init_verbs,
Kailang Yangdf694da2005-12-05 19:42:22 +01003517 alc880_gpio2_init_verbs }, /* use GPIO2 */
3518 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3519 .dac_nids = alc880_asus_dac_nids,
3520 .dig_out_nid = ALC880_DIGOUT_NID,
3521 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3522 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003523 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01003524 .input_mux = &alc880_capture_source,
3525 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003526 [ALC880_ASUS_W1V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003527 .mixers = { alc880_asus_mixer, alc880_asus_w1v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003528 .init_verbs = { alc880_volume_init_verbs,
3529 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003530 alc880_gpio1_init_verbs },
3531 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3532 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003533 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003534 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3535 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003536 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003537 .input_mux = &alc880_capture_source,
3538 },
3539 [ALC880_UNIWILL_DIG] = {
Takashi Iwai3c10a9d2005-08-23 20:02:27 +02003540 .mixers = { alc880_asus_mixer, alc880_pcbeep_mixer },
Kailang Yangccc656c2006-10-17 12:32:26 +02003541 .init_verbs = { alc880_volume_init_verbs,
3542 alc880_pin_asus_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003543 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3544 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003545 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003546 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3547 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003548 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003549 .input_mux = &alc880_capture_source,
3550 },
Kailang Yangccc656c2006-10-17 12:32:26 +02003551 [ALC880_UNIWILL] = {
3552 .mixers = { alc880_uniwill_mixer },
3553 .init_verbs = { alc880_volume_init_verbs,
3554 alc880_uniwill_init_verbs },
3555 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3556 .dac_nids = alc880_asus_dac_nids,
3557 .dig_out_nid = ALC880_DIGOUT_NID,
3558 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
3559 .channel_mode = alc880_threestack_modes,
3560 .need_dac_fix = 1,
3561 .input_mux = &alc880_capture_source,
3562 .unsol_event = alc880_uniwill_unsol_event,
3563 .init_hook = alc880_uniwill_automute,
3564 },
3565 [ALC880_UNIWILL_P53] = {
3566 .mixers = { alc880_uniwill_p53_mixer },
3567 .init_verbs = { alc880_volume_init_verbs,
3568 alc880_uniwill_p53_init_verbs },
3569 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3570 .dac_nids = alc880_asus_dac_nids,
3571 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003572 .channel_mode = alc880_threestack_modes,
3573 .input_mux = &alc880_capture_source,
3574 .unsol_event = alc880_uniwill_p53_unsol_event,
3575 .init_hook = alc880_uniwill_p53_hp_automute,
3576 },
3577 [ALC880_FUJITSU] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003578 .mixers = { alc880_fujitsu_mixer,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003579 alc880_pcbeep_mixer, },
3580 .init_verbs = { alc880_volume_init_verbs,
3581 alc880_uniwill_p53_init_verbs,
3582 alc880_beep_init_verbs },
3583 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3584 .dac_nids = alc880_dac_nids,
Takashi Iwaid53d7d92007-08-20 15:20:02 +02003585 .dig_out_nid = ALC880_DIGOUT_NID,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003586 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3587 .channel_mode = alc880_2_jack_modes,
Kailang Yangccc656c2006-10-17 12:32:26 +02003588 .input_mux = &alc880_capture_source,
3589 .unsol_event = alc880_uniwill_p53_unsol_event,
3590 .init_hook = alc880_uniwill_p53_hp_automute,
3591 },
Kailang Yangdf694da2005-12-05 19:42:22 +01003592 [ALC880_CLEVO] = {
3593 .mixers = { alc880_three_stack_mixer },
3594 .init_verbs = { alc880_volume_init_verbs,
3595 alc880_pin_clevo_init_verbs },
3596 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3597 .dac_nids = alc880_dac_nids,
3598 .hp_nid = 0x03,
3599 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
3600 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003601 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01003602 .input_mux = &alc880_capture_source,
3603 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003604 [ALC880_LG] = {
3605 .mixers = { alc880_lg_mixer },
3606 .init_verbs = { alc880_volume_init_verbs,
3607 alc880_lg_init_verbs },
3608 .num_dacs = ARRAY_SIZE(alc880_lg_dac_nids),
3609 .dac_nids = alc880_lg_dac_nids,
3610 .dig_out_nid = ALC880_DIGOUT_NID,
3611 .num_channel_mode = ARRAY_SIZE(alc880_lg_ch_modes),
3612 .channel_mode = alc880_lg_ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003613 .need_dac_fix = 1,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003614 .input_mux = &alc880_lg_capture_source,
3615 .unsol_event = alc880_lg_unsol_event,
3616 .init_hook = alc880_lg_automute,
Takashi Iwaicb53c622007-08-10 17:21:45 +02003617#ifdef CONFIG_SND_HDA_POWER_SAVE
3618 .loopbacks = alc880_lg_loopbacks,
3619#endif
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003620 },
Takashi Iwaid6815182006-03-23 16:06:23 +01003621 [ALC880_LG_LW] = {
3622 .mixers = { alc880_lg_lw_mixer },
3623 .init_verbs = { alc880_volume_init_verbs,
3624 alc880_lg_lw_init_verbs },
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003625 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwaid6815182006-03-23 16:06:23 +01003626 .dac_nids = alc880_dac_nids,
3627 .dig_out_nid = ALC880_DIGOUT_NID,
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003628 .num_channel_mode = ARRAY_SIZE(alc880_lg_lw_modes),
3629 .channel_mode = alc880_lg_lw_modes,
Takashi Iwaid6815182006-03-23 16:06:23 +01003630 .input_mux = &alc880_lg_lw_capture_source,
3631 .unsol_event = alc880_lg_lw_unsol_event,
3632 .init_hook = alc880_lg_lw_automute,
3633 },
Takashi Iwaidf99cd32008-04-25 15:25:04 +02003634 [ALC880_MEDION_RIM] = {
3635 .mixers = { alc880_medion_rim_mixer },
3636 .init_verbs = { alc880_volume_init_verbs,
3637 alc880_medion_rim_init_verbs,
3638 alc_gpio2_init_verbs },
3639 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3640 .dac_nids = alc880_dac_nids,
3641 .dig_out_nid = ALC880_DIGOUT_NID,
3642 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3643 .channel_mode = alc880_2_jack_modes,
3644 .input_mux = &alc880_medion_rim_capture_source,
3645 .unsol_event = alc880_medion_rim_unsol_event,
3646 .init_hook = alc880_medion_rim_automute,
3647 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003648#ifdef CONFIG_SND_DEBUG
3649 [ALC880_TEST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003650 .mixers = { alc880_test_mixer },
3651 .init_verbs = { alc880_test_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003652 .num_dacs = ARRAY_SIZE(alc880_test_dac_nids),
3653 .dac_nids = alc880_test_dac_nids,
3654 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003655 .num_channel_mode = ARRAY_SIZE(alc880_test_modes),
3656 .channel_mode = alc880_test_modes,
3657 .input_mux = &alc880_test_capture_source,
3658 },
3659#endif
3660};
3661
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003662/*
3663 * Automatic parse of I/O pins from the BIOS configuration
3664 */
3665
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003666enum {
3667 ALC_CTL_WIDGET_VOL,
3668 ALC_CTL_WIDGET_MUTE,
3669 ALC_CTL_BIND_MUTE,
3670};
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003671static struct snd_kcontrol_new alc880_control_templates[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003672 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
3673 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Takashi Iwai985be542005-11-02 18:26:49 +01003674 HDA_BIND_MUTE(NULL, 0, 0, 0),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003675};
3676
3677/* add dynamic controls */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003678static int add_control(struct alc_spec *spec, int type, const char *name,
3679 unsigned long val)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003680{
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003681 struct snd_kcontrol_new *knew;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003682
Takashi Iwai603c4012008-07-30 15:01:44 +02003683 snd_array_init(&spec->kctls, sizeof(*knew), 32);
3684 knew = snd_array_new(&spec->kctls);
3685 if (!knew)
3686 return -ENOMEM;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003687 *knew = alc880_control_templates[type];
Paulo Marques543537b2005-06-23 00:09:02 -07003688 knew->name = kstrdup(name, GFP_KERNEL);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003689 if (!knew->name)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003690 return -ENOMEM;
3691 knew->private_value = val;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003692 return 0;
3693}
3694
3695#define alc880_is_fixed_pin(nid) ((nid) >= 0x14 && (nid) <= 0x17)
3696#define alc880_fixed_pin_idx(nid) ((nid) - 0x14)
3697#define alc880_is_multi_pin(nid) ((nid) >= 0x18)
3698#define alc880_multi_pin_idx(nid) ((nid) - 0x18)
3699#define alc880_is_input_pin(nid) ((nid) >= 0x18)
3700#define alc880_input_pin_idx(nid) ((nid) - 0x18)
3701#define alc880_idx_to_dac(nid) ((nid) + 0x02)
3702#define alc880_dac_to_idx(nid) ((nid) - 0x02)
3703#define alc880_idx_to_mixer(nid) ((nid) + 0x0c)
3704#define alc880_idx_to_selector(nid) ((nid) + 0x10)
3705#define ALC880_PIN_CD_NID 0x1c
3706
3707/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003708static int alc880_auto_fill_dac_nids(struct alc_spec *spec,
3709 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003710{
3711 hda_nid_t nid;
3712 int assigned[4];
3713 int i, j;
3714
3715 memset(assigned, 0, sizeof(assigned));
Takashi Iwaib0af0de2005-06-21 14:49:19 +02003716 spec->multiout.dac_nids = spec->private_dac_nids;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003717
3718 /* check the pins hardwired to audio widget */
3719 for (i = 0; i < cfg->line_outs; i++) {
3720 nid = cfg->line_out_pins[i];
3721 if (alc880_is_fixed_pin(nid)) {
3722 int idx = alc880_fixed_pin_idx(nid);
Libin Yang5014f192005-11-23 15:48:36 +01003723 spec->multiout.dac_nids[i] = alc880_idx_to_dac(idx);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003724 assigned[idx] = 1;
3725 }
3726 }
3727 /* left pins can be connect to any audio widget */
3728 for (i = 0; i < cfg->line_outs; i++) {
3729 nid = cfg->line_out_pins[i];
3730 if (alc880_is_fixed_pin(nid))
3731 continue;
3732 /* search for an empty channel */
3733 for (j = 0; j < cfg->line_outs; j++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003734 if (!assigned[j]) {
3735 spec->multiout.dac_nids[i] =
3736 alc880_idx_to_dac(j);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003737 assigned[j] = 1;
3738 break;
3739 }
3740 }
3741 }
3742 spec->multiout.num_dacs = cfg->line_outs;
3743 return 0;
3744}
3745
3746/* add playback controls from the parsed DAC table */
Kailang Yangdf694da2005-12-05 19:42:22 +01003747static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
3748 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003749{
3750 char name[32];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003751 static const char *chname[4] = {
3752 "Front", "Surround", NULL /*CLFE*/, "Side"
3753 };
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003754 hda_nid_t nid;
3755 int i, err;
3756
3757 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003758 if (!spec->multiout.dac_nids[i])
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003759 continue;
3760 nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i]));
3761 if (i == 2) {
3762 /* Center/LFE */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003763 err = add_control(spec, ALC_CTL_WIDGET_VOL,
3764 "Center Playback Volume",
3765 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
3766 HDA_OUTPUT));
3767 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003768 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003769 err = add_control(spec, ALC_CTL_WIDGET_VOL,
3770 "LFE Playback Volume",
3771 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
3772 HDA_OUTPUT));
3773 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003774 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003775 err = add_control(spec, ALC_CTL_BIND_MUTE,
3776 "Center Playback Switch",
3777 HDA_COMPOSE_AMP_VAL(nid, 1, 2,
3778 HDA_INPUT));
3779 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003780 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003781 err = add_control(spec, ALC_CTL_BIND_MUTE,
3782 "LFE Playback Switch",
3783 HDA_COMPOSE_AMP_VAL(nid, 2, 2,
3784 HDA_INPUT));
3785 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003786 return err;
3787 } else {
3788 sprintf(name, "%s Playback Volume", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003789 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
3790 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
3791 HDA_OUTPUT));
3792 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003793 return err;
3794 sprintf(name, "%s Playback Switch", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003795 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
3796 HDA_COMPOSE_AMP_VAL(nid, 3, 2,
3797 HDA_INPUT));
3798 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003799 return err;
3800 }
3801 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003802 return 0;
3803}
3804
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003805/* add playback controls for speaker and HP outputs */
3806static int alc880_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
3807 const char *pfx)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003808{
3809 hda_nid_t nid;
3810 int err;
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003811 char name[32];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003812
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003813 if (!pin)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003814 return 0;
3815
3816 if (alc880_is_fixed_pin(pin)) {
3817 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
Takashi Iwai82bc9552006-03-21 11:24:42 +01003818 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003819 if (!spec->multiout.hp_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003820 spec->multiout.hp_nid = nid;
Takashi Iwai82bc9552006-03-21 11:24:42 +01003821 else
3822 spec->multiout.extra_out_nid[0] = nid;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003823 /* control HP volume/switch on the output mixer amp */
3824 nid = alc880_idx_to_mixer(alc880_fixed_pin_idx(pin));
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003825 sprintf(name, "%s Playback Volume", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003826 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
3827 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
3828 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003829 return err;
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003830 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003831 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
3832 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
3833 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003834 return err;
3835 } else if (alc880_is_multi_pin(pin)) {
3836 /* set manual connection */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003837 /* we have only a switch on HP-out PIN */
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003838 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003839 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
3840 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
3841 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003842 return err;
3843 }
3844 return 0;
3845}
3846
3847/* create input playback/capture controls for the given pin */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003848static int new_analog_input(struct alc_spec *spec, hda_nid_t pin,
3849 const char *ctlname,
Kailang Yangdf694da2005-12-05 19:42:22 +01003850 int idx, hda_nid_t mix_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003851{
3852 char name[32];
Kailang Yangdf694da2005-12-05 19:42:22 +01003853 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003854
3855 sprintf(name, "%s Playback Volume", ctlname);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003856 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
3857 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
3858 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003859 return err;
3860 sprintf(name, "%s Playback Switch", ctlname);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003861 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
3862 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
3863 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003864 return err;
3865 return 0;
3866}
3867
3868/* create playback/capture controls for input pins */
Kailang Yangdf694da2005-12-05 19:42:22 +01003869static int alc880_auto_create_analog_input_ctls(struct alc_spec *spec,
3870 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003871{
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003872 struct hda_input_mux *imux = &spec->private_imux;
Kailang Yangdf694da2005-12-05 19:42:22 +01003873 int i, err, idx;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003874
3875 for (i = 0; i < AUTO_PIN_LAST; i++) {
3876 if (alc880_is_input_pin(cfg->input_pins[i])) {
Kailang Yangdf694da2005-12-05 19:42:22 +01003877 idx = alc880_input_pin_idx(cfg->input_pins[i]);
Takashi Iwai4a471b72005-12-07 13:56:29 +01003878 err = new_analog_input(spec, cfg->input_pins[i],
3879 auto_pin_cfg_labels[i],
Kailang Yangdf694da2005-12-05 19:42:22 +01003880 idx, 0x0b);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003881 if (err < 0)
3882 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003883 imux->items[imux->num_items].label =
3884 auto_pin_cfg_labels[i];
3885 imux->items[imux->num_items].index =
3886 alc880_input_pin_idx(cfg->input_pins[i]);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003887 imux->num_items++;
3888 }
3889 }
3890 return 0;
3891}
3892
Takashi Iwaif6c7e542008-02-12 18:32:23 +01003893static void alc_set_pin_output(struct hda_codec *codec, hda_nid_t nid,
3894 unsigned int pin_type)
3895{
3896 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
3897 pin_type);
3898 /* unmute pin */
Takashi Iwaid260cdf2008-02-13 17:19:35 +01003899 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
3900 AMP_OUT_UNMUTE);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01003901}
3902
Kailang Yangdf694da2005-12-05 19:42:22 +01003903static void alc880_auto_set_output_and_unmute(struct hda_codec *codec,
3904 hda_nid_t nid, int pin_type,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003905 int dac_idx)
3906{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01003907 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003908 /* need the manual connection? */
3909 if (alc880_is_multi_pin(nid)) {
3910 struct alc_spec *spec = codec->spec;
3911 int idx = alc880_multi_pin_idx(nid);
3912 snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
3913 AC_VERB_SET_CONNECT_SEL,
3914 alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
3915 }
3916}
3917
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02003918static int get_pin_type(int line_out_type)
3919{
3920 if (line_out_type == AUTO_PIN_HP_OUT)
3921 return PIN_HP;
3922 else
3923 return PIN_OUT;
3924}
3925
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003926static void alc880_auto_init_multi_out(struct hda_codec *codec)
3927{
3928 struct alc_spec *spec = codec->spec;
3929 int i;
Kailang Yangea1fb292008-08-26 12:58:38 +02003930
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003931 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003932 for (i = 0; i < spec->autocfg.line_outs; i++) {
3933 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02003934 int pin_type = get_pin_type(spec->autocfg.line_out_type);
3935 alc880_auto_set_output_and_unmute(codec, nid, pin_type, i);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003936 }
3937}
3938
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003939static void alc880_auto_init_extra_out(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003940{
3941 struct alc_spec *spec = codec->spec;
3942 hda_nid_t pin;
3943
Takashi Iwai82bc9552006-03-21 11:24:42 +01003944 pin = spec->autocfg.speaker_pins[0];
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003945 if (pin) /* connect to front */
3946 alc880_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003947 pin = spec->autocfg.hp_pins[0];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003948 if (pin) /* connect to front */
3949 alc880_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
3950}
3951
3952static void alc880_auto_init_analog_input(struct hda_codec *codec)
3953{
3954 struct alc_spec *spec = codec->spec;
3955 int i;
3956
3957 for (i = 0; i < AUTO_PIN_LAST; i++) {
3958 hda_nid_t nid = spec->autocfg.input_pins[i];
3959 if (alc880_is_input_pin(nid)) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003960 snd_hda_codec_write(codec, nid, 0,
3961 AC_VERB_SET_PIN_WIDGET_CONTROL,
3962 i <= AUTO_PIN_FRONT_MIC ?
3963 PIN_VREF80 : PIN_IN);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003964 if (nid != ALC880_PIN_CD_NID)
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003965 snd_hda_codec_write(codec, nid, 0,
3966 AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003967 AMP_OUT_MUTE);
3968 }
3969 }
3970}
3971
3972/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003973/* return 1 if successful, 0 if the proper config is not found,
3974 * or a negative error code
3975 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003976static int alc880_parse_auto_config(struct hda_codec *codec)
3977{
3978 struct alc_spec *spec = codec->spec;
3979 int err;
Kailang Yangdf694da2005-12-05 19:42:22 +01003980 static hda_nid_t alc880_ignore[] = { 0x1d, 0 };
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003981
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003982 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
3983 alc880_ignore);
3984 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003985 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003986 if (!spec->autocfg.line_outs)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003987 return 0; /* can't find valid BIOS pin config */
Kailang Yangdf694da2005-12-05 19:42:22 +01003988
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003989 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
3990 if (err < 0)
3991 return err;
3992 err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
3993 if (err < 0)
3994 return err;
3995 err = alc880_auto_create_extra_out(spec,
3996 spec->autocfg.speaker_pins[0],
3997 "Speaker");
3998 if (err < 0)
3999 return err;
4000 err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
4001 "Headphone");
4002 if (err < 0)
4003 return err;
4004 err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg);
4005 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004006 return err;
4007
4008 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
4009
4010 if (spec->autocfg.dig_out_pin)
4011 spec->multiout.dig_out_nid = ALC880_DIGOUT_NID;
4012 if (spec->autocfg.dig_in_pin)
4013 spec->dig_in_nid = ALC880_DIGIN_NID;
4014
Takashi Iwai603c4012008-07-30 15:01:44 +02004015 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +01004016 add_mixer(spec, spec->kctls.list);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004017
Takashi Iwaid88897e2008-10-31 15:01:37 +01004018 add_verb(spec, alc880_volume_init_verbs);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004019
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004020 spec->num_mux_defs = 1;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004021 spec->input_mux = &spec->private_imux;
4022
Takashi Iwaie044c392008-10-27 16:56:24 +01004023 store_pin_configs(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004024 return 1;
4025}
4026
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004027/* additional initialization for auto-configuration model */
4028static void alc880_auto_init(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004029{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004030 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004031 alc880_auto_init_multi_out(codec);
Takashi Iwai8d88bc32005-11-17 11:09:23 +01004032 alc880_auto_init_extra_out(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004033 alc880_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004034 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02004035 alc_inithook(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004036}
4037
4038/*
4039 * OK, here we have finally the patch for ALC880
4040 */
4041
Takashi Iwaif9e336f2008-10-31 16:37:07 +01004042static void set_capture_mixer(struct alc_spec *spec)
4043{
4044 static struct snd_kcontrol_new *caps[3] = {
4045 alc_capture_mixer1,
4046 alc_capture_mixer2,
4047 alc_capture_mixer3,
4048 };
4049 if (spec->num_adc_nids > 0 && spec->num_adc_nids < 3)
4050 spec->cap_mixer = caps[spec->num_adc_nids - 1];
4051}
4052
Linus Torvalds1da177e2005-04-16 15:20:36 -07004053static int patch_alc880(struct hda_codec *codec)
4054{
4055 struct alc_spec *spec;
4056 int board_config;
Kailang Yangdf694da2005-12-05 19:42:22 +01004057 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004058
Takashi Iwaie560d8d2005-09-09 14:21:46 +02004059 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004060 if (spec == NULL)
4061 return -ENOMEM;
4062
4063 codec->spec = spec;
4064
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004065 board_config = snd_hda_check_board_config(codec, ALC880_MODEL_LAST,
4066 alc880_models,
4067 alc880_cfg_tbl);
4068 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004069 printk(KERN_INFO "hda_codec: Unknown model for ALC880, "
4070 "trying auto-probe from BIOS...\n");
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004071 board_config = ALC880_AUTO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004072 }
4073
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004074 if (board_config == ALC880_AUTO) {
4075 /* automatic parse from the BIOS config */
4076 err = alc880_parse_auto_config(codec);
4077 if (err < 0) {
4078 alc_free(codec);
4079 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004080 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004081 printk(KERN_INFO
4082 "hda_codec: Cannot set up configuration "
4083 "from BIOS. Using 3-stack mode...\n");
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004084 board_config = ALC880_3ST;
4085 }
4086 }
4087
Kailang Yangdf694da2005-12-05 19:42:22 +01004088 if (board_config != ALC880_AUTO)
4089 setup_preset(spec, &alc880_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004090
4091 spec->stream_name_analog = "ALC880 Analog";
4092 spec->stream_analog_playback = &alc880_pcm_analog_playback;
4093 spec->stream_analog_capture = &alc880_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01004094 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004095
4096 spec->stream_name_digital = "ALC880 Digital";
4097 spec->stream_digital_playback = &alc880_pcm_digital_playback;
4098 spec->stream_digital_capture = &alc880_pcm_digital_capture;
4099
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004100 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004101 /* check whether NID 0x07 is valid */
Takashi Iwai54d17402005-11-21 16:33:22 +01004102 unsigned int wcap = get_wcaps(codec, alc880_adc_nids[0]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004103 /* get type */
4104 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004105 if (wcap != AC_WID_AUD_IN) {
4106 spec->adc_nids = alc880_adc_nids_alt;
4107 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids_alt);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004108 } else {
4109 spec->adc_nids = alc880_adc_nids;
4110 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004111 }
4112 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01004113 set_capture_mixer(spec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004114
Takashi Iwai2134ea42008-01-10 16:53:55 +01004115 spec->vmaster_nid = 0x0c;
4116
Linus Torvalds1da177e2005-04-16 15:20:36 -07004117 codec->patch_ops = alc_patch_ops;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004118 if (board_config == ALC880_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004119 spec->init_hook = alc880_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02004120#ifdef CONFIG_SND_HDA_POWER_SAVE
4121 if (!spec->loopback.amplist)
4122 spec->loopback.amplist = alc880_loopbacks;
4123#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07004124
4125 return 0;
4126}
4127
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004128
Linus Torvalds1da177e2005-04-16 15:20:36 -07004129/*
4130 * ALC260 support
4131 */
4132
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004133static hda_nid_t alc260_dac_nids[1] = {
4134 /* front */
4135 0x02,
4136};
4137
4138static hda_nid_t alc260_adc_nids[1] = {
4139 /* ADC0 */
4140 0x04,
4141};
4142
Kailang Yangdf694da2005-12-05 19:42:22 +01004143static hda_nid_t alc260_adc_nids_alt[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004144 /* ADC1 */
4145 0x05,
4146};
4147
Jonathan Woithed57fdac2006-02-28 11:38:35 +01004148/* NIDs used when simultaneous access to both ADCs makes sense. Note that
4149 * alc260_capture_mixer assumes ADC0 (nid 0x04) is the first ADC.
4150 */
4151static hda_nid_t alc260_dual_adc_nids[2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004152 /* ADC0, ADC1 */
4153 0x04, 0x05
4154};
4155
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004156#define ALC260_DIGOUT_NID 0x03
4157#define ALC260_DIGIN_NID 0x06
4158
4159static struct hda_input_mux alc260_capture_source = {
4160 .num_items = 4,
4161 .items = {
4162 { "Mic", 0x0 },
4163 { "Front Mic", 0x1 },
4164 { "Line", 0x2 },
4165 { "CD", 0x4 },
4166 },
4167};
4168
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01004169/* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004170 * headphone jack and the internal CD lines since these are the only pins at
4171 * which audio can appear. For flexibility, also allow the option of
4172 * recording the mixer output on the second ADC (ADC0 doesn't have a
4173 * connection to the mixer output).
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004174 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004175static struct hda_input_mux alc260_fujitsu_capture_sources[2] = {
4176 {
4177 .num_items = 3,
4178 .items = {
4179 { "Mic/Line", 0x0 },
4180 { "CD", 0x4 },
4181 { "Headphone", 0x2 },
4182 },
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004183 },
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004184 {
4185 .num_items = 4,
4186 .items = {
4187 { "Mic/Line", 0x0 },
4188 { "CD", 0x4 },
4189 { "Headphone", 0x2 },
4190 { "Mixer", 0x5 },
4191 },
4192 },
4193
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004194};
4195
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004196/* Acer TravelMate(/Extensa/Aspire) notebooks have similar configuration to
4197 * the Fujitsu S702x, but jacks are marked differently.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004198 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004199static struct hda_input_mux alc260_acer_capture_sources[2] = {
4200 {
4201 .num_items = 4,
4202 .items = {
4203 { "Mic", 0x0 },
4204 { "Line", 0x2 },
4205 { "CD", 0x4 },
4206 { "Headphone", 0x5 },
4207 },
4208 },
4209 {
4210 .num_items = 5,
4211 .items = {
4212 { "Mic", 0x0 },
4213 { "Line", 0x2 },
4214 { "CD", 0x4 },
4215 { "Headphone", 0x6 },
4216 { "Mixer", 0x5 },
4217 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004218 },
4219};
Linus Torvalds1da177e2005-04-16 15:20:36 -07004220/*
4221 * This is just place-holder, so there's something for alc_build_pcms to look
4222 * at when it calculates the maximum number of channels. ALC260 has no mixer
4223 * element which allows changing the channel mode, so the verb list is
4224 * never used.
4225 */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01004226static struct hda_channel_mode alc260_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004227 { 2, NULL },
4228};
4229
Kailang Yangdf694da2005-12-05 19:42:22 +01004230
4231/* Mixer combinations
4232 *
4233 * basic: base_output + input + pc_beep + capture
4234 * HP: base_output + input + capture_alt
4235 * HP_3013: hp_3013 + input + capture
4236 * fujitsu: fujitsu + capture
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004237 * acer: acer + capture
Kailang Yangdf694da2005-12-05 19:42:22 +01004238 */
4239
4240static struct snd_kcontrol_new alc260_base_output_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02004241 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01004242 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01004243 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
4244 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
4245 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
4246 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
4247 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004248};
Kailang Yangdf694da2005-12-05 19:42:22 +01004249
4250static struct snd_kcontrol_new alc260_input_mixer[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004251 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4252 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
4253 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
4254 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
4255 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
4256 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
4257 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT),
4258 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004259 { } /* end */
4260};
4261
Kailang Yangdf694da2005-12-05 19:42:22 +01004262static struct snd_kcontrol_new alc260_pc_beep_mixer[] = {
4263 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x07, 0x05, HDA_INPUT),
4264 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x07, 0x05, HDA_INPUT),
4265 { } /* end */
4266};
4267
Takashi Iwaibec15c32008-01-28 18:16:30 +01004268/* update HP, line and mono out pins according to the master switch */
4269static void alc260_hp_master_update(struct hda_codec *codec,
4270 hda_nid_t hp, hda_nid_t line,
4271 hda_nid_t mono)
4272{
4273 struct alc_spec *spec = codec->spec;
4274 unsigned int val = spec->master_sw ? PIN_HP : 0;
4275 /* change HP and line-out pins */
Takashi Iwai30cde0a2008-11-07 14:49:28 +01004276 snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwaibec15c32008-01-28 18:16:30 +01004277 val);
Takashi Iwai30cde0a2008-11-07 14:49:28 +01004278 snd_hda_codec_write(codec, line, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwaibec15c32008-01-28 18:16:30 +01004279 val);
4280 /* mono (speaker) depending on the HP jack sense */
4281 val = (val && !spec->jack_present) ? PIN_OUT : 0;
Takashi Iwai30cde0a2008-11-07 14:49:28 +01004282 snd_hda_codec_write(codec, mono, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwaibec15c32008-01-28 18:16:30 +01004283 val);
4284}
4285
4286static int alc260_hp_master_sw_get(struct snd_kcontrol *kcontrol,
4287 struct snd_ctl_elem_value *ucontrol)
4288{
4289 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4290 struct alc_spec *spec = codec->spec;
4291 *ucontrol->value.integer.value = spec->master_sw;
4292 return 0;
4293}
4294
4295static int alc260_hp_master_sw_put(struct snd_kcontrol *kcontrol,
4296 struct snd_ctl_elem_value *ucontrol)
4297{
4298 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4299 struct alc_spec *spec = codec->spec;
4300 int val = !!*ucontrol->value.integer.value;
4301 hda_nid_t hp, line, mono;
4302
4303 if (val == spec->master_sw)
4304 return 0;
4305 spec->master_sw = val;
4306 hp = (kcontrol->private_value >> 16) & 0xff;
4307 line = (kcontrol->private_value >> 8) & 0xff;
4308 mono = kcontrol->private_value & 0xff;
4309 alc260_hp_master_update(codec, hp, line, mono);
4310 return 1;
4311}
4312
4313static struct snd_kcontrol_new alc260_hp_output_mixer[] = {
4314 {
4315 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4316 .name = "Master Playback Switch",
4317 .info = snd_ctl_boolean_mono_info,
4318 .get = alc260_hp_master_sw_get,
4319 .put = alc260_hp_master_sw_put,
4320 .private_value = (0x0f << 16) | (0x10 << 8) | 0x11
4321 },
4322 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4323 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
4324 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
4325 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
4326 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
4327 HDA_OUTPUT),
4328 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2, HDA_INPUT),
4329 { } /* end */
4330};
4331
4332static struct hda_verb alc260_hp_unsol_verbs[] = {
4333 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
4334 {},
4335};
4336
4337static void alc260_hp_automute(struct hda_codec *codec)
4338{
4339 struct alc_spec *spec = codec->spec;
4340 unsigned int present;
4341
4342 present = snd_hda_codec_read(codec, 0x10, 0,
4343 AC_VERB_GET_PIN_SENSE, 0);
4344 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
4345 alc260_hp_master_update(codec, 0x0f, 0x10, 0x11);
4346}
4347
4348static void alc260_hp_unsol_event(struct hda_codec *codec, unsigned int res)
4349{
4350 if ((res >> 26) == ALC880_HP_EVENT)
4351 alc260_hp_automute(codec);
4352}
4353
Kailang Yangdf694da2005-12-05 19:42:22 +01004354static struct snd_kcontrol_new alc260_hp_3013_mixer[] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01004355 {
4356 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4357 .name = "Master Playback Switch",
4358 .info = snd_ctl_boolean_mono_info,
4359 .get = alc260_hp_master_sw_get,
4360 .put = alc260_hp_master_sw_put,
Takashi Iwai30cde0a2008-11-07 14:49:28 +01004361 .private_value = (0x15 << 16) | (0x10 << 8) | 0x11
Takashi Iwaibec15c32008-01-28 18:16:30 +01004362 },
Kailang Yangdf694da2005-12-05 19:42:22 +01004363 HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT),
4364 HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT),
4365 HDA_CODEC_VOLUME("Aux-In Playback Volume", 0x07, 0x06, HDA_INPUT),
4366 HDA_CODEC_MUTE("Aux-In Playback Switch", 0x07, 0x06, HDA_INPUT),
4367 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4368 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01004369 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
4370 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02004371 { } /* end */
4372};
4373
Kailang Yang3f878302008-08-26 13:02:23 +02004374static struct hda_bind_ctls alc260_dc7600_bind_master_vol = {
4375 .ops = &snd_hda_bind_vol,
4376 .values = {
4377 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_OUTPUT),
4378 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_OUTPUT),
4379 HDA_COMPOSE_AMP_VAL(0x0a, 3, 0, HDA_OUTPUT),
4380 0
4381 },
4382};
4383
4384static struct hda_bind_ctls alc260_dc7600_bind_switch = {
4385 .ops = &snd_hda_bind_sw,
4386 .values = {
4387 HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT),
4388 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
4389 0
4390 },
4391};
4392
4393static struct snd_kcontrol_new alc260_hp_dc7600_mixer[] = {
4394 HDA_BIND_VOL("Master Playback Volume", &alc260_dc7600_bind_master_vol),
4395 HDA_BIND_SW("LineOut Playback Switch", &alc260_dc7600_bind_switch),
4396 HDA_CODEC_MUTE("Speaker Playback Switch", 0x0f, 0x0, HDA_OUTPUT),
4397 HDA_CODEC_MUTE("Headphone Playback Switch", 0x10, 0x0, HDA_OUTPUT),
4398 { } /* end */
4399};
4400
Takashi Iwaibec15c32008-01-28 18:16:30 +01004401static struct hda_verb alc260_hp_3013_unsol_verbs[] = {
4402 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
4403 {},
4404};
4405
4406static void alc260_hp_3013_automute(struct hda_codec *codec)
4407{
4408 struct alc_spec *spec = codec->spec;
4409 unsigned int present;
4410
4411 present = snd_hda_codec_read(codec, 0x15, 0,
4412 AC_VERB_GET_PIN_SENSE, 0);
4413 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
Takashi Iwai30cde0a2008-11-07 14:49:28 +01004414 alc260_hp_master_update(codec, 0x15, 0x10, 0x11);
Takashi Iwaibec15c32008-01-28 18:16:30 +01004415}
4416
4417static void alc260_hp_3013_unsol_event(struct hda_codec *codec,
4418 unsigned int res)
4419{
4420 if ((res >> 26) == ALC880_HP_EVENT)
4421 alc260_hp_3013_automute(codec);
4422}
4423
Kailang Yang3f878302008-08-26 13:02:23 +02004424static void alc260_hp_3012_automute(struct hda_codec *codec)
4425{
4426 unsigned int present, bits;
4427
4428 present = snd_hda_codec_read(codec, 0x10, 0,
4429 AC_VERB_GET_PIN_SENSE, 0) & AC_PINSENSE_PRESENCE;
4430
4431 bits = present ? 0 : PIN_OUT;
4432 snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
4433 bits);
4434 snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
4435 bits);
4436 snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
4437 bits);
4438}
4439
4440static void alc260_hp_3012_unsol_event(struct hda_codec *codec,
4441 unsigned int res)
4442{
4443 if ((res >> 26) == ALC880_HP_EVENT)
4444 alc260_hp_3012_automute(codec);
4445}
4446
4447/* Fujitsu S702x series laptops. ALC260 pin usage: Mic/Line jack = 0x12,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004448 * HP jack = 0x14, CD audio = 0x16, internal speaker = 0x10.
4449 */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01004450static struct snd_kcontrol_new alc260_fujitsu_mixer[] = {
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004451 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01004452 HDA_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004453 ALC_PIN_MODE("Headphone Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004454 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4455 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
4456 HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT),
4457 HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004458 ALC_PIN_MODE("Mic/Line Jack Mode", 0x12, ALC_PIN_DIR_IN),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004459 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
4460 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01004461 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT),
4462 HDA_BIND_MUTE("Speaker Playback Switch", 0x09, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01004463 { } /* end */
4464};
4465
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004466/* Mixer for Acer TravelMate(/Extensa/Aspire) notebooks. Note that current
4467 * versions of the ALC260 don't act on requests to enable mic bias from NID
4468 * 0x0f (used to drive the headphone jack in these laptops). The ALC260
4469 * datasheet doesn't mention this restriction. At this stage it's not clear
4470 * whether this behaviour is intentional or is a hardware bug in chip
4471 * revisions available in early 2006. Therefore for now allow the
4472 * "Headphone Jack Mode" control to span all choices, but if it turns out
4473 * that the lack of mic bias for this NID is intentional we could change the
4474 * mode from ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
4475 *
4476 * In addition, Acer TravelMate(/Extensa/Aspire) notebooks in early 2006
4477 * don't appear to make the mic bias available from the "line" jack, even
4478 * though the NID used for this jack (0x14) can supply it. The theory is
4479 * that perhaps Acer have included blocking capacitors between the ALC260
4480 * and the output jack. If this turns out to be the case for all such
4481 * models the "Line Jack Mode" mode could be changed from ALC_PIN_DIR_INOUT
4482 * to ALC_PIN_DIR_INOUT_NOMICBIAS.
Jonathan Woithebd869482006-11-28 11:35:52 +01004483 *
4484 * The C20x Tablet series have a mono internal speaker which is controlled
4485 * via the chip's Mono sum widget and pin complex, so include the necessary
4486 * controls for such models. On models without a "mono speaker" the control
4487 * won't do anything.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004488 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004489static struct snd_kcontrol_new alc260_acer_mixer[] = {
4490 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4491 HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004492 ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01004493 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
Jonathan Woithebd869482006-11-28 11:35:52 +01004494 HDA_OUTPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01004495 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2,
Jonathan Woithebd869482006-11-28 11:35:52 +01004496 HDA_INPUT),
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004497 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4498 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
4499 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
4500 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
4501 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
4502 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
4503 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
4504 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
4505 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
4506 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
4507 { } /* end */
4508};
4509
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004510/* Packard bell V7900 ALC260 pin usage: HP = 0x0f, Mic jack = 0x12,
4511 * Line In jack = 0x14, CD audio = 0x16, pc beep = 0x17.
4512 */
4513static struct snd_kcontrol_new alc260_will_mixer[] = {
4514 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4515 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
4516 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
4517 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
4518 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
4519 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
4520 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
4521 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
4522 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4523 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
4524 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
4525 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
4526 { } /* end */
4527};
4528
4529/* Replacer 672V ALC260 pin usage: Mic jack = 0x12,
4530 * Line In jack = 0x14, ATAPI Mic = 0x13, speaker = 0x0f.
4531 */
4532static struct snd_kcontrol_new alc260_replacer_672v_mixer[] = {
4533 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4534 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
4535 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
4536 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
4537 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
4538 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x07, 0x1, HDA_INPUT),
4539 HDA_CODEC_MUTE("ATATI Mic Playback Switch", 0x07, 0x1, HDA_INPUT),
4540 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
4541 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
4542 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
4543 { } /* end */
4544};
4545
Kailang Yangdf694da2005-12-05 19:42:22 +01004546/*
4547 * initialization verbs
4548 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004549static struct hda_verb alc260_init_verbs[] = {
4550 /* Line In pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02004551 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004552 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02004553 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004554 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02004555 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004556 /* Mic2 (front panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02004557 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004558 /* LINE-2 is used for line-out in rear */
Takashi Iwai05acb862005-06-10 19:50:25 +02004559 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004560 /* select line-out */
Jonathan Woithefd56f2d2006-01-24 10:35:46 +01004561 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004562 /* LINE-OUT pin */
Takashi Iwai05acb862005-06-10 19:50:25 +02004563 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004564 /* enable HP */
Takashi Iwai05acb862005-06-10 19:50:25 +02004565 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004566 /* enable Mono */
Takashi Iwai05acb862005-06-10 19:50:25 +02004567 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4568 /* mute capture amp left and right */
Takashi Iwai16ded522005-06-10 19:58:24 +02004569 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004570 /* set connection select to line in (default select for this ADC) */
4571 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai16ded522005-06-10 19:58:24 +02004572 /* mute capture amp left and right */
4573 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4574 /* set connection select to line in (default select for this ADC) */
4575 {0x05, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai05acb862005-06-10 19:50:25 +02004576 /* set vol=0 Line-Out mixer amp left and right */
4577 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4578 /* unmute pin widget amp left and right (no gain on this amp) */
4579 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4580 /* set vol=0 HP mixer amp left and right */
4581 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4582 /* unmute pin widget amp left and right (no gain on this amp) */
4583 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4584 /* set vol=0 Mono mixer amp left and right */
4585 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4586 /* unmute pin widget amp left and right (no gain on this amp) */
4587 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4588 /* unmute LINE-2 out pin */
4589 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004590 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
4591 * Line In 2 = 0x03
4592 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02004593 /* mute analog inputs */
4594 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4595 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4596 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4597 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4598 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004599 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
Takashi Iwai05acb862005-06-10 19:50:25 +02004600 /* mute Front out path */
4601 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4602 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4603 /* mute Headphone out path */
4604 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4605 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4606 /* mute Mono out path */
4607 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4608 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004609 { }
4610};
4611
Takashi Iwai474167d2006-05-17 17:17:43 +02004612#if 0 /* should be identical with alc260_init_verbs? */
Kailang Yangdf694da2005-12-05 19:42:22 +01004613static struct hda_verb alc260_hp_init_verbs[] = {
4614 /* Headphone and output */
4615 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
4616 /* mono output */
4617 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4618 /* Mic1 (rear panel) pin widget for input and vref at 80% */
4619 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4620 /* Mic2 (front panel) pin widget for input and vref at 80% */
4621 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4622 /* Line In pin widget for input */
4623 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4624 /* Line-2 pin widget for output */
4625 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4626 /* CD pin widget for input */
4627 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4628 /* unmute amp left and right */
4629 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
4630 /* set connection select to line in (default select for this ADC) */
4631 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
4632 /* unmute Line-Out mixer amp left and right (volume = 0) */
4633 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
4634 /* mute pin widget amp left and right (no gain on this amp) */
4635 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
4636 /* unmute HP mixer amp left and right (volume = 0) */
4637 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
4638 /* mute pin widget amp left and right (no gain on this amp) */
4639 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004640 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
4641 * Line In 2 = 0x03
4642 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02004643 /* mute analog inputs */
4644 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4645 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4646 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4647 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4648 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01004649 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
4650 /* Unmute Front out path */
4651 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4652 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4653 /* Unmute Headphone out path */
4654 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4655 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4656 /* Unmute Mono out path */
4657 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4658 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4659 { }
4660};
Takashi Iwai474167d2006-05-17 17:17:43 +02004661#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01004662
4663static struct hda_verb alc260_hp_3013_init_verbs[] = {
4664 /* Line out and output */
4665 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4666 /* mono output */
4667 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4668 /* Mic1 (rear panel) pin widget for input and vref at 80% */
4669 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4670 /* Mic2 (front panel) pin widget for input and vref at 80% */
4671 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4672 /* Line In pin widget for input */
4673 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4674 /* Headphone pin widget for output */
4675 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
4676 /* CD pin widget for input */
4677 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4678 /* unmute amp left and right */
4679 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
4680 /* set connection select to line in (default select for this ADC) */
4681 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
4682 /* unmute Line-Out mixer amp left and right (volume = 0) */
4683 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
4684 /* mute pin widget amp left and right (no gain on this amp) */
4685 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
4686 /* unmute HP mixer amp left and right (volume = 0) */
4687 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
4688 /* mute pin widget amp left and right (no gain on this amp) */
4689 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004690 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
4691 * Line In 2 = 0x03
4692 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02004693 /* mute analog inputs */
4694 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4695 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4696 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4697 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4698 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01004699 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
4700 /* Unmute Front out path */
4701 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4702 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4703 /* Unmute Headphone out path */
4704 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4705 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4706 /* Unmute Mono out path */
4707 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4708 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4709 { }
4710};
4711
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004712/* Initialisation sequence for ALC260 as configured in Fujitsu S702x
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004713 * laptops. ALC260 pin usage: Mic/Line jack = 0x12, HP jack = 0x14, CD
4714 * audio = 0x16, internal speaker = 0x10.
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004715 */
4716static struct hda_verb alc260_fujitsu_init_verbs[] = {
4717 /* Disable all GPIOs */
4718 {0x01, AC_VERB_SET_GPIO_MASK, 0},
4719 /* Internal speaker is connected to headphone pin */
4720 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4721 /* Headphone/Line-out jack connects to Line1 pin; make it an output */
4722 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Jonathan Woithef7ace402006-02-28 11:46:14 +01004723 /* Mic/Line-in jack is connected to mic1 pin, so make it an input */
4724 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4725 /* Ensure all other unused pins are disabled and muted. */
4726 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4727 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004728 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01004729 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004730 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01004731 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4732 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4733 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004734
Jonathan Woithef7ace402006-02-28 11:46:14 +01004735 /* Disable digital (SPDIF) pins */
4736 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
4737 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004738
Kailang Yangea1fb292008-08-26 12:58:38 +02004739 /* Ensure Line1 pin widget takes its input from the OUT1 sum bus
Jonathan Woithef7ace402006-02-28 11:46:14 +01004740 * when acting as an output.
4741 */
4742 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
4743
4744 /* Start with output sum widgets muted and their output gains at min */
Takashi Iwai8b33a5a2006-02-09 11:57:01 +01004745 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4746 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4747 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4748 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4749 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4750 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4751 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4752 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4753 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004754
Jonathan Woithef7ace402006-02-28 11:46:14 +01004755 /* Unmute HP pin widget amp left and right (no equiv mixer ctrl) */
4756 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4757 /* Unmute Line1 pin widget output buffer since it starts as an output.
4758 * If the pin mode is changed by the user the pin mode control will
4759 * take care of enabling the pin's input/output buffers as needed.
4760 * Therefore there's no need to enable the input buffer at this
4761 * stage.
Jonathan Woithecdcd9262006-02-28 11:36:42 +01004762 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01004763 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +02004764 /* Unmute input buffer of pin widget used for Line-in (no equiv
Jonathan Woithecdcd9262006-02-28 11:36:42 +01004765 * mixer ctrl)
4766 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01004767 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004768
Jonathan Woithef7ace402006-02-28 11:46:14 +01004769 /* Mute capture amp left and right */
4770 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +02004771 /* Set ADC connection select to match default mixer setting - line
Jonathan Woithef7ace402006-02-28 11:46:14 +01004772 * in (on mic1 pin)
4773 */
4774 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004775
Jonathan Woithef7ace402006-02-28 11:46:14 +01004776 /* Do the same for the second ADC: mute capture input amp and
4777 * set ADC connection to line in (on mic1 pin)
4778 */
4779 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4780 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004781
Jonathan Woithef7ace402006-02-28 11:46:14 +01004782 /* Mute all inputs to mixer widget (even unconnected ones) */
4783 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
4784 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
4785 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
4786 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
4787 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
4788 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
4789 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
4790 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
Takashi Iwai4a471b72005-12-07 13:56:29 +01004791
4792 { }
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004793};
4794
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004795/* Initialisation sequence for ALC260 as configured in Acer TravelMate and
4796 * similar laptops (adapted from Fujitsu init verbs).
4797 */
4798static struct hda_verb alc260_acer_init_verbs[] = {
4799 /* On TravelMate laptops, GPIO 0 enables the internal speaker and
4800 * the headphone jack. Turn this on and rely on the standard mute
4801 * methods whenever the user wants to turn these outputs off.
4802 */
4803 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
4804 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
4805 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
4806 /* Internal speaker/Headphone jack is connected to Line-out pin */
4807 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4808 /* Internal microphone/Mic jack is connected to Mic1 pin */
4809 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
4810 /* Line In jack is connected to Line1 pin */
4811 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Jonathan Woithebd869482006-11-28 11:35:52 +01004812 /* Some Acers (eg: C20x Tablets) use Mono pin for internal speaker */
4813 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004814 /* Ensure all other unused pins are disabled and muted. */
4815 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4816 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004817 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4818 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4819 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4820 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4821 /* Disable digital (SPDIF) pins */
4822 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
4823 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
4824
Kailang Yangea1fb292008-08-26 12:58:38 +02004825 /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004826 * bus when acting as outputs.
4827 */
4828 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
4829 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
4830
4831 /* Start with output sum widgets muted and their output gains at min */
4832 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4833 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4834 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4835 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4836 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4837 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4838 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4839 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4840 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4841
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004842 /* Unmute Line-out pin widget amp left and right
4843 * (no equiv mixer ctrl)
4844 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004845 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithebd869482006-11-28 11:35:52 +01004846 /* Unmute mono pin widget amp output (no equiv mixer ctrl) */
4847 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004848 /* Unmute Mic1 and Line1 pin widget input buffers since they start as
4849 * inputs. If the pin mode is changed by the user the pin mode control
4850 * will take care of enabling the pin's input/output buffers as needed.
4851 * Therefore there's no need to enable the input buffer at this
4852 * stage.
4853 */
4854 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4855 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4856
4857 /* Mute capture amp left and right */
4858 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4859 /* Set ADC connection select to match default mixer setting - mic
4860 * (on mic1 pin)
4861 */
4862 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
4863
4864 /* Do similar with the second ADC: mute capture input amp and
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004865 * set ADC connection to mic to match ALSA's default state.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004866 */
4867 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004868 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004869
4870 /* Mute all inputs to mixer widget (even unconnected ones) */
4871 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
4872 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
4873 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
4874 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
4875 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
4876 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
4877 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
4878 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
4879
4880 { }
4881};
4882
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004883static struct hda_verb alc260_will_verbs[] = {
4884 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4885 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x00},
4886 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
4887 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
4888 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
4889 {0x1a, AC_VERB_SET_PROC_COEF, 0x3040},
4890 {}
4891};
4892
4893static struct hda_verb alc260_replacer_672v_verbs[] = {
4894 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
4895 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
4896 {0x1a, AC_VERB_SET_PROC_COEF, 0x3050},
4897
4898 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
4899 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
4900 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
4901
4902 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
4903 {}
4904};
4905
4906/* toggle speaker-output according to the hp-jack state */
4907static void alc260_replacer_672v_automute(struct hda_codec *codec)
4908{
4909 unsigned int present;
4910
4911 /* speaker --> GPIO Data 0, hp or spdif --> GPIO data 1 */
4912 present = snd_hda_codec_read(codec, 0x0f, 0,
4913 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
4914 if (present) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02004915 snd_hda_codec_write_cache(codec, 0x01, 0,
4916 AC_VERB_SET_GPIO_DATA, 1);
4917 snd_hda_codec_write_cache(codec, 0x0f, 0,
4918 AC_VERB_SET_PIN_WIDGET_CONTROL,
4919 PIN_HP);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004920 } else {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02004921 snd_hda_codec_write_cache(codec, 0x01, 0,
4922 AC_VERB_SET_GPIO_DATA, 0);
4923 snd_hda_codec_write_cache(codec, 0x0f, 0,
4924 AC_VERB_SET_PIN_WIDGET_CONTROL,
4925 PIN_OUT);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004926 }
4927}
4928
4929static void alc260_replacer_672v_unsol_event(struct hda_codec *codec,
4930 unsigned int res)
4931{
4932 if ((res >> 26) == ALC880_HP_EVENT)
4933 alc260_replacer_672v_automute(codec);
4934}
4935
Kailang Yang3f878302008-08-26 13:02:23 +02004936static struct hda_verb alc260_hp_dc7600_verbs[] = {
4937 {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
4938 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
4939 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4940 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4941 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4942 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4943 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4944 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
4945 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
4946 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
4947 {}
4948};
4949
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004950/* Test configuration for debugging, modelled after the ALC880 test
4951 * configuration.
4952 */
4953#ifdef CONFIG_SND_DEBUG
4954static hda_nid_t alc260_test_dac_nids[1] = {
4955 0x02,
4956};
4957static hda_nid_t alc260_test_adc_nids[2] = {
4958 0x04, 0x05,
4959};
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004960/* For testing the ALC260, each input MUX needs its own definition since
Kailang Yangea1fb292008-08-26 12:58:38 +02004961 * the signal assignments are different. This assumes that the first ADC
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004962 * is NID 0x04.
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01004963 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004964static struct hda_input_mux alc260_test_capture_sources[2] = {
4965 {
4966 .num_items = 7,
4967 .items = {
4968 { "MIC1 pin", 0x0 },
4969 { "MIC2 pin", 0x1 },
4970 { "LINE1 pin", 0x2 },
4971 { "LINE2 pin", 0x3 },
4972 { "CD pin", 0x4 },
4973 { "LINE-OUT pin", 0x5 },
4974 { "HP-OUT pin", 0x6 },
4975 },
4976 },
4977 {
4978 .num_items = 8,
4979 .items = {
4980 { "MIC1 pin", 0x0 },
4981 { "MIC2 pin", 0x1 },
4982 { "LINE1 pin", 0x2 },
4983 { "LINE2 pin", 0x3 },
4984 { "CD pin", 0x4 },
4985 { "Mixer", 0x5 },
4986 { "LINE-OUT pin", 0x6 },
4987 { "HP-OUT pin", 0x7 },
4988 },
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004989 },
4990};
4991static struct snd_kcontrol_new alc260_test_mixer[] = {
4992 /* Output driver widgets */
4993 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
4994 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
4995 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x09, 0x0, HDA_OUTPUT),
4996 HDA_BIND_MUTE("LOUT2 Playback Switch", 0x09, 2, HDA_INPUT),
4997 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4998 HDA_BIND_MUTE("LOUT1 Playback Switch", 0x08, 2, HDA_INPUT),
4999
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005000 /* Modes for retasking pin widgets
5001 * Note: the ALC260 doesn't seem to act on requests to enable mic
5002 * bias from NIDs 0x0f and 0x10. The ALC260 datasheet doesn't
5003 * mention this restriction. At this stage it's not clear whether
5004 * this behaviour is intentional or is a hardware bug in chip
5005 * revisions available at least up until early 2006. Therefore for
5006 * now allow the "HP-OUT" and "LINE-OUT" Mode controls to span all
5007 * choices, but if it turns out that the lack of mic bias for these
5008 * NIDs is intentional we could change their modes from
5009 * ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
5010 */
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005011 ALC_PIN_MODE("HP-OUT pin mode", 0x10, ALC_PIN_DIR_INOUT),
5012 ALC_PIN_MODE("LINE-OUT pin mode", 0x0f, ALC_PIN_DIR_INOUT),
5013 ALC_PIN_MODE("LINE2 pin mode", 0x15, ALC_PIN_DIR_INOUT),
5014 ALC_PIN_MODE("LINE1 pin mode", 0x14, ALC_PIN_DIR_INOUT),
5015 ALC_PIN_MODE("MIC2 pin mode", 0x13, ALC_PIN_DIR_INOUT),
5016 ALC_PIN_MODE("MIC1 pin mode", 0x12, ALC_PIN_DIR_INOUT),
5017
5018 /* Loopback mixer controls */
5019 HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x07, 0x00, HDA_INPUT),
5020 HDA_CODEC_MUTE("MIC1 Playback Switch", 0x07, 0x00, HDA_INPUT),
5021 HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x07, 0x01, HDA_INPUT),
5022 HDA_CODEC_MUTE("MIC2 Playback Switch", 0x07, 0x01, HDA_INPUT),
5023 HDA_CODEC_VOLUME("LINE1 Playback Volume", 0x07, 0x02, HDA_INPUT),
5024 HDA_CODEC_MUTE("LINE1 Playback Switch", 0x07, 0x02, HDA_INPUT),
5025 HDA_CODEC_VOLUME("LINE2 Playback Volume", 0x07, 0x03, HDA_INPUT),
5026 HDA_CODEC_MUTE("LINE2 Playback Switch", 0x07, 0x03, HDA_INPUT),
5027 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
5028 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
5029 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
5030 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
5031 HDA_CODEC_VOLUME("LINE-OUT loopback Playback Volume", 0x07, 0x06, HDA_INPUT),
5032 HDA_CODEC_MUTE("LINE-OUT loopback Playback Switch", 0x07, 0x06, HDA_INPUT),
5033 HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x07, 0x7, HDA_INPUT),
5034 HDA_CODEC_MUTE("HP-OUT loopback Playback Switch", 0x07, 0x7, HDA_INPUT),
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01005035
5036 /* Controls for GPIO pins, assuming they are configured as outputs */
5037 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
5038 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
5039 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
5040 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
5041
Jonathan Woithe92621f12006-02-28 11:47:47 +01005042 /* Switches to allow the digital IO pins to be enabled. The datasheet
5043 * is ambigious as to which NID is which; testing on laptops which
Kailang Yangea1fb292008-08-26 12:58:38 +02005044 * make this output available should provide clarification.
Jonathan Woithe92621f12006-02-28 11:47:47 +01005045 */
5046 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x03, 0x01),
5047 ALC_SPDIF_CTRL_SWITCH("SPDIF Capture Switch", 0x06, 0x01),
5048
Jonathan Woithef8225f62008-01-08 12:16:54 +01005049 /* A switch allowing EAPD to be enabled. Some laptops seem to use
5050 * this output to turn on an external amplifier.
5051 */
5052 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
5053 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
5054
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005055 { } /* end */
5056};
5057static struct hda_verb alc260_test_init_verbs[] = {
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01005058 /* Enable all GPIOs as outputs with an initial value of 0 */
5059 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f},
5060 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
5061 {0x01, AC_VERB_SET_GPIO_MASK, 0x0f},
5062
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005063 /* Enable retasking pins as output, initially without power amp */
5064 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5065 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5066 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5067 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5068 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5069 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5070
Jonathan Woithe92621f12006-02-28 11:47:47 +01005071 /* Disable digital (SPDIF) pins initially, but users can enable
5072 * them via a mixer switch. In the case of SPDIF-out, this initverb
5073 * payload also sets the generation to 0, output to be in "consumer"
5074 * PCM format, copyright asserted, no pre-emphasis and no validity
5075 * control.
5076 */
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005077 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
5078 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
5079
Kailang Yangea1fb292008-08-26 12:58:38 +02005080 /* Ensure mic1, mic2, line1 and line2 pin widgets take input from the
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005081 * OUT1 sum bus when acting as an output.
5082 */
5083 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
5084 {0x0c, AC_VERB_SET_CONNECT_SEL, 0},
5085 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
5086 {0x0e, AC_VERB_SET_CONNECT_SEL, 0},
5087
5088 /* Start with output sum widgets muted and their output gains at min */
5089 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5090 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5091 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5092 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5093 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5094 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5095 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5096 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5097 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5098
Jonathan Woithecdcd9262006-02-28 11:36:42 +01005099 /* Unmute retasking pin widget output buffers since the default
5100 * state appears to be output. As the pin mode is changed by the
5101 * user the pin mode control will take care of enabling the pin's
5102 * input/output buffers as needed.
5103 */
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005104 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5105 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5106 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5107 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5108 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5109 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5110 /* Also unmute the mono-out pin widget */
5111 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5112
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005113 /* Mute capture amp left and right */
5114 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithef7ace402006-02-28 11:46:14 +01005115 /* Set ADC connection select to match default mixer setting (mic1
5116 * pin)
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005117 */
5118 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
5119
5120 /* Do the same for the second ADC: mute capture input amp and
Jonathan Woithef7ace402006-02-28 11:46:14 +01005121 * set ADC connection to mic1 pin
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005122 */
5123 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5124 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
5125
5126 /* Mute all inputs to mixer widget (even unconnected ones) */
5127 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
5128 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
5129 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
5130 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
5131 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
5132 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
5133 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
5134 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
5135
5136 { }
5137};
5138#endif
5139
Takashi Iwai63300792008-01-24 15:31:36 +01005140#define alc260_pcm_analog_playback alc880_pcm_analog_alt_playback
5141#define alc260_pcm_analog_capture alc880_pcm_analog_capture
Linus Torvalds1da177e2005-04-16 15:20:36 -07005142
Takashi Iwaia3bcba32005-12-06 19:05:29 +01005143#define alc260_pcm_digital_playback alc880_pcm_digital_playback
5144#define alc260_pcm_digital_capture alc880_pcm_digital_capture
5145
Kailang Yangdf694da2005-12-05 19:42:22 +01005146/*
5147 * for BIOS auto-configuration
5148 */
5149
5150static int alc260_add_playback_controls(struct alc_spec *spec, hda_nid_t nid,
Takashi Iwai863b4512008-10-21 17:01:47 +02005151 const char *pfx, int *vol_bits)
Kailang Yangdf694da2005-12-05 19:42:22 +01005152{
5153 hda_nid_t nid_vol;
5154 unsigned long vol_val, sw_val;
5155 char name[32];
5156 int err;
5157
5158 if (nid >= 0x0f && nid < 0x11) {
5159 nid_vol = nid - 0x7;
5160 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
5161 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
5162 } else if (nid == 0x11) {
5163 nid_vol = nid - 0x7;
5164 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT);
5165 sw_val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
5166 } else if (nid >= 0x12 && nid <= 0x15) {
5167 nid_vol = 0x08;
5168 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
5169 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
5170 } else
5171 return 0; /* N/A */
Kailang Yangea1fb292008-08-26 12:58:38 +02005172
Takashi Iwai863b4512008-10-21 17:01:47 +02005173 if (!(*vol_bits & (1 << nid_vol))) {
5174 /* first control for the volume widget */
5175 snprintf(name, sizeof(name), "%s Playback Volume", pfx);
5176 err = add_control(spec, ALC_CTL_WIDGET_VOL, name, vol_val);
5177 if (err < 0)
5178 return err;
5179 *vol_bits |= (1 << nid_vol);
5180 }
Kailang Yangdf694da2005-12-05 19:42:22 +01005181 snprintf(name, sizeof(name), "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005182 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, sw_val);
5183 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01005184 return err;
5185 return 1;
5186}
5187
5188/* add playback controls from the parsed DAC table */
5189static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec,
5190 const struct auto_pin_cfg *cfg)
5191{
5192 hda_nid_t nid;
5193 int err;
Takashi Iwai863b4512008-10-21 17:01:47 +02005194 int vols = 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01005195
5196 spec->multiout.num_dacs = 1;
5197 spec->multiout.dac_nids = spec->private_dac_nids;
5198 spec->multiout.dac_nids[0] = 0x02;
5199
5200 nid = cfg->line_out_pins[0];
5201 if (nid) {
Takashi Iwai863b4512008-10-21 17:01:47 +02005202 err = alc260_add_playback_controls(spec, nid, "Front", &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01005203 if (err < 0)
5204 return err;
5205 }
5206
Takashi Iwai82bc9552006-03-21 11:24:42 +01005207 nid = cfg->speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01005208 if (nid) {
Takashi Iwai863b4512008-10-21 17:01:47 +02005209 err = alc260_add_playback_controls(spec, nid, "Speaker", &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01005210 if (err < 0)
5211 return err;
5212 }
5213
Takashi Iwaieb06ed82006-09-20 17:10:27 +02005214 nid = cfg->hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01005215 if (nid) {
Takashi Iwai863b4512008-10-21 17:01:47 +02005216 err = alc260_add_playback_controls(spec, nid, "Headphone",
5217 &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01005218 if (err < 0)
5219 return err;
5220 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005221 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01005222}
5223
5224/* create playback/capture controls for input pins */
5225static int alc260_auto_create_analog_input_ctls(struct alc_spec *spec,
5226 const struct auto_pin_cfg *cfg)
5227{
Kailang Yangdf694da2005-12-05 19:42:22 +01005228 struct hda_input_mux *imux = &spec->private_imux;
5229 int i, err, idx;
5230
5231 for (i = 0; i < AUTO_PIN_LAST; i++) {
5232 if (cfg->input_pins[i] >= 0x12) {
5233 idx = cfg->input_pins[i] - 0x12;
Takashi Iwai4a471b72005-12-07 13:56:29 +01005234 err = new_analog_input(spec, cfg->input_pins[i],
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005235 auto_pin_cfg_labels[i], idx,
5236 0x07);
Kailang Yangdf694da2005-12-05 19:42:22 +01005237 if (err < 0)
5238 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005239 imux->items[imux->num_items].label =
5240 auto_pin_cfg_labels[i];
Kailang Yangdf694da2005-12-05 19:42:22 +01005241 imux->items[imux->num_items].index = idx;
5242 imux->num_items++;
5243 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005244 if (cfg->input_pins[i] >= 0x0f && cfg->input_pins[i] <= 0x10){
Kailang Yangdf694da2005-12-05 19:42:22 +01005245 idx = cfg->input_pins[i] - 0x09;
Takashi Iwai4a471b72005-12-07 13:56:29 +01005246 err = new_analog_input(spec, cfg->input_pins[i],
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005247 auto_pin_cfg_labels[i], idx,
5248 0x07);
Kailang Yangdf694da2005-12-05 19:42:22 +01005249 if (err < 0)
5250 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005251 imux->items[imux->num_items].label =
5252 auto_pin_cfg_labels[i];
Kailang Yangdf694da2005-12-05 19:42:22 +01005253 imux->items[imux->num_items].index = idx;
5254 imux->num_items++;
5255 }
5256 }
5257 return 0;
5258}
5259
5260static void alc260_auto_set_output_and_unmute(struct hda_codec *codec,
5261 hda_nid_t nid, int pin_type,
5262 int sel_idx)
5263{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005264 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01005265 /* need the manual connection? */
5266 if (nid >= 0x12) {
5267 int idx = nid - 0x12;
5268 snd_hda_codec_write(codec, idx + 0x0b, 0,
5269 AC_VERB_SET_CONNECT_SEL, sel_idx);
Kailang Yangdf694da2005-12-05 19:42:22 +01005270 }
5271}
5272
5273static void alc260_auto_init_multi_out(struct hda_codec *codec)
5274{
5275 struct alc_spec *spec = codec->spec;
5276 hda_nid_t nid;
5277
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005278 alc_subsystem_id(codec, 0x10, 0x15, 0x0f);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005279 nid = spec->autocfg.line_out_pins[0];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02005280 if (nid) {
5281 int pin_type = get_pin_type(spec->autocfg.line_out_type);
5282 alc260_auto_set_output_and_unmute(codec, nid, pin_type, 0);
5283 }
Kailang Yangea1fb292008-08-26 12:58:38 +02005284
Takashi Iwai82bc9552006-03-21 11:24:42 +01005285 nid = spec->autocfg.speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01005286 if (nid)
5287 alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
5288
Takashi Iwaieb06ed82006-09-20 17:10:27 +02005289 nid = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01005290 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02005291 alc260_auto_set_output_and_unmute(codec, nid, PIN_HP, 0);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005292}
Kailang Yangdf694da2005-12-05 19:42:22 +01005293
5294#define ALC260_PIN_CD_NID 0x16
5295static void alc260_auto_init_analog_input(struct hda_codec *codec)
5296{
5297 struct alc_spec *spec = codec->spec;
5298 int i;
5299
5300 for (i = 0; i < AUTO_PIN_LAST; i++) {
5301 hda_nid_t nid = spec->autocfg.input_pins[i];
5302 if (nid >= 0x12) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005303 snd_hda_codec_write(codec, nid, 0,
5304 AC_VERB_SET_PIN_WIDGET_CONTROL,
5305 i <= AUTO_PIN_FRONT_MIC ?
5306 PIN_VREF80 : PIN_IN);
Kailang Yangdf694da2005-12-05 19:42:22 +01005307 if (nid != ALC260_PIN_CD_NID)
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005308 snd_hda_codec_write(codec, nid, 0,
5309 AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangdf694da2005-12-05 19:42:22 +01005310 AMP_OUT_MUTE);
5311 }
5312 }
5313}
5314
5315/*
5316 * generic initialization of ADC, input mixers and output mixers
5317 */
5318static struct hda_verb alc260_volume_init_verbs[] = {
5319 /*
5320 * Unmute ADC0-1 and set the default input to mic-in
5321 */
5322 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
5323 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5324 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
5325 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +02005326
Kailang Yangdf694da2005-12-05 19:42:22 +01005327 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
5328 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005329 * Note: PASD motherboards uses the Line In 2 as the input for
5330 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01005331 */
5332 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02005333 /* mute analog inputs */
5334 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5335 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5336 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5337 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5338 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01005339
5340 /*
5341 * Set up output mixers (0x08 - 0x0a)
5342 */
5343 /* set vol=0 to output mixers */
5344 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5345 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5346 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5347 /* set up input amps for analog loopback */
5348 /* Amp Indices: DAC = 0, mixer = 1 */
5349 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5350 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5351 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5352 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5353 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5354 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +02005355
Kailang Yangdf694da2005-12-05 19:42:22 +01005356 { }
5357};
5358
5359static int alc260_parse_auto_config(struct hda_codec *codec)
5360{
5361 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01005362 int err;
5363 static hda_nid_t alc260_ignore[] = { 0x17, 0 };
5364
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005365 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
5366 alc260_ignore);
5367 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01005368 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005369 err = alc260_auto_create_multi_out_ctls(spec, &spec->autocfg);
5370 if (err < 0)
Takashi Iwai4a471b72005-12-07 13:56:29 +01005371 return err;
Takashi Iwai603c4012008-07-30 15:01:44 +02005372 if (!spec->kctls.list)
Kailang Yangdf694da2005-12-05 19:42:22 +01005373 return 0; /* can't find valid BIOS pin config */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005374 err = alc260_auto_create_analog_input_ctls(spec, &spec->autocfg);
5375 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01005376 return err;
5377
5378 spec->multiout.max_channels = 2;
5379
5380 if (spec->autocfg.dig_out_pin)
5381 spec->multiout.dig_out_nid = ALC260_DIGOUT_NID;
Takashi Iwai603c4012008-07-30 15:01:44 +02005382 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +01005383 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +01005384
Takashi Iwaid88897e2008-10-31 15:01:37 +01005385 add_verb(spec, alc260_volume_init_verbs);
Kailang Yangdf694da2005-12-05 19:42:22 +01005386
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005387 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +01005388 spec->input_mux = &spec->private_imux;
5389
Takashi Iwaie044c392008-10-27 16:56:24 +01005390 store_pin_configs(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01005391 return 1;
5392}
5393
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005394/* additional initialization for auto-configuration model */
5395static void alc260_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01005396{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005397 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01005398 alc260_auto_init_multi_out(codec);
5399 alc260_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005400 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02005401 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01005402}
5403
Takashi Iwaicb53c622007-08-10 17:21:45 +02005404#ifdef CONFIG_SND_HDA_POWER_SAVE
5405static struct hda_amp_list alc260_loopbacks[] = {
5406 { 0x07, HDA_INPUT, 0 },
5407 { 0x07, HDA_INPUT, 1 },
5408 { 0x07, HDA_INPUT, 2 },
5409 { 0x07, HDA_INPUT, 3 },
5410 { 0x07, HDA_INPUT, 4 },
5411 { } /* end */
5412};
5413#endif
5414
Kailang Yangdf694da2005-12-05 19:42:22 +01005415/*
5416 * ALC260 configurations
5417 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005418static const char *alc260_models[ALC260_MODEL_LAST] = {
5419 [ALC260_BASIC] = "basic",
5420 [ALC260_HP] = "hp",
5421 [ALC260_HP_3013] = "hp-3013",
Takashi Iwai2922c9a2008-08-27 18:12:42 +02005422 [ALC260_HP_DC7600] = "hp-dc7600",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005423 [ALC260_FUJITSU_S702X] = "fujitsu",
5424 [ALC260_ACER] = "acer",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005425 [ALC260_WILL] = "will",
5426 [ALC260_REPLACER_672V] = "replacer",
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005427#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005428 [ALC260_TEST] = "test",
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005429#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005430 [ALC260_AUTO] = "auto",
5431};
5432
5433static struct snd_pci_quirk alc260_cfg_tbl[] = {
Jonathan Woithebd869482006-11-28 11:35:52 +01005434 SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005435 SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER),
Takashi Iwai9720b712007-03-13 21:46:23 +01005436 SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013),
Takashi Iwaia8a5d062007-03-15 15:10:28 +01005437 SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_HP_3013),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005438 SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013),
Jaroslav Kysela34ec8a02008-07-10 14:49:19 +02005439 SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP_3013),
Kailang Yang3f878302008-08-26 13:02:23 +02005440 SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_DC7600),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005441 SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013),
5442 SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP),
5443 SND_PCI_QUIRK(0x103c, 0x3015, "HP", ALC260_HP),
5444 SND_PCI_QUIRK(0x103c, 0x3016, "HP", ALC260_HP),
5445 SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_BASIC),
5446 SND_PCI_QUIRK(0x104d, 0x81cc, "Sony VAIO", ALC260_BASIC),
5447 SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC),
5448 SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X),
5449 SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005450 SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_REPLACER_672V),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01005451 SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_WILL),
Takashi Iwai16ded522005-06-10 19:58:24 +02005452 {}
5453};
5454
Kailang Yangdf694da2005-12-05 19:42:22 +01005455static struct alc_config_preset alc260_presets[] = {
5456 [ALC260_BASIC] = {
5457 .mixers = { alc260_base_output_mixer,
5458 alc260_input_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005459 alc260_pc_beep_mixer },
Kailang Yangdf694da2005-12-05 19:42:22 +01005460 .init_verbs = { alc260_init_verbs },
5461 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5462 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005463 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
Kailang Yangdf694da2005-12-05 19:42:22 +01005464 .adc_nids = alc260_adc_nids,
5465 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5466 .channel_mode = alc260_modes,
5467 .input_mux = &alc260_capture_source,
5468 },
5469 [ALC260_HP] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01005470 .mixers = { alc260_hp_output_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005471 alc260_input_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01005472 .init_verbs = { alc260_init_verbs,
5473 alc260_hp_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01005474 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5475 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005476 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
5477 .adc_nids = alc260_adc_nids_alt,
Kailang Yangdf694da2005-12-05 19:42:22 +01005478 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5479 .channel_mode = alc260_modes,
5480 .input_mux = &alc260_capture_source,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005481 .unsol_event = alc260_hp_unsol_event,
5482 .init_hook = alc260_hp_automute,
Kailang Yangdf694da2005-12-05 19:42:22 +01005483 },
Kailang Yang3f878302008-08-26 13:02:23 +02005484 [ALC260_HP_DC7600] = {
5485 .mixers = { alc260_hp_dc7600_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005486 alc260_input_mixer },
Kailang Yang3f878302008-08-26 13:02:23 +02005487 .init_verbs = { alc260_init_verbs,
5488 alc260_hp_dc7600_verbs },
5489 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5490 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005491 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
5492 .adc_nids = alc260_adc_nids_alt,
Kailang Yang3f878302008-08-26 13:02:23 +02005493 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5494 .channel_mode = alc260_modes,
5495 .input_mux = &alc260_capture_source,
5496 .unsol_event = alc260_hp_3012_unsol_event,
5497 .init_hook = alc260_hp_3012_automute,
5498 },
Kailang Yangdf694da2005-12-05 19:42:22 +01005499 [ALC260_HP_3013] = {
5500 .mixers = { alc260_hp_3013_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005501 alc260_input_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01005502 .init_verbs = { alc260_hp_3013_init_verbs,
5503 alc260_hp_3013_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01005504 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5505 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005506 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
5507 .adc_nids = alc260_adc_nids_alt,
Kailang Yangdf694da2005-12-05 19:42:22 +01005508 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5509 .channel_mode = alc260_modes,
5510 .input_mux = &alc260_capture_source,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005511 .unsol_event = alc260_hp_3013_unsol_event,
5512 .init_hook = alc260_hp_3013_automute,
Kailang Yangdf694da2005-12-05 19:42:22 +01005513 },
5514 [ALC260_FUJITSU_S702X] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005515 .mixers = { alc260_fujitsu_mixer },
Kailang Yangdf694da2005-12-05 19:42:22 +01005516 .init_verbs = { alc260_fujitsu_init_verbs },
5517 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5518 .dac_nids = alc260_dac_nids,
Jonathan Woithed57fdac2006-02-28 11:38:35 +01005519 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
5520 .adc_nids = alc260_dual_adc_nids,
Kailang Yangdf694da2005-12-05 19:42:22 +01005521 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5522 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005523 .num_mux_defs = ARRAY_SIZE(alc260_fujitsu_capture_sources),
5524 .input_mux = alc260_fujitsu_capture_sources,
Kailang Yangdf694da2005-12-05 19:42:22 +01005525 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005526 [ALC260_ACER] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005527 .mixers = { alc260_acer_mixer },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005528 .init_verbs = { alc260_acer_init_verbs },
5529 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5530 .dac_nids = alc260_dac_nids,
5531 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
5532 .adc_nids = alc260_dual_adc_nids,
5533 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5534 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005535 .num_mux_defs = ARRAY_SIZE(alc260_acer_capture_sources),
5536 .input_mux = alc260_acer_capture_sources,
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005537 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005538 [ALC260_WILL] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005539 .mixers = { alc260_will_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005540 .init_verbs = { alc260_init_verbs, alc260_will_verbs },
5541 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5542 .dac_nids = alc260_dac_nids,
5543 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
5544 .adc_nids = alc260_adc_nids,
5545 .dig_out_nid = ALC260_DIGOUT_NID,
5546 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5547 .channel_mode = alc260_modes,
5548 .input_mux = &alc260_capture_source,
5549 },
5550 [ALC260_REPLACER_672V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005551 .mixers = { alc260_replacer_672v_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005552 .init_verbs = { alc260_init_verbs, alc260_replacer_672v_verbs },
5553 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5554 .dac_nids = alc260_dac_nids,
5555 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
5556 .adc_nids = alc260_adc_nids,
5557 .dig_out_nid = ALC260_DIGOUT_NID,
5558 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5559 .channel_mode = alc260_modes,
5560 .input_mux = &alc260_capture_source,
5561 .unsol_event = alc260_replacer_672v_unsol_event,
5562 .init_hook = alc260_replacer_672v_automute,
5563 },
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005564#ifdef CONFIG_SND_DEBUG
5565 [ALC260_TEST] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005566 .mixers = { alc260_test_mixer },
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005567 .init_verbs = { alc260_test_init_verbs },
5568 .num_dacs = ARRAY_SIZE(alc260_test_dac_nids),
5569 .dac_nids = alc260_test_dac_nids,
5570 .num_adc_nids = ARRAY_SIZE(alc260_test_adc_nids),
5571 .adc_nids = alc260_test_adc_nids,
5572 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5573 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005574 .num_mux_defs = ARRAY_SIZE(alc260_test_capture_sources),
5575 .input_mux = alc260_test_capture_sources,
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005576 },
5577#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01005578};
5579
Linus Torvalds1da177e2005-04-16 15:20:36 -07005580static int patch_alc260(struct hda_codec *codec)
5581{
5582 struct alc_spec *spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01005583 int err, board_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005584
Takashi Iwaie560d8d2005-09-09 14:21:46 +02005585 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005586 if (spec == NULL)
5587 return -ENOMEM;
5588
5589 codec->spec = spec;
5590
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005591 board_config = snd_hda_check_board_config(codec, ALC260_MODEL_LAST,
5592 alc260_models,
5593 alc260_cfg_tbl);
5594 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02005595 snd_printd(KERN_INFO "hda_codec: Unknown model for ALC260, "
5596 "trying auto-probe from BIOS...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01005597 board_config = ALC260_AUTO;
Takashi Iwai16ded522005-06-10 19:58:24 +02005598 }
5599
Kailang Yangdf694da2005-12-05 19:42:22 +01005600 if (board_config == ALC260_AUTO) {
5601 /* automatic parse from the BIOS config */
5602 err = alc260_parse_auto_config(codec);
5603 if (err < 0) {
5604 alc_free(codec);
5605 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005606 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02005607 printk(KERN_INFO
5608 "hda_codec: Cannot set up configuration "
5609 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01005610 board_config = ALC260_BASIC;
5611 }
Takashi Iwai16ded522005-06-10 19:58:24 +02005612 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005613
Kailang Yangdf694da2005-12-05 19:42:22 +01005614 if (board_config != ALC260_AUTO)
5615 setup_preset(spec, &alc260_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005616
5617 spec->stream_name_analog = "ALC260 Analog";
5618 spec->stream_analog_playback = &alc260_pcm_analog_playback;
5619 spec->stream_analog_capture = &alc260_pcm_analog_capture;
5620
Takashi Iwaia3bcba32005-12-06 19:05:29 +01005621 spec->stream_name_digital = "ALC260 Digital";
5622 spec->stream_digital_playback = &alc260_pcm_digital_playback;
5623 spec->stream_digital_capture = &alc260_pcm_digital_capture;
5624
Takashi Iwai4ef0ef12008-11-03 17:47:49 +01005625 if (!spec->adc_nids && spec->input_mux) {
5626 /* check whether NID 0x04 is valid */
5627 unsigned int wcap = get_wcaps(codec, 0x04);
5628 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
5629 /* get type */
5630 if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
5631 spec->adc_nids = alc260_adc_nids_alt;
5632 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt);
5633 } else {
5634 spec->adc_nids = alc260_adc_nids;
5635 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids);
5636 }
5637 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005638 set_capture_mixer(spec);
5639
Takashi Iwai2134ea42008-01-10 16:53:55 +01005640 spec->vmaster_nid = 0x08;
5641
Linus Torvalds1da177e2005-04-16 15:20:36 -07005642 codec->patch_ops = alc_patch_ops;
Kailang Yangdf694da2005-12-05 19:42:22 +01005643 if (board_config == ALC260_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005644 spec->init_hook = alc260_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02005645#ifdef CONFIG_SND_HDA_POWER_SAVE
5646 if (!spec->loopback.amplist)
5647 spec->loopback.amplist = alc260_loopbacks;
5648#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005649
5650 return 0;
5651}
5652
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005653
Linus Torvalds1da177e2005-04-16 15:20:36 -07005654/*
5655 * ALC882 support
5656 *
5657 * ALC882 is almost identical with ALC880 but has cleaner and more flexible
5658 * configuration. Each pin widget can choose any input DACs and a mixer.
5659 * Each ADC is connected from a mixer of all inputs. This makes possible
5660 * 6-channel independent captures.
5661 *
5662 * In addition, an independent DAC for the multi-playback (not used in this
5663 * driver yet).
5664 */
Kailang Yangdf694da2005-12-05 19:42:22 +01005665#define ALC882_DIGOUT_NID 0x06
5666#define ALC882_DIGIN_NID 0x0a
Linus Torvalds1da177e2005-04-16 15:20:36 -07005667
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01005668static struct hda_channel_mode alc882_ch_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005669 { 8, NULL }
5670};
5671
5672static hda_nid_t alc882_dac_nids[4] = {
5673 /* front, rear, clfe, rear_surr */
5674 0x02, 0x03, 0x04, 0x05
5675};
5676
Kailang Yangdf694da2005-12-05 19:42:22 +01005677/* identical with ALC880 */
5678#define alc882_adc_nids alc880_adc_nids
5679#define alc882_adc_nids_alt alc880_adc_nids_alt
Linus Torvalds1da177e2005-04-16 15:20:36 -07005680
Takashi Iwaie1406342008-02-11 18:32:32 +01005681static hda_nid_t alc882_capsrc_nids[3] = { 0x24, 0x23, 0x22 };
5682static hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 };
5683
Linus Torvalds1da177e2005-04-16 15:20:36 -07005684/* input MUX */
5685/* FIXME: should be a matrix-type input source selection */
5686
5687static struct hda_input_mux alc882_capture_source = {
5688 .num_items = 4,
5689 .items = {
5690 { "Mic", 0x0 },
5691 { "Front Mic", 0x1 },
5692 { "Line", 0x2 },
5693 { "CD", 0x4 },
5694 },
5695};
Kailang Yangdf694da2005-12-05 19:42:22 +01005696/*
Kailang Yang272a5272007-05-14 11:00:38 +02005697 * 2ch mode
5698 */
5699static struct hda_verb alc882_3ST_ch2_init[] = {
5700 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
5701 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
5702 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
5703 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
5704 { } /* end */
5705};
5706
5707/*
5708 * 6ch mode
5709 */
5710static struct hda_verb alc882_3ST_ch6_init[] = {
5711 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5712 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
5713 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
5714 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5715 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
5716 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
5717 { } /* end */
5718};
5719
5720static struct hda_channel_mode alc882_3ST_6ch_modes[2] = {
5721 { 2, alc882_3ST_ch2_init },
5722 { 6, alc882_3ST_ch6_init },
5723};
5724
5725/*
Kailang Yangdf694da2005-12-05 19:42:22 +01005726 * 6ch mode
5727 */
5728static struct hda_verb alc882_sixstack_ch6_init[] = {
5729 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
5730 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5731 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5732 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5733 { } /* end */
5734};
5735
5736/*
5737 * 8ch mode
5738 */
5739static struct hda_verb alc882_sixstack_ch8_init[] = {
5740 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5741 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5742 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5743 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5744 { } /* end */
5745};
5746
5747static struct hda_channel_mode alc882_sixstack_modes[2] = {
5748 { 6, alc882_sixstack_ch6_init },
5749 { 8, alc882_sixstack_ch8_init },
5750};
5751
Takashi Iwai87350ad2007-08-16 18:19:38 +02005752/*
5753 * macbook pro ALC885 can switch LineIn to LineOut without loosing Mic
5754 */
5755
5756/*
5757 * 2ch mode
5758 */
5759static struct hda_verb alc885_mbp_ch2_init[] = {
5760 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
5761 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5762 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5763 { } /* end */
5764};
5765
5766/*
5767 * 6ch mode
5768 */
5769static struct hda_verb alc885_mbp_ch6_init[] = {
5770 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5771 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5772 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
5773 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5774 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5775 { } /* end */
5776};
5777
5778static struct hda_channel_mode alc885_mbp_6ch_modes[2] = {
5779 { 2, alc885_mbp_ch2_init },
5780 { 6, alc885_mbp_ch6_init },
5781};
5782
5783
Linus Torvalds1da177e2005-04-16 15:20:36 -07005784/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
5785 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
5786 */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01005787static struct snd_kcontrol_new alc882_base_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02005788 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005789 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02005790 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005791 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02005792 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
5793 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005794 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
5795 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02005796 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005797 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005798 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
5799 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5800 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5801 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5802 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5803 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01005804 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005805 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
5806 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01005807 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005808 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
5809 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
5810 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005811 { } /* end */
5812};
5813
Takashi Iwai87350ad2007-08-16 18:19:38 +02005814static struct snd_kcontrol_new alc885_mbp3_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01005815 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
5816 HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
5817 HDA_CODEC_MUTE ("Speaker Playback Switch", 0x14, 0x00, HDA_OUTPUT),
5818 HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
5819 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5820 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02005821 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
5822 HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01005823 HDA_CODEC_VOLUME("Line Boost", 0x1a, 0x00, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02005824 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT),
5825 { } /* end */
5826};
Kailang Yangbdd148a2007-05-08 15:19:08 +02005827static struct snd_kcontrol_new alc882_w2jc_mixer[] = {
5828 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5829 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
5830 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5831 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5832 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5833 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5834 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5835 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
5836 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
5837 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
5838 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
5839 { } /* end */
5840};
5841
Kailang Yang272a5272007-05-14 11:00:38 +02005842static struct snd_kcontrol_new alc882_targa_mixer[] = {
5843 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5844 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
5845 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
5846 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5847 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5848 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5849 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5850 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5851 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai96fe7cc82007-09-07 10:57:44 +02005852 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02005853 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
5854 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai96fe7cc82007-09-07 10:57:44 +02005855 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02005856 { } /* end */
5857};
5858
5859/* Pin assignment: Front=0x14, HP = 0x15, Front = 0x16, ???
5860 * Front Mic=0x18, Line In = 0x1a, Line In = 0x1b, CD = 0x1c
5861 */
5862static struct snd_kcontrol_new alc882_asus_a7j_mixer[] = {
5863 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5864 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
5865 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
5866 HDA_CODEC_MUTE("Mobile Front Playback Switch", 0x16, 0x0, HDA_OUTPUT),
5867 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5868 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5869 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5870 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5871 HDA_CODEC_VOLUME("Mobile Line Playback Volume", 0x0b, 0x03, HDA_INPUT),
5872 HDA_CODEC_MUTE("Mobile Line Playback Switch", 0x0b, 0x03, HDA_INPUT),
5873 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5874 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai96fe7cc82007-09-07 10:57:44 +02005875 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02005876 { } /* end */
5877};
5878
Takashi Iwai914759b2007-09-06 14:52:04 +02005879static struct snd_kcontrol_new alc882_asus_a7m_mixer[] = {
5880 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5881 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
5882 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
5883 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5884 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5885 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5886 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5887 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5888 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
5889 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
5890 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
5891 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
5892 { } /* end */
5893};
5894
Kailang Yangdf694da2005-12-05 19:42:22 +01005895static struct snd_kcontrol_new alc882_chmode_mixer[] = {
5896 {
5897 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5898 .name = "Channel Mode",
5899 .info = alc_ch_mode_info,
5900 .get = alc_ch_mode_get,
5901 .put = alc_ch_mode_put,
5902 },
5903 { } /* end */
5904};
5905
Linus Torvalds1da177e2005-04-16 15:20:36 -07005906static struct hda_verb alc882_init_verbs[] = {
5907 /* Front mixer: unmute input/output amp left and right (volume = 0) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005908 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5909 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5910 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005911 /* Rear mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02005912 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5913 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5914 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005915 /* CLFE mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02005916 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5917 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5918 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005919 /* Side mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02005920 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5921 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5922 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005923
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005924 /* Front Pin: output 0 (0x0c) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005925 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02005926 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005927 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005928 /* Rear Pin: output 1 (0x0d) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005929 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02005930 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005931 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005932 /* CLFE Pin: output 2 (0x0e) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005933 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02005934 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005935 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005936 /* Side Pin: output 3 (0x0f) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005937 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02005938 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005939 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005940 /* Mic (rear) pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02005941 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005942 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5943 /* Front Mic pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02005944 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005945 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5946 /* Line In pin: input */
Takashi Iwai05acb862005-06-10 19:50:25 +02005947 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005948 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5949 /* Line-2 In: Headphone output (output 0 - 0x0c) */
5950 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5951 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5952 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005953 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02005954 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005955
5956 /* FIXME: use matrix-type input source selection */
5957 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
5958 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
Takashi Iwai05acb862005-06-10 19:50:25 +02005959 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5960 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5961 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5962 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005963 /* Input mixer2 */
Takashi Iwai05acb862005-06-10 19:50:25 +02005964 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5965 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5966 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5967 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005968 /* Input mixer3 */
Takashi Iwai05acb862005-06-10 19:50:25 +02005969 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5970 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5971 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5972 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5973 /* ADC1: mute amp left and right */
5974 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02005975 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02005976 /* ADC2: mute amp left and right */
5977 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02005978 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02005979 /* ADC3: mute amp left and right */
5980 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02005981 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005982
5983 { }
5984};
5985
Takashi Iwai4b146cb2006-07-28 14:42:36 +02005986static struct hda_verb alc882_eapd_verbs[] = {
5987 /* change to EAPD mode */
5988 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01005989 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005990 { }
Takashi Iwai4b146cb2006-07-28 14:42:36 +02005991};
5992
Tobin Davis9102cd12006-12-15 10:02:12 +01005993/* Mac Pro test */
5994static struct snd_kcontrol_new alc882_macpro_mixer[] = {
5995 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5996 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
5997 HDA_CODEC_MUTE("Headphone Playback Switch", 0x18, 0x0, HDA_OUTPUT),
5998 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
5999 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
6000 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x02, HDA_INPUT),
6001 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x02, HDA_INPUT),
6002 { } /* end */
6003};
6004
6005static struct hda_verb alc882_macpro_init_verbs[] = {
6006 /* Front mixer: unmute input/output amp left and right (volume = 0) */
6007 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6008 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6009 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6010 /* Front Pin: output 0 (0x0c) */
6011 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6012 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6013 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
6014 /* Front Mic pin: input vref at 80% */
6015 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
6016 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6017 /* Speaker: output */
6018 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6019 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6020 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x04},
6021 /* Headphone output (output 0 - 0x0c) */
6022 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6023 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6024 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
6025
6026 /* FIXME: use matrix-type input source selection */
6027 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
6028 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
6029 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6030 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6031 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6032 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6033 /* Input mixer2 */
6034 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6035 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6036 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6037 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6038 /* Input mixer3 */
6039 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6040 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6041 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6042 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6043 /* ADC1: mute amp left and right */
6044 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6045 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
6046 /* ADC2: mute amp left and right */
6047 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6048 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
6049 /* ADC3: mute amp left and right */
6050 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6051 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
6052
6053 { }
6054};
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006055
Takashi Iwai87350ad2007-08-16 18:19:38 +02006056/* Macbook Pro rev3 */
6057static struct hda_verb alc885_mbp3_init_verbs[] = {
6058 /* Front mixer: unmute input/output amp left and right (volume = 0) */
6059 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6060 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6061 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6062 /* Rear mixer */
6063 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6064 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6065 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6066 /* Front Pin: output 0 (0x0c) */
6067 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6068 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6069 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
6070 /* HP Pin: output 0 (0x0d) */
6071 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
6072 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6073 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
6074 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
6075 /* Mic (rear) pin: input vref at 80% */
6076 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
6077 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6078 /* Front Mic pin: input vref at 80% */
6079 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
6080 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6081 /* Line In pin: use output 1 when in LineOut mode */
6082 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
6083 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6084 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
6085
6086 /* FIXME: use matrix-type input source selection */
6087 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
6088 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
6089 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6090 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6091 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6092 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6093 /* Input mixer2 */
6094 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6095 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6096 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6097 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6098 /* Input mixer3 */
6099 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6100 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6101 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6102 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6103 /* ADC1: mute amp left and right */
6104 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6105 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
6106 /* ADC2: mute amp left and right */
6107 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6108 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
6109 /* ADC3: mute amp left and right */
6110 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6111 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
6112
6113 { }
6114};
6115
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006116/* iMac 24 mixer. */
6117static struct snd_kcontrol_new alc885_imac24_mixer[] = {
6118 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
6119 HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x00, HDA_INPUT),
6120 { } /* end */
6121};
6122
6123/* iMac 24 init verbs. */
6124static struct hda_verb alc885_imac24_init_verbs[] = {
6125 /* Internal speakers: output 0 (0x0c) */
6126 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6127 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6128 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
6129 /* Internal speakers: output 0 (0x0c) */
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, 0x00},
6133 /* Headphone: output 0 (0x0c) */
6134 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6135 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6136 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
6137 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
6138 /* Front Mic: input vref at 80% */
6139 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
6140 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6141 { }
6142};
6143
6144/* Toggle speaker-output according to the hp-jack state */
6145static void alc885_imac24_automute(struct hda_codec *codec)
6146{
6147 unsigned int present;
6148
6149 present = snd_hda_codec_read(codec, 0x14, 0,
6150 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02006151 snd_hda_codec_amp_stereo(codec, 0x18, HDA_OUTPUT, 0,
6152 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
6153 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0,
6154 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006155}
6156
6157/* Processes unsolicited events. */
6158static void alc885_imac24_unsol_event(struct hda_codec *codec,
6159 unsigned int res)
6160{
6161 /* Headphone insertion or removal. */
6162 if ((res >> 26) == ALC880_HP_EVENT)
6163 alc885_imac24_automute(codec);
6164}
6165
Takashi Iwai87350ad2007-08-16 18:19:38 +02006166static void alc885_mbp3_automute(struct hda_codec *codec)
6167{
6168 unsigned int present;
6169
6170 present = snd_hda_codec_read(codec, 0x15, 0,
6171 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
6172 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
6173 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
6174 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
6175 HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE);
6176
6177}
6178static void alc885_mbp3_unsol_event(struct hda_codec *codec,
6179 unsigned int res)
6180{
6181 /* Headphone insertion or removal. */
6182 if ((res >> 26) == ALC880_HP_EVENT)
6183 alc885_mbp3_automute(codec);
6184}
6185
6186
Kailang Yang272a5272007-05-14 11:00:38 +02006187static struct hda_verb alc882_targa_verbs[] = {
6188 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6189 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6190
6191 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6192 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02006193
Kailang Yang272a5272007-05-14 11:00:38 +02006194 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
6195 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
6196 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
6197
6198 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
6199 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
6200 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
6201 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
6202 { } /* end */
6203};
6204
6205/* toggle speaker-output according to the hp-jack state */
6206static void alc882_targa_automute(struct hda_codec *codec)
6207{
6208 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02006209
Kailang Yang272a5272007-05-14 11:00:38 +02006210 present = snd_hda_codec_read(codec, 0x14, 0,
6211 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02006212 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
6213 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02006214 snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
6215 present ? 1 : 3);
Kailang Yang272a5272007-05-14 11:00:38 +02006216}
6217
6218static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res)
6219{
6220 /* Looks like the unsol event is incompatible with the standard
6221 * definition. 4bit tag is placed at 26 bit!
6222 */
6223 if (((res >> 26) == ALC880_HP_EVENT)) {
6224 alc882_targa_automute(codec);
6225 }
6226}
6227
6228static struct hda_verb alc882_asus_a7j_verbs[] = {
6229 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6230 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6231
6232 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6233 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6234 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02006235
Kailang Yang272a5272007-05-14 11:00:38 +02006236 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
6237 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
6238 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
6239
6240 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
6241 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
6242 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
6243 { } /* end */
6244};
6245
Takashi Iwai914759b2007-09-06 14:52:04 +02006246static struct hda_verb alc882_asus_a7m_verbs[] = {
6247 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6248 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6249
6250 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6251 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6252 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02006253
Takashi Iwai914759b2007-09-06 14:52:04 +02006254 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
6255 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
6256 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
6257
6258 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
6259 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
6260 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
6261 { } /* end */
6262};
6263
Tobin Davis9102cd12006-12-15 10:02:12 +01006264static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted)
6265{
6266 unsigned int gpiostate, gpiomask, gpiodir;
6267
6268 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
6269 AC_VERB_GET_GPIO_DATA, 0);
6270
6271 if (!muted)
6272 gpiostate |= (1 << pin);
6273 else
6274 gpiostate &= ~(1 << pin);
6275
6276 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
6277 AC_VERB_GET_GPIO_MASK, 0);
6278 gpiomask |= (1 << pin);
6279
6280 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
6281 AC_VERB_GET_GPIO_DIRECTION, 0);
6282 gpiodir |= (1 << pin);
6283
6284
6285 snd_hda_codec_write(codec, codec->afg, 0,
6286 AC_VERB_SET_GPIO_MASK, gpiomask);
6287 snd_hda_codec_write(codec, codec->afg, 0,
6288 AC_VERB_SET_GPIO_DIRECTION, gpiodir);
6289
6290 msleep(1);
6291
6292 snd_hda_codec_write(codec, codec->afg, 0,
6293 AC_VERB_SET_GPIO_DATA, gpiostate);
6294}
6295
Takashi Iwai7debbe52007-08-16 15:01:03 +02006296/* set up GPIO at initialization */
6297static void alc885_macpro_init_hook(struct hda_codec *codec)
6298{
6299 alc882_gpio_mute(codec, 0, 0);
6300 alc882_gpio_mute(codec, 1, 0);
6301}
6302
6303/* set up GPIO and update auto-muting at initialization */
6304static void alc885_imac24_init_hook(struct hda_codec *codec)
6305{
6306 alc885_macpro_init_hook(codec);
6307 alc885_imac24_automute(codec);
6308}
6309
Kailang Yangdf694da2005-12-05 19:42:22 +01006310/*
6311 * generic initialization of ADC, input mixers and output mixers
6312 */
6313static struct hda_verb alc882_auto_init_verbs[] = {
6314 /*
6315 * Unmute ADC0-2 and set the default input to mic-in
6316 */
6317 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
6318 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6319 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
6320 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6321 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
6322 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6323
Takashi Iwaicb53c622007-08-10 17:21:45 +02006324 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +01006325 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006326 * Note: PASD motherboards uses the Line In 2 as the input for
6327 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01006328 */
6329 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02006330 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6331 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6332 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6333 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6334 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01006335
6336 /*
6337 * Set up output mixers (0x0c - 0x0f)
6338 */
6339 /* set vol=0 to output mixers */
6340 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6341 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6342 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6343 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6344 /* set up input amps for analog loopback */
6345 /* Amp Indices: DAC = 0, mixer = 1 */
6346 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6347 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6348 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6349 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6350 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6351 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6352 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6353 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6354 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6355 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6356
6357 /* FIXME: use matrix-type input source selection */
6358 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
6359 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
6360 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6361 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
6362 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
6363 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
6364 /* Input mixer2 */
6365 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6366 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
6367 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
6368 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
6369 /* Input mixer3 */
6370 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6371 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
6372 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
6373 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
6374
6375 { }
6376};
6377
Takashi Iwaicb53c622007-08-10 17:21:45 +02006378#ifdef CONFIG_SND_HDA_POWER_SAVE
6379#define alc882_loopbacks alc880_loopbacks
6380#endif
6381
Kailang Yangdf694da2005-12-05 19:42:22 +01006382/* pcm configuration: identiacal with ALC880 */
6383#define alc882_pcm_analog_playback alc880_pcm_analog_playback
6384#define alc882_pcm_analog_capture alc880_pcm_analog_capture
6385#define alc882_pcm_digital_playback alc880_pcm_digital_playback
6386#define alc882_pcm_digital_capture alc880_pcm_digital_capture
6387
6388/*
6389 * configuration and preset
6390 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006391static const char *alc882_models[ALC882_MODEL_LAST] = {
6392 [ALC882_3ST_DIG] = "3stack-dig",
6393 [ALC882_6ST_DIG] = "6stack-dig",
6394 [ALC882_ARIMA] = "arima",
Kailang Yangbdd148a2007-05-08 15:19:08 +02006395 [ALC882_W2JC] = "w2jc",
Takashi Iwai0438a002007-09-06 14:54:11 +02006396 [ALC882_TARGA] = "targa",
6397 [ALC882_ASUS_A7J] = "asus-a7j",
6398 [ALC882_ASUS_A7M] = "asus-a7m",
Tobin Davis9102cd12006-12-15 10:02:12 +01006399 [ALC885_MACPRO] = "macpro",
Takashi Iwai87350ad2007-08-16 18:19:38 +02006400 [ALC885_MBP3] = "mbp3",
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006401 [ALC885_IMAC24] = "imac24",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006402 [ALC882_AUTO] = "auto",
6403};
6404
6405static struct snd_pci_quirk alc882_cfg_tbl[] = {
6406 SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG),
Kailang Yang272a5272007-05-14 11:00:38 +02006407 SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J),
Kailang Yangac8842a2007-09-20 12:51:39 +02006408 SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J),
Takashi Iwai914759b2007-09-06 14:52:04 +02006409 SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01006410 SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC),
Claudio Matsuokac5d9f1c2007-07-19 23:18:32 +02006411 SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG),
Tobin Davis7b9470d2006-12-28 13:56:48 +01006412 SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01006413 SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG),
Jiang zhe44447042008-01-28 12:28:24 +01006414 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01006415 SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */
6416 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG),
6417 SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA),
Kailang Yangdf694da2005-12-05 19:42:22 +01006418 {}
6419};
6420
6421static struct alc_config_preset alc882_presets[] = {
6422 [ALC882_3ST_DIG] = {
6423 .mixers = { alc882_base_mixer },
6424 .init_verbs = { alc882_init_verbs },
6425 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6426 .dac_nids = alc882_dac_nids,
6427 .dig_out_nid = ALC882_DIGOUT_NID,
Kailang Yangdf694da2005-12-05 19:42:22 +01006428 .dig_in_nid = ALC882_DIGIN_NID,
6429 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
6430 .channel_mode = alc882_ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02006431 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01006432 .input_mux = &alc882_capture_source,
6433 },
6434 [ALC882_6ST_DIG] = {
6435 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
6436 .init_verbs = { alc882_init_verbs },
6437 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6438 .dac_nids = alc882_dac_nids,
6439 .dig_out_nid = ALC882_DIGOUT_NID,
Kailang Yangdf694da2005-12-05 19:42:22 +01006440 .dig_in_nid = ALC882_DIGIN_NID,
6441 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
6442 .channel_mode = alc882_sixstack_modes,
6443 .input_mux = &alc882_capture_source,
6444 },
Takashi Iwai4b146cb2006-07-28 14:42:36 +02006445 [ALC882_ARIMA] = {
6446 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
6447 .init_verbs = { alc882_init_verbs, alc882_eapd_verbs },
6448 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6449 .dac_nids = alc882_dac_nids,
6450 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
6451 .channel_mode = alc882_sixstack_modes,
6452 .input_mux = &alc882_capture_source,
6453 },
Kailang Yangbdd148a2007-05-08 15:19:08 +02006454 [ALC882_W2JC] = {
6455 .mixers = { alc882_w2jc_mixer, alc882_chmode_mixer },
6456 .init_verbs = { alc882_init_verbs, alc882_eapd_verbs,
6457 alc880_gpio1_init_verbs },
6458 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6459 .dac_nids = alc882_dac_nids,
6460 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
6461 .channel_mode = alc880_threestack_modes,
6462 .need_dac_fix = 1,
6463 .input_mux = &alc882_capture_source,
6464 .dig_out_nid = ALC882_DIGOUT_NID,
6465 },
Takashi Iwai87350ad2007-08-16 18:19:38 +02006466 [ALC885_MBP3] = {
6467 .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer },
6468 .init_verbs = { alc885_mbp3_init_verbs,
6469 alc880_gpio1_init_verbs },
6470 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6471 .dac_nids = alc882_dac_nids,
6472 .channel_mode = alc885_mbp_6ch_modes,
6473 .num_channel_mode = ARRAY_SIZE(alc885_mbp_6ch_modes),
6474 .input_mux = &alc882_capture_source,
6475 .dig_out_nid = ALC882_DIGOUT_NID,
6476 .dig_in_nid = ALC882_DIGIN_NID,
6477 .unsol_event = alc885_mbp3_unsol_event,
6478 .init_hook = alc885_mbp3_automute,
6479 },
Tobin Davis9102cd12006-12-15 10:02:12 +01006480 [ALC885_MACPRO] = {
6481 .mixers = { alc882_macpro_mixer },
6482 .init_verbs = { alc882_macpro_init_verbs },
6483 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6484 .dac_nids = alc882_dac_nids,
6485 .dig_out_nid = ALC882_DIGOUT_NID,
6486 .dig_in_nid = ALC882_DIGIN_NID,
6487 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
6488 .channel_mode = alc882_ch_modes,
6489 .input_mux = &alc882_capture_source,
Takashi Iwai7debbe52007-08-16 15:01:03 +02006490 .init_hook = alc885_macpro_init_hook,
Tobin Davis9102cd12006-12-15 10:02:12 +01006491 },
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006492 [ALC885_IMAC24] = {
6493 .mixers = { alc885_imac24_mixer },
6494 .init_verbs = { alc885_imac24_init_verbs },
6495 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6496 .dac_nids = alc882_dac_nids,
6497 .dig_out_nid = ALC882_DIGOUT_NID,
6498 .dig_in_nid = ALC882_DIGIN_NID,
6499 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
6500 .channel_mode = alc882_ch_modes,
6501 .input_mux = &alc882_capture_source,
6502 .unsol_event = alc885_imac24_unsol_event,
Takashi Iwai7debbe52007-08-16 15:01:03 +02006503 .init_hook = alc885_imac24_init_hook,
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006504 },
Kailang Yang272a5272007-05-14 11:00:38 +02006505 [ALC882_TARGA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006506 .mixers = { alc882_targa_mixer, alc882_chmode_mixer },
Kailang Yang272a5272007-05-14 11:00:38 +02006507 .init_verbs = { alc882_init_verbs, alc882_targa_verbs},
6508 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6509 .dac_nids = alc882_dac_nids,
6510 .dig_out_nid = ALC882_DIGOUT_NID,
6511 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
6512 .adc_nids = alc882_adc_nids,
Takashi Iwaie1406342008-02-11 18:32:32 +01006513 .capsrc_nids = alc882_capsrc_nids,
Kailang Yang272a5272007-05-14 11:00:38 +02006514 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
6515 .channel_mode = alc882_3ST_6ch_modes,
6516 .need_dac_fix = 1,
6517 .input_mux = &alc882_capture_source,
6518 .unsol_event = alc882_targa_unsol_event,
6519 .init_hook = alc882_targa_automute,
6520 },
6521 [ALC882_ASUS_A7J] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006522 .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer },
Kailang Yang272a5272007-05-14 11:00:38 +02006523 .init_verbs = { alc882_init_verbs, alc882_asus_a7j_verbs},
6524 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6525 .dac_nids = alc882_dac_nids,
6526 .dig_out_nid = ALC882_DIGOUT_NID,
6527 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
6528 .adc_nids = alc882_adc_nids,
Takashi Iwaie1406342008-02-11 18:32:32 +01006529 .capsrc_nids = alc882_capsrc_nids,
Kailang Yang272a5272007-05-14 11:00:38 +02006530 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
6531 .channel_mode = alc882_3ST_6ch_modes,
6532 .need_dac_fix = 1,
6533 .input_mux = &alc882_capture_source,
Kailang Yangea1fb292008-08-26 12:58:38 +02006534 },
Takashi Iwai914759b2007-09-06 14:52:04 +02006535 [ALC882_ASUS_A7M] = {
6536 .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer },
6537 .init_verbs = { alc882_init_verbs, alc882_eapd_verbs,
6538 alc880_gpio1_init_verbs,
6539 alc882_asus_a7m_verbs },
6540 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6541 .dac_nids = alc882_dac_nids,
6542 .dig_out_nid = ALC882_DIGOUT_NID,
6543 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
6544 .channel_mode = alc880_threestack_modes,
6545 .need_dac_fix = 1,
6546 .input_mux = &alc882_capture_source,
Kailang Yangea1fb292008-08-26 12:58:38 +02006547 },
Kailang Yangdf694da2005-12-05 19:42:22 +01006548};
6549
6550
6551/*
Takashi Iwaif95474e2007-07-10 00:47:43 +02006552 * Pin config fixes
6553 */
Kailang Yangea1fb292008-08-26 12:58:38 +02006554enum {
Takashi Iwaif95474e2007-07-10 00:47:43 +02006555 PINFIX_ABIT_AW9D_MAX
6556};
6557
6558static struct alc_pincfg alc882_abit_aw9d_pinfix[] = {
6559 { 0x15, 0x01080104 }, /* side */
6560 { 0x16, 0x01011012 }, /* rear */
6561 { 0x17, 0x01016011 }, /* clfe */
6562 { }
6563};
6564
6565static const struct alc_pincfg *alc882_pin_fixes[] = {
6566 [PINFIX_ABIT_AW9D_MAX] = alc882_abit_aw9d_pinfix,
6567};
6568
6569static struct snd_pci_quirk alc882_pinfix_tbl[] = {
6570 SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
6571 {}
6572};
6573
6574/*
Kailang Yangdf694da2005-12-05 19:42:22 +01006575 * BIOS auto configuration
6576 */
6577static void alc882_auto_set_output_and_unmute(struct hda_codec *codec,
6578 hda_nid_t nid, int pin_type,
6579 int dac_idx)
6580{
6581 /* set as output */
6582 struct alc_spec *spec = codec->spec;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006583 int idx;
6584
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006585 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01006586 if (spec->multiout.dac_nids[dac_idx] == 0x25)
6587 idx = 4;
6588 else
6589 idx = spec->multiout.dac_nids[dac_idx] - 2;
Kailang Yangdf694da2005-12-05 19:42:22 +01006590 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
6591
6592}
6593
6594static void alc882_auto_init_multi_out(struct hda_codec *codec)
6595{
6596 struct alc_spec *spec = codec->spec;
6597 int i;
6598
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006599 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Kailang Yangdf694da2005-12-05 19:42:22 +01006600 for (i = 0; i <= HDA_SIDE; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006601 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02006602 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01006603 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02006604 alc882_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006605 i);
Kailang Yangdf694da2005-12-05 19:42:22 +01006606 }
6607}
6608
6609static void alc882_auto_init_hp_out(struct hda_codec *codec)
6610{
6611 struct alc_spec *spec = codec->spec;
6612 hda_nid_t pin;
6613
Takashi Iwaieb06ed82006-09-20 17:10:27 +02006614 pin = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006615 if (pin) /* connect to front */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006616 /* use dac 0 */
6617 alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006618 pin = spec->autocfg.speaker_pins[0];
6619 if (pin)
6620 alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Kailang Yangdf694da2005-12-05 19:42:22 +01006621}
6622
6623#define alc882_is_input_pin(nid) alc880_is_input_pin(nid)
6624#define ALC882_PIN_CD_NID ALC880_PIN_CD_NID
6625
6626static void alc882_auto_init_analog_input(struct hda_codec *codec)
6627{
6628 struct alc_spec *spec = codec->spec;
6629 int i;
6630
6631 for (i = 0; i < AUTO_PIN_LAST; i++) {
6632 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwai7194cae2008-03-06 16:58:17 +01006633 unsigned int vref;
6634 if (!nid)
6635 continue;
6636 vref = PIN_IN;
6637 if (1 /*i <= AUTO_PIN_FRONT_MIC*/) {
Kailang Yang531240f2008-05-27 12:10:25 +02006638 unsigned int pincap;
6639 pincap = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
6640 if ((pincap >> AC_PINCAP_VREF_SHIFT) &
Takashi Iwai7194cae2008-03-06 16:58:17 +01006641 AC_PINCAP_VREF_80)
6642 vref = PIN_VREF80;
Kailang Yangdf694da2005-12-05 19:42:22 +01006643 }
Takashi Iwai7194cae2008-03-06 16:58:17 +01006644 snd_hda_codec_write(codec, nid, 0,
6645 AC_VERB_SET_PIN_WIDGET_CONTROL, vref);
6646 if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
6647 snd_hda_codec_write(codec, nid, 0,
6648 AC_VERB_SET_AMP_GAIN_MUTE,
6649 AMP_OUT_MUTE);
Kailang Yangdf694da2005-12-05 19:42:22 +01006650 }
6651}
6652
Takashi Iwaif511b012008-08-15 16:46:42 +02006653static void alc882_auto_init_input_src(struct hda_codec *codec)
6654{
6655 struct alc_spec *spec = codec->spec;
6656 const struct hda_input_mux *imux = spec->input_mux;
6657 int c;
6658
6659 for (c = 0; c < spec->num_adc_nids; c++) {
6660 hda_nid_t conn_list[HDA_MAX_NUM_INPUTS];
6661 hda_nid_t nid = spec->capsrc_nids[c];
6662 int conns, mute, idx, item;
6663
6664 conns = snd_hda_get_connections(codec, nid, conn_list,
6665 ARRAY_SIZE(conn_list));
6666 if (conns < 0)
6667 continue;
6668 for (idx = 0; idx < conns; idx++) {
6669 /* if the current connection is the selected one,
6670 * unmute it as default - otherwise mute it
6671 */
6672 mute = AMP_IN_MUTE(idx);
6673 for (item = 0; item < imux->num_items; item++) {
6674 if (imux->items[item].index == idx) {
6675 if (spec->cur_mux[c] == item)
6676 mute = AMP_IN_UNMUTE(idx);
6677 break;
6678 }
6679 }
6680 snd_hda_codec_write(codec, nid, 0,
6681 AC_VERB_SET_AMP_GAIN_MUTE, mute);
6682 }
6683 }
6684}
6685
Takashi Iwai776e1842007-08-29 15:07:11 +02006686/* add mic boosts if needed */
6687static int alc_auto_add_mic_boost(struct hda_codec *codec)
6688{
6689 struct alc_spec *spec = codec->spec;
6690 int err;
6691 hda_nid_t nid;
6692
6693 nid = spec->autocfg.input_pins[AUTO_PIN_MIC];
Takashi Iwaice22e032008-01-11 17:38:35 +01006694 if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
Takashi Iwai776e1842007-08-29 15:07:11 +02006695 err = add_control(spec, ALC_CTL_WIDGET_VOL,
6696 "Mic Boost",
6697 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
6698 if (err < 0)
6699 return err;
6700 }
6701 nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC];
Takashi Iwaice22e032008-01-11 17:38:35 +01006702 if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
Takashi Iwai776e1842007-08-29 15:07:11 +02006703 err = add_control(spec, ALC_CTL_WIDGET_VOL,
6704 "Front Mic Boost",
6705 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
6706 if (err < 0)
6707 return err;
6708 }
6709 return 0;
6710}
6711
Kailang Yangdf694da2005-12-05 19:42:22 +01006712/* almost identical with ALC880 parser... */
6713static int alc882_parse_auto_config(struct hda_codec *codec)
6714{
6715 struct alc_spec *spec = codec->spec;
6716 int err = alc880_parse_auto_config(codec);
6717
6718 if (err < 0)
6719 return err;
Takashi Iwai776e1842007-08-29 15:07:11 +02006720 else if (!err)
6721 return 0; /* no config found */
6722
6723 err = alc_auto_add_mic_boost(codec);
6724 if (err < 0)
6725 return err;
6726
6727 /* hack - override the init verbs */
6728 spec->init_verbs[0] = alc882_auto_init_verbs;
6729
6730 return 1; /* config found */
Kailang Yangdf694da2005-12-05 19:42:22 +01006731}
6732
Takashi Iwaiae6b8132006-03-03 16:47:17 +01006733/* additional initialization for auto-configuration model */
6734static void alc882_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01006735{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006736 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01006737 alc882_auto_init_multi_out(codec);
6738 alc882_auto_init_hp_out(codec);
6739 alc882_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +02006740 alc882_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006741 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02006742 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01006743}
6744
Takashi Iwai7943a8a2008-04-16 17:29:09 +02006745static int patch_alc883(struct hda_codec *codec); /* called in patch_alc882() */
6746
Linus Torvalds1da177e2005-04-16 15:20:36 -07006747static int patch_alc882(struct hda_codec *codec)
6748{
6749 struct alc_spec *spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01006750 int err, board_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006751
Takashi Iwaie560d8d2005-09-09 14:21:46 +02006752 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006753 if (spec == NULL)
6754 return -ENOMEM;
6755
Linus Torvalds1da177e2005-04-16 15:20:36 -07006756 codec->spec = spec;
6757
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006758 board_config = snd_hda_check_board_config(codec, ALC882_MODEL_LAST,
6759 alc882_models,
6760 alc882_cfg_tbl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006761
Kailang Yangdf694da2005-12-05 19:42:22 +01006762 if (board_config < 0 || board_config >= ALC882_MODEL_LAST) {
Tobin Davis081d17c2007-02-15 17:46:18 +01006763 /* Pick up systems that don't supply PCI SSID */
6764 switch (codec->subsystem_id) {
6765 case 0x106b0c00: /* Mac Pro */
6766 board_config = ALC885_MACPRO;
6767 break;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006768 case 0x106b1000: /* iMac 24 */
Peter Korsgaardf3911c52008-09-27 09:13:45 +02006769 case 0x106b2800: /* AppleTV */
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006770 board_config = ALC885_IMAC24;
6771 break;
Takashi Iwaic7e07572008-06-26 14:42:51 +02006772 case 0x106b00a1: /* Macbook (might be wrong - PCI SSID?) */
David Woodhouse9c95c432008-09-18 13:37:13 -07006773 case 0x106b00a4: /* MacbookPro4,1 */
Takashi Iwai87350ad2007-08-16 18:19:38 +02006774 case 0x106b2c00: /* Macbook Pro rev3 */
Takashi Iwaic7e07572008-06-26 14:42:51 +02006775 case 0x106b3600: /* Macbook 3.1 */
Takashi Iwai87350ad2007-08-16 18:19:38 +02006776 board_config = ALC885_MBP3;
6777 break;
Tobin Davis081d17c2007-02-15 17:46:18 +01006778 default:
Takashi Iwai7943a8a2008-04-16 17:29:09 +02006779 /* ALC889A is handled better as ALC888-compatible */
Clive Messer669faba2008-09-30 15:49:13 +02006780 if (codec->revision_id == 0x100101 ||
6781 codec->revision_id == 0x100103) {
Takashi Iwai7943a8a2008-04-16 17:29:09 +02006782 alc_free(codec);
6783 return patch_alc883(codec);
6784 }
Tobin Davis081d17c2007-02-15 17:46:18 +01006785 printk(KERN_INFO "hda_codec: Unknown model for ALC882, "
6786 "trying auto-probe from BIOS...\n");
6787 board_config = ALC882_AUTO;
6788 }
Kailang Yangdf694da2005-12-05 19:42:22 +01006789 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006790
Takashi Iwaif95474e2007-07-10 00:47:43 +02006791 alc_fix_pincfg(codec, alc882_pinfix_tbl, alc882_pin_fixes);
6792
Kailang Yangdf694da2005-12-05 19:42:22 +01006793 if (board_config == ALC882_AUTO) {
6794 /* automatic parse from the BIOS config */
6795 err = alc882_parse_auto_config(codec);
6796 if (err < 0) {
6797 alc_free(codec);
6798 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006799 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006800 printk(KERN_INFO
6801 "hda_codec: Cannot set up configuration "
6802 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01006803 board_config = ALC882_3ST_DIG;
6804 }
6805 }
6806
6807 if (board_config != ALC882_AUTO)
6808 setup_preset(spec, &alc882_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006809
Kailang Yang2f893282008-05-27 12:14:47 +02006810 if (codec->vendor_id == 0x10ec0885) {
6811 spec->stream_name_analog = "ALC885 Analog";
6812 spec->stream_name_digital = "ALC885 Digital";
6813 } else {
6814 spec->stream_name_analog = "ALC882 Analog";
6815 spec->stream_name_digital = "ALC882 Digital";
6816 }
6817
Kailang Yangdf694da2005-12-05 19:42:22 +01006818 spec->stream_analog_playback = &alc882_pcm_analog_playback;
6819 spec->stream_analog_capture = &alc882_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01006820 /* FIXME: setup DAC5 */
6821 /*spec->stream_analog_alt_playback = &alc880_pcm_analog_alt_playback;*/
6822 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006823
Kailang Yangdf694da2005-12-05 19:42:22 +01006824 spec->stream_digital_playback = &alc882_pcm_digital_playback;
6825 spec->stream_digital_capture = &alc882_pcm_digital_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006826
Takashi Iwai54cbc9a2008-10-31 15:24:04 +01006827 spec->is_mix_capture = 1; /* matrix-style capture */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006828 if (!spec->adc_nids && spec->input_mux) {
Kailang Yangdf694da2005-12-05 19:42:22 +01006829 /* check whether NID 0x07 is valid */
Takashi Iwai4a471b72005-12-07 13:56:29 +01006830 unsigned int wcap = get_wcaps(codec, 0x07);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006831 /* get type */
6832 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Kailang Yangdf694da2005-12-05 19:42:22 +01006833 if (wcap != AC_WID_AUD_IN) {
6834 spec->adc_nids = alc882_adc_nids_alt;
6835 spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids_alt);
Takashi Iwaie1406342008-02-11 18:32:32 +01006836 spec->capsrc_nids = alc882_capsrc_nids_alt;
Kailang Yangdf694da2005-12-05 19:42:22 +01006837 } else {
6838 spec->adc_nids = alc882_adc_nids;
6839 spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids);
Takashi Iwaie1406342008-02-11 18:32:32 +01006840 spec->capsrc_nids = alc882_capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +01006841 }
6842 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006843 set_capture_mixer(spec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006844
Takashi Iwai2134ea42008-01-10 16:53:55 +01006845 spec->vmaster_nid = 0x0c;
6846
Linus Torvalds1da177e2005-04-16 15:20:36 -07006847 codec->patch_ops = alc_patch_ops;
Kailang Yangdf694da2005-12-05 19:42:22 +01006848 if (board_config == ALC882_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01006849 spec->init_hook = alc882_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02006850#ifdef CONFIG_SND_HDA_POWER_SAVE
6851 if (!spec->loopback.amplist)
6852 spec->loopback.amplist = alc882_loopbacks;
6853#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006854
6855 return 0;
6856}
6857
6858/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006859 * ALC883 support
6860 *
6861 * ALC883 is almost identical with ALC880 but has cleaner and more flexible
6862 * configuration. Each pin widget can choose any input DACs and a mixer.
6863 * Each ADC is connected from a mixer of all inputs. This makes possible
6864 * 6-channel independent captures.
6865 *
6866 * In addition, an independent DAC for the multi-playback (not used in this
6867 * driver yet).
6868 */
6869#define ALC883_DIGOUT_NID 0x06
6870#define ALC883_DIGIN_NID 0x0a
6871
Wu Fengguang3ab90932008-11-17 09:51:09 +01006872#define ALC1200_DIGOUT_NID 0x10
6873
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006874static hda_nid_t alc883_dac_nids[4] = {
6875 /* front, rear, clfe, rear_surr */
Herton Ronaldo Krzesinskif32a19e2008-03-18 09:27:08 +01006876 0x02, 0x03, 0x04, 0x05
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006877};
6878
6879static hda_nid_t alc883_adc_nids[2] = {
6880 /* ADC1-2 */
6881 0x08, 0x09,
6882};
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006883
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006884static hda_nid_t alc883_adc_nids_alt[1] = {
6885 /* ADC1 */
6886 0x08,
6887};
6888
Takashi Iwaie1406342008-02-11 18:32:32 +01006889static hda_nid_t alc883_capsrc_nids[2] = { 0x23, 0x22 };
6890
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006891/* input MUX */
6892/* FIXME: should be a matrix-type input source selection */
6893
6894static struct hda_input_mux alc883_capture_source = {
6895 .num_items = 4,
6896 .items = {
6897 { "Mic", 0x0 },
6898 { "Front Mic", 0x1 },
6899 { "Line", 0x2 },
6900 { "CD", 0x4 },
6901 },
6902};
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006903
Jiang zhe17bba1b2008-06-04 12:11:07 +02006904static struct hda_input_mux alc883_3stack_6ch_intel = {
6905 .num_items = 4,
6906 .items = {
6907 { "Mic", 0x1 },
6908 { "Front Mic", 0x0 },
6909 { "Line", 0x2 },
6910 { "CD", 0x4 },
6911 },
6912};
6913
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006914static struct hda_input_mux alc883_lenovo_101e_capture_source = {
6915 .num_items = 2,
6916 .items = {
6917 { "Mic", 0x1 },
6918 { "Line", 0x2 },
6919 },
6920};
6921
Kailang Yang272a5272007-05-14 11:00:38 +02006922static struct hda_input_mux alc883_lenovo_nb0763_capture_source = {
6923 .num_items = 4,
6924 .items = {
6925 { "Mic", 0x0 },
6926 { "iMic", 0x1 },
6927 { "Line", 0x2 },
6928 { "CD", 0x4 },
6929 },
6930};
6931
Jiang zhefb97dc62008-03-06 11:07:11 +01006932static struct hda_input_mux alc883_fujitsu_pi2515_capture_source = {
6933 .num_items = 2,
6934 .items = {
6935 { "Mic", 0x0 },
6936 { "Int Mic", 0x1 },
6937 },
6938};
6939
Kailang Yange2757d52008-08-26 13:17:46 +02006940static struct hda_input_mux alc883_lenovo_sky_capture_source = {
6941 .num_items = 3,
6942 .items = {
6943 { "Mic", 0x0 },
6944 { "Front Mic", 0x1 },
6945 { "Line", 0x4 },
6946 },
6947};
6948
6949static struct hda_input_mux alc883_asus_eee1601_capture_source = {
6950 .num_items = 2,
6951 .items = {
6952 { "Mic", 0x0 },
6953 { "Line", 0x2 },
6954 },
6955};
6956
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006957/*
6958 * 2ch mode
6959 */
6960static struct hda_channel_mode alc883_3ST_2ch_modes[1] = {
6961 { 2, NULL }
6962};
6963
6964/*
6965 * 2ch mode
6966 */
6967static struct hda_verb alc883_3ST_ch2_init[] = {
6968 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
6969 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6970 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
6971 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6972 { } /* end */
6973};
6974
6975/*
Tobin Davisb2011312007-09-17 12:45:11 +02006976 * 4ch mode
6977 */
6978static struct hda_verb alc883_3ST_ch4_init[] = {
6979 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
6980 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6981 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6982 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6983 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6984 { } /* end */
6985};
6986
6987/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006988 * 6ch mode
6989 */
6990static struct hda_verb alc883_3ST_ch6_init[] = {
6991 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6992 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6993 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
6994 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6995 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6996 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6997 { } /* end */
6998};
6999
Tobin Davisb2011312007-09-17 12:45:11 +02007000static struct hda_channel_mode alc883_3ST_6ch_modes[3] = {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007001 { 2, alc883_3ST_ch2_init },
Tobin Davisb2011312007-09-17 12:45:11 +02007002 { 4, alc883_3ST_ch4_init },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007003 { 6, alc883_3ST_ch6_init },
7004};
7005
7006/*
Jiang zhe17bba1b2008-06-04 12:11:07 +02007007 * 2ch mode
7008 */
7009static struct hda_verb alc883_3ST_ch2_intel_init[] = {
7010 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7011 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7012 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7013 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7014 { } /* end */
7015};
7016
7017/*
7018 * 4ch mode
7019 */
7020static struct hda_verb alc883_3ST_ch4_intel_init[] = {
7021 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7022 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7023 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7024 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7025 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7026 { } /* end */
7027};
7028
7029/*
7030 * 6ch mode
7031 */
7032static struct hda_verb alc883_3ST_ch6_intel_init[] = {
7033 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7034 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7035 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x02 },
7036 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7037 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7038 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7039 { } /* end */
7040};
7041
7042static struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = {
7043 { 2, alc883_3ST_ch2_intel_init },
7044 { 4, alc883_3ST_ch4_intel_init },
7045 { 6, alc883_3ST_ch6_intel_init },
7046};
7047
7048/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007049 * 6ch mode
7050 */
7051static struct hda_verb alc883_sixstack_ch6_init[] = {
7052 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
7053 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7054 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7055 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7056 { } /* end */
7057};
7058
7059/*
7060 * 8ch mode
7061 */
7062static struct hda_verb alc883_sixstack_ch8_init[] = {
7063 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7064 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7065 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7066 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7067 { } /* end */
7068};
7069
7070static struct hda_channel_mode alc883_sixstack_modes[2] = {
7071 { 6, alc883_sixstack_ch6_init },
7072 { 8, alc883_sixstack_ch8_init },
7073};
7074
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01007075static struct hda_verb alc883_medion_eapd_verbs[] = {
7076 /* eanable EAPD on medion laptop */
7077 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
7078 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
7079 { }
7080};
7081
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007082/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
7083 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
7084 */
7085
7086static struct snd_kcontrol_new alc883_base_mixer[] = {
7087 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7088 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7089 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7090 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
7091 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7092 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
7093 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7094 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
7095 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
7096 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
7097 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7098 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7099 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7100 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7101 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7102 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007103 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007104 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7105 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007106 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007107 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
7108 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
7109 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007110 { } /* end */
7111};
7112
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01007113static struct snd_kcontrol_new alc883_mitac_mixer[] = {
7114 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7115 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7116 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7117 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
7118 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7119 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
7120 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
7121 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7122 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7123 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7124 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7125 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
7126 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01007127 { } /* end */
7128};
7129
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007130static struct snd_kcontrol_new alc883_clevo_m720_mixer[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01007131 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7132 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
7133 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7134 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
7135 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7136 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7137 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7138 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7139 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
7140 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Jiang zhe368c7a92008-03-04 11:20:33 +01007141 { } /* end */
7142};
7143
Jiang zhefb97dc62008-03-06 11:07:11 +01007144static struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = {
7145 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7146 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
7147 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7148 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
7149 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7150 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7151 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7152 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7153 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
7154 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Jiang zhefb97dc62008-03-06 11:07:11 +01007155 { } /* end */
7156};
7157
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007158static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = {
7159 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7160 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7161 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7162 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7163 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7164 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7165 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7166 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007167 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007168 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7169 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007170 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007171 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
7172 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
7173 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007174 { } /* end */
7175};
7176
7177static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
7178 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7179 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7180 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7181 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
7182 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7183 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
7184 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7185 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
7186 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7187 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7188 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7189 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7190 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7191 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007192 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007193 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7194 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007195 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007196 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
7197 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
7198 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007199 { } /* end */
7200};
7201
Jiang zhe17bba1b2008-06-04 12:11:07 +02007202static struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = {
7203 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7204 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7205 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7206 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
7207 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
7208 HDA_OUTPUT),
7209 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
7210 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7211 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
7212 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
7213 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7214 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7215 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7216 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7217 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7218 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
7219 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
7220 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7221 HDA_CODEC_VOLUME("Front Mic Boost", 0x18, 0, HDA_INPUT),
7222 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7223 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
7224 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Jiang zhe17bba1b2008-06-04 12:11:07 +02007225 { } /* end */
7226};
7227
Takashi Iwaid1d985f2006-11-23 19:27:12 +01007228static struct snd_kcontrol_new alc883_fivestack_mixer[] = {
Tobin Davisc07584c2006-10-13 12:32:16 +02007229 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02007230 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007231 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02007232 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007233 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7234 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02007235 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7236 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007237 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7238 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7239 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7240 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7241 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7242 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007243 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007244 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7245 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007246 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007247 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
7248 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
7249 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007250 { } /* end */
7251};
7252
Kailang Yangccc656c2006-10-17 12:32:26 +02007253static struct snd_kcontrol_new alc883_tagra_mixer[] = {
7254 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7255 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7256 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7257 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7258 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
7259 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7260 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
7261 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7262 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
7263 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7264 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7265 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7266 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7267 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007268 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02007269 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02007270 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007271};
Kailang Yangccc656c2006-10-17 12:32:26 +02007272
7273static struct snd_kcontrol_new alc883_tagra_2ch_mixer[] = {
7274 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7275 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7276 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7277 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7278 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7279 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007280 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02007281 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Jiang zhe4383fae2008-04-14 12:58:57 +02007282 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7283 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
7284 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02007285 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007286};
Kailang Yangccc656c2006-10-17 12:32:26 +02007287
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007288static struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = {
7289 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7290 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01007291 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7292 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007293 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7294 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7295 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7296 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007297 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007298};
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007299
Kailang Yang272a5272007-05-14 11:00:38 +02007300static struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = {
7301 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7302 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
7303 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7304 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7305 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7306 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7307 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7308 HDA_CODEC_VOLUME("iMic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7309 HDA_CODEC_MUTE("iMic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02007310 { } /* end */
7311};
7312
7313static struct snd_kcontrol_new alc883_medion_md2_mixer[] = {
7314 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7315 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7316 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
7317 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7318 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7319 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7320 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7321 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7322 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02007323 { } /* end */
Kailang Yangea1fb292008-08-26 12:58:38 +02007324};
Kailang Yang272a5272007-05-14 11:00:38 +02007325
Tobin Davis2880a862007-08-07 11:50:26 +02007326static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = {
Kailang Yangd1a991a2007-08-15 16:21:59 +02007327 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7328 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02007329 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02007330 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7331 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Kailang Yangd1a991a2007-08-15 16:21:59 +02007332 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7333 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7334 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02007335 { } /* end */
Kailang Yangd1a991a2007-08-15 16:21:59 +02007336};
Tobin Davis2880a862007-08-07 11:50:26 +02007337
Kailang Yange2757d52008-08-26 13:17:46 +02007338static struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = {
7339 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7340 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7341 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
7342 HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
7343 HDA_CODEC_VOLUME_MONO("Center Playback Volume",
7344 0x0d, 1, 0x0, HDA_OUTPUT),
7345 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
7346 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
7347 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
7348 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
7349 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
7350 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7351 HDA_CODEC_MUTE("iSpeaker Playback Switch", 0x1a, 0x0, HDA_OUTPUT),
7352 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7353 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7354 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7355 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7356 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7357 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7358 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7359 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7360 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
7361 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02007362 { } /* end */
7363};
7364
7365static struct hda_bind_ctls alc883_bind_cap_vol = {
7366 .ops = &snd_hda_bind_vol,
7367 .values = {
7368 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
7369 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
7370 0
7371 },
7372};
7373
7374static struct hda_bind_ctls alc883_bind_cap_switch = {
7375 .ops = &snd_hda_bind_sw,
7376 .values = {
7377 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
7378 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
7379 0
7380 },
7381};
7382
7383static struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = {
7384 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7385 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7386 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7387 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7388 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7389 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7390 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7391 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007392 { } /* end */
7393};
7394
7395static struct snd_kcontrol_new alc883_asus_eee1601_cap_mixer[] = {
Kailang Yange2757d52008-08-26 13:17:46 +02007396 HDA_BIND_VOL("Capture Volume", &alc883_bind_cap_vol),
7397 HDA_BIND_SW("Capture Switch", &alc883_bind_cap_switch),
7398 {
7399 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7400 /* .name = "Capture Source", */
7401 .name = "Input Source",
7402 .count = 1,
Takashi Iwai54cbc9a2008-10-31 15:24:04 +01007403 .info = alc_mux_enum_info,
7404 .get = alc_mux_enum_get,
7405 .put = alc_mux_enum_put,
Kailang Yange2757d52008-08-26 13:17:46 +02007406 },
7407 { } /* end */
7408};
7409
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007410static struct snd_kcontrol_new alc883_chmode_mixer[] = {
7411 {
7412 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7413 .name = "Channel Mode",
7414 .info = alc_ch_mode_info,
7415 .get = alc_ch_mode_get,
7416 .put = alc_ch_mode_put,
7417 },
7418 { } /* end */
7419};
7420
7421static struct hda_verb alc883_init_verbs[] = {
7422 /* ADC1: mute amp left and right */
Kailang Yange2757d52008-08-26 13:17:46 +02007423 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007424 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
7425 /* ADC2: mute amp left and right */
7426 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7427 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
7428 /* Front mixer: unmute input/output amp left and right (volume = 0) */
7429 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7430 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7431 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7432 /* Rear mixer */
7433 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7434 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7435 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7436 /* CLFE mixer */
7437 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7438 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7439 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7440 /* Side mixer */
7441 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7442 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7443 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7444
Takashi Iwaicb53c622007-08-10 17:21:45 +02007445 /* mute analog input loopbacks */
7446 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7447 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7448 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7449 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7450 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007451
7452 /* Front Pin: output 0 (0x0c) */
7453 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7454 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7455 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
7456 /* Rear Pin: output 1 (0x0d) */
7457 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7458 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7459 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
7460 /* CLFE Pin: output 2 (0x0e) */
7461 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7462 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7463 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
7464 /* Side Pin: output 3 (0x0f) */
7465 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7466 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7467 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
7468 /* Mic (rear) pin: input vref at 80% */
7469 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7470 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7471 /* Front Mic pin: input vref at 80% */
7472 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7473 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7474 /* Line In pin: input */
7475 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
7476 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7477 /* Line-2 In: Headphone output (output 0 - 0x0c) */
7478 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7479 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7480 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
7481 /* CD pin widget for input */
7482 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
7483
7484 /* FIXME: use matrix-type input source selection */
7485 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
7486 /* Input mixer2 */
7487 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yange2757d52008-08-26 13:17:46 +02007488 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7489 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7490 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007491 /* Input mixer3 */
7492 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yange2757d52008-08-26 13:17:46 +02007493 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7494 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7495 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007496 { }
7497};
7498
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01007499/* toggle speaker-output according to the hp-jack state */
7500static void alc883_mitac_hp_automute(struct hda_codec *codec)
7501{
7502 unsigned int present;
7503
7504 present = snd_hda_codec_read(codec, 0x15, 0,
7505 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7506 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7507 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7508 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
7509 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7510}
7511
7512/* auto-toggle front mic */
7513/*
7514static void alc883_mitac_mic_automute(struct hda_codec *codec)
7515{
7516 unsigned int present;
7517 unsigned char bits;
7518
7519 present = snd_hda_codec_read(codec, 0x18, 0,
7520 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7521 bits = present ? HDA_AMP_MUTE : 0;
7522 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
7523}
7524*/
7525
7526static void alc883_mitac_automute(struct hda_codec *codec)
7527{
7528 alc883_mitac_hp_automute(codec);
7529 /* alc883_mitac_mic_automute(codec); */
7530}
7531
7532static void alc883_mitac_unsol_event(struct hda_codec *codec,
7533 unsigned int res)
7534{
7535 switch (res >> 26) {
7536 case ALC880_HP_EVENT:
7537 alc883_mitac_hp_automute(codec);
7538 break;
7539 case ALC880_MIC_EVENT:
7540 /* alc883_mitac_mic_automute(codec); */
7541 break;
7542 }
7543}
7544
7545static struct hda_verb alc883_mitac_verbs[] = {
7546 /* HP */
7547 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7548 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7549 /* Subwoofer */
7550 {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
7551 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7552
7553 /* enable unsolicited event */
7554 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7555 /* {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, */
7556
7557 { } /* end */
7558};
7559
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007560static struct hda_verb alc883_clevo_m720_verbs[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01007561 /* HP */
7562 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7563 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7564 /* Int speaker */
7565 {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
7566 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7567
7568 /* enable unsolicited event */
7569 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007570 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Jiang zhe368c7a92008-03-04 11:20:33 +01007571
7572 { } /* end */
7573};
7574
Jiang zhefb97dc62008-03-06 11:07:11 +01007575static struct hda_verb alc883_2ch_fujitsu_pi2515_verbs[] = {
7576 /* HP */
7577 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
7578 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7579 /* Subwoofer */
7580 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
7581 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7582
7583 /* enable unsolicited event */
7584 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7585
7586 { } /* end */
7587};
7588
Kailang Yangccc656c2006-10-17 12:32:26 +02007589static struct hda_verb alc883_tagra_verbs[] = {
7590 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7591 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7592
7593 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7594 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02007595
Kailang Yangccc656c2006-10-17 12:32:26 +02007596 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
7597 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
7598 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
7599
7600 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007601 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
7602 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
7603 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
Kailang Yangccc656c2006-10-17 12:32:26 +02007604
7605 { } /* end */
7606};
7607
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007608static struct hda_verb alc883_lenovo_101e_verbs[] = {
7609 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7610 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT|AC_USRSP_EN},
7611 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT|AC_USRSP_EN},
7612 { } /* end */
7613};
7614
Kailang Yang272a5272007-05-14 11:00:38 +02007615static struct hda_verb alc883_lenovo_nb0763_verbs[] = {
7616 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7617 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7618 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7619 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7620 { } /* end */
7621};
7622
7623static struct hda_verb alc888_lenovo_ms7195_verbs[] = {
7624 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7625 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7626 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7627 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT | AC_USRSP_EN},
7628 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7629 { } /* end */
7630};
7631
Kailang Yang189609a2007-08-20 11:31:23 +02007632static struct hda_verb alc883_haier_w66_verbs[] = {
7633 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7634 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7635
7636 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7637
7638 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
7639 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7640 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7641 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7642 { } /* end */
7643};
7644
Kailang Yange2757d52008-08-26 13:17:46 +02007645static struct hda_verb alc888_lenovo_sky_verbs[] = {
7646 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7647 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7648 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7649 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7650 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7651 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7652 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
7653 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7654 { } /* end */
7655};
7656
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007657static struct hda_verb alc888_3st_hp_verbs[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007658 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */
Herton Ronaldo Krzesinskif32a19e2008-03-18 09:27:08 +01007659 {0x16, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Rear : output 1 (0x0d) */
7660 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* CLFE : output 2 (0x0e) */
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007661 { }
7662};
7663
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007664static struct hda_verb alc888_6st_dell_verbs[] = {
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007665 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7666 { }
7667};
7668
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007669static struct hda_verb alc888_3st_hp_2ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007670 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7671 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7672 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7673 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7674 { }
7675};
7676
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007677static struct hda_verb alc888_3st_hp_6ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007678 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7679 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7680 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7681 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7682 { }
7683};
7684
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007685static struct hda_channel_mode alc888_3st_hp_modes[2] = {
7686 { 2, alc888_3st_hp_2ch_init },
7687 { 6, alc888_3st_hp_6ch_init },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007688};
7689
Kailang Yang272a5272007-05-14 11:00:38 +02007690/* toggle front-jack and RCA according to the hp-jack state */
7691static void alc888_lenovo_ms7195_front_automute(struct hda_codec *codec)
7692{
7693 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02007694
Kailang Yang272a5272007-05-14 11:00:38 +02007695 present = snd_hda_codec_read(codec, 0x1b, 0,
7696 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007697 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7698 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7699 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7700 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02007701}
7702
7703/* toggle RCA according to the front-jack state */
7704static void alc888_lenovo_ms7195_rca_automute(struct hda_codec *codec)
7705{
7706 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02007707
Kailang Yang272a5272007-05-14 11:00:38 +02007708 present = snd_hda_codec_read(codec, 0x14, 0,
7709 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007710 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7711 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02007712}
Takashi Iwai47fd8302007-08-10 17:11:07 +02007713
Kailang Yang272a5272007-05-14 11:00:38 +02007714static void alc883_lenovo_ms7195_unsol_event(struct hda_codec *codec,
7715 unsigned int res)
7716{
7717 if ((res >> 26) == ALC880_HP_EVENT)
7718 alc888_lenovo_ms7195_front_automute(codec);
7719 if ((res >> 26) == ALC880_FRONT_EVENT)
7720 alc888_lenovo_ms7195_rca_automute(codec);
7721}
7722
7723static struct hda_verb alc883_medion_md2_verbs[] = {
7724 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7725 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7726
7727 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7728
7729 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7730 { } /* end */
7731};
7732
7733/* toggle speaker-output according to the hp-jack state */
7734static void alc883_medion_md2_automute(struct hda_codec *codec)
7735{
7736 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02007737
Kailang Yang272a5272007-05-14 11:00:38 +02007738 present = snd_hda_codec_read(codec, 0x14, 0,
7739 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007740 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7741 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02007742}
7743
7744static void alc883_medion_md2_unsol_event(struct hda_codec *codec,
7745 unsigned int res)
7746{
7747 if ((res >> 26) == ALC880_HP_EVENT)
7748 alc883_medion_md2_automute(codec);
7749}
7750
Kailang Yangccc656c2006-10-17 12:32:26 +02007751/* toggle speaker-output according to the hp-jack state */
7752static void alc883_tagra_automute(struct hda_codec *codec)
7753{
7754 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007755 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02007756
7757 present = snd_hda_codec_read(codec, 0x14, 0,
7758 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007759 bits = present ? HDA_AMP_MUTE : 0;
7760 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
7761 HDA_AMP_MUTE, bits);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02007762 snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
7763 present ? 1 : 3);
Kailang Yangccc656c2006-10-17 12:32:26 +02007764}
7765
7766static void alc883_tagra_unsol_event(struct hda_codec *codec, unsigned int res)
7767{
7768 if ((res >> 26) == ALC880_HP_EVENT)
7769 alc883_tagra_automute(codec);
7770}
7771
Jiang zhe368c7a92008-03-04 11:20:33 +01007772/* toggle speaker-output according to the hp-jack state */
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007773static void alc883_clevo_m720_hp_automute(struct hda_codec *codec)
Jiang zhe368c7a92008-03-04 11:20:33 +01007774{
7775 unsigned int present;
7776 unsigned char bits;
7777
7778 present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0)
7779 & AC_PINSENSE_PRESENCE;
7780 bits = present ? HDA_AMP_MUTE : 0;
7781 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7782 HDA_AMP_MUTE, bits);
7783}
7784
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007785static void alc883_clevo_m720_mic_automute(struct hda_codec *codec)
7786{
7787 unsigned int present;
7788
7789 present = snd_hda_codec_read(codec, 0x18, 0,
7790 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7791 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
7792 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7793}
7794
7795static void alc883_clevo_m720_automute(struct hda_codec *codec)
7796{
7797 alc883_clevo_m720_hp_automute(codec);
7798 alc883_clevo_m720_mic_automute(codec);
7799}
7800
7801static void alc883_clevo_m720_unsol_event(struct hda_codec *codec,
Jiang zhe368c7a92008-03-04 11:20:33 +01007802 unsigned int res)
7803{
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007804 switch (res >> 26) {
7805 case ALC880_HP_EVENT:
7806 alc883_clevo_m720_hp_automute(codec);
7807 break;
7808 case ALC880_MIC_EVENT:
7809 alc883_clevo_m720_mic_automute(codec);
7810 break;
7811 }
Jiang zhe368c7a92008-03-04 11:20:33 +01007812}
7813
Jiang zhefb97dc62008-03-06 11:07:11 +01007814/* toggle speaker-output according to the hp-jack state */
7815static void alc883_2ch_fujitsu_pi2515_automute(struct hda_codec *codec)
7816{
7817 unsigned int present;
7818 unsigned char bits;
7819
7820 present = snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0)
7821 & AC_PINSENSE_PRESENCE;
7822 bits = present ? HDA_AMP_MUTE : 0;
7823 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7824 HDA_AMP_MUTE, bits);
7825}
7826
7827static void alc883_2ch_fujitsu_pi2515_unsol_event(struct hda_codec *codec,
7828 unsigned int res)
7829{
7830 if ((res >> 26) == ALC880_HP_EVENT)
7831 alc883_2ch_fujitsu_pi2515_automute(codec);
7832}
7833
Kailang Yang189609a2007-08-20 11:31:23 +02007834static void alc883_haier_w66_automute(struct hda_codec *codec)
7835{
7836 unsigned int present;
7837 unsigned char bits;
7838
7839 present = snd_hda_codec_read(codec, 0x1b, 0,
7840 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7841 bits = present ? 0x80 : 0;
7842 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7843 0x80, bits);
7844}
7845
7846static void alc883_haier_w66_unsol_event(struct hda_codec *codec,
7847 unsigned int res)
7848{
7849 if ((res >> 26) == ALC880_HP_EVENT)
7850 alc883_haier_w66_automute(codec);
7851}
7852
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007853static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
7854{
7855 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007856 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007857
7858 present = snd_hda_codec_read(codec, 0x14, 0,
7859 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007860 bits = present ? HDA_AMP_MUTE : 0;
7861 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7862 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007863}
7864
7865static void alc883_lenovo_101e_all_automute(struct hda_codec *codec)
7866{
7867 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007868 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007869
7870 present = snd_hda_codec_read(codec, 0x1b, 0,
7871 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007872 bits = present ? HDA_AMP_MUTE : 0;
7873 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7874 HDA_AMP_MUTE, bits);
7875 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7876 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007877}
7878
7879static void alc883_lenovo_101e_unsol_event(struct hda_codec *codec,
7880 unsigned int res)
7881{
7882 if ((res >> 26) == ALC880_HP_EVENT)
7883 alc883_lenovo_101e_all_automute(codec);
7884 if ((res >> 26) == ALC880_FRONT_EVENT)
7885 alc883_lenovo_101e_ispeaker_automute(codec);
7886}
7887
Takashi Iwai676a9b52007-08-16 15:23:35 +02007888/* toggle speaker-output according to the hp-jack state */
7889static void alc883_acer_aspire_automute(struct hda_codec *codec)
7890{
7891 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02007892
Takashi Iwai676a9b52007-08-16 15:23:35 +02007893 present = snd_hda_codec_read(codec, 0x14, 0,
7894 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7895 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7896 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7897 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
7898 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7899}
7900
7901static void alc883_acer_aspire_unsol_event(struct hda_codec *codec,
7902 unsigned int res)
7903{
7904 if ((res >> 26) == ALC880_HP_EVENT)
7905 alc883_acer_aspire_automute(codec);
7906}
7907
Kailang Yangd1a991a2007-08-15 16:21:59 +02007908static struct hda_verb alc883_acer_eapd_verbs[] = {
7909 /* HP Pin: output 0 (0x0c) */
7910 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7911 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7912 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
7913 /* Front Pin: output 0 (0x0c) */
Takashi Iwai676a9b52007-08-16 15:23:35 +02007914 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7915 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangd1a991a2007-08-15 16:21:59 +02007916 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangd1a991a2007-08-15 16:21:59 +02007917 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
7918 /* eanable EAPD on medion laptop */
7919 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
7920 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
Takashi Iwai676a9b52007-08-16 15:23:35 +02007921 /* enable unsolicited event */
7922 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yangd1a991a2007-08-15 16:21:59 +02007923 { }
7924};
7925
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007926static void alc888_6st_dell_front_automute(struct hda_codec *codec)
7927{
7928 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02007929
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007930 present = snd_hda_codec_read(codec, 0x1b, 0,
7931 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7932 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7933 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7934 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7935 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7936 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
7937 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7938 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
7939 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7940}
7941
7942static void alc888_6st_dell_unsol_event(struct hda_codec *codec,
7943 unsigned int res)
7944{
7945 switch (res >> 26) {
7946 case ALC880_HP_EVENT:
7947 printk("hp_event\n");
7948 alc888_6st_dell_front_automute(codec);
7949 break;
7950 }
7951}
7952
Kailang Yange2757d52008-08-26 13:17:46 +02007953static void alc888_lenovo_sky_front_automute(struct hda_codec *codec)
7954{
7955 unsigned int mute;
7956 unsigned int present;
7957
7958 snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
7959 present = snd_hda_codec_read(codec, 0x1b, 0,
7960 AC_VERB_GET_PIN_SENSE, 0);
7961 present = (present & 0x80000000) != 0;
7962 if (present) {
7963 /* mute internal speaker */
7964 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7965 HDA_AMP_MUTE, HDA_AMP_MUTE);
7966 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7967 HDA_AMP_MUTE, HDA_AMP_MUTE);
7968 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
7969 HDA_AMP_MUTE, HDA_AMP_MUTE);
7970 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
7971 HDA_AMP_MUTE, HDA_AMP_MUTE);
7972 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0,
7973 HDA_AMP_MUTE, HDA_AMP_MUTE);
7974 } else {
7975 /* unmute internal speaker if necessary */
7976 mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
7977 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7978 HDA_AMP_MUTE, mute);
7979 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7980 HDA_AMP_MUTE, mute);
7981 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
7982 HDA_AMP_MUTE, mute);
7983 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
7984 HDA_AMP_MUTE, mute);
7985 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0,
7986 HDA_AMP_MUTE, mute);
7987 }
7988}
7989
7990static void alc883_lenovo_sky_unsol_event(struct hda_codec *codec,
7991 unsigned int res)
7992{
7993 if ((res >> 26) == ALC880_HP_EVENT)
7994 alc888_lenovo_sky_front_automute(codec);
7995}
7996
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007997/*
7998 * generic initialization of ADC, input mixers and output mixers
7999 */
8000static struct hda_verb alc883_auto_init_verbs[] = {
8001 /*
8002 * Unmute ADC0-2 and set the default input to mic-in
8003 */
8004 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8005 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8006 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8007 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8008
Takashi Iwaicb53c622007-08-10 17:21:45 +02008009 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008010 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008011 * Note: PASD motherboards uses the Line In 2 as the input for
8012 * front panel mic (mic 2)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008013 */
8014 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02008015 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8016 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8017 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8018 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8019 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008020
8021 /*
8022 * Set up output mixers (0x0c - 0x0f)
8023 */
8024 /* set vol=0 to output mixers */
8025 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8026 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8027 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8028 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8029 /* set up input amps for analog loopback */
8030 /* Amp Indices: DAC = 0, mixer = 1 */
8031 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8032 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8033 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8034 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8035 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8036 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8037 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8038 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8039 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8040 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8041
8042 /* FIXME: use matrix-type input source selection */
8043 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
8044 /* Input mixer1 */
8045 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8046 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8047 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008048 /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, */
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008049 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
8050 /* Input mixer2 */
8051 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8052 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8053 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008054 /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, */
Andy Shevchenkoe3cde642007-12-03 16:50:58 +01008055 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008056
8057 { }
8058};
8059
Kailang Yange2757d52008-08-26 13:17:46 +02008060static struct hda_verb alc888_asus_m90v_verbs[] = {
8061 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8062 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8063 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8064 /* enable unsolicited event */
8065 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8066 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
8067 { } /* end */
8068};
8069
8070static void alc883_nb_mic_automute(struct hda_codec *codec)
8071{
8072 unsigned int present;
8073
8074 present = snd_hda_codec_read(codec, 0x18, 0,
8075 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
8076 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
8077 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
8078 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
8079 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
8080}
8081
8082static void alc883_M90V_speaker_automute(struct hda_codec *codec)
8083{
8084 unsigned int present;
8085 unsigned char bits;
8086
8087 present = snd_hda_codec_read(codec, 0x1b, 0,
8088 AC_VERB_GET_PIN_SENSE, 0)
8089 & AC_PINSENSE_PRESENCE;
8090 bits = present ? 0 : PIN_OUT;
8091 snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
8092 bits);
8093 snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
8094 bits);
8095 snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
8096 bits);
8097}
8098
8099static void alc883_mode2_unsol_event(struct hda_codec *codec,
8100 unsigned int res)
8101{
8102 switch (res >> 26) {
8103 case ALC880_HP_EVENT:
8104 alc883_M90V_speaker_automute(codec);
8105 break;
8106 case ALC880_MIC_EVENT:
8107 alc883_nb_mic_automute(codec);
8108 break;
8109 }
8110}
8111
8112static void alc883_mode2_inithook(struct hda_codec *codec)
8113{
8114 alc883_M90V_speaker_automute(codec);
8115 alc883_nb_mic_automute(codec);
8116}
8117
8118static struct hda_verb alc888_asus_eee1601_verbs[] = {
8119 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8120 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8121 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8122 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8123 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8124 {0x20, AC_VERB_SET_COEF_INDEX, 0x0b},
8125 {0x20, AC_VERB_SET_PROC_COEF, 0x0838},
8126 /* enable unsolicited event */
8127 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8128 { } /* end */
8129};
8130
8131static void alc883_eee1601_speaker_automute(struct hda_codec *codec)
8132{
8133 unsigned int present;
8134 unsigned char bits;
8135
8136 present = snd_hda_codec_read(codec, 0x14, 0,
8137 AC_VERB_GET_PIN_SENSE, 0)
8138 & AC_PINSENSE_PRESENCE;
8139 bits = present ? 0 : PIN_OUT;
8140 snd_hda_codec_write(codec, 0x1b, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
8141 bits);
8142}
8143
8144static void alc883_eee1601_unsol_event(struct hda_codec *codec,
8145 unsigned int res)
8146{
8147 switch (res >> 26) {
8148 case ALC880_HP_EVENT:
8149 alc883_eee1601_speaker_automute(codec);
8150 break;
8151 }
8152}
8153
8154static void alc883_eee1601_inithook(struct hda_codec *codec)
8155{
8156 alc883_eee1601_speaker_automute(codec);
8157}
8158
Takashi Iwaicb53c622007-08-10 17:21:45 +02008159#ifdef CONFIG_SND_HDA_POWER_SAVE
8160#define alc883_loopbacks alc880_loopbacks
8161#endif
8162
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008163/* pcm configuration: identiacal with ALC880 */
8164#define alc883_pcm_analog_playback alc880_pcm_analog_playback
8165#define alc883_pcm_analog_capture alc880_pcm_analog_capture
Takashi Iwai63300792008-01-24 15:31:36 +01008166#define alc883_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008167#define alc883_pcm_digital_playback alc880_pcm_digital_playback
8168#define alc883_pcm_digital_capture alc880_pcm_digital_capture
8169
8170/*
8171 * configuration and preset
8172 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008173static const char *alc883_models[ALC883_MODEL_LAST] = {
8174 [ALC883_3ST_2ch_DIG] = "3stack-dig",
8175 [ALC883_3ST_6ch_DIG] = "3stack-6ch-dig",
8176 [ALC883_3ST_6ch] = "3stack-6ch",
8177 [ALC883_6ST_DIG] = "6stack-dig",
8178 [ALC883_TARGA_DIG] = "targa-dig",
8179 [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008180 [ALC883_ACER] = "acer",
Tobin Davis2880a862007-08-07 11:50:26 +02008181 [ALC883_ACER_ASPIRE] = "acer-aspire",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008182 [ALC883_MEDION] = "medion",
Kailang Yang272a5272007-05-14 11:00:38 +02008183 [ALC883_MEDION_MD2] = "medion-md2",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008184 [ALC883_LAPTOP_EAPD] = "laptop-eapd",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008185 [ALC883_LENOVO_101E_2ch] = "lenovo-101e",
Kailang Yang272a5272007-05-14 11:00:38 +02008186 [ALC883_LENOVO_NB0763] = "lenovo-nb0763",
8187 [ALC888_LENOVO_MS7195_DIG] = "lenovo-ms7195-dig",
Kailang Yange2757d52008-08-26 13:17:46 +02008188 [ALC888_LENOVO_SKY] = "lenovo-sky",
Kailang Yang189609a2007-08-20 11:31:23 +02008189 [ALC883_HAIER_W66] = "haier-w66",
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008190 [ALC888_3ST_HP] = "3stack-hp",
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008191 [ALC888_6ST_DELL] = "6stack-dell",
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008192 [ALC883_MITAC] = "mitac",
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008193 [ALC883_CLEVO_M720] = "clevo-m720",
Jiang zhefb97dc62008-03-06 11:07:11 +01008194 [ALC883_FUJITSU_PI2515] = "fujitsu-pi2515",
Jiang zhe17bba1b2008-06-04 12:11:07 +02008195 [ALC883_3ST_6ch_INTEL] = "3stack-6ch-intel",
Wu Fengguang3ab90932008-11-17 09:51:09 +01008196 [ALC1200_ASUS_P5Q] = "asus-p5q",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008197 [ALC883_AUTO] = "auto",
8198};
8199
8200static struct snd_pci_quirk alc883_cfg_tbl[] = {
8201 SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC883_3ST_6ch_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008202 SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE),
Takashi Iwai69e50282008-11-03 10:07:43 +01008203 SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_ACER_ASPIRE),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008204 SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE),
8205 SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE),
Jaroslav Kysela0b18cb12008-07-28 17:07:07 +02008206 SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_ACER_ASPIRE),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008207 SND_PCI_QUIRK(0x1025, 0, "Acer laptop", ALC883_ACER), /* default Acer */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008208 SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL),
Tobin Davisfebe3372007-06-12 11:27:46 +02008209 SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008210 SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP),
8211 SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP),
Herton Ronaldo Krzesinski5d85f8d2008-03-20 12:13:46 +01008212 SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG),
Kailang Yanga01c30c2008-10-15 11:14:58 +02008213 SND_PCI_QUIRK(0x1043, 0x1873, "Asus M90V", ALC888_ASUS_M90V),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008214 SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG),
Wu Fengguang3ab90932008-11-17 09:51:09 +01008215 SND_PCI_QUIRK(0x1043, 0x82fe, "Asus P5Q-EM HDMI", ALC1200_ASUS_P5Q),
Kailang Yange2757d52008-08-26 13:17:46 +02008216 SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_ASUS_EEE1601),
Travis Place97ec7102008-05-23 18:31:46 +02008217 SND_PCI_QUIRK(0x105b, 0x0ce8, "Foxconn P35AX-S", ALC883_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008218 SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008219 SND_PCI_QUIRK(0x1071, 0x8253, "Mitac 8252d", ALC883_MITAC),
8220 SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD),
Kailang Yange2757d52008-08-26 13:17:46 +02008221 SND_PCI_QUIRK(0x10f1, 0x2350, "TYAN-S2350", ALC888_6ST_DELL),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008222 SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch),
Tobin Davis57b14f22007-04-18 23:05:36 +02008223 SND_PCI_QUIRK(0x1458, 0xa002, "MSI", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008224 SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG),
8225 SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG),
8226 SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG),
Jiang zhe4383fae2008-04-14 12:58:57 +02008227 SND_PCI_QUIRK(0x1462, 0x2fb3, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008228 SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG),
Pascal Terjan82808232008-03-04 11:33:28 +01008229 SND_PCI_QUIRK(0x1462, 0x3783, "NEC S970", ALC883_TARGA_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008230 SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG),
8231 SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG),
8232 SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG),
8233 SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG),
8234 SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG),
8235 SND_PCI_QUIRK(0x1462, 0x3fdf, "MSI", ALC883_TARGA_DIG),
8236 SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG),
8237 SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG),
8238 SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008239 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG),
8240 SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG),
Tobin Davis799f88a2007-05-29 14:29:08 +02008241 SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG),
Herton Ronaldo Krzesinski86d34b72008-03-18 09:27:59 +01008242 SND_PCI_QUIRK(0x1462, 0x7267, "MSI", ALC883_3ST_6ch_DIG),
Leonard Norrgard2a296cb2007-01-08 11:28:22 +01008243 SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG),
Tobin Davis2dcd5222007-07-10 17:04:57 +02008244 SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008245 SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008246 SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG),
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008247 SND_PCI_QUIRK(0x1558, 0x0721, "Clevo laptop M720R", ALC883_CLEVO_M720),
8248 SND_PCI_QUIRK(0x1558, 0x0722, "Clevo laptop M720SR", ALC883_CLEVO_M720),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008249 SND_PCI_QUIRK(0x1558, 0, "Clevo laptop", ALC883_LAPTOP_EAPD),
Daniel T Chene60623b2007-05-29 03:41:55 -04008250 SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008251 SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION),
Jiang zhefb97dc62008-03-06 11:07:11 +01008252 SND_PCI_QUIRK(0x1734, 0x1108, "Fujitsu AMILO Pi2515", ALC883_FUJITSU_PI2515),
Kailang Yang272a5272007-05-14 11:00:38 +02008253 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch),
Kailang Yang272a5272007-05-14 11:00:38 +02008254 SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008255 SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763),
8256 SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Kailang Yange2757d52008-08-26 13:17:46 +02008257 SND_PCI_QUIRK(0x17aa, 0x101d, "Lenovo Sky", ALC888_LENOVO_SKY),
Kailang Yang272a5272007-05-14 11:00:38 +02008258 SND_PCI_QUIRK(0x17c0, 0x4071, "MEDION MD2", ALC883_MEDION_MD2),
Takashi Iwai959973b2008-11-05 11:30:56 +01008259 SND_PCI_QUIRK(0x17c0, 0x4085, "MEDION MD96630", ALC888_LENOVO_MS7195_DIG),
Andrew Paprocki0b167bf2008-02-03 10:15:44 +01008260 SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG),
Kailang Yang189609a2007-08-20 11:31:23 +02008261 SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66),
Jiang zhe17bba1b2008-06-04 12:11:07 +02008262 SND_PCI_QUIRK(0x8086, 0x0001, "DG33BUC", ALC883_3ST_6ch_INTEL),
8263 SND_PCI_QUIRK(0x8086, 0x0002, "DG33FBC", ALC883_3ST_6ch_INTEL),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008264 SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008265 {}
8266};
8267
8268static struct alc_config_preset alc883_presets[] = {
8269 [ALC883_3ST_2ch_DIG] = {
8270 .mixers = { alc883_3ST_2ch_mixer },
8271 .init_verbs = { alc883_init_verbs },
8272 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8273 .dac_nids = alc883_dac_nids,
8274 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008275 .dig_in_nid = ALC883_DIGIN_NID,
8276 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8277 .channel_mode = alc883_3ST_2ch_modes,
8278 .input_mux = &alc883_capture_source,
8279 },
8280 [ALC883_3ST_6ch_DIG] = {
8281 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
8282 .init_verbs = { alc883_init_verbs },
8283 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8284 .dac_nids = alc883_dac_nids,
8285 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008286 .dig_in_nid = ALC883_DIGIN_NID,
8287 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
8288 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02008289 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008290 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008291 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008292 [ALC883_3ST_6ch] = {
8293 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
8294 .init_verbs = { alc883_init_verbs },
8295 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8296 .dac_nids = alc883_dac_nids,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008297 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
8298 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02008299 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008300 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008301 },
Jiang zhe17bba1b2008-06-04 12:11:07 +02008302 [ALC883_3ST_6ch_INTEL] = {
8303 .mixers = { alc883_3ST_6ch_intel_mixer, alc883_chmode_mixer },
8304 .init_verbs = { alc883_init_verbs },
8305 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8306 .dac_nids = alc883_dac_nids,
8307 .dig_out_nid = ALC883_DIGOUT_NID,
8308 .dig_in_nid = ALC883_DIGIN_NID,
8309 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_intel_modes),
8310 .channel_mode = alc883_3ST_6ch_intel_modes,
8311 .need_dac_fix = 1,
8312 .input_mux = &alc883_3stack_6ch_intel,
8313 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008314 [ALC883_6ST_DIG] = {
8315 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
8316 .init_verbs = { alc883_init_verbs },
8317 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8318 .dac_nids = alc883_dac_nids,
8319 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008320 .dig_in_nid = ALC883_DIGIN_NID,
8321 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
8322 .channel_mode = alc883_sixstack_modes,
8323 .input_mux = &alc883_capture_source,
8324 },
Kailang Yangccc656c2006-10-17 12:32:26 +02008325 [ALC883_TARGA_DIG] = {
8326 .mixers = { alc883_tagra_mixer, alc883_chmode_mixer },
8327 .init_verbs = { alc883_init_verbs, alc883_tagra_verbs},
8328 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8329 .dac_nids = alc883_dac_nids,
8330 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +02008331 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
8332 .channel_mode = alc883_3ST_6ch_modes,
8333 .need_dac_fix = 1,
8334 .input_mux = &alc883_capture_source,
8335 .unsol_event = alc883_tagra_unsol_event,
8336 .init_hook = alc883_tagra_automute,
8337 },
8338 [ALC883_TARGA_2ch_DIG] = {
8339 .mixers = { alc883_tagra_2ch_mixer},
8340 .init_verbs = { alc883_init_verbs, alc883_tagra_verbs},
8341 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8342 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01008343 .adc_nids = alc883_adc_nids_alt,
8344 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Kailang Yangccc656c2006-10-17 12:32:26 +02008345 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +02008346 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8347 .channel_mode = alc883_3ST_2ch_modes,
8348 .input_mux = &alc883_capture_source,
8349 .unsol_event = alc883_tagra_unsol_event,
8350 .init_hook = alc883_tagra_automute,
8351 },
Vladimir Avdoninbab282b92006-08-22 13:31:58 +02008352 [ALC883_ACER] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02008353 .mixers = { alc883_base_mixer },
Vladimir Avdoninbab282b92006-08-22 13:31:58 +02008354 /* On TravelMate laptops, GPIO 0 enables the internal speaker
8355 * and the headphone jack. Turn this on and rely on the
8356 * standard mute methods whenever the user wants to turn
8357 * these outputs off.
8358 */
8359 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs },
8360 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8361 .dac_nids = alc883_dac_nids,
Vladimir Avdoninbab282b92006-08-22 13:31:58 +02008362 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8363 .channel_mode = alc883_3ST_2ch_modes,
8364 .input_mux = &alc883_capture_source,
8365 },
Tobin Davis2880a862007-08-07 11:50:26 +02008366 [ALC883_ACER_ASPIRE] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02008367 .mixers = { alc883_acer_aspire_mixer },
Kailang Yangd1a991a2007-08-15 16:21:59 +02008368 .init_verbs = { alc883_init_verbs, alc883_acer_eapd_verbs },
Tobin Davis2880a862007-08-07 11:50:26 +02008369 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8370 .dac_nids = alc883_dac_nids,
8371 .dig_out_nid = ALC883_DIGOUT_NID,
Tobin Davis2880a862007-08-07 11:50:26 +02008372 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8373 .channel_mode = alc883_3ST_2ch_modes,
8374 .input_mux = &alc883_capture_source,
Takashi Iwai676a9b52007-08-16 15:23:35 +02008375 .unsol_event = alc883_acer_aspire_unsol_event,
8376 .init_hook = alc883_acer_aspire_automute,
Kailang Yangd1a991a2007-08-15 16:21:59 +02008377 },
Tobin Davisc07584c2006-10-13 12:32:16 +02008378 [ALC883_MEDION] = {
8379 .mixers = { alc883_fivestack_mixer,
8380 alc883_chmode_mixer },
8381 .init_verbs = { alc883_init_verbs,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008382 alc883_medion_eapd_verbs },
Tobin Davisc07584c2006-10-13 12:32:16 +02008383 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8384 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01008385 .adc_nids = alc883_adc_nids_alt,
8386 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Tobin Davisc07584c2006-10-13 12:32:16 +02008387 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
8388 .channel_mode = alc883_sixstack_modes,
8389 .input_mux = &alc883_capture_source,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008390 },
Kailang Yang272a5272007-05-14 11:00:38 +02008391 [ALC883_MEDION_MD2] = {
8392 .mixers = { alc883_medion_md2_mixer},
8393 .init_verbs = { alc883_init_verbs, alc883_medion_md2_verbs},
8394 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8395 .dac_nids = alc883_dac_nids,
8396 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang272a5272007-05-14 11:00:38 +02008397 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8398 .channel_mode = alc883_3ST_2ch_modes,
8399 .input_mux = &alc883_capture_source,
8400 .unsol_event = alc883_medion_md2_unsol_event,
8401 .init_hook = alc883_medion_md2_automute,
Kailang Yangea1fb292008-08-26 12:58:38 +02008402 },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008403 [ALC883_LAPTOP_EAPD] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02008404 .mixers = { alc883_base_mixer },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008405 .init_verbs = { alc883_init_verbs, alc882_eapd_verbs },
8406 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8407 .dac_nids = alc883_dac_nids,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008408 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8409 .channel_mode = alc883_3ST_2ch_modes,
8410 .input_mux = &alc883_capture_source,
8411 },
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008412 [ALC883_CLEVO_M720] = {
8413 .mixers = { alc883_clevo_m720_mixer },
8414 .init_verbs = { alc883_init_verbs, alc883_clevo_m720_verbs },
Jiang zhe368c7a92008-03-04 11:20:33 +01008415 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8416 .dac_nids = alc883_dac_nids,
8417 .dig_out_nid = ALC883_DIGOUT_NID,
8418 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8419 .channel_mode = alc883_3ST_2ch_modes,
8420 .input_mux = &alc883_capture_source,
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008421 .unsol_event = alc883_clevo_m720_unsol_event,
8422 .init_hook = alc883_clevo_m720_automute,
Jiang zhe368c7a92008-03-04 11:20:33 +01008423 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008424 [ALC883_LENOVO_101E_2ch] = {
8425 .mixers = { alc883_lenovo_101e_2ch_mixer},
8426 .init_verbs = { alc883_init_verbs, alc883_lenovo_101e_verbs},
8427 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8428 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01008429 .adc_nids = alc883_adc_nids_alt,
8430 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008431 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8432 .channel_mode = alc883_3ST_2ch_modes,
8433 .input_mux = &alc883_lenovo_101e_capture_source,
8434 .unsol_event = alc883_lenovo_101e_unsol_event,
8435 .init_hook = alc883_lenovo_101e_all_automute,
8436 },
Kailang Yang272a5272007-05-14 11:00:38 +02008437 [ALC883_LENOVO_NB0763] = {
8438 .mixers = { alc883_lenovo_nb0763_mixer },
8439 .init_verbs = { alc883_init_verbs, alc883_lenovo_nb0763_verbs},
8440 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8441 .dac_nids = alc883_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +02008442 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8443 .channel_mode = alc883_3ST_2ch_modes,
8444 .need_dac_fix = 1,
8445 .input_mux = &alc883_lenovo_nb0763_capture_source,
8446 .unsol_event = alc883_medion_md2_unsol_event,
8447 .init_hook = alc883_medion_md2_automute,
8448 },
8449 [ALC888_LENOVO_MS7195_DIG] = {
8450 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
8451 .init_verbs = { alc883_init_verbs, alc888_lenovo_ms7195_verbs},
8452 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8453 .dac_nids = alc883_dac_nids,
8454 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang272a5272007-05-14 11:00:38 +02008455 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
8456 .channel_mode = alc883_3ST_6ch_modes,
8457 .need_dac_fix = 1,
8458 .input_mux = &alc883_capture_source,
8459 .unsol_event = alc883_lenovo_ms7195_unsol_event,
8460 .init_hook = alc888_lenovo_ms7195_front_automute,
Kailang Yang189609a2007-08-20 11:31:23 +02008461 },
8462 [ALC883_HAIER_W66] = {
8463 .mixers = { alc883_tagra_2ch_mixer},
8464 .init_verbs = { alc883_init_verbs, alc883_haier_w66_verbs},
8465 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8466 .dac_nids = alc883_dac_nids,
8467 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang189609a2007-08-20 11:31:23 +02008468 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8469 .channel_mode = alc883_3ST_2ch_modes,
8470 .input_mux = &alc883_capture_source,
8471 .unsol_event = alc883_haier_w66_unsol_event,
8472 .init_hook = alc883_haier_w66_automute,
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +01008473 },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008474 [ALC888_3ST_HP] = {
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +01008475 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008476 .init_verbs = { alc883_init_verbs, alc888_3st_hp_verbs },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008477 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8478 .dac_nids = alc883_dac_nids,
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008479 .num_channel_mode = ARRAY_SIZE(alc888_3st_hp_modes),
8480 .channel_mode = alc888_3st_hp_modes,
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008481 .need_dac_fix = 1,
8482 .input_mux = &alc883_capture_source,
8483 },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008484 [ALC888_6ST_DELL] = {
Herton Ronaldo Krzesinskif24dbdc2008-03-20 12:14:28 +01008485 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008486 .init_verbs = { alc883_init_verbs, alc888_6st_dell_verbs },
8487 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8488 .dac_nids = alc883_dac_nids,
8489 .dig_out_nid = ALC883_DIGOUT_NID,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008490 .dig_in_nid = ALC883_DIGIN_NID,
8491 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
8492 .channel_mode = alc883_sixstack_modes,
8493 .input_mux = &alc883_capture_source,
8494 .unsol_event = alc888_6st_dell_unsol_event,
8495 .init_hook = alc888_6st_dell_front_automute,
8496 },
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008497 [ALC883_MITAC] = {
8498 .mixers = { alc883_mitac_mixer },
8499 .init_verbs = { alc883_init_verbs, alc883_mitac_verbs },
8500 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8501 .dac_nids = alc883_dac_nids,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008502 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8503 .channel_mode = alc883_3ST_2ch_modes,
8504 .input_mux = &alc883_capture_source,
8505 .unsol_event = alc883_mitac_unsol_event,
8506 .init_hook = alc883_mitac_automute,
8507 },
Jiang zhefb97dc62008-03-06 11:07:11 +01008508 [ALC883_FUJITSU_PI2515] = {
8509 .mixers = { alc883_2ch_fujitsu_pi2515_mixer },
8510 .init_verbs = { alc883_init_verbs,
8511 alc883_2ch_fujitsu_pi2515_verbs},
8512 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8513 .dac_nids = alc883_dac_nids,
8514 .dig_out_nid = ALC883_DIGOUT_NID,
8515 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8516 .channel_mode = alc883_3ST_2ch_modes,
8517 .input_mux = &alc883_fujitsu_pi2515_capture_source,
8518 .unsol_event = alc883_2ch_fujitsu_pi2515_unsol_event,
8519 .init_hook = alc883_2ch_fujitsu_pi2515_automute,
8520 },
Kailang Yange2757d52008-08-26 13:17:46 +02008521 [ALC888_LENOVO_SKY] = {
8522 .mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer },
8523 .init_verbs = { alc883_init_verbs, alc888_lenovo_sky_verbs},
8524 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8525 .dac_nids = alc883_dac_nids,
8526 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yange2757d52008-08-26 13:17:46 +02008527 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
8528 .channel_mode = alc883_sixstack_modes,
8529 .need_dac_fix = 1,
8530 .input_mux = &alc883_lenovo_sky_capture_source,
8531 .unsol_event = alc883_lenovo_sky_unsol_event,
8532 .init_hook = alc888_lenovo_sky_front_automute,
8533 },
8534 [ALC888_ASUS_M90V] = {
8535 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
8536 .init_verbs = { alc883_init_verbs, alc888_asus_m90v_verbs },
8537 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8538 .dac_nids = alc883_dac_nids,
8539 .dig_out_nid = ALC883_DIGOUT_NID,
8540 .dig_in_nid = ALC883_DIGIN_NID,
8541 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
8542 .channel_mode = alc883_3ST_6ch_modes,
8543 .need_dac_fix = 1,
8544 .input_mux = &alc883_fujitsu_pi2515_capture_source,
8545 .unsol_event = alc883_mode2_unsol_event,
8546 .init_hook = alc883_mode2_inithook,
8547 },
8548 [ALC888_ASUS_EEE1601] = {
8549 .mixers = { alc883_asus_eee1601_mixer },
Takashi Iwaif9e336f2008-10-31 16:37:07 +01008550 .cap_mixer = alc883_asus_eee1601_cap_mixer,
Kailang Yange2757d52008-08-26 13:17:46 +02008551 .init_verbs = { alc883_init_verbs, alc888_asus_eee1601_verbs },
8552 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8553 .dac_nids = alc883_dac_nids,
8554 .dig_out_nid = ALC883_DIGOUT_NID,
8555 .dig_in_nid = ALC883_DIGIN_NID,
8556 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8557 .channel_mode = alc883_3ST_2ch_modes,
8558 .need_dac_fix = 1,
8559 .input_mux = &alc883_asus_eee1601_capture_source,
8560 .unsol_event = alc883_eee1601_unsol_event,
8561 .init_hook = alc883_eee1601_inithook,
8562 },
Wu Fengguang3ab90932008-11-17 09:51:09 +01008563 [ALC1200_ASUS_P5Q] = {
8564 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
8565 .init_verbs = { alc883_init_verbs },
8566 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8567 .dac_nids = alc883_dac_nids,
8568 .dig_out_nid = ALC1200_DIGOUT_NID,
8569 .dig_in_nid = ALC883_DIGIN_NID,
8570 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
8571 .channel_mode = alc883_sixstack_modes,
8572 .input_mux = &alc883_capture_source,
8573 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008574};
8575
8576
8577/*
8578 * BIOS auto configuration
8579 */
8580static void alc883_auto_set_output_and_unmute(struct hda_codec *codec,
8581 hda_nid_t nid, int pin_type,
8582 int dac_idx)
8583{
8584 /* set as output */
8585 struct alc_spec *spec = codec->spec;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008586 int idx;
8587
Takashi Iwaif6c7e542008-02-12 18:32:23 +01008588 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008589 if (spec->multiout.dac_nids[dac_idx] == 0x25)
8590 idx = 4;
8591 else
8592 idx = spec->multiout.dac_nids[dac_idx] - 2;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008593 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
8594
8595}
8596
8597static void alc883_auto_init_multi_out(struct hda_codec *codec)
8598{
8599 struct alc_spec *spec = codec->spec;
8600 int i;
8601
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008602 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008603 for (i = 0; i <= HDA_SIDE; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008604 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02008605 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008606 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02008607 alc883_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008608 i);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008609 }
8610}
8611
8612static void alc883_auto_init_hp_out(struct hda_codec *codec)
8613{
8614 struct alc_spec *spec = codec->spec;
8615 hda_nid_t pin;
8616
Takashi Iwaieb06ed82006-09-20 17:10:27 +02008617 pin = spec->autocfg.hp_pins[0];
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008618 if (pin) /* connect to front */
8619 /* use dac 0 */
8620 alc883_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01008621 pin = spec->autocfg.speaker_pins[0];
8622 if (pin)
8623 alc883_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008624}
8625
8626#define alc883_is_input_pin(nid) alc880_is_input_pin(nid)
8627#define ALC883_PIN_CD_NID ALC880_PIN_CD_NID
8628
8629static void alc883_auto_init_analog_input(struct hda_codec *codec)
8630{
8631 struct alc_spec *spec = codec->spec;
8632 int i;
8633
8634 for (i = 0; i < AUTO_PIN_LAST; i++) {
8635 hda_nid_t nid = spec->autocfg.input_pins[i];
8636 if (alc883_is_input_pin(nid)) {
8637 snd_hda_codec_write(codec, nid, 0,
8638 AC_VERB_SET_PIN_WIDGET_CONTROL,
8639 (i <= AUTO_PIN_FRONT_MIC ?
8640 PIN_VREF80 : PIN_IN));
8641 if (nid != ALC883_PIN_CD_NID)
8642 snd_hda_codec_write(codec, nid, 0,
8643 AC_VERB_SET_AMP_GAIN_MUTE,
8644 AMP_OUT_MUTE);
8645 }
8646 }
8647}
8648
Takashi Iwaif511b012008-08-15 16:46:42 +02008649#define alc883_auto_init_input_src alc882_auto_init_input_src
8650
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008651/* almost identical with ALC880 parser... */
8652static int alc883_parse_auto_config(struct hda_codec *codec)
8653{
8654 struct alc_spec *spec = codec->spec;
8655 int err = alc880_parse_auto_config(codec);
8656
8657 if (err < 0)
8658 return err;
Takashi Iwai776e1842007-08-29 15:07:11 +02008659 else if (!err)
8660 return 0; /* no config found */
8661
8662 err = alc_auto_add_mic_boost(codec);
8663 if (err < 0)
8664 return err;
8665
8666 /* hack - override the init verbs */
8667 spec->init_verbs[0] = alc883_auto_init_verbs;
Takashi Iwai776e1842007-08-29 15:07:11 +02008668
8669 return 1; /* config found */
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008670}
8671
8672/* additional initialization for auto-configuration model */
8673static void alc883_auto_init(struct hda_codec *codec)
8674{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01008675 struct alc_spec *spec = codec->spec;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008676 alc883_auto_init_multi_out(codec);
8677 alc883_auto_init_hp_out(codec);
8678 alc883_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +02008679 alc883_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01008680 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02008681 alc_inithook(codec);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008682}
8683
8684static int patch_alc883(struct hda_codec *codec)
8685{
8686 struct alc_spec *spec;
8687 int err, board_config;
8688
8689 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
8690 if (spec == NULL)
8691 return -ENOMEM;
8692
8693 codec->spec = spec;
8694
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02008695 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
8696
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008697 board_config = snd_hda_check_board_config(codec, ALC883_MODEL_LAST,
8698 alc883_models,
8699 alc883_cfg_tbl);
8700 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008701 printk(KERN_INFO "hda_codec: Unknown model for ALC883, "
8702 "trying auto-probe from BIOS...\n");
8703 board_config = ALC883_AUTO;
8704 }
8705
8706 if (board_config == ALC883_AUTO) {
8707 /* automatic parse from the BIOS config */
8708 err = alc883_parse_auto_config(codec);
8709 if (err < 0) {
8710 alc_free(codec);
8711 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008712 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008713 printk(KERN_INFO
8714 "hda_codec: Cannot set up configuration "
8715 "from BIOS. Using base mode...\n");
8716 board_config = ALC883_3ST_2ch_DIG;
8717 }
8718 }
8719
8720 if (board_config != ALC883_AUTO)
8721 setup_preset(spec, &alc883_presets[board_config]);
8722
Kailang Yang2f893282008-05-27 12:14:47 +02008723 switch (codec->vendor_id) {
8724 case 0x10ec0888:
Kailang Yang44426082008-10-15 11:18:05 +02008725 if (codec->revision_id == 0x100101) {
8726 spec->stream_name_analog = "ALC1200 Analog";
8727 spec->stream_name_digital = "ALC1200 Digital";
8728 } else {
8729 spec->stream_name_analog = "ALC888 Analog";
8730 spec->stream_name_digital = "ALC888 Digital";
8731 }
Kailang Yang2f893282008-05-27 12:14:47 +02008732 break;
8733 case 0x10ec0889:
8734 spec->stream_name_analog = "ALC889 Analog";
8735 spec->stream_name_digital = "ALC889 Digital";
8736 break;
8737 default:
8738 spec->stream_name_analog = "ALC883 Analog";
8739 spec->stream_name_digital = "ALC883 Digital";
8740 break;
8741 }
8742
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008743 spec->stream_analog_playback = &alc883_pcm_analog_playback;
8744 spec->stream_analog_capture = &alc883_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01008745 spec->stream_analog_alt_capture = &alc883_pcm_analog_alt_capture;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008746
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008747 spec->stream_digital_playback = &alc883_pcm_digital_playback;
8748 spec->stream_digital_capture = &alc883_pcm_digital_capture;
8749
Takashi Iwaif9e336f2008-10-31 16:37:07 +01008750 if (!spec->num_adc_nids) {
8751 spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids);
8752 spec->adc_nids = alc883_adc_nids;
8753 }
8754 if (!spec->capsrc_nids)
8755 spec->capsrc_nids = alc883_capsrc_nids;
Takashi Iwai54cbc9a2008-10-31 15:24:04 +01008756 spec->is_mix_capture = 1; /* matrix-style capture */
Takashi Iwaif9e336f2008-10-31 16:37:07 +01008757 if (!spec->cap_mixer)
8758 set_capture_mixer(spec);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008759
Takashi Iwai2134ea42008-01-10 16:53:55 +01008760 spec->vmaster_nid = 0x0c;
8761
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008762 codec->patch_ops = alc_patch_ops;
8763 if (board_config == ALC883_AUTO)
8764 spec->init_hook = alc883_auto_init;
Kailang Yangf9423e72008-05-27 12:32:25 +02008765
Takashi Iwaicb53c622007-08-10 17:21:45 +02008766#ifdef CONFIG_SND_HDA_POWER_SAVE
8767 if (!spec->loopback.amplist)
8768 spec->loopback.amplist = alc883_loopbacks;
8769#endif
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008770
8771 return 0;
8772}
8773
8774/*
Kailang Yangdf694da2005-12-05 19:42:22 +01008775 * ALC262 support
8776 */
8777
8778#define ALC262_DIGOUT_NID ALC880_DIGOUT_NID
8779#define ALC262_DIGIN_NID ALC880_DIGIN_NID
8780
8781#define alc262_dac_nids alc260_dac_nids
8782#define alc262_adc_nids alc882_adc_nids
8783#define alc262_adc_nids_alt alc882_adc_nids_alt
Takashi Iwai88c71a92008-02-14 17:27:17 +01008784#define alc262_capsrc_nids alc882_capsrc_nids
8785#define alc262_capsrc_nids_alt alc882_capsrc_nids_alt
Kailang Yangdf694da2005-12-05 19:42:22 +01008786
8787#define alc262_modes alc260_modes
Takashi Iwaic5f2ea02005-12-06 18:54:31 +01008788#define alc262_capture_source alc882_capture_source
Kailang Yangdf694da2005-12-05 19:42:22 +01008789
Kailang Yang4e555fe2008-08-26 13:05:55 +02008790static hda_nid_t alc262_dmic_adc_nids[1] = {
8791 /* ADC0 */
8792 0x09
8793};
8794
8795static hda_nid_t alc262_dmic_capsrc_nids[1] = { 0x22 };
8796
Kailang Yangdf694da2005-12-05 19:42:22 +01008797static struct snd_kcontrol_new alc262_base_mixer[] = {
8798 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8799 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8800 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8801 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8802 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8803 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8804 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8805 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008806 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01008807 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
8808 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008809 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01008810 /* HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01008811 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT), */
Kailang Yangdf694da2005-12-05 19:42:22 +01008812 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),
8813 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8814 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8815 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01008816 { } /* end */
Takashi Iwai834be882006-03-01 14:16:17 +01008817};
8818
Kailang Yangccc656c2006-10-17 12:32:26 +02008819static struct snd_kcontrol_new alc262_hippo1_mixer[] = {
8820 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8821 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8822 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8823 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8824 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8825 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8826 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8827 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008828 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008829 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
8830 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008831 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008832 /* HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01008833 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT), */
Kailang Yangccc656c2006-10-17 12:32:26 +02008834 /*HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),*/
8835 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8836 { } /* end */
8837};
8838
Takashi Iwaice875f02008-01-28 18:17:43 +01008839/* update HP, line and mono-out pins according to the master switch */
8840static void alc262_hp_master_update(struct hda_codec *codec)
8841{
8842 struct alc_spec *spec = codec->spec;
8843 int val = spec->master_sw;
8844
8845 /* HP & line-out */
8846 snd_hda_codec_write_cache(codec, 0x1b, 0,
8847 AC_VERB_SET_PIN_WIDGET_CONTROL,
8848 val ? PIN_HP : 0);
8849 snd_hda_codec_write_cache(codec, 0x15, 0,
8850 AC_VERB_SET_PIN_WIDGET_CONTROL,
8851 val ? PIN_HP : 0);
8852 /* mono (speaker) depending on the HP jack sense */
8853 val = val && !spec->jack_present;
8854 snd_hda_codec_write_cache(codec, 0x16, 0,
8855 AC_VERB_SET_PIN_WIDGET_CONTROL,
8856 val ? PIN_OUT : 0);
8857}
8858
8859static void alc262_hp_bpc_automute(struct hda_codec *codec)
8860{
8861 struct alc_spec *spec = codec->spec;
8862 unsigned int presence;
8863 presence = snd_hda_codec_read(codec, 0x1b, 0,
8864 AC_VERB_GET_PIN_SENSE, 0);
8865 spec->jack_present = !!(presence & AC_PINSENSE_PRESENCE);
8866 alc262_hp_master_update(codec);
8867}
8868
8869static void alc262_hp_bpc_unsol_event(struct hda_codec *codec, unsigned int res)
8870{
8871 if ((res >> 26) != ALC880_HP_EVENT)
8872 return;
8873 alc262_hp_bpc_automute(codec);
8874}
8875
8876static void alc262_hp_wildwest_automute(struct hda_codec *codec)
8877{
8878 struct alc_spec *spec = codec->spec;
8879 unsigned int presence;
8880 presence = snd_hda_codec_read(codec, 0x15, 0,
8881 AC_VERB_GET_PIN_SENSE, 0);
8882 spec->jack_present = !!(presence & AC_PINSENSE_PRESENCE);
8883 alc262_hp_master_update(codec);
8884}
8885
8886static void alc262_hp_wildwest_unsol_event(struct hda_codec *codec,
8887 unsigned int res)
8888{
8889 if ((res >> 26) != ALC880_HP_EVENT)
8890 return;
8891 alc262_hp_wildwest_automute(codec);
8892}
8893
8894static int alc262_hp_master_sw_get(struct snd_kcontrol *kcontrol,
8895 struct snd_ctl_elem_value *ucontrol)
8896{
8897 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
8898 struct alc_spec *spec = codec->spec;
8899 *ucontrol->value.integer.value = spec->master_sw;
8900 return 0;
8901}
8902
8903static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol,
8904 struct snd_ctl_elem_value *ucontrol)
8905{
8906 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
8907 struct alc_spec *spec = codec->spec;
8908 int val = !!*ucontrol->value.integer.value;
8909
8910 if (val == spec->master_sw)
8911 return 0;
8912 spec->master_sw = val;
8913 alc262_hp_master_update(codec);
8914 return 1;
8915}
8916
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008917static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
Takashi Iwaice875f02008-01-28 18:17:43 +01008918 {
8919 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8920 .name = "Master Playback Switch",
8921 .info = snd_ctl_boolean_mono_info,
8922 .get = alc262_hp_master_sw_get,
8923 .put = alc262_hp_master_sw_put,
8924 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008925 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8926 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8927 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +01008928 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
8929 HDA_OUTPUT),
8930 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
8931 HDA_OUTPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008932 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8933 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008934 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008935 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
8936 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008937 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008938 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8939 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8940 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8941 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8942 HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
8943 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT),
8944 HDA_CODEC_VOLUME("AUX IN Playback Volume", 0x0b, 0x06, HDA_INPUT),
8945 HDA_CODEC_MUTE("AUX IN Playback Switch", 0x0b, 0x06, HDA_INPUT),
8946 { } /* end */
8947};
8948
Kailang Yangcd7509a2007-01-26 18:33:17 +01008949static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = {
Takashi Iwaice875f02008-01-28 18:17:43 +01008950 {
8951 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8952 .name = "Master Playback Switch",
8953 .info = snd_ctl_boolean_mono_info,
8954 .get = alc262_hp_master_sw_get,
8955 .put = alc262_hp_master_sw_put,
8956 },
Kailang Yangcd7509a2007-01-26 18:33:17 +01008957 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8958 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8959 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8960 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +01008961 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
8962 HDA_OUTPUT),
8963 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
8964 HDA_OUTPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +01008965 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT),
8966 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008967 HDA_CODEC_VOLUME("Front Mic Boost", 0x1a, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +01008968 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
8969 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
8970 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8971 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8972 HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
8973 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT),
8974 { } /* end */
8975};
8976
8977static struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = {
8978 HDA_CODEC_VOLUME("Rear Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8979 HDA_CODEC_MUTE("Rear Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008980 HDA_CODEC_VOLUME("Rear Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +01008981 { } /* end */
8982};
8983
Kailang Yang66d2a9d2007-11-14 12:06:21 +01008984/* mute/unmute internal speaker according to the hp jack and mute state */
8985static void alc262_hp_t5735_automute(struct hda_codec *codec, int force)
8986{
8987 struct alc_spec *spec = codec->spec;
Kailang Yang66d2a9d2007-11-14 12:06:21 +01008988
8989 if (force || !spec->sense_updated) {
8990 unsigned int present;
8991 present = snd_hda_codec_read(codec, 0x15, 0,
8992 AC_VERB_GET_PIN_SENSE, 0);
Takashi Iwai4bb26132008-01-28 18:12:42 +01008993 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
Kailang Yang66d2a9d2007-11-14 12:06:21 +01008994 spec->sense_updated = 1;
8995 }
Takashi Iwai4bb26132008-01-28 18:12:42 +01008996 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0, HDA_AMP_MUTE,
8997 spec->jack_present ? HDA_AMP_MUTE : 0);
Kailang Yang66d2a9d2007-11-14 12:06:21 +01008998}
8999
9000static void alc262_hp_t5735_unsol_event(struct hda_codec *codec,
9001 unsigned int res)
9002{
9003 if ((res >> 26) != ALC880_HP_EVENT)
9004 return;
9005 alc262_hp_t5735_automute(codec, 1);
9006}
9007
9008static void alc262_hp_t5735_init_hook(struct hda_codec *codec)
9009{
9010 alc262_hp_t5735_automute(codec, 1);
9011}
9012
9013static struct snd_kcontrol_new alc262_hp_t5735_mixer[] = {
Takashi Iwai86cd9292008-01-28 18:09:56 +01009014 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9015 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009016 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
9017 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9018 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9019 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9020 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9021 { } /* end */
9022};
9023
9024static struct hda_verb alc262_hp_t5735_verbs[] = {
9025 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9026 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9027
9028 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9029 { }
9030};
9031
Kailang Yang8c427222008-01-10 13:03:59 +01009032static struct snd_kcontrol_new alc262_hp_rp5700_mixer[] = {
Takashi Iwaif2f48e12008-01-28 18:14:43 +01009033 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9034 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01009035 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
9036 HDA_CODEC_MUTE("Speaker Playback Switch", 0x16, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +01009037 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
9038 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
9039 { } /* end */
9040};
9041
9042static struct hda_verb alc262_hp_rp5700_verbs[] = {
9043 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9044 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9045 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9046 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9047 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
9048 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
9049 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
9050 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
9051 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
9052 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
9053 {}
9054};
9055
9056static struct hda_input_mux alc262_hp_rp5700_capture_source = {
9057 .num_items = 1,
9058 .items = {
9059 { "Line", 0x1 },
9060 },
9061};
9062
Takashi Iwai0724ea22007-08-23 00:31:43 +02009063/* bind hp and internal speaker mute (with plug check) */
9064static int alc262_sony_master_sw_put(struct snd_kcontrol *kcontrol,
9065 struct snd_ctl_elem_value *ucontrol)
9066{
9067 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
9068 long *valp = ucontrol->value.integer.value;
9069 int change;
9070
9071 /* change hp mute */
9072 change = snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0,
9073 HDA_AMP_MUTE,
9074 valp[0] ? 0 : HDA_AMP_MUTE);
9075 change |= snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0,
9076 HDA_AMP_MUTE,
9077 valp[1] ? 0 : HDA_AMP_MUTE);
9078 if (change) {
9079 /* change speaker according to HP jack state */
9080 struct alc_spec *spec = codec->spec;
9081 unsigned int mute;
9082 if (spec->jack_present)
9083 mute = HDA_AMP_MUTE;
9084 else
9085 mute = snd_hda_codec_amp_read(codec, 0x15, 0,
9086 HDA_OUTPUT, 0);
9087 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9088 HDA_AMP_MUTE, mute);
9089 }
9090 return change;
9091}
Takashi Iwai5b319542007-07-26 11:49:22 +02009092
Kailang Yang272a5272007-05-14 11:00:38 +02009093static struct snd_kcontrol_new alc262_sony_mixer[] = {
Takashi Iwai0724ea22007-08-23 00:31:43 +02009094 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9095 {
9096 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9097 .name = "Master Playback Switch",
9098 .info = snd_hda_mixer_amp_switch_info,
9099 .get = snd_hda_mixer_amp_switch_get,
9100 .put = alc262_sony_master_sw_put,
9101 .private_value = HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
9102 },
Kailang Yang272a5272007-05-14 11:00:38 +02009103 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9104 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9105 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
9106 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
9107 { } /* end */
9108};
9109
Kailang Yang83c34212007-07-05 11:43:05 +02009110static struct snd_kcontrol_new alc262_benq_t31_mixer[] = {
9111 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9112 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9113 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9114 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9115 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9116 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
9117 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
9118 { } /* end */
9119};
Kailang Yang272a5272007-05-14 11:00:38 +02009120
Kailang Yangdf694da2005-12-05 19:42:22 +01009121#define alc262_capture_mixer alc882_capture_mixer
9122#define alc262_capture_alt_mixer alc882_capture_alt_mixer
9123
9124/*
9125 * generic initialization of ADC, input mixers and output mixers
9126 */
9127static struct hda_verb alc262_init_verbs[] = {
9128 /*
9129 * Unmute ADC0-2 and set the default input to mic-in
9130 */
9131 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
9132 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9133 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
9134 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9135 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
9136 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9137
Takashi Iwaicb53c622007-08-10 17:21:45 +02009138 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +01009139 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009140 * Note: PASD motherboards uses the Line In 2 as the input for
9141 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01009142 */
9143 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02009144 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9145 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
9146 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
9147 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
9148 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01009149
9150 /*
9151 * Set up output mixers (0x0c - 0x0e)
9152 */
9153 /* set vol=0 to output mixers */
9154 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9155 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9156 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9157 /* set up input amps for analog loopback */
9158 /* Amp Indices: DAC = 0, mixer = 1 */
9159 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9160 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9161 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9162 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9163 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9164 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9165
9166 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
9167 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
9168 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
9169 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9170 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9171 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9172
9173 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
9174 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
9175 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
9176 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
9177 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Kailang Yangea1fb292008-08-26 12:58:38 +02009178
Kailang Yangdf694da2005-12-05 19:42:22 +01009179 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
9180 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Kailang Yangea1fb292008-08-26 12:58:38 +02009181
Kailang Yangdf694da2005-12-05 19:42:22 +01009182 /* FIXME: use matrix-type input source selection */
9183 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
9184 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
9185 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9186 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
9187 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
9188 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
9189 /* Input mixer2 */
9190 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9191 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
9192 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
9193 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
9194 /* Input mixer3 */
9195 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9196 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
9197 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009198 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
Kailang Yangdf694da2005-12-05 19:42:22 +01009199
9200 { }
9201};
9202
Kailang Yang4e555fe2008-08-26 13:05:55 +02009203static struct hda_verb alc262_eapd_verbs[] = {
9204 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
9205 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
9206 { }
9207};
9208
Kailang Yangccc656c2006-10-17 12:32:26 +02009209static struct hda_verb alc262_hippo_unsol_verbs[] = {
9210 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
9211 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9212 {}
9213};
9214
9215static struct hda_verb alc262_hippo1_unsol_verbs[] = {
9216 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
9217 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
9218 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
9219
9220 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
9221 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9222 {}
9223};
9224
Kailang Yang272a5272007-05-14 11:00:38 +02009225static struct hda_verb alc262_sony_unsol_verbs[] = {
9226 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
9227 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9228 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, // Front Mic
9229
9230 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
9231 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Akio Idehara7b1e8792008-06-09 22:46:07 +09009232 {}
Kailang Yang272a5272007-05-14 11:00:38 +02009233};
9234
Kailang Yang4e555fe2008-08-26 13:05:55 +02009235static struct hda_input_mux alc262_dmic_capture_source = {
9236 .num_items = 2,
9237 .items = {
9238 { "Int DMic", 0x9 },
9239 { "Mic", 0x0 },
9240 },
9241};
9242
9243static struct snd_kcontrol_new alc262_toshiba_s06_mixer[] = {
9244 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9245 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9246 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9247 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9248 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang4e555fe2008-08-26 13:05:55 +02009249 { } /* end */
9250};
9251
9252static struct hda_verb alc262_toshiba_s06_verbs[] = {
9253 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
9254 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9255 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9256 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9257 {0x22, AC_VERB_SET_CONNECT_SEL, 0x09},
9258 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9259 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
9260 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
9261 {}
9262};
9263
9264static void alc262_dmic_automute(struct hda_codec *codec)
9265{
9266 unsigned int present;
9267
9268 present = snd_hda_codec_read(codec, 0x18, 0,
9269 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
9270 snd_hda_codec_write(codec, 0x22, 0,
9271 AC_VERB_SET_CONNECT_SEL, present ? 0x0 : 0x09);
9272}
9273
9274/* toggle speaker-output according to the hp-jack state */
9275static void alc262_toshiba_s06_speaker_automute(struct hda_codec *codec)
9276{
9277 unsigned int present;
9278 unsigned char bits;
9279
9280 present = snd_hda_codec_read(codec, 0x15, 0,
9281 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
9282 bits = present ? 0 : PIN_OUT;
9283 snd_hda_codec_write(codec, 0x14, 0,
9284 AC_VERB_SET_PIN_WIDGET_CONTROL, bits);
9285}
9286
9287
9288
9289/* unsolicited event for HP jack sensing */
9290static void alc262_toshiba_s06_unsol_event(struct hda_codec *codec,
9291 unsigned int res)
9292{
9293 if ((res >> 26) == ALC880_HP_EVENT)
9294 alc262_toshiba_s06_speaker_automute(codec);
9295 if ((res >> 26) == ALC880_MIC_EVENT)
9296 alc262_dmic_automute(codec);
9297
9298}
9299
9300static void alc262_toshiba_s06_init_hook(struct hda_codec *codec)
9301{
9302 alc262_toshiba_s06_speaker_automute(codec);
9303 alc262_dmic_automute(codec);
9304}
9305
Kailang Yangccc656c2006-10-17 12:32:26 +02009306/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwai5b319542007-07-26 11:49:22 +02009307static void alc262_hippo_automute(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02009308{
9309 struct alc_spec *spec = codec->spec;
9310 unsigned int mute;
Takashi Iwai5b319542007-07-26 11:49:22 +02009311 unsigned int present;
Kailang Yangccc656c2006-10-17 12:32:26 +02009312
Takashi Iwai5b319542007-07-26 11:49:22 +02009313 /* need to execute and sync at first */
9314 snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0);
9315 present = snd_hda_codec_read(codec, 0x15, 0,
9316 AC_VERB_GET_PIN_SENSE, 0);
9317 spec->jack_present = (present & 0x80000000) != 0;
Kailang Yangccc656c2006-10-17 12:32:26 +02009318 if (spec->jack_present) {
9319 /* mute internal speaker */
Takashi Iwai47fd8302007-08-10 17:11:07 +02009320 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9321 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yangccc656c2006-10-17 12:32:26 +02009322 } else {
9323 /* unmute internal speaker if necessary */
9324 mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0);
Takashi Iwai47fd8302007-08-10 17:11:07 +02009325 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9326 HDA_AMP_MUTE, mute);
Kailang Yangccc656c2006-10-17 12:32:26 +02009327 }
9328}
9329
9330/* unsolicited event for HP jack sensing */
9331static void alc262_hippo_unsol_event(struct hda_codec *codec,
9332 unsigned int res)
9333{
9334 if ((res >> 26) != ALC880_HP_EVENT)
9335 return;
Takashi Iwai5b319542007-07-26 11:49:22 +02009336 alc262_hippo_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02009337}
9338
Takashi Iwai5b319542007-07-26 11:49:22 +02009339static void alc262_hippo1_automute(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02009340{
Kailang Yangccc656c2006-10-17 12:32:26 +02009341 unsigned int mute;
Takashi Iwai5b319542007-07-26 11:49:22 +02009342 unsigned int present;
Kailang Yangccc656c2006-10-17 12:32:26 +02009343
Takashi Iwai5b319542007-07-26 11:49:22 +02009344 snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
9345 present = snd_hda_codec_read(codec, 0x1b, 0,
9346 AC_VERB_GET_PIN_SENSE, 0);
9347 present = (present & 0x80000000) != 0;
9348 if (present) {
Kailang Yangccc656c2006-10-17 12:32:26 +02009349 /* mute internal speaker */
Takashi Iwai47fd8302007-08-10 17:11:07 +02009350 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9351 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yangccc656c2006-10-17 12:32:26 +02009352 } else {
9353 /* unmute internal speaker if necessary */
9354 mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
Takashi Iwai47fd8302007-08-10 17:11:07 +02009355 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9356 HDA_AMP_MUTE, mute);
Kailang Yangccc656c2006-10-17 12:32:26 +02009357 }
9358}
9359
9360/* unsolicited event for HP jack sensing */
9361static void alc262_hippo1_unsol_event(struct hda_codec *codec,
9362 unsigned int res)
9363{
9364 if ((res >> 26) != ALC880_HP_EVENT)
9365 return;
Takashi Iwai5b319542007-07-26 11:49:22 +02009366 alc262_hippo1_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02009367}
9368
Takashi Iwai834be882006-03-01 14:16:17 +01009369/*
Pascal Terjane8f9ae22008-08-04 14:36:05 +02009370 * nec model
9371 * 0x15 = headphone
9372 * 0x16 = internal speaker
9373 * 0x18 = external mic
9374 */
9375
9376static struct snd_kcontrol_new alc262_nec_mixer[] = {
9377 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
9378 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 0, 0x0, HDA_OUTPUT),
9379
9380 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9381 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9382 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9383
9384 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
9385 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9386 { } /* end */
9387};
9388
9389static struct hda_verb alc262_nec_verbs[] = {
9390 /* Unmute Speaker */
9391 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9392
9393 /* Headphone */
9394 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
9395 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9396
9397 /* External mic to headphone */
9398 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9399 /* External mic to speaker */
9400 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9401 {}
9402};
9403
9404/*
Takashi Iwai834be882006-03-01 14:16:17 +01009405 * fujitsu model
Tony Vroon5d9fab22008-03-14 17:09:18 +01009406 * 0x14 = headphone/spdif-out, 0x15 = internal speaker,
9407 * 0x1b = port replicator headphone out
Takashi Iwai834be882006-03-01 14:16:17 +01009408 */
9409
9410#define ALC_HP_EVENT 0x37
9411
9412static struct hda_verb alc262_fujitsu_unsol_verbs[] = {
9413 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
9414 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Tony Vroon5d9fab22008-03-14 17:09:18 +01009415 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
9416 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai834be882006-03-01 14:16:17 +01009417 {}
9418};
9419
Jiang zhe0e31daf2008-03-20 12:12:39 +01009420static struct hda_verb alc262_lenovo_3000_unsol_verbs[] = {
9421 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
9422 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9423 {}
9424};
9425
Takashi Iwai834be882006-03-01 14:16:17 +01009426static struct hda_input_mux alc262_fujitsu_capture_source = {
Takashi Iwai39d3ed32007-10-12 15:03:48 +02009427 .num_items = 3,
Takashi Iwai834be882006-03-01 14:16:17 +01009428 .items = {
9429 { "Mic", 0x0 },
Takashi Iwai39d3ed32007-10-12 15:03:48 +02009430 { "Int Mic", 0x1 },
Takashi Iwai834be882006-03-01 14:16:17 +01009431 { "CD", 0x4 },
9432 },
9433};
9434
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009435static struct hda_input_mux alc262_HP_capture_source = {
9436 .num_items = 5,
9437 .items = {
9438 { "Mic", 0x0 },
zhejiangaccbe492007-08-31 12:36:05 +02009439 { "Front Mic", 0x1 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009440 { "Line", 0x2 },
9441 { "CD", 0x4 },
9442 { "AUX IN", 0x6 },
9443 },
9444};
9445
zhejiangaccbe492007-08-31 12:36:05 +02009446static struct hda_input_mux alc262_HP_D7000_capture_source = {
9447 .num_items = 4,
9448 .items = {
9449 { "Mic", 0x0 },
9450 { "Front Mic", 0x2 },
9451 { "Line", 0x1 },
9452 { "CD", 0x4 },
9453 },
9454};
9455
Takashi Iwaiebc7a402008-05-20 09:23:05 +02009456/* mute/unmute internal speaker according to the hp jacks and mute state */
Takashi Iwai834be882006-03-01 14:16:17 +01009457static void alc262_fujitsu_automute(struct hda_codec *codec, int force)
9458{
9459 struct alc_spec *spec = codec->spec;
9460 unsigned int mute;
9461
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009462 if (force || !spec->sense_updated) {
Takashi Iwaiebc7a402008-05-20 09:23:05 +02009463 unsigned int present;
Takashi Iwai834be882006-03-01 14:16:17 +01009464 /* need to execute and sync at first */
9465 snd_hda_codec_read(codec, 0x14, 0, AC_VERB_SET_PIN_SENSE, 0);
Takashi Iwaiebc7a402008-05-20 09:23:05 +02009466 /* check laptop HP jack */
9467 present = snd_hda_codec_read(codec, 0x14, 0,
9468 AC_VERB_GET_PIN_SENSE, 0);
9469 /* need to execute and sync at first */
9470 snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
9471 /* check docking HP jack */
9472 present |= snd_hda_codec_read(codec, 0x1b, 0,
9473 AC_VERB_GET_PIN_SENSE, 0);
9474 if (present & AC_PINSENSE_PRESENCE)
9475 spec->jack_present = 1;
9476 else
9477 spec->jack_present = 0;
Takashi Iwai834be882006-03-01 14:16:17 +01009478 spec->sense_updated = 1;
9479 }
Takashi Iwaiebc7a402008-05-20 09:23:05 +02009480 /* unmute internal speaker only if both HPs are unplugged and
9481 * master switch is on
9482 */
9483 if (spec->jack_present)
9484 mute = HDA_AMP_MUTE;
9485 else
Takashi Iwai834be882006-03-01 14:16:17 +01009486 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
Takashi Iwaiebc7a402008-05-20 09:23:05 +02009487 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9488 HDA_AMP_MUTE, mute);
Takashi Iwai834be882006-03-01 14:16:17 +01009489}
9490
9491/* unsolicited event for HP jack sensing */
9492static void alc262_fujitsu_unsol_event(struct hda_codec *codec,
9493 unsigned int res)
9494{
9495 if ((res >> 26) != ALC_HP_EVENT)
9496 return;
9497 alc262_fujitsu_automute(codec, 1);
9498}
9499
Takashi Iwaiebc7a402008-05-20 09:23:05 +02009500static void alc262_fujitsu_init_hook(struct hda_codec *codec)
9501{
9502 alc262_fujitsu_automute(codec, 1);
9503}
9504
Takashi Iwai834be882006-03-01 14:16:17 +01009505/* bind volumes of both NID 0x0c and 0x0d */
Takashi Iwaicca3b372007-08-10 17:12:15 +02009506static struct hda_bind_ctls alc262_fujitsu_bind_master_vol = {
9507 .ops = &snd_hda_bind_vol,
9508 .values = {
9509 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT),
9510 HDA_COMPOSE_AMP_VAL(0x0d, 3, 0, HDA_OUTPUT),
9511 0
9512 },
9513};
Takashi Iwai834be882006-03-01 14:16:17 +01009514
Jiang zhe0e31daf2008-03-20 12:12:39 +01009515/* mute/unmute internal speaker according to the hp jack and mute state */
9516static void alc262_lenovo_3000_automute(struct hda_codec *codec, int force)
9517{
9518 struct alc_spec *spec = codec->spec;
9519 unsigned int mute;
9520
9521 if (force || !spec->sense_updated) {
9522 unsigned int present_int_hp;
9523 /* need to execute and sync at first */
9524 snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
9525 present_int_hp = snd_hda_codec_read(codec, 0x1b, 0,
9526 AC_VERB_GET_PIN_SENSE, 0);
9527 spec->jack_present = (present_int_hp & 0x80000000) != 0;
9528 spec->sense_updated = 1;
9529 }
9530 if (spec->jack_present) {
9531 /* mute internal speaker */
9532 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9533 HDA_AMP_MUTE, HDA_AMP_MUTE);
9534 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
9535 HDA_AMP_MUTE, HDA_AMP_MUTE);
9536 } else {
9537 /* unmute internal speaker if necessary */
9538 mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
9539 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9540 HDA_AMP_MUTE, mute);
9541 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
9542 HDA_AMP_MUTE, mute);
9543 }
9544}
9545
9546/* unsolicited event for HP jack sensing */
9547static void alc262_lenovo_3000_unsol_event(struct hda_codec *codec,
9548 unsigned int res)
9549{
9550 if ((res >> 26) != ALC_HP_EVENT)
9551 return;
9552 alc262_lenovo_3000_automute(codec, 1);
9553}
9554
Takashi Iwai834be882006-03-01 14:16:17 +01009555/* bind hp and internal speaker mute (with plug check) */
9556static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol,
9557 struct snd_ctl_elem_value *ucontrol)
9558{
9559 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
9560 long *valp = ucontrol->value.integer.value;
9561 int change;
9562
Tony Vroon5d9fab22008-03-14 17:09:18 +01009563 change = snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9564 HDA_AMP_MUTE,
9565 valp ? 0 : HDA_AMP_MUTE);
9566 change |= snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
9567 HDA_AMP_MUTE,
9568 valp ? 0 : HDA_AMP_MUTE);
9569
Takashi Iwai82beb8f2007-08-10 17:09:26 +02009570 if (change)
9571 alc262_fujitsu_automute(codec, 0);
Takashi Iwai834be882006-03-01 14:16:17 +01009572 return change;
9573}
9574
9575static struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02009576 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
Takashi Iwai834be882006-03-01 14:16:17 +01009577 {
9578 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9579 .name = "Master Playback Switch",
9580 .info = snd_hda_mixer_amp_switch_info,
9581 .get = snd_hda_mixer_amp_switch_get,
9582 .put = alc262_fujitsu_master_sw_put,
9583 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
9584 },
9585 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9586 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Tony Vroon06a9c302008-04-14 13:31:45 +02009587 HDA_CODEC_VOLUME("PC Speaker Volume", 0x0b, 0x05, HDA_INPUT),
9588 HDA_CODEC_MUTE("PC Speaker Switch", 0x0b, 0x05, HDA_INPUT),
Takashi Iwai834be882006-03-01 14:16:17 +01009589 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9590 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9591 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai39d3ed32007-10-12 15:03:48 +02009592 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
9593 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
9594 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai834be882006-03-01 14:16:17 +01009595 { } /* end */
9596};
9597
Jiang zhe0e31daf2008-03-20 12:12:39 +01009598/* bind hp and internal speaker mute (with plug check) */
9599static int alc262_lenovo_3000_master_sw_put(struct snd_kcontrol *kcontrol,
9600 struct snd_ctl_elem_value *ucontrol)
9601{
9602 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
9603 long *valp = ucontrol->value.integer.value;
9604 int change;
9605
9606 change = snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
9607 HDA_AMP_MUTE,
9608 valp ? 0 : HDA_AMP_MUTE);
9609
9610 if (change)
9611 alc262_lenovo_3000_automute(codec, 0);
9612 return change;
9613}
9614
9615static struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = {
9616 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
9617 {
9618 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9619 .name = "Master Playback Switch",
9620 .info = snd_hda_mixer_amp_switch_info,
9621 .get = snd_hda_mixer_amp_switch_get,
9622 .put = alc262_lenovo_3000_master_sw_put,
9623 .private_value = HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
9624 },
9625 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9626 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9627 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9628 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9629 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9630 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
9631 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
9632 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
9633 { } /* end */
9634};
9635
Hiroshi Miura9f99a632008-08-28 16:09:06 +02009636static struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = {
9637 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
9638 {
9639 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9640 .name = "Master Playback Switch",
9641 .info = snd_hda_mixer_amp_switch_info,
9642 .get = snd_hda_mixer_amp_switch_get,
9643 .put = alc262_sony_master_sw_put,
9644 .private_value = HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
9645 },
9646 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9647 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9648 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9649 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
9650 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
9651 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
9652 { } /* end */
9653};
9654
Takashi Iwai304dcaa2006-07-25 14:51:16 +02009655/* additional init verbs for Benq laptops */
9656static struct hda_verb alc262_EAPD_verbs[] = {
9657 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
9658 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
9659 {}
9660};
9661
Kailang Yang83c34212007-07-05 11:43:05 +02009662static struct hda_verb alc262_benq_t31_EAPD_verbs[] = {
9663 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9664 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9665
9666 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
9667 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
9668 {}
9669};
9670
Tobin Davisf651b502007-10-26 12:40:47 +02009671/* Samsung Q1 Ultra Vista model setup */
9672static struct snd_kcontrol_new alc262_ultra_mixer[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01009673 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9674 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +02009675 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
9676 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
9677 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01009678 HDA_CODEC_VOLUME("Headphone Mic Boost", 0x15, 0, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +02009679 { } /* end */
9680};
9681
9682static struct hda_verb alc262_ultra_verbs[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01009683 /* output mixer */
9684 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9685 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
9686 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9687 /* speaker */
9688 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9689 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9690 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9691 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
9692 /* HP */
Tobin Davisf651b502007-10-26 12:40:47 +02009693 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01009694 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9695 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9696 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9697 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
9698 /* internal mic */
9699 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
9700 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
9701 /* ADC, choose mic */
9702 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9703 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9704 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9705 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
9706 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
9707 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
9708 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
9709 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
9710 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
9711 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(8)},
Tobin Davisf651b502007-10-26 12:40:47 +02009712 {}
9713};
9714
Tobin Davisf651b502007-10-26 12:40:47 +02009715/* mute/unmute internal speaker according to the hp jack and mute state */
9716static void alc262_ultra_automute(struct hda_codec *codec)
9717{
9718 struct alc_spec *spec = codec->spec;
9719 unsigned int mute;
Tobin Davisf651b502007-10-26 12:40:47 +02009720
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01009721 mute = 0;
9722 /* auto-mute only when HP is used as HP */
9723 if (!spec->cur_mux[0]) {
9724 unsigned int present;
9725 /* need to execute and sync at first */
9726 snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0);
9727 present = snd_hda_codec_read(codec, 0x15, 0,
9728 AC_VERB_GET_PIN_SENSE, 0);
9729 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
9730 if (spec->jack_present)
9731 mute = HDA_AMP_MUTE;
Tobin Davisf651b502007-10-26 12:40:47 +02009732 }
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01009733 /* mute/unmute internal speaker */
9734 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9735 HDA_AMP_MUTE, mute);
9736 /* mute/unmute HP */
9737 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9738 HDA_AMP_MUTE, mute ? 0 : HDA_AMP_MUTE);
Tobin Davisf651b502007-10-26 12:40:47 +02009739}
9740
9741/* unsolicited event for HP jack sensing */
9742static void alc262_ultra_unsol_event(struct hda_codec *codec,
9743 unsigned int res)
9744{
9745 if ((res >> 26) != ALC880_HP_EVENT)
9746 return;
9747 alc262_ultra_automute(codec);
9748}
9749
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01009750static struct hda_input_mux alc262_ultra_capture_source = {
9751 .num_items = 2,
9752 .items = {
9753 { "Mic", 0x1 },
9754 { "Headphone", 0x7 },
9755 },
9756};
9757
9758static int alc262_ultra_mux_enum_put(struct snd_kcontrol *kcontrol,
9759 struct snd_ctl_elem_value *ucontrol)
9760{
9761 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
9762 struct alc_spec *spec = codec->spec;
9763 int ret;
9764
Takashi Iwai54cbc9a2008-10-31 15:24:04 +01009765 ret = alc_mux_enum_put(kcontrol, ucontrol);
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01009766 if (!ret)
9767 return 0;
9768 /* reprogram the HP pin as mic or HP according to the input source */
9769 snd_hda_codec_write_cache(codec, 0x15, 0,
9770 AC_VERB_SET_PIN_WIDGET_CONTROL,
9771 spec->cur_mux[0] ? PIN_VREF80 : PIN_HP);
9772 alc262_ultra_automute(codec); /* mute/unmute HP */
9773 return ret;
9774}
9775
9776static struct snd_kcontrol_new alc262_ultra_capture_mixer[] = {
9777 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
9778 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
9779 {
9780 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9781 .name = "Capture Source",
Takashi Iwai54cbc9a2008-10-31 15:24:04 +01009782 .info = alc_mux_enum_info,
9783 .get = alc_mux_enum_get,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01009784 .put = alc262_ultra_mux_enum_put,
9785 },
9786 { } /* end */
9787};
9788
Kailang Yangdf694da2005-12-05 19:42:22 +01009789/* add playback controls from the parsed DAC table */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009790static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
9791 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +01009792{
9793 hda_nid_t nid;
9794 int err;
9795
9796 spec->multiout.num_dacs = 1; /* only use one dac */
9797 spec->multiout.dac_nids = spec->private_dac_nids;
9798 spec->multiout.dac_nids[0] = 2;
9799
9800 nid = cfg->line_out_pins[0];
9801 if (nid) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009802 err = add_control(spec, ALC_CTL_WIDGET_VOL,
9803 "Front Playback Volume",
9804 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT));
9805 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009806 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009807 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
9808 "Front Playback Switch",
9809 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
9810 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009811 return err;
9812 }
9813
Takashi Iwai82bc9552006-03-21 11:24:42 +01009814 nid = cfg->speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01009815 if (nid) {
9816 if (nid == 0x16) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009817 err = add_control(spec, ALC_CTL_WIDGET_VOL,
9818 "Speaker Playback Volume",
9819 HDA_COMPOSE_AMP_VAL(0x0e, 2, 0,
9820 HDA_OUTPUT));
9821 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009822 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009823 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
9824 "Speaker Playback Switch",
9825 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
9826 HDA_OUTPUT));
9827 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009828 return err;
9829 } else {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009830 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
9831 "Speaker Playback Switch",
9832 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
9833 HDA_OUTPUT));
9834 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009835 return err;
9836 }
9837 }
Takashi Iwaieb06ed82006-09-20 17:10:27 +02009838 nid = cfg->hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01009839 if (nid) {
9840 /* spec->multiout.hp_nid = 2; */
9841 if (nid == 0x16) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009842 err = add_control(spec, ALC_CTL_WIDGET_VOL,
9843 "Headphone Playback Volume",
9844 HDA_COMPOSE_AMP_VAL(0x0e, 2, 0,
9845 HDA_OUTPUT));
9846 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009847 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009848 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
9849 "Headphone Playback Switch",
9850 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
9851 HDA_OUTPUT));
9852 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009853 return err;
9854 } else {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009855 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
9856 "Headphone Playback Switch",
9857 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
9858 HDA_OUTPUT));
9859 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009860 return err;
9861 }
9862 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009863 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01009864}
9865
9866/* identical with ALC880 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009867#define alc262_auto_create_analog_input_ctls \
9868 alc880_auto_create_analog_input_ctls
Kailang Yangdf694da2005-12-05 19:42:22 +01009869
9870/*
9871 * generic initialization of ADC, input mixers and output mixers
9872 */
9873static struct hda_verb alc262_volume_init_verbs[] = {
9874 /*
9875 * Unmute ADC0-2 and set the default input to mic-in
9876 */
9877 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
9878 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9879 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
9880 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9881 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
9882 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9883
Takashi Iwaicb53c622007-08-10 17:21:45 +02009884 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +01009885 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009886 * Note: PASD motherboards uses the Line In 2 as the input for
9887 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01009888 */
9889 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02009890 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9891 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
9892 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
9893 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
9894 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01009895
9896 /*
9897 * Set up output mixers (0x0c - 0x0f)
9898 */
9899 /* set vol=0 to output mixers */
9900 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9901 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9902 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yangea1fb292008-08-26 12:58:38 +02009903
Kailang Yangdf694da2005-12-05 19:42:22 +01009904 /* set up input amps for analog loopback */
9905 /* Amp Indices: DAC = 0, mixer = 1 */
9906 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9907 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9908 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9909 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9910 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9911 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9912
9913 /* FIXME: use matrix-type input source selection */
9914 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
9915 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
9916 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9917 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
9918 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
9919 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
9920 /* Input mixer2 */
9921 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9922 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
9923 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
9924 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
9925 /* Input mixer3 */
9926 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9927 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
9928 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
9929 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
9930
9931 { }
9932};
9933
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009934static struct hda_verb alc262_HP_BPC_init_verbs[] = {
9935 /*
9936 * Unmute ADC0-2 and set the default input to mic-in
9937 */
9938 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
9939 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9940 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
9941 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9942 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
9943 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9944
Takashi Iwaicb53c622007-08-10 17:21:45 +02009945 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009946 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009947 * Note: PASD motherboards uses the Line In 2 as the input for
9948 * front panel mic (mic 2)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009949 */
9950 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02009951 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9952 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
9953 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
9954 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
9955 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
9956 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
9957 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
Kailang Yangea1fb292008-08-26 12:58:38 +02009958
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009959 /*
9960 * Set up output mixers (0x0c - 0x0e)
9961 */
9962 /* set vol=0 to output mixers */
9963 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9964 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9965 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9966
9967 /* set up input amps for analog loopback */
9968 /* Amp Indices: DAC = 0, mixer = 1 */
9969 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9970 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9971 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9972 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9973 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9974 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9975
Takashi Iwaice875f02008-01-28 18:17:43 +01009976 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009977 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9978 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9979
9980 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
9981 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
9982
9983 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
9984 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9985
9986 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9987 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9988 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9989 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9990 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9991
9992 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
9993 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
9994 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
9995 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
9996 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
9997 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
9998
9999
10000 /* FIXME: use matrix-type input source selection */
10001 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
10002 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
10003 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10004 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
10005 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
10006 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
10007 /* Input mixer2 */
10008 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10009 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
10010 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
10011 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
10012 /* Input mixer3 */
10013 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10014 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
10015 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
10016 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
10017
Takashi Iwaice875f02008-01-28 18:17:43 +010010018 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
10019
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010020 { }
10021};
10022
Kailang Yangcd7509a2007-01-26 18:33:17 +010010023static struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = {
10024 /*
10025 * Unmute ADC0-2 and set the default input to mic-in
10026 */
10027 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
10028 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10029 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
10030 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10031 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
10032 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10033
Takashi Iwaicb53c622007-08-10 17:21:45 +020010034 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangcd7509a2007-01-26 18:33:17 +010010035 * mixer widget
10036 * Note: PASD motherboards uses the Line In 2 as the input for front
10037 * panel mic (mic 2)
10038 */
10039 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020010040 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
10041 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10042 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
10043 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
10044 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
10045 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
10046 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
10047 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Kailang Yangcd7509a2007-01-26 18:33:17 +010010048 /*
10049 * Set up output mixers (0x0c - 0x0e)
10050 */
10051 /* set vol=0 to output mixers */
10052 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10053 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10054 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10055
10056 /* set up input amps for analog loopback */
10057 /* Amp Indices: DAC = 0, mixer = 1 */
10058 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10059 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10060 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10061 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10062 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10063 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10064
10065
10066 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP */
10067 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Mono */
10068 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* rear MIC */
10069 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* Line in */
10070 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
10071 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Line out */
10072 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD in */
10073
10074 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
10075 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
10076
10077 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
10078 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
10079
10080 /* {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, */
10081 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10082 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10083 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
10084 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10085 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10086
10087 /* FIXME: use matrix-type input source selection */
10088 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
10089 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
10090 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, /*rear MIC*/
10091 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, /*Line in*/
10092 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, /*F MIC*/
10093 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, /*Front*/
10094 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, /*CD*/
10095 /* {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
10096 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, /*HP*/
10097 /* Input mixer2 */
10098 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10099 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
10100 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
10101 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
10102 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
10103 /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
10104 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
10105 /* Input mixer3 */
10106 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10107 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
10108 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
10109 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
10110 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
10111 /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
10112 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
10113
Takashi Iwaice875f02008-01-28 18:17:43 +010010114 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
10115
Kailang Yangcd7509a2007-01-26 18:33:17 +010010116 { }
10117};
10118
Hiroshi Miura9f99a632008-08-28 16:09:06 +020010119static struct hda_verb alc262_toshiba_rx1_unsol_verbs[] = {
10120
10121 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Front Speaker */
10122 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
10123 {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
10124
10125 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* MIC jack */
10126 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
10127 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
10128 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
10129
10130 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP jack */
10131 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
10132 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
10133 {}
10134};
10135
10136
Takashi Iwaicb53c622007-08-10 17:21:45 +020010137#ifdef CONFIG_SND_HDA_POWER_SAVE
10138#define alc262_loopbacks alc880_loopbacks
10139#endif
10140
Kailang Yangdf694da2005-12-05 19:42:22 +010010141/* pcm configuration: identiacal with ALC880 */
10142#define alc262_pcm_analog_playback alc880_pcm_analog_playback
10143#define alc262_pcm_analog_capture alc880_pcm_analog_capture
10144#define alc262_pcm_digital_playback alc880_pcm_digital_playback
10145#define alc262_pcm_digital_capture alc880_pcm_digital_capture
10146
10147/*
10148 * BIOS auto configuration
10149 */
10150static int alc262_parse_auto_config(struct hda_codec *codec)
10151{
10152 struct alc_spec *spec = codec->spec;
10153 int err;
10154 static hda_nid_t alc262_ignore[] = { 0x1d, 0 };
10155
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010156 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
10157 alc262_ignore);
10158 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010159 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010160 if (!spec->autocfg.line_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +010010161 return 0; /* can't find valid BIOS pin config */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010162 err = alc262_auto_create_multi_out_ctls(spec, &spec->autocfg);
10163 if (err < 0)
10164 return err;
10165 err = alc262_auto_create_analog_input_ctls(spec, &spec->autocfg);
10166 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010167 return err;
10168
10169 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
10170
10171 if (spec->autocfg.dig_out_pin)
10172 spec->multiout.dig_out_nid = ALC262_DIGOUT_NID;
10173 if (spec->autocfg.dig_in_pin)
10174 spec->dig_in_nid = ALC262_DIGIN_NID;
10175
Takashi Iwai603c4012008-07-30 15:01:44 +020010176 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010010177 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +010010178
Takashi Iwaid88897e2008-10-31 15:01:37 +010010179 add_verb(spec, alc262_volume_init_verbs);
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020010180 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +010010181 spec->input_mux = &spec->private_imux;
10182
Takashi Iwai776e1842007-08-29 15:07:11 +020010183 err = alc_auto_add_mic_boost(codec);
10184 if (err < 0)
10185 return err;
10186
Takashi Iwaie044c392008-10-27 16:56:24 +010010187 store_pin_configs(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010010188 return 1;
10189}
10190
10191#define alc262_auto_init_multi_out alc882_auto_init_multi_out
10192#define alc262_auto_init_hp_out alc882_auto_init_hp_out
10193#define alc262_auto_init_analog_input alc882_auto_init_analog_input
Takashi Iwaif511b012008-08-15 16:46:42 +020010194#define alc262_auto_init_input_src alc882_auto_init_input_src
Kailang Yangdf694da2005-12-05 19:42:22 +010010195
10196
10197/* init callback for auto-configuration model -- overriding the default init */
Takashi Iwaiae6b8132006-03-03 16:47:17 +010010198static void alc262_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010010199{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010200 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010010201 alc262_auto_init_multi_out(codec);
10202 alc262_auto_init_hp_out(codec);
10203 alc262_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020010204 alc262_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010205 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020010206 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010010207}
10208
10209/*
10210 * configuration and preset
10211 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010212static const char *alc262_models[ALC262_MODEL_LAST] = {
10213 [ALC262_BASIC] = "basic",
10214 [ALC262_HIPPO] = "hippo",
10215 [ALC262_HIPPO_1] = "hippo_1",
10216 [ALC262_FUJITSU] = "fujitsu",
10217 [ALC262_HP_BPC] = "hp-bpc",
Kailang Yangcd7509a2007-01-26 18:33:17 +010010218 [ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000",
Takashi Iwai61dc35d2007-11-14 12:26:44 +010010219 [ALC262_HP_TC_T5735] = "hp-tc-t5735",
Kailang Yang8c427222008-01-10 13:03:59 +010010220 [ALC262_HP_RP5700] = "hp-rp5700",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010221 [ALC262_BENQ_ED8] = "benq",
Takashi Iwai0f405022007-07-06 12:24:11 +020010222 [ALC262_BENQ_T31] = "benq-t31",
10223 [ALC262_SONY_ASSAMD] = "sony-assamd",
Takashi Iwai2922c9a2008-08-27 18:12:42 +020010224 [ALC262_TOSHIBA_S06] = "toshiba-s06",
Hiroshi Miura9f99a632008-08-28 16:09:06 +020010225 [ALC262_TOSHIBA_RX1] = "toshiba-rx1",
Tobin Davisf651b502007-10-26 12:40:47 +020010226 [ALC262_ULTRA] = "ultra",
Jiang zhe0e31daf2008-03-20 12:12:39 +010010227 [ALC262_LENOVO_3000] = "lenovo-3000",
Pascal Terjane8f9ae22008-08-04 14:36:05 +020010228 [ALC262_NEC] = "nec",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010229 [ALC262_AUTO] = "auto",
10230};
10231
10232static struct snd_pci_quirk alc262_cfg_tbl[] = {
10233 SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO),
Pascal Terjane8f9ae22008-08-04 14:36:05 +020010234 SND_PCI_QUIRK(0x1033, 0x8895, "NEC Versa S9100", ALC262_NEC),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010235 SND_PCI_QUIRK(0x103c, 0x12fe, "HP xw9400", ALC262_HP_BPC),
Kailang Yang7d87de22007-06-05 12:17:21 +020010236 SND_PCI_QUIRK(0x103c, 0x12ff, "HP xw4550", ALC262_HP_BPC),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010237 SND_PCI_QUIRK(0x103c, 0x1306, "HP xw8600", ALC262_HP_BPC),
10238 SND_PCI_QUIRK(0x103c, 0x1307, "HP xw6600", ALC262_HP_BPC),
Kailang Yang7d87de22007-06-05 12:17:21 +020010239 SND_PCI_QUIRK(0x103c, 0x1308, "HP xw4600", ALC262_HP_BPC),
Takashi Iwaib98f9332007-11-07 14:18:01 +010010240 SND_PCI_QUIRK(0x103c, 0x1309, "HP xw4*00", ALC262_HP_BPC),
Takashi Iwaib98f9332007-11-07 14:18:01 +010010241 SND_PCI_QUIRK(0x103c, 0x130a, "HP xw6*00", ALC262_HP_BPC),
Takashi Iwaib98f9332007-11-07 14:18:01 +010010242 SND_PCI_QUIRK(0x103c, 0x130b, "HP xw8*00", ALC262_HP_BPC),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010243 SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010244 SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010245 SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010246 SND_PCI_QUIRK(0x103c, 0x2803, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010247 SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010248 SND_PCI_QUIRK(0x103c, 0x2805, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010249 SND_PCI_QUIRK(0x103c, 0x2806, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010250 SND_PCI_QUIRK(0x103c, 0x2807, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010251 SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC),
10252 SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC),
10253 SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC),
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010254 SND_PCI_QUIRK(0x103c, 0x302f, "HP Thin Client T5735",
10255 ALC262_HP_TC_T5735),
Kailang Yang8c427222008-01-10 13:03:59 +010010256 SND_PCI_QUIRK(0x103c, 0x2817, "HP RP5700", ALC262_HP_RP5700),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010257 SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010258 SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010259 SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD),
10260 SND_PCI_QUIRK(0x104d, 0x900e, "Sony ASSAMD", ALC262_SONY_ASSAMD),
10261 SND_PCI_QUIRK(0x104d, 0x9015, "Sony 0x9015", ALC262_SONY_ASSAMD),
Akio Idehara36ca6e12008-06-09 22:57:40 +090010262 SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1",
Hiroshi Miura9f99a632008-08-28 16:09:06 +020010263 ALC262_TOSHIBA_RX1),
Kailang Yang80ffe862008-10-15 11:23:27 +020010264 SND_PCI_QUIRK(0x1179, 0xff7b, "Toshiba S06", ALC262_TOSHIBA_S06),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010265 SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU),
Tony Vroon3f1eeae2008-02-25 16:44:13 +010010266 SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010267 SND_PCI_QUIRK(0x144d, 0xc032, "Samsung Q1 Ultra", ALC262_ULTRA),
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010268 SND_PCI_QUIRK(0x144d, 0xc039, "Samsung Q1U EL", ALC262_ULTRA),
Jiang zhe0e31daf2008-03-20 12:12:39 +010010269 SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 y410", ALC262_LENOVO_3000),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010270 SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8),
Kailang Yang83c34212007-07-05 11:43:05 +020010271 SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010272 SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1),
Kailang Yangdf694da2005-12-05 19:42:22 +010010273 {}
10274};
10275
10276static struct alc_config_preset alc262_presets[] = {
10277 [ALC262_BASIC] = {
10278 .mixers = { alc262_base_mixer },
10279 .init_verbs = { alc262_init_verbs },
10280 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10281 .dac_nids = alc262_dac_nids,
10282 .hp_nid = 0x03,
10283 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10284 .channel_mode = alc262_modes,
Takashi Iwaia3bcba32005-12-06 19:05:29 +010010285 .input_mux = &alc262_capture_source,
Kailang Yangdf694da2005-12-05 19:42:22 +010010286 },
Kailang Yangccc656c2006-10-17 12:32:26 +020010287 [ALC262_HIPPO] = {
10288 .mixers = { alc262_base_mixer },
10289 .init_verbs = { alc262_init_verbs, alc262_hippo_unsol_verbs},
10290 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10291 .dac_nids = alc262_dac_nids,
10292 .hp_nid = 0x03,
10293 .dig_out_nid = ALC262_DIGOUT_NID,
10294 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10295 .channel_mode = alc262_modes,
10296 .input_mux = &alc262_capture_source,
10297 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +020010298 .init_hook = alc262_hippo_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020010299 },
10300 [ALC262_HIPPO_1] = {
10301 .mixers = { alc262_hippo1_mixer },
10302 .init_verbs = { alc262_init_verbs, alc262_hippo1_unsol_verbs},
10303 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10304 .dac_nids = alc262_dac_nids,
10305 .hp_nid = 0x02,
10306 .dig_out_nid = ALC262_DIGOUT_NID,
10307 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10308 .channel_mode = alc262_modes,
10309 .input_mux = &alc262_capture_source,
10310 .unsol_event = alc262_hippo1_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +020010311 .init_hook = alc262_hippo1_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020010312 },
Takashi Iwai834be882006-03-01 14:16:17 +010010313 [ALC262_FUJITSU] = {
10314 .mixers = { alc262_fujitsu_mixer },
Takashi Iwai39d3ed32007-10-12 15:03:48 +020010315 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
10316 alc262_fujitsu_unsol_verbs },
Takashi Iwai834be882006-03-01 14:16:17 +010010317 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10318 .dac_nids = alc262_dac_nids,
10319 .hp_nid = 0x03,
10320 .dig_out_nid = ALC262_DIGOUT_NID,
10321 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10322 .channel_mode = alc262_modes,
10323 .input_mux = &alc262_fujitsu_capture_source,
Takashi Iwaiae6b8132006-03-03 16:47:17 +010010324 .unsol_event = alc262_fujitsu_unsol_event,
Takashi Iwaiebc7a402008-05-20 09:23:05 +020010325 .init_hook = alc262_fujitsu_init_hook,
Takashi Iwai834be882006-03-01 14:16:17 +010010326 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010327 [ALC262_HP_BPC] = {
10328 .mixers = { alc262_HP_BPC_mixer },
10329 .init_verbs = { alc262_HP_BPC_init_verbs },
10330 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10331 .dac_nids = alc262_dac_nids,
10332 .hp_nid = 0x03,
10333 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10334 .channel_mode = alc262_modes,
10335 .input_mux = &alc262_HP_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010010336 .unsol_event = alc262_hp_bpc_unsol_event,
10337 .init_hook = alc262_hp_bpc_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010338 },
Kailang Yangcd7509a2007-01-26 18:33:17 +010010339 [ALC262_HP_BPC_D7000_WF] = {
10340 .mixers = { alc262_HP_BPC_WildWest_mixer },
10341 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
10342 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10343 .dac_nids = alc262_dac_nids,
10344 .hp_nid = 0x03,
10345 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10346 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +020010347 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010010348 .unsol_event = alc262_hp_wildwest_unsol_event,
10349 .init_hook = alc262_hp_wildwest_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010350 },
Kailang Yangcd7509a2007-01-26 18:33:17 +010010351 [ALC262_HP_BPC_D7000_WL] = {
10352 .mixers = { alc262_HP_BPC_WildWest_mixer,
10353 alc262_HP_BPC_WildWest_option_mixer },
10354 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
10355 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10356 .dac_nids = alc262_dac_nids,
10357 .hp_nid = 0x03,
10358 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10359 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +020010360 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010010361 .unsol_event = alc262_hp_wildwest_unsol_event,
10362 .init_hook = alc262_hp_wildwest_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010363 },
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010364 [ALC262_HP_TC_T5735] = {
10365 .mixers = { alc262_hp_t5735_mixer },
10366 .init_verbs = { alc262_init_verbs, alc262_hp_t5735_verbs },
10367 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10368 .dac_nids = alc262_dac_nids,
10369 .hp_nid = 0x03,
10370 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10371 .channel_mode = alc262_modes,
10372 .input_mux = &alc262_capture_source,
10373 .unsol_event = alc262_hp_t5735_unsol_event,
10374 .init_hook = alc262_hp_t5735_init_hook,
Kailang Yang8c427222008-01-10 13:03:59 +010010375 },
10376 [ALC262_HP_RP5700] = {
10377 .mixers = { alc262_hp_rp5700_mixer },
10378 .init_verbs = { alc262_init_verbs, alc262_hp_rp5700_verbs },
10379 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10380 .dac_nids = alc262_dac_nids,
10381 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10382 .channel_mode = alc262_modes,
10383 .input_mux = &alc262_hp_rp5700_capture_source,
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010384 },
Takashi Iwai304dcaa2006-07-25 14:51:16 +020010385 [ALC262_BENQ_ED8] = {
10386 .mixers = { alc262_base_mixer },
10387 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs },
10388 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10389 .dac_nids = alc262_dac_nids,
10390 .hp_nid = 0x03,
10391 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10392 .channel_mode = alc262_modes,
10393 .input_mux = &alc262_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010394 },
Kailang Yang272a5272007-05-14 11:00:38 +020010395 [ALC262_SONY_ASSAMD] = {
10396 .mixers = { alc262_sony_mixer },
10397 .init_verbs = { alc262_init_verbs, alc262_sony_unsol_verbs},
10398 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10399 .dac_nids = alc262_dac_nids,
10400 .hp_nid = 0x02,
10401 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10402 .channel_mode = alc262_modes,
10403 .input_mux = &alc262_capture_source,
10404 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +020010405 .init_hook = alc262_hippo_automute,
Kailang Yang83c34212007-07-05 11:43:05 +020010406 },
10407 [ALC262_BENQ_T31] = {
10408 .mixers = { alc262_benq_t31_mixer },
10409 .init_verbs = { alc262_init_verbs, alc262_benq_t31_EAPD_verbs, alc262_hippo_unsol_verbs },
10410 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10411 .dac_nids = alc262_dac_nids,
10412 .hp_nid = 0x03,
10413 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10414 .channel_mode = alc262_modes,
10415 .input_mux = &alc262_capture_source,
10416 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +020010417 .init_hook = alc262_hippo_automute,
Kailang Yangea1fb292008-08-26 12:58:38 +020010418 },
Tobin Davisf651b502007-10-26 12:40:47 +020010419 [ALC262_ULTRA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010420 .mixers = { alc262_ultra_mixer },
10421 .cap_mixer = alc262_ultra_capture_mixer,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010422 .init_verbs = { alc262_ultra_verbs },
Tobin Davisf651b502007-10-26 12:40:47 +020010423 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10424 .dac_nids = alc262_dac_nids,
Tobin Davisf651b502007-10-26 12:40:47 +020010425 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10426 .channel_mode = alc262_modes,
10427 .input_mux = &alc262_ultra_capture_source,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010428 .adc_nids = alc262_adc_nids, /* ADC0 */
10429 .capsrc_nids = alc262_capsrc_nids,
10430 .num_adc_nids = 1, /* single ADC */
Tobin Davisf651b502007-10-26 12:40:47 +020010431 .unsol_event = alc262_ultra_unsol_event,
10432 .init_hook = alc262_ultra_automute,
10433 },
Jiang zhe0e31daf2008-03-20 12:12:39 +010010434 [ALC262_LENOVO_3000] = {
10435 .mixers = { alc262_lenovo_3000_mixer },
10436 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
10437 alc262_lenovo_3000_unsol_verbs },
10438 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10439 .dac_nids = alc262_dac_nids,
10440 .hp_nid = 0x03,
10441 .dig_out_nid = ALC262_DIGOUT_NID,
10442 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10443 .channel_mode = alc262_modes,
10444 .input_mux = &alc262_fujitsu_capture_source,
10445 .unsol_event = alc262_lenovo_3000_unsol_event,
10446 },
Pascal Terjane8f9ae22008-08-04 14:36:05 +020010447 [ALC262_NEC] = {
10448 .mixers = { alc262_nec_mixer },
10449 .init_verbs = { alc262_nec_verbs },
10450 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10451 .dac_nids = alc262_dac_nids,
10452 .hp_nid = 0x03,
10453 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10454 .channel_mode = alc262_modes,
10455 .input_mux = &alc262_capture_source,
10456 },
Kailang Yang4e555fe2008-08-26 13:05:55 +020010457 [ALC262_TOSHIBA_S06] = {
10458 .mixers = { alc262_toshiba_s06_mixer },
10459 .init_verbs = { alc262_init_verbs, alc262_toshiba_s06_verbs,
10460 alc262_eapd_verbs },
10461 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10462 .capsrc_nids = alc262_dmic_capsrc_nids,
10463 .dac_nids = alc262_dac_nids,
10464 .adc_nids = alc262_dmic_adc_nids, /* ADC0 */
10465 .dig_out_nid = ALC262_DIGOUT_NID,
10466 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10467 .channel_mode = alc262_modes,
10468 .input_mux = &alc262_dmic_capture_source,
10469 .unsol_event = alc262_toshiba_s06_unsol_event,
10470 .init_hook = alc262_toshiba_s06_init_hook,
10471 },
Hiroshi Miura9f99a632008-08-28 16:09:06 +020010472 [ALC262_TOSHIBA_RX1] = {
10473 .mixers = { alc262_toshiba_rx1_mixer },
10474 .init_verbs = { alc262_init_verbs, alc262_toshiba_rx1_unsol_verbs },
10475 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10476 .dac_nids = alc262_dac_nids,
10477 .hp_nid = 0x03,
10478 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10479 .channel_mode = alc262_modes,
10480 .input_mux = &alc262_capture_source,
10481 .unsol_event = alc262_hippo_unsol_event,
10482 .init_hook = alc262_hippo_automute,
10483 },
Kailang Yangdf694da2005-12-05 19:42:22 +010010484};
10485
10486static int patch_alc262(struct hda_codec *codec)
10487{
10488 struct alc_spec *spec;
10489 int board_config;
10490 int err;
10491
Robert P. J. Daydc041e02006-12-19 14:44:15 +010010492 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010010493 if (spec == NULL)
10494 return -ENOMEM;
10495
10496 codec->spec = spec;
10497#if 0
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010498 /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is
10499 * under-run
10500 */
Kailang Yangdf694da2005-12-05 19:42:22 +010010501 {
10502 int tmp;
10503 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
10504 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
10505 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
10506 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80);
10507 }
10508#endif
10509
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020010510 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
10511
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010512 board_config = snd_hda_check_board_config(codec, ALC262_MODEL_LAST,
10513 alc262_models,
10514 alc262_cfg_tbl);
Kailang Yangcd7509a2007-01-26 18:33:17 +010010515
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010516 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010517 printk(KERN_INFO "hda_codec: Unknown model for ALC262, "
10518 "trying auto-probe from BIOS...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010010519 board_config = ALC262_AUTO;
10520 }
10521
10522 if (board_config == ALC262_AUTO) {
10523 /* automatic parse from the BIOS config */
10524 err = alc262_parse_auto_config(codec);
10525 if (err < 0) {
10526 alc_free(codec);
10527 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010528 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010529 printk(KERN_INFO
10530 "hda_codec: Cannot set up configuration "
10531 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010010532 board_config = ALC262_BASIC;
10533 }
10534 }
10535
10536 if (board_config != ALC262_AUTO)
10537 setup_preset(spec, &alc262_presets[board_config]);
10538
10539 spec->stream_name_analog = "ALC262 Analog";
10540 spec->stream_analog_playback = &alc262_pcm_analog_playback;
10541 spec->stream_analog_capture = &alc262_pcm_analog_capture;
Kailang Yangea1fb292008-08-26 12:58:38 +020010542
Kailang Yangdf694da2005-12-05 19:42:22 +010010543 spec->stream_name_digital = "ALC262 Digital";
10544 spec->stream_digital_playback = &alc262_pcm_digital_playback;
10545 spec->stream_digital_capture = &alc262_pcm_digital_capture;
10546
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010010547 spec->is_mix_capture = 1;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010548 if (!spec->adc_nids && spec->input_mux) {
Kailang Yangdf694da2005-12-05 19:42:22 +010010549 /* check whether NID 0x07 is valid */
Takashi Iwai4a471b72005-12-07 13:56:29 +010010550 unsigned int wcap = get_wcaps(codec, 0x07);
10551
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010552 /* get type */
10553 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Kailang Yangdf694da2005-12-05 19:42:22 +010010554 if (wcap != AC_WID_AUD_IN) {
10555 spec->adc_nids = alc262_adc_nids_alt;
10556 spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids_alt);
Takashi Iwai88c71a92008-02-14 17:27:17 +010010557 spec->capsrc_nids = alc262_capsrc_nids_alt;
Kailang Yangdf694da2005-12-05 19:42:22 +010010558 } else {
10559 spec->adc_nids = alc262_adc_nids;
10560 spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids);
Takashi Iwai88c71a92008-02-14 17:27:17 +010010561 spec->capsrc_nids = alc262_capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +010010562 }
10563 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010564 if (!spec->cap_mixer)
10565 set_capture_mixer(spec);
Kailang Yangdf694da2005-12-05 19:42:22 +010010566
Takashi Iwai2134ea42008-01-10 16:53:55 +010010567 spec->vmaster_nid = 0x0c;
10568
Kailang Yangdf694da2005-12-05 19:42:22 +010010569 codec->patch_ops = alc_patch_ops;
10570 if (board_config == ALC262_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +010010571 spec->init_hook = alc262_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020010572#ifdef CONFIG_SND_HDA_POWER_SAVE
10573 if (!spec->loopback.amplist)
10574 spec->loopback.amplist = alc262_loopbacks;
10575#endif
Kailang Yangea1fb292008-08-26 12:58:38 +020010576
Kailang Yangdf694da2005-12-05 19:42:22 +010010577 return 0;
10578}
10579
Kailang Yangdf694da2005-12-05 19:42:22 +010010580/*
Kailang Yanga361d842007-06-05 12:30:55 +020010581 * ALC268 channel source setting (2 channel)
10582 */
10583#define ALC268_DIGOUT_NID ALC880_DIGOUT_NID
10584#define alc268_modes alc260_modes
Kailang Yangea1fb292008-08-26 12:58:38 +020010585
Kailang Yanga361d842007-06-05 12:30:55 +020010586static hda_nid_t alc268_dac_nids[2] = {
10587 /* front, hp */
10588 0x02, 0x03
10589};
10590
10591static hda_nid_t alc268_adc_nids[2] = {
10592 /* ADC0-1 */
10593 0x08, 0x07
10594};
10595
10596static hda_nid_t alc268_adc_nids_alt[1] = {
10597 /* ADC0 */
10598 0x08
10599};
10600
Takashi Iwaie1406342008-02-11 18:32:32 +010010601static hda_nid_t alc268_capsrc_nids[2] = { 0x23, 0x24 };
10602
Kailang Yanga361d842007-06-05 12:30:55 +020010603static struct snd_kcontrol_new alc268_base_mixer[] = {
10604 /* output mixer control */
10605 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
10606 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
10607 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
10608 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai33bf17a2007-08-21 11:51:42 +020010609 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10610 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
10611 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
Kailang Yanga361d842007-06-05 12:30:55 +020010612 { }
10613};
10614
Takashi Iwaiaef9d312008-02-19 13:16:41 +010010615/* bind Beep switches of both NID 0x0f and 0x10 */
10616static struct hda_bind_ctls alc268_bind_beep_sw = {
10617 .ops = &snd_hda_bind_sw,
10618 .values = {
10619 HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT),
10620 HDA_COMPOSE_AMP_VAL(0x10, 3, 1, HDA_INPUT),
10621 0
10622 },
10623};
10624
10625static struct snd_kcontrol_new alc268_beep_mixer[] = {
10626 HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT),
10627 HDA_BIND_SW("Beep Playback Switch", &alc268_bind_beep_sw),
10628 { }
10629};
10630
Kailang Yangd1a991a2007-08-15 16:21:59 +020010631static struct hda_verb alc268_eapd_verbs[] = {
10632 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
10633 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
10634 { }
10635};
10636
Takashi Iwaid2738092007-08-16 14:59:45 +020010637/* Toshiba specific */
10638#define alc268_toshiba_automute alc262_hippo_automute
10639
10640static struct hda_verb alc268_toshiba_verbs[] = {
10641 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
10642 { } /* end */
10643};
10644
Kailang Yang8ef355d2008-08-26 13:10:22 +020010645static struct hda_input_mux alc268_acer_lc_capture_source = {
10646 .num_items = 2,
10647 .items = {
10648 { "i-Mic", 0x6 },
10649 { "E-Mic", 0x0 },
10650 },
10651};
10652
Takashi Iwaid2738092007-08-16 14:59:45 +020010653/* Acer specific */
Takashi Iwai889c4392007-08-23 18:56:52 +020010654/* bind volumes of both NID 0x02 and 0x03 */
Takashi Iwai6bc96852007-08-17 09:02:12 +020010655static struct hda_bind_ctls alc268_acer_bind_master_vol = {
10656 .ops = &snd_hda_bind_vol,
10657 .values = {
10658 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
10659 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
10660 0
10661 },
10662};
10663
Takashi Iwai889c4392007-08-23 18:56:52 +020010664/* mute/unmute internal speaker according to the hp jack and mute state */
10665static void alc268_acer_automute(struct hda_codec *codec, int force)
10666{
10667 struct alc_spec *spec = codec->spec;
10668 unsigned int mute;
10669
10670 if (force || !spec->sense_updated) {
10671 unsigned int present;
10672 present = snd_hda_codec_read(codec, 0x14, 0,
10673 AC_VERB_GET_PIN_SENSE, 0);
10674 spec->jack_present = (present & 0x80000000) != 0;
10675 spec->sense_updated = 1;
10676 }
10677 if (spec->jack_present)
10678 mute = HDA_AMP_MUTE; /* mute internal speaker */
10679 else /* unmute internal speaker if necessary */
10680 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
10681 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
10682 HDA_AMP_MUTE, mute);
10683}
10684
10685
10686/* bind hp and internal speaker mute (with plug check) */
10687static int alc268_acer_master_sw_put(struct snd_kcontrol *kcontrol,
10688 struct snd_ctl_elem_value *ucontrol)
10689{
10690 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
10691 long *valp = ucontrol->value.integer.value;
10692 int change;
10693
10694 change = snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0,
10695 HDA_AMP_MUTE,
10696 valp[0] ? 0 : HDA_AMP_MUTE);
10697 change |= snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0,
10698 HDA_AMP_MUTE,
10699 valp[1] ? 0 : HDA_AMP_MUTE);
10700 if (change)
10701 alc268_acer_automute(codec, 0);
10702 return change;
10703}
Takashi Iwaid2738092007-08-16 14:59:45 +020010704
Kailang Yang8ef355d2008-08-26 13:10:22 +020010705static struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = {
10706 /* output mixer control */
10707 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
10708 {
10709 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10710 .name = "Master Playback Switch",
10711 .info = snd_hda_mixer_amp_switch_info,
10712 .get = snd_hda_mixer_amp_switch_get,
10713 .put = alc268_acer_master_sw_put,
10714 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
10715 },
10716 HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x18, 0, HDA_INPUT),
10717 { }
10718};
10719
Takashi Iwaid2738092007-08-16 14:59:45 +020010720static struct snd_kcontrol_new alc268_acer_mixer[] = {
10721 /* output mixer control */
10722 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
10723 {
10724 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10725 .name = "Master Playback Switch",
10726 .info = snd_hda_mixer_amp_switch_info,
10727 .get = snd_hda_mixer_amp_switch_get,
10728 .put = alc268_acer_master_sw_put,
10729 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
10730 },
Takashi Iwai33bf17a2007-08-21 11:51:42 +020010731 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10732 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
10733 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
Takashi Iwaid2738092007-08-16 14:59:45 +020010734 { }
10735};
10736
Takashi Iwaic238b4f2008-11-05 14:57:20 +010010737static struct snd_kcontrol_new alc268_acer_dmic_mixer[] = {
10738 /* output mixer control */
10739 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
10740 {
10741 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10742 .name = "Master Playback Switch",
10743 .info = snd_hda_mixer_amp_switch_info,
10744 .get = snd_hda_mixer_amp_switch_get,
10745 .put = alc268_acer_master_sw_put,
10746 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
10747 },
10748 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10749 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
10750 { }
10751};
10752
Kailang Yang8ef355d2008-08-26 13:10:22 +020010753static struct hda_verb alc268_acer_aspire_one_verbs[] = {
10754 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
10755 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
10756 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
10757 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
10758 {0x23, AC_VERB_SET_CONNECT_SEL, 0x06},
10759 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, 0xa017},
10760 { }
10761};
10762
Takashi Iwaid2738092007-08-16 14:59:45 +020010763static struct hda_verb alc268_acer_verbs[] = {
Takashi Iwai0ccb5412008-03-06 16:58:35 +010010764 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* internal dmic? */
10765 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaid2738092007-08-16 14:59:45 +020010766 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
10767 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai0ccb5412008-03-06 16:58:35 +010010768 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
10769 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaid2738092007-08-16 14:59:45 +020010770 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
10771 { }
10772};
10773
10774/* unsolicited event for HP jack sensing */
10775static void alc268_toshiba_unsol_event(struct hda_codec *codec,
10776 unsigned int res)
10777{
Takashi Iwai889c4392007-08-23 18:56:52 +020010778 if ((res >> 26) != ALC880_HP_EVENT)
Takashi Iwaid2738092007-08-16 14:59:45 +020010779 return;
10780 alc268_toshiba_automute(codec);
10781}
10782
10783static void alc268_acer_unsol_event(struct hda_codec *codec,
10784 unsigned int res)
10785{
Takashi Iwai889c4392007-08-23 18:56:52 +020010786 if ((res >> 26) != ALC880_HP_EVENT)
Takashi Iwaid2738092007-08-16 14:59:45 +020010787 return;
10788 alc268_acer_automute(codec, 1);
10789}
10790
Takashi Iwai889c4392007-08-23 18:56:52 +020010791static void alc268_acer_init_hook(struct hda_codec *codec)
10792{
10793 alc268_acer_automute(codec, 1);
10794}
10795
Kailang Yang8ef355d2008-08-26 13:10:22 +020010796/* toggle speaker-output according to the hp-jack state */
10797static void alc268_aspire_one_speaker_automute(struct hda_codec *codec)
10798{
10799 unsigned int present;
10800 unsigned char bits;
10801
10802 present = snd_hda_codec_read(codec, 0x15, 0,
10803 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
10804 bits = present ? AMP_IN_MUTE(0) : 0;
10805 snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 0,
10806 AMP_IN_MUTE(0), bits);
10807 snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 1,
10808 AMP_IN_MUTE(0), bits);
10809}
10810
10811
10812static void alc268_acer_mic_automute(struct hda_codec *codec)
10813{
10814 unsigned int present;
10815
10816 present = snd_hda_codec_read(codec, 0x18, 0,
10817 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
10818 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_CONNECT_SEL,
10819 present ? 0x0 : 0x6);
10820}
10821
10822static void alc268_acer_lc_unsol_event(struct hda_codec *codec,
10823 unsigned int res)
10824{
10825 if ((res >> 26) == ALC880_HP_EVENT)
10826 alc268_aspire_one_speaker_automute(codec);
10827 if ((res >> 26) == ALC880_MIC_EVENT)
10828 alc268_acer_mic_automute(codec);
10829}
10830
10831static void alc268_acer_lc_init_hook(struct hda_codec *codec)
10832{
10833 alc268_aspire_one_speaker_automute(codec);
10834 alc268_acer_mic_automute(codec);
10835}
10836
Takashi Iwai3866f0b2008-01-15 12:37:42 +010010837static struct snd_kcontrol_new alc268_dell_mixer[] = {
10838 /* output mixer control */
10839 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
10840 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
10841 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
10842 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
10843 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10844 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
10845 { }
10846};
10847
10848static struct hda_verb alc268_dell_verbs[] = {
10849 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
10850 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
10851 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
10852 { }
10853};
10854
10855/* mute/unmute internal speaker according to the hp jack and mute state */
10856static void alc268_dell_automute(struct hda_codec *codec)
10857{
10858 unsigned int present;
10859 unsigned int mute;
10860
10861 present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0);
10862 if (present & 0x80000000)
10863 mute = HDA_AMP_MUTE;
10864 else
10865 mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0);
10866 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
10867 HDA_AMP_MUTE, mute);
10868}
10869
10870static void alc268_dell_unsol_event(struct hda_codec *codec,
10871 unsigned int res)
10872{
10873 if ((res >> 26) != ALC880_HP_EVENT)
10874 return;
10875 alc268_dell_automute(codec);
10876}
10877
10878#define alc268_dell_init_hook alc268_dell_automute
10879
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020010880static struct snd_kcontrol_new alc267_quanta_il1_mixer[] = {
10881 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x2, 0x0, HDA_OUTPUT),
10882 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
10883 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
10884 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
10885 HDA_CODEC_VOLUME("Mic Capture Volume", 0x23, 0x0, HDA_OUTPUT),
10886 HDA_BIND_MUTE("Mic Capture Switch", 0x23, 2, HDA_OUTPUT),
10887 HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
10888 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
10889 { }
10890};
10891
10892static struct hda_verb alc267_quanta_il1_verbs[] = {
10893 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
10894 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
10895 { }
10896};
10897
10898static void alc267_quanta_il1_hp_automute(struct hda_codec *codec)
10899{
10900 unsigned int present;
10901
10902 present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0)
10903 & AC_PINSENSE_PRESENCE;
10904 snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
10905 present ? 0 : PIN_OUT);
10906}
10907
10908static void alc267_quanta_il1_mic_automute(struct hda_codec *codec)
10909{
10910 unsigned int present;
10911
10912 present = snd_hda_codec_read(codec, 0x18, 0,
10913 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
10914 snd_hda_codec_write(codec, 0x23, 0,
10915 AC_VERB_SET_CONNECT_SEL,
10916 present ? 0x00 : 0x01);
10917}
10918
10919static void alc267_quanta_il1_automute(struct hda_codec *codec)
10920{
10921 alc267_quanta_il1_hp_automute(codec);
10922 alc267_quanta_il1_mic_automute(codec);
10923}
10924
10925static void alc267_quanta_il1_unsol_event(struct hda_codec *codec,
10926 unsigned int res)
10927{
10928 switch (res >> 26) {
10929 case ALC880_HP_EVENT:
10930 alc267_quanta_il1_hp_automute(codec);
10931 break;
10932 case ALC880_MIC_EVENT:
10933 alc267_quanta_il1_mic_automute(codec);
10934 break;
10935 }
10936}
10937
Kailang Yanga361d842007-06-05 12:30:55 +020010938/*
10939 * generic initialization of ADC, input mixers and output mixers
10940 */
10941static struct hda_verb alc268_base_init_verbs[] = {
10942 /* Unmute DAC0-1 and set vol = 0 */
10943 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10944 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10945 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10946 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10947 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10948 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10949
10950 /*
10951 * Set up output mixers (0x0c - 0x0e)
10952 */
10953 /* set vol=0 to output mixers */
10954 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10955 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10956 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10957 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
10958
10959 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10960 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10961
10962 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
10963 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
10964 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
10965 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
10966 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
10967 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10968 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10969 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10970
10971 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10972 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10973 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10974 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10975 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10976 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10977 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwaiaef9d312008-02-19 13:16:41 +010010978
10979 /* set PCBEEP vol = 0, mute connections */
10980 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10981 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10982 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020010983
Jiang Zhea9b3aa82007-12-20 13:13:13 +010010984 /* Unmute Selector 23h,24h and set the default input to mic-in */
Kailang Yangea1fb292008-08-26 12:58:38 +020010985
Jiang Zhea9b3aa82007-12-20 13:13:13 +010010986 {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
10987 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10988 {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
10989 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020010990
Kailang Yanga361d842007-06-05 12:30:55 +020010991 { }
10992};
10993
10994/*
10995 * generic initialization of ADC, input mixers and output mixers
10996 */
10997static struct hda_verb alc268_volume_init_verbs[] = {
10998 /* set output DAC */
10999 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11000 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11001 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11002 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11003
11004 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11005 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11006 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11007 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11008 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11009
11010 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11011 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11012 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11013 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11014 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11015
11016 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11017 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11018 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11019 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11020
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011021 /* set PCBEEP vol = 0, mute connections */
11022 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11023 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11024 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020011025
11026 { }
11027};
11028
Kailang Yanga361d842007-06-05 12:30:55 +020011029static struct snd_kcontrol_new alc268_capture_alt_mixer[] = {
11030 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
11031 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
11032 {
11033 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11034 /* The multiple "Capture Source" controls confuse alsamixer
11035 * So call somewhat different..
Kailang Yanga361d842007-06-05 12:30:55 +020011036 */
11037 /* .name = "Capture Source", */
11038 .name = "Input Source",
11039 .count = 1,
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010011040 .info = alc_mux_enum_info,
11041 .get = alc_mux_enum_get,
11042 .put = alc_mux_enum_put,
Kailang Yanga361d842007-06-05 12:30:55 +020011043 },
11044 { } /* end */
11045};
11046
11047static struct snd_kcontrol_new alc268_capture_mixer[] = {
11048 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
11049 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
11050 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x24, 0x0, HDA_OUTPUT),
11051 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x24, 0x0, HDA_OUTPUT),
11052 {
11053 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11054 /* The multiple "Capture Source" controls confuse alsamixer
11055 * So call somewhat different..
Kailang Yanga361d842007-06-05 12:30:55 +020011056 */
11057 /* .name = "Capture Source", */
11058 .name = "Input Source",
11059 .count = 2,
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010011060 .info = alc_mux_enum_info,
11061 .get = alc_mux_enum_get,
11062 .put = alc_mux_enum_put,
Kailang Yanga361d842007-06-05 12:30:55 +020011063 },
11064 { } /* end */
11065};
11066
11067static struct hda_input_mux alc268_capture_source = {
11068 .num_items = 4,
11069 .items = {
11070 { "Mic", 0x0 },
11071 { "Front Mic", 0x1 },
11072 { "Line", 0x2 },
11073 { "CD", 0x3 },
11074 },
11075};
11076
Takashi Iwai0ccb5412008-03-06 16:58:35 +010011077static struct hda_input_mux alc268_acer_capture_source = {
11078 .num_items = 3,
11079 .items = {
11080 { "Mic", 0x0 },
Takashi Iwaic238b4f2008-11-05 14:57:20 +010011081 { "Internal Mic", 0x1 },
11082 { "Line", 0x2 },
11083 },
11084};
11085
11086static struct hda_input_mux alc268_acer_dmic_capture_source = {
11087 .num_items = 3,
11088 .items = {
11089 { "Mic", 0x0 },
Takashi Iwai0ccb5412008-03-06 16:58:35 +010011090 { "Internal Mic", 0x6 },
11091 { "Line", 0x2 },
11092 },
11093};
11094
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010011095#ifdef CONFIG_SND_DEBUG
11096static struct snd_kcontrol_new alc268_test_mixer[] = {
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010011097 /* Volume widgets */
11098 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x02, 0x0, HDA_OUTPUT),
11099 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x03, 0x0, HDA_OUTPUT),
11100 HDA_BIND_MUTE_MONO("Mono sum Playback Switch", 0x0e, 1, 2, HDA_INPUT),
11101 HDA_BIND_MUTE("LINE-OUT sum Playback Switch", 0x0f, 2, HDA_INPUT),
11102 HDA_BIND_MUTE("HP-OUT sum Playback Switch", 0x10, 2, HDA_INPUT),
11103 HDA_BIND_MUTE("LINE-OUT Playback Switch", 0x14, 2, HDA_OUTPUT),
11104 HDA_BIND_MUTE("HP-OUT Playback Switch", 0x15, 2, HDA_OUTPUT),
11105 HDA_BIND_MUTE("Mono Playback Switch", 0x16, 2, HDA_OUTPUT),
11106 HDA_CODEC_VOLUME("MIC1 Capture Volume", 0x18, 0x0, HDA_INPUT),
11107 HDA_BIND_MUTE("MIC1 Capture Switch", 0x18, 2, HDA_OUTPUT),
11108 HDA_CODEC_VOLUME("MIC2 Capture Volume", 0x19, 0x0, HDA_INPUT),
11109 HDA_CODEC_VOLUME("LINE1 Capture Volume", 0x1a, 0x0, HDA_INPUT),
11110 HDA_BIND_MUTE("LINE1 Capture Switch", 0x1a, 2, HDA_OUTPUT),
Takashi Iwaif0747ee2008-01-15 11:41:41 +010011111 /* The below appears problematic on some hardwares */
11112 /*HDA_CODEC_VOLUME("PCBEEP Playback Volume", 0x1d, 0x0, HDA_INPUT),*/
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010011113 HDA_CODEC_VOLUME("PCM-IN1 Capture Volume", 0x23, 0x0, HDA_OUTPUT),
11114 HDA_BIND_MUTE("PCM-IN1 Capture Switch", 0x23, 2, HDA_OUTPUT),
11115 HDA_CODEC_VOLUME("PCM-IN2 Capture Volume", 0x24, 0x0, HDA_OUTPUT),
11116 HDA_BIND_MUTE("PCM-IN2 Capture Switch", 0x24, 2, HDA_OUTPUT),
11117
11118 /* Modes for retasking pin widgets */
11119 ALC_PIN_MODE("LINE-OUT pin mode", 0x14, ALC_PIN_DIR_INOUT),
11120 ALC_PIN_MODE("HP-OUT pin mode", 0x15, ALC_PIN_DIR_INOUT),
11121 ALC_PIN_MODE("MIC1 pin mode", 0x18, ALC_PIN_DIR_INOUT),
11122 ALC_PIN_MODE("LINE1 pin mode", 0x1a, ALC_PIN_DIR_INOUT),
11123
11124 /* Controls for GPIO pins, assuming they are configured as outputs */
11125 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
11126 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
11127 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
11128 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
11129
11130 /* Switches to allow the digital SPDIF output pin to be enabled.
11131 * The ALC268 does not have an SPDIF input.
11132 */
11133 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x06, 0x01),
11134
11135 /* A switch allowing EAPD to be enabled. Some laptops seem to use
11136 * this output to turn on an external amplifier.
11137 */
11138 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
11139 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
11140
11141 { } /* end */
11142};
11143#endif
11144
Kailang Yanga361d842007-06-05 12:30:55 +020011145/* create input playback/capture controls for the given pin */
11146static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
11147 const char *ctlname, int idx)
11148{
11149 char name[32];
11150 int err;
11151
11152 sprintf(name, "%s Playback Volume", ctlname);
11153 if (nid == 0x14) {
11154 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
11155 HDA_COMPOSE_AMP_VAL(0x02, 3, idx,
11156 HDA_OUTPUT));
11157 if (err < 0)
11158 return err;
11159 } else if (nid == 0x15) {
11160 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
11161 HDA_COMPOSE_AMP_VAL(0x03, 3, idx,
11162 HDA_OUTPUT));
11163 if (err < 0)
11164 return err;
11165 } else
11166 return -1;
11167 sprintf(name, "%s Playback Switch", ctlname);
11168 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
11169 HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
11170 if (err < 0)
11171 return err;
11172 return 0;
11173}
11174
11175/* add playback controls from the parsed DAC table */
11176static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
11177 const struct auto_pin_cfg *cfg)
11178{
11179 hda_nid_t nid;
11180 int err;
11181
11182 spec->multiout.num_dacs = 2; /* only use one dac */
11183 spec->multiout.dac_nids = spec->private_dac_nids;
11184 spec->multiout.dac_nids[0] = 2;
11185 spec->multiout.dac_nids[1] = 3;
11186
11187 nid = cfg->line_out_pins[0];
11188 if (nid)
Kailang Yangea1fb292008-08-26 12:58:38 +020011189 alc268_new_analog_output(spec, nid, "Front", 0);
Kailang Yanga361d842007-06-05 12:30:55 +020011190
11191 nid = cfg->speaker_pins[0];
11192 if (nid == 0x1d) {
11193 err = add_control(spec, ALC_CTL_WIDGET_VOL,
11194 "Speaker Playback Volume",
11195 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
11196 if (err < 0)
11197 return err;
11198 }
11199 nid = cfg->hp_pins[0];
11200 if (nid)
11201 alc268_new_analog_output(spec, nid, "Headphone", 0);
11202
11203 nid = cfg->line_out_pins[1] | cfg->line_out_pins[2];
11204 if (nid == 0x16) {
11205 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
11206 "Mono Playback Switch",
11207 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_INPUT));
11208 if (err < 0)
11209 return err;
11210 }
Kailang Yangea1fb292008-08-26 12:58:38 +020011211 return 0;
Kailang Yanga361d842007-06-05 12:30:55 +020011212}
11213
11214/* create playback/capture controls for input pins */
11215static int alc268_auto_create_analog_input_ctls(struct alc_spec *spec,
11216 const struct auto_pin_cfg *cfg)
11217{
11218 struct hda_input_mux *imux = &spec->private_imux;
11219 int i, idx1;
11220
11221 for (i = 0; i < AUTO_PIN_LAST; i++) {
11222 switch(cfg->input_pins[i]) {
11223 case 0x18:
11224 idx1 = 0; /* Mic 1 */
11225 break;
11226 case 0x19:
11227 idx1 = 1; /* Mic 2 */
11228 break;
11229 case 0x1a:
11230 idx1 = 2; /* Line In */
11231 break;
Kailang Yangea1fb292008-08-26 12:58:38 +020011232 case 0x1c:
Kailang Yanga361d842007-06-05 12:30:55 +020011233 idx1 = 3; /* CD */
11234 break;
Takashi Iwai7194cae2008-03-06 16:58:17 +010011235 case 0x12:
11236 case 0x13:
11237 idx1 = 6; /* digital mics */
11238 break;
Kailang Yanga361d842007-06-05 12:30:55 +020011239 default:
11240 continue;
11241 }
11242 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
11243 imux->items[imux->num_items].index = idx1;
Kailang Yangea1fb292008-08-26 12:58:38 +020011244 imux->num_items++;
Kailang Yanga361d842007-06-05 12:30:55 +020011245 }
11246 return 0;
11247}
11248
11249static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec)
11250{
11251 struct alc_spec *spec = codec->spec;
11252 hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
11253 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
11254 hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
11255 unsigned int dac_vol1, dac_vol2;
11256
11257 if (speaker_nid) {
11258 snd_hda_codec_write(codec, speaker_nid, 0,
11259 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
11260 snd_hda_codec_write(codec, 0x0f, 0,
11261 AC_VERB_SET_AMP_GAIN_MUTE,
11262 AMP_IN_UNMUTE(1));
11263 snd_hda_codec_write(codec, 0x10, 0,
11264 AC_VERB_SET_AMP_GAIN_MUTE,
11265 AMP_IN_UNMUTE(1));
11266 } else {
11267 snd_hda_codec_write(codec, 0x0f, 0,
11268 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
11269 snd_hda_codec_write(codec, 0x10, 0,
11270 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
11271 }
11272
11273 dac_vol1 = dac_vol2 = 0xb000 | 0x40; /* set max volume */
Kailang Yangea1fb292008-08-26 12:58:38 +020011274 if (line_nid == 0x14)
Kailang Yanga361d842007-06-05 12:30:55 +020011275 dac_vol2 = AMP_OUT_ZERO;
11276 else if (line_nid == 0x15)
11277 dac_vol1 = AMP_OUT_ZERO;
Kailang Yangea1fb292008-08-26 12:58:38 +020011278 if (hp_nid == 0x14)
Kailang Yanga361d842007-06-05 12:30:55 +020011279 dac_vol2 = AMP_OUT_ZERO;
11280 else if (hp_nid == 0x15)
11281 dac_vol1 = AMP_OUT_ZERO;
11282 if (line_nid != 0x16 || hp_nid != 0x16 ||
11283 spec->autocfg.line_out_pins[1] != 0x16 ||
11284 spec->autocfg.line_out_pins[2] != 0x16)
11285 dac_vol1 = dac_vol2 = AMP_OUT_ZERO;
11286
11287 snd_hda_codec_write(codec, 0x02, 0,
11288 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol1);
11289 snd_hda_codec_write(codec, 0x03, 0,
11290 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol2);
11291}
11292
11293/* pcm configuration: identiacal with ALC880 */
11294#define alc268_pcm_analog_playback alc880_pcm_analog_playback
11295#define alc268_pcm_analog_capture alc880_pcm_analog_capture
Takashi Iwai63300792008-01-24 15:31:36 +010011296#define alc268_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
Kailang Yanga361d842007-06-05 12:30:55 +020011297#define alc268_pcm_digital_playback alc880_pcm_digital_playback
11298
11299/*
11300 * BIOS auto configuration
11301 */
11302static int alc268_parse_auto_config(struct hda_codec *codec)
11303{
11304 struct alc_spec *spec = codec->spec;
11305 int err;
11306 static hda_nid_t alc268_ignore[] = { 0 };
11307
11308 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
11309 alc268_ignore);
11310 if (err < 0)
11311 return err;
11312 if (!spec->autocfg.line_outs)
11313 return 0; /* can't find valid BIOS pin config */
11314
11315 err = alc268_auto_create_multi_out_ctls(spec, &spec->autocfg);
11316 if (err < 0)
11317 return err;
11318 err = alc268_auto_create_analog_input_ctls(spec, &spec->autocfg);
11319 if (err < 0)
11320 return err;
11321
11322 spec->multiout.max_channels = 2;
11323
11324 /* digital only support output */
11325 if (spec->autocfg.dig_out_pin)
11326 spec->multiout.dig_out_nid = ALC268_DIGOUT_NID;
11327
Takashi Iwai603c4012008-07-30 15:01:44 +020011328 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010011329 add_mixer(spec, spec->kctls.list);
Kailang Yanga361d842007-06-05 12:30:55 +020011330
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011331 if (spec->autocfg.speaker_pins[0] != 0x1d)
Takashi Iwaid88897e2008-10-31 15:01:37 +010011332 add_mixer(spec, alc268_beep_mixer);
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011333
Takashi Iwaid88897e2008-10-31 15:01:37 +010011334 add_verb(spec, alc268_volume_init_verbs);
Kailang Yanga361d842007-06-05 12:30:55 +020011335 spec->num_mux_defs = 1;
11336 spec->input_mux = &spec->private_imux;
11337
Takashi Iwai776e1842007-08-29 15:07:11 +020011338 err = alc_auto_add_mic_boost(codec);
11339 if (err < 0)
11340 return err;
11341
Takashi Iwaie044c392008-10-27 16:56:24 +010011342 store_pin_configs(codec);
Kailang Yanga361d842007-06-05 12:30:55 +020011343 return 1;
11344}
11345
11346#define alc268_auto_init_multi_out alc882_auto_init_multi_out
11347#define alc268_auto_init_hp_out alc882_auto_init_hp_out
11348#define alc268_auto_init_analog_input alc882_auto_init_analog_input
11349
11350/* init callback for auto-configuration model -- overriding the default init */
11351static void alc268_auto_init(struct hda_codec *codec)
11352{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010011353 struct alc_spec *spec = codec->spec;
Kailang Yanga361d842007-06-05 12:30:55 +020011354 alc268_auto_init_multi_out(codec);
11355 alc268_auto_init_hp_out(codec);
11356 alc268_auto_init_mono_speaker_out(codec);
11357 alc268_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010011358 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020011359 alc_inithook(codec);
Kailang Yanga361d842007-06-05 12:30:55 +020011360}
11361
11362/*
11363 * configuration and preset
11364 */
11365static const char *alc268_models[ALC268_MODEL_LAST] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020011366 [ALC267_QUANTA_IL1] = "quanta-il1",
Kailang Yanga361d842007-06-05 12:30:55 +020011367 [ALC268_3ST] = "3stack",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020011368 [ALC268_TOSHIBA] = "toshiba",
Takashi Iwaid2738092007-08-16 14:59:45 +020011369 [ALC268_ACER] = "acer",
Takashi Iwaic238b4f2008-11-05 14:57:20 +010011370 [ALC268_ACER_DMIC] = "acer-dmic",
Kailang Yang8ef355d2008-08-26 13:10:22 +020011371 [ALC268_ACER_ASPIRE_ONE] = "acer-aspire",
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011372 [ALC268_DELL] = "dell",
Mirco Tischlerf12462c2008-02-04 12:33:59 +010011373 [ALC268_ZEPTO] = "zepto",
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010011374#ifdef CONFIG_SND_DEBUG
11375 [ALC268_TEST] = "test",
11376#endif
Kailang Yanga361d842007-06-05 12:30:55 +020011377 [ALC268_AUTO] = "auto",
11378};
11379
11380static struct snd_pci_quirk alc268_cfg_tbl[] = {
Takashi Iwaia0b8f7d2008-04-22 19:39:49 +020011381 SND_PCI_QUIRK(0x1025, 0x011e, "Acer Aspire 5720z", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011382 SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER),
Andy Shevchenkodafc8352008-01-25 11:53:50 +010011383 SND_PCI_QUIRK(0x1025, 0x012e, "Acer Aspire 5310", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011384 SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER),
Andy Shevchenko29a52c22008-01-24 17:29:00 +010011385 SND_PCI_QUIRK(0x1025, 0x0136, "Acer Aspire 5315", ALC268_ACER),
Kailang Yang8ef355d2008-08-26 13:10:22 +020011386 SND_PCI_QUIRK(0x1025, 0x015b, "Acer Aspire One",
11387 ALC268_ACER_ASPIRE_ONE),
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011388 SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011389 SND_PCI_QUIRK(0x103c, 0x30cc, "TOSHIBA", ALC268_TOSHIBA),
Kailang Yanga361d842007-06-05 12:30:55 +020011390 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST),
Kailang Yangd1a991a2007-08-15 16:21:59 +020011391 SND_PCI_QUIRK(0x1179, 0xff10, "TOSHIBA A205", ALC268_TOSHIBA),
Takashi Iwai8e7f00f2007-09-07 10:58:58 +020011392 SND_PCI_QUIRK(0x1179, 0xff50, "TOSHIBA A305", ALC268_TOSHIBA),
Travis Place2346d0c2008-09-01 08:24:00 +020011393 SND_PCI_QUIRK(0x1179, 0xff64, "TOSHIBA L305", ALC268_TOSHIBA),
Tony Vroon378bd6a2008-06-04 12:08:30 +020011394 SND_PCI_QUIRK(0x14c0, 0x0025, "COMPAL IFL90/JFL-92", ALC268_TOSHIBA),
Takashi Iwaib875bf32007-09-06 15:00:27 +020011395 SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER),
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020011396 SND_PCI_QUIRK(0x152d, 0x0771, "Quanta IL1", ALC267_QUANTA_IL1),
Mirco Tischlerf12462c2008-02-04 12:33:59 +010011397 SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO),
Kailang Yanga361d842007-06-05 12:30:55 +020011398 {}
11399};
11400
11401static struct alc_config_preset alc268_presets[] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020011402 [ALC267_QUANTA_IL1] = {
11403 .mixers = { alc267_quanta_il1_mixer },
11404 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
11405 alc267_quanta_il1_verbs },
11406 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11407 .dac_nids = alc268_dac_nids,
11408 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
11409 .adc_nids = alc268_adc_nids_alt,
11410 .hp_nid = 0x03,
11411 .num_channel_mode = ARRAY_SIZE(alc268_modes),
11412 .channel_mode = alc268_modes,
11413 .input_mux = &alc268_capture_source,
11414 .unsol_event = alc267_quanta_il1_unsol_event,
11415 .init_hook = alc267_quanta_il1_automute,
11416 },
Kailang Yanga361d842007-06-05 12:30:55 +020011417 [ALC268_3ST] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011418 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
11419 alc268_beep_mixer },
Kailang Yanga361d842007-06-05 12:30:55 +020011420 .init_verbs = { alc268_base_init_verbs },
11421 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11422 .dac_nids = alc268_dac_nids,
11423 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
11424 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010011425 .capsrc_nids = alc268_capsrc_nids,
Kailang Yanga361d842007-06-05 12:30:55 +020011426 .hp_nid = 0x03,
11427 .dig_out_nid = ALC268_DIGOUT_NID,
11428 .num_channel_mode = ARRAY_SIZE(alc268_modes),
11429 .channel_mode = alc268_modes,
11430 .input_mux = &alc268_capture_source,
11431 },
Kailang Yangd1a991a2007-08-15 16:21:59 +020011432 [ALC268_TOSHIBA] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011433 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
11434 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020011435 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
11436 alc268_toshiba_verbs },
Kailang Yangd1a991a2007-08-15 16:21:59 +020011437 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11438 .dac_nids = alc268_dac_nids,
11439 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
11440 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010011441 .capsrc_nids = alc268_capsrc_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020011442 .hp_nid = 0x03,
11443 .num_channel_mode = ARRAY_SIZE(alc268_modes),
11444 .channel_mode = alc268_modes,
11445 .input_mux = &alc268_capture_source,
Takashi Iwaid2738092007-08-16 14:59:45 +020011446 .unsol_event = alc268_toshiba_unsol_event,
11447 .init_hook = alc268_toshiba_automute,
11448 },
11449 [ALC268_ACER] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011450 .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer,
11451 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020011452 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
11453 alc268_acer_verbs },
11454 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11455 .dac_nids = alc268_dac_nids,
11456 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
11457 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010011458 .capsrc_nids = alc268_capsrc_nids,
Takashi Iwaid2738092007-08-16 14:59:45 +020011459 .hp_nid = 0x02,
11460 .num_channel_mode = ARRAY_SIZE(alc268_modes),
11461 .channel_mode = alc268_modes,
Takashi Iwai0ccb5412008-03-06 16:58:35 +010011462 .input_mux = &alc268_acer_capture_source,
Takashi Iwaid2738092007-08-16 14:59:45 +020011463 .unsol_event = alc268_acer_unsol_event,
Takashi Iwai889c4392007-08-23 18:56:52 +020011464 .init_hook = alc268_acer_init_hook,
Kailang Yangd1a991a2007-08-15 16:21:59 +020011465 },
Takashi Iwaic238b4f2008-11-05 14:57:20 +010011466 [ALC268_ACER_DMIC] = {
11467 .mixers = { alc268_acer_dmic_mixer, alc268_capture_alt_mixer,
11468 alc268_beep_mixer },
11469 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
11470 alc268_acer_verbs },
11471 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11472 .dac_nids = alc268_dac_nids,
11473 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
11474 .adc_nids = alc268_adc_nids_alt,
11475 .capsrc_nids = alc268_capsrc_nids,
11476 .hp_nid = 0x02,
11477 .num_channel_mode = ARRAY_SIZE(alc268_modes),
11478 .channel_mode = alc268_modes,
11479 .input_mux = &alc268_acer_dmic_capture_source,
11480 .unsol_event = alc268_acer_unsol_event,
11481 .init_hook = alc268_acer_init_hook,
11482 },
Kailang Yang8ef355d2008-08-26 13:10:22 +020011483 [ALC268_ACER_ASPIRE_ONE] = {
11484 .mixers = { alc268_acer_aspire_one_mixer,
11485 alc268_capture_alt_mixer },
11486 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
11487 alc268_acer_aspire_one_verbs },
11488 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11489 .dac_nids = alc268_dac_nids,
11490 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
11491 .adc_nids = alc268_adc_nids_alt,
11492 .capsrc_nids = alc268_capsrc_nids,
11493 .hp_nid = 0x03,
11494 .num_channel_mode = ARRAY_SIZE(alc268_modes),
11495 .channel_mode = alc268_modes,
11496 .input_mux = &alc268_acer_lc_capture_source,
11497 .unsol_event = alc268_acer_lc_unsol_event,
11498 .init_hook = alc268_acer_lc_init_hook,
11499 },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011500 [ALC268_DELL] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011501 .mixers = { alc268_dell_mixer, alc268_beep_mixer },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011502 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
11503 alc268_dell_verbs },
11504 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11505 .dac_nids = alc268_dac_nids,
11506 .hp_nid = 0x02,
11507 .num_channel_mode = ARRAY_SIZE(alc268_modes),
11508 .channel_mode = alc268_modes,
11509 .unsol_event = alc268_dell_unsol_event,
11510 .init_hook = alc268_dell_init_hook,
11511 .input_mux = &alc268_capture_source,
11512 },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010011513 [ALC268_ZEPTO] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011514 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
11515 alc268_beep_mixer },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010011516 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
11517 alc268_toshiba_verbs },
11518 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11519 .dac_nids = alc268_dac_nids,
11520 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
11521 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010011522 .capsrc_nids = alc268_capsrc_nids,
Mirco Tischlerf12462c2008-02-04 12:33:59 +010011523 .hp_nid = 0x03,
11524 .dig_out_nid = ALC268_DIGOUT_NID,
11525 .num_channel_mode = ARRAY_SIZE(alc268_modes),
11526 .channel_mode = alc268_modes,
11527 .input_mux = &alc268_capture_source,
11528 .unsol_event = alc268_toshiba_unsol_event,
11529 .init_hook = alc268_toshiba_automute
11530 },
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010011531#ifdef CONFIG_SND_DEBUG
11532 [ALC268_TEST] = {
11533 .mixers = { alc268_test_mixer, alc268_capture_mixer },
11534 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
11535 alc268_volume_init_verbs },
11536 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11537 .dac_nids = alc268_dac_nids,
11538 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
11539 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010011540 .capsrc_nids = alc268_capsrc_nids,
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010011541 .hp_nid = 0x03,
11542 .dig_out_nid = ALC268_DIGOUT_NID,
11543 .num_channel_mode = ARRAY_SIZE(alc268_modes),
11544 .channel_mode = alc268_modes,
11545 .input_mux = &alc268_capture_source,
11546 },
11547#endif
Kailang Yanga361d842007-06-05 12:30:55 +020011548};
11549
11550static int patch_alc268(struct hda_codec *codec)
11551{
11552 struct alc_spec *spec;
11553 int board_config;
11554 int err;
11555
11556 spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
11557 if (spec == NULL)
11558 return -ENOMEM;
11559
11560 codec->spec = spec;
11561
11562 board_config = snd_hda_check_board_config(codec, ALC268_MODEL_LAST,
11563 alc268_models,
11564 alc268_cfg_tbl);
11565
11566 if (board_config < 0 || board_config >= ALC268_MODEL_LAST) {
11567 printk(KERN_INFO "hda_codec: Unknown model for ALC268, "
11568 "trying auto-probe from BIOS...\n");
11569 board_config = ALC268_AUTO;
11570 }
11571
11572 if (board_config == ALC268_AUTO) {
11573 /* automatic parse from the BIOS config */
11574 err = alc268_parse_auto_config(codec);
11575 if (err < 0) {
11576 alc_free(codec);
11577 return err;
11578 } else if (!err) {
11579 printk(KERN_INFO
11580 "hda_codec: Cannot set up configuration "
11581 "from BIOS. Using base mode...\n");
11582 board_config = ALC268_3ST;
11583 }
11584 }
11585
11586 if (board_config != ALC268_AUTO)
11587 setup_preset(spec, &alc268_presets[board_config]);
11588
Kailang Yang2f893282008-05-27 12:14:47 +020011589 if (codec->vendor_id == 0x10ec0267) {
11590 spec->stream_name_analog = "ALC267 Analog";
11591 spec->stream_name_digital = "ALC267 Digital";
11592 } else {
11593 spec->stream_name_analog = "ALC268 Analog";
11594 spec->stream_name_digital = "ALC268 Digital";
11595 }
11596
Kailang Yanga361d842007-06-05 12:30:55 +020011597 spec->stream_analog_playback = &alc268_pcm_analog_playback;
11598 spec->stream_analog_capture = &alc268_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +010011599 spec->stream_analog_alt_capture = &alc268_pcm_analog_alt_capture;
Kailang Yanga361d842007-06-05 12:30:55 +020011600
Kailang Yanga361d842007-06-05 12:30:55 +020011601 spec->stream_digital_playback = &alc268_pcm_digital_playback;
11602
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011603 if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
11604 /* override the amp caps for beep generator */
11605 snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT,
11606 (0x0c << AC_AMPCAP_OFFSET_SHIFT) |
11607 (0x0c << AC_AMPCAP_NUM_STEPS_SHIFT) |
11608 (0x07 << AC_AMPCAP_STEP_SIZE_SHIFT) |
11609 (0 << AC_AMPCAP_MUTE_SHIFT));
11610
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011611 if (!spec->adc_nids && spec->input_mux) {
11612 /* check whether NID 0x07 is valid */
11613 unsigned int wcap = get_wcaps(codec, 0x07);
Takashi Iwai85860c02008-02-19 15:00:15 +010011614 int i;
Kailang Yanga361d842007-06-05 12:30:55 +020011615
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011616 /* get type */
11617 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Takashi Iwai67ebcb02008-02-19 15:03:57 +010011618 if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011619 spec->adc_nids = alc268_adc_nids_alt;
11620 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt);
Takashi Iwaid88897e2008-10-31 15:01:37 +010011621 add_mixer(spec, alc268_capture_alt_mixer);
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011622 } else {
11623 spec->adc_nids = alc268_adc_nids;
11624 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids);
Takashi Iwaid88897e2008-10-31 15:01:37 +010011625 add_mixer(spec, alc268_capture_mixer);
Kailang Yanga361d842007-06-05 12:30:55 +020011626 }
Takashi Iwaie1406342008-02-11 18:32:32 +010011627 spec->capsrc_nids = alc268_capsrc_nids;
Takashi Iwai85860c02008-02-19 15:00:15 +010011628 /* set default input source */
11629 for (i = 0; i < spec->num_adc_nids; i++)
11630 snd_hda_codec_write_cache(codec, alc268_capsrc_nids[i],
11631 0, AC_VERB_SET_CONNECT_SEL,
11632 spec->input_mux->items[0].index);
Kailang Yanga361d842007-06-05 12:30:55 +020011633 }
Takashi Iwai2134ea42008-01-10 16:53:55 +010011634
11635 spec->vmaster_nid = 0x02;
11636
Kailang Yanga361d842007-06-05 12:30:55 +020011637 codec->patch_ops = alc_patch_ops;
11638 if (board_config == ALC268_AUTO)
11639 spec->init_hook = alc268_auto_init;
Kailang Yangea1fb292008-08-26 12:58:38 +020011640
Kailang Yanga361d842007-06-05 12:30:55 +020011641 return 0;
11642}
11643
11644/*
Kailang Yangf6a92242007-12-13 16:52:54 +010011645 * ALC269 channel source setting (2 channel)
11646 */
11647#define ALC269_DIGOUT_NID ALC880_DIGOUT_NID
11648
11649#define alc269_dac_nids alc260_dac_nids
11650
11651static hda_nid_t alc269_adc_nids[1] = {
11652 /* ADC1 */
Kailang Yangf53281e2008-07-18 12:36:43 +020011653 0x08,
11654};
11655
Takashi Iwaie01bf502008-08-21 16:25:07 +020011656static hda_nid_t alc269_capsrc_nids[1] = {
11657 0x23,
11658};
11659
11660/* NOTE: ADC2 (0x07) is connected from a recording *MIXER* (0x24),
11661 * not a mux!
11662 */
11663
Kailang Yangf53281e2008-07-18 12:36:43 +020011664static struct hda_input_mux alc269_eeepc_dmic_capture_source = {
11665 .num_items = 2,
11666 .items = {
11667 { "i-Mic", 0x5 },
11668 { "e-Mic", 0x0 },
11669 },
11670};
11671
11672static struct hda_input_mux alc269_eeepc_amic_capture_source = {
11673 .num_items = 2,
11674 .items = {
11675 { "i-Mic", 0x1 },
11676 { "e-Mic", 0x0 },
11677 },
Kailang Yangf6a92242007-12-13 16:52:54 +010011678};
11679
11680#define alc269_modes alc260_modes
11681#define alc269_capture_source alc880_lg_lw_capture_source
11682
11683static struct snd_kcontrol_new alc269_base_mixer[] = {
11684 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
11685 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11686 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11687 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11688 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11689 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai2005af22008-08-20 18:38:26 +020011690 HDA_CODEC_VOLUME("Beep Playback Volume", 0x0b, 0x4, HDA_INPUT),
11691 HDA_CODEC_MUTE("Beep Playback Switch", 0x0b, 0x4, HDA_INPUT),
Kailang Yangf6a92242007-12-13 16:52:54 +010011692 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11693 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11694 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11695 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
11696 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11697 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
11698 { } /* end */
11699};
11700
Kailang Yang60db6b52008-08-26 13:13:00 +020011701static struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = {
11702 /* output mixer control */
11703 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
11704 {
11705 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11706 .name = "Master Playback Switch",
11707 .info = snd_hda_mixer_amp_switch_info,
11708 .get = snd_hda_mixer_amp_switch_get,
11709 .put = alc268_acer_master_sw_put,
11710 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
11711 },
11712 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11713 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11714 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11715 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11716 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11717 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
11718 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x04, HDA_INPUT),
11719 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x04, HDA_INPUT),
11720 { }
11721};
11722
Tony Vroon64154832008-11-06 15:08:49 +000011723static struct snd_kcontrol_new alc269_lifebook_mixer[] = {
11724 /* output mixer control */
11725 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
11726 {
11727 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11728 .name = "Master Playback Switch",
11729 .info = snd_hda_mixer_amp_switch_info,
11730 .get = snd_hda_mixer_amp_switch_get,
11731 .put = alc268_acer_master_sw_put,
11732 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
11733 },
11734 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11735 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11736 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11737 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11738 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11739 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
11740 HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x0b, 0x03, HDA_INPUT),
11741 HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x0b, 0x03, HDA_INPUT),
11742 HDA_CODEC_VOLUME("Dock Mic Boost", 0x1b, 0, HDA_INPUT),
11743 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x04, HDA_INPUT),
11744 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x04, HDA_INPUT),
11745 { }
11746};
11747
Kailang Yangf53281e2008-07-18 12:36:43 +020011748/* bind volumes of both NID 0x0c and 0x0d */
11749static struct hda_bind_ctls alc269_epc_bind_vol = {
11750 .ops = &snd_hda_bind_vol,
11751 .values = {
11752 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
11753 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
11754 0
11755 },
11756};
11757
11758static struct snd_kcontrol_new alc269_eeepc_mixer[] = {
11759 HDA_CODEC_MUTE("iSpeaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11760 HDA_BIND_VOL("LineOut Playback Volume", &alc269_epc_bind_vol),
11761 HDA_CODEC_MUTE("LineOut Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11762 { } /* end */
11763};
11764
Kailang Yangf6a92242007-12-13 16:52:54 +010011765/* capture mixer elements */
Kailang Yangf53281e2008-07-18 12:36:43 +020011766static struct snd_kcontrol_new alc269_epc_capture_mixer[] = {
11767 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
11768 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
Takashi Iwai26f5df22008-11-03 17:39:46 +010011769 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11770 { } /* end */
11771};
11772
11773/* FSC amilo */
11774static struct snd_kcontrol_new alc269_fujitsu_mixer[] = {
11775 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11776 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11777 HDA_BIND_VOL("PCM Playback Volume", &alc269_epc_bind_vol),
Kailang Yangf53281e2008-07-18 12:36:43 +020011778 { } /* end */
11779};
11780
Takashi Iwai2005af22008-08-20 18:38:26 +020011781/* beep control */
11782static struct snd_kcontrol_new alc269_beep_mixer[] = {
11783 HDA_CODEC_VOLUME("Beep Playback Volume", 0x0b, 0x4, HDA_INPUT),
11784 HDA_CODEC_MUTE("Beep Playback Switch", 0x0b, 0x4, HDA_INPUT),
11785 { } /* end */
11786};
11787
Kailang Yang60db6b52008-08-26 13:13:00 +020011788static struct hda_verb alc269_quanta_fl1_verbs[] = {
11789 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
11790 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11791 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11792 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
11793 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
11794 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11795 { }
11796};
11797
Tony Vroon64154832008-11-06 15:08:49 +000011798static struct hda_verb alc269_lifebook_verbs[] = {
11799 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
11800 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
11801 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11802 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11803 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
11804 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11805 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11806 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
11807 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
11808 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11809 { }
11810};
11811
Kailang Yang60db6b52008-08-26 13:13:00 +020011812/* toggle speaker-output according to the hp-jack state */
11813static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec)
11814{
11815 unsigned int present;
11816 unsigned char bits;
11817
11818 present = snd_hda_codec_read(codec, 0x15, 0,
11819 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
11820 bits = present ? AMP_IN_MUTE(0) : 0;
11821 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
11822 AMP_IN_MUTE(0), bits);
11823 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
11824 AMP_IN_MUTE(0), bits);
11825
11826 snd_hda_codec_write(codec, 0x20, 0,
11827 AC_VERB_SET_COEF_INDEX, 0x0c);
11828 snd_hda_codec_write(codec, 0x20, 0,
11829 AC_VERB_SET_PROC_COEF, 0x680);
11830
11831 snd_hda_codec_write(codec, 0x20, 0,
11832 AC_VERB_SET_COEF_INDEX, 0x0c);
11833 snd_hda_codec_write(codec, 0x20, 0,
11834 AC_VERB_SET_PROC_COEF, 0x480);
11835}
11836
Tony Vroon64154832008-11-06 15:08:49 +000011837/* toggle speaker-output according to the hp-jacks state */
11838static void alc269_lifebook_speaker_automute(struct hda_codec *codec)
11839{
11840 unsigned int present;
11841 unsigned char bits;
11842
11843 /* Check laptop headphone socket */
11844 present = snd_hda_codec_read(codec, 0x15, 0,
11845 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
11846
11847 /* Check port replicator headphone socket */
11848 present |= snd_hda_codec_read(codec, 0x1a, 0,
11849 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
11850
11851 bits = present ? AMP_IN_MUTE(0) : 0;
11852 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
11853 AMP_IN_MUTE(0), bits);
11854 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
11855 AMP_IN_MUTE(0), bits);
11856
11857 snd_hda_codec_write(codec, 0x20, 0,
11858 AC_VERB_SET_COEF_INDEX, 0x0c);
11859 snd_hda_codec_write(codec, 0x20, 0,
11860 AC_VERB_SET_PROC_COEF, 0x680);
11861
11862 snd_hda_codec_write(codec, 0x20, 0,
11863 AC_VERB_SET_COEF_INDEX, 0x0c);
11864 snd_hda_codec_write(codec, 0x20, 0,
11865 AC_VERB_SET_PROC_COEF, 0x480);
11866}
11867
Kailang Yang60db6b52008-08-26 13:13:00 +020011868static void alc269_quanta_fl1_mic_automute(struct hda_codec *codec)
11869{
11870 unsigned int present;
11871
11872 present = snd_hda_codec_read(codec, 0x18, 0,
11873 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
11874 snd_hda_codec_write(codec, 0x23, 0,
11875 AC_VERB_SET_CONNECT_SEL, present ? 0x0 : 0x1);
11876}
11877
Tony Vroon64154832008-11-06 15:08:49 +000011878static void alc269_lifebook_mic_autoswitch(struct hda_codec *codec)
11879{
11880 unsigned int present_laptop;
11881 unsigned int present_dock;
11882
11883 present_laptop = snd_hda_codec_read(codec, 0x18, 0,
11884 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
11885
11886 present_dock = snd_hda_codec_read(codec, 0x1b, 0,
11887 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
11888
11889 /* Laptop mic port overrides dock mic port, design decision */
11890 if (present_dock)
11891 snd_hda_codec_write(codec, 0x23, 0,
11892 AC_VERB_SET_CONNECT_SEL, 0x3);
11893 if (present_laptop)
11894 snd_hda_codec_write(codec, 0x23, 0,
11895 AC_VERB_SET_CONNECT_SEL, 0x0);
11896 if (!present_dock && !present_laptop)
11897 snd_hda_codec_write(codec, 0x23, 0,
11898 AC_VERB_SET_CONNECT_SEL, 0x1);
11899}
11900
Kailang Yang60db6b52008-08-26 13:13:00 +020011901static void alc269_quanta_fl1_unsol_event(struct hda_codec *codec,
11902 unsigned int res)
11903{
11904 if ((res >> 26) == ALC880_HP_EVENT)
11905 alc269_quanta_fl1_speaker_automute(codec);
11906 if ((res >> 26) == ALC880_MIC_EVENT)
11907 alc269_quanta_fl1_mic_automute(codec);
11908}
11909
Tony Vroon64154832008-11-06 15:08:49 +000011910static void alc269_lifebook_unsol_event(struct hda_codec *codec,
11911 unsigned int res)
11912{
11913 if ((res >> 26) == ALC880_HP_EVENT)
11914 alc269_lifebook_speaker_automute(codec);
11915 if ((res >> 26) == ALC880_MIC_EVENT)
11916 alc269_lifebook_mic_autoswitch(codec);
11917}
11918
Kailang Yang60db6b52008-08-26 13:13:00 +020011919static void alc269_quanta_fl1_init_hook(struct hda_codec *codec)
11920{
11921 alc269_quanta_fl1_speaker_automute(codec);
11922 alc269_quanta_fl1_mic_automute(codec);
11923}
11924
Tony Vroon64154832008-11-06 15:08:49 +000011925static void alc269_lifebook_init_hook(struct hda_codec *codec)
11926{
11927 alc269_lifebook_speaker_automute(codec);
11928 alc269_lifebook_mic_autoswitch(codec);
11929}
11930
Kailang Yang60db6b52008-08-26 13:13:00 +020011931static struct hda_verb alc269_eeepc_dmic_init_verbs[] = {
11932 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
11933 {0x23, AC_VERB_SET_CONNECT_SEL, 0x05},
11934 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
11935 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
11936 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11937 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
11938 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11939 {}
11940};
11941
11942static struct hda_verb alc269_eeepc_amic_init_verbs[] = {
11943 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
11944 {0x23, AC_VERB_SET_CONNECT_SEL, 0x01},
11945 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
11946 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x701b | (0x00 << 8))},
11947 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
11948 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11949 {}
11950};
11951
11952/* toggle speaker-output according to the hp-jack state */
11953static void alc269_speaker_automute(struct hda_codec *codec)
11954{
11955 unsigned int present;
11956 unsigned char bits;
11957
11958 present = snd_hda_codec_read(codec, 0x15, 0,
11959 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
11960 bits = present ? AMP_IN_MUTE(0) : 0;
11961 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
11962 AMP_IN_MUTE(0), bits);
11963 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
11964 AMP_IN_MUTE(0), bits);
11965}
11966
11967static void alc269_eeepc_dmic_automute(struct hda_codec *codec)
11968{
11969 unsigned int present;
11970
11971 present = snd_hda_codec_read(codec, 0x18, 0,
11972 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
11973 snd_hda_codec_write(codec, 0x23, 0,
11974 AC_VERB_SET_CONNECT_SEL, (present ? 0 : 5));
11975}
11976
11977static void alc269_eeepc_amic_automute(struct hda_codec *codec)
11978{
11979 unsigned int present;
11980
11981 present = snd_hda_codec_read(codec, 0x18, 0,
11982 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
11983 snd_hda_codec_write(codec, 0x24, 0, AC_VERB_SET_AMP_GAIN_MUTE,
11984 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
11985 snd_hda_codec_write(codec, 0x24, 0, AC_VERB_SET_AMP_GAIN_MUTE,
11986 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
11987}
11988
11989/* unsolicited event for HP jack sensing */
11990static void alc269_eeepc_dmic_unsol_event(struct hda_codec *codec,
11991 unsigned int res)
11992{
11993 if ((res >> 26) == ALC880_HP_EVENT)
11994 alc269_speaker_automute(codec);
11995
11996 if ((res >> 26) == ALC880_MIC_EVENT)
11997 alc269_eeepc_dmic_automute(codec);
11998}
11999
12000static void alc269_eeepc_dmic_inithook(struct hda_codec *codec)
12001{
12002 alc269_speaker_automute(codec);
12003 alc269_eeepc_dmic_automute(codec);
12004}
12005
12006/* unsolicited event for HP jack sensing */
12007static void alc269_eeepc_amic_unsol_event(struct hda_codec *codec,
12008 unsigned int res)
12009{
12010 if ((res >> 26) == ALC880_HP_EVENT)
12011 alc269_speaker_automute(codec);
12012
12013 if ((res >> 26) == ALC880_MIC_EVENT)
12014 alc269_eeepc_amic_automute(codec);
12015}
12016
12017static void alc269_eeepc_amic_inithook(struct hda_codec *codec)
12018{
12019 alc269_speaker_automute(codec);
12020 alc269_eeepc_amic_automute(codec);
12021}
12022
Kailang Yangf6a92242007-12-13 16:52:54 +010012023/*
12024 * generic initialization of ADC, input mixers and output mixers
12025 */
12026static struct hda_verb alc269_init_verbs[] = {
12027 /*
12028 * Unmute ADC0 and set the default input to mic-in
12029 */
Kailang Yang60db6b52008-08-26 13:13:00 +020012030 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangf6a92242007-12-13 16:52:54 +010012031
12032 /* Mute input amps (PCBeep, Line In, Mic 1 & Mic 2) of the
12033 * analog-loopback mixer widget
12034 * Note: PASD motherboards uses the Line In 2 as the input for
12035 * front panel mic (mic 2)
12036 */
12037 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
12038 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12039 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12040 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12041 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12042 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
12043
12044 /*
12045 * Set up output mixers (0x0c - 0x0e)
12046 */
12047 /* set vol=0 to output mixers */
12048 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12049 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12050
12051 /* set up input amps for analog loopback */
12052 /* Amp Indices: DAC = 0, mixer = 1 */
12053 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12054 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12055 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12056 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12057 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12058 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12059
12060 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12061 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12062 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12063 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
12064 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
12065 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12066 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12067
12068 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12069 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12070 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12071 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12072 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12073 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12074 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12075
12076 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
12077 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
12078
12079 /* FIXME: use matrix-type input source selection */
12080 /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
12081 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yang60db6b52008-08-26 13:13:00 +020012082 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12083 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangf6a92242007-12-13 16:52:54 +010012084 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12085 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12086
12087 /* set EAPD */
12088 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
12089 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
12090 { }
12091};
12092
12093/* add playback controls from the parsed DAC table */
12094static int alc269_auto_create_multi_out_ctls(struct alc_spec *spec,
12095 const struct auto_pin_cfg *cfg)
12096{
12097 hda_nid_t nid;
12098 int err;
12099
12100 spec->multiout.num_dacs = 1; /* only use one dac */
12101 spec->multiout.dac_nids = spec->private_dac_nids;
12102 spec->multiout.dac_nids[0] = 2;
12103
12104 nid = cfg->line_out_pins[0];
12105 if (nid) {
12106 err = add_control(spec, ALC_CTL_WIDGET_VOL,
12107 "Front Playback Volume",
12108 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT));
12109 if (err < 0)
12110 return err;
12111 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
12112 "Front Playback Switch",
12113 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
12114 if (err < 0)
12115 return err;
12116 }
12117
12118 nid = cfg->speaker_pins[0];
12119 if (nid) {
12120 if (!cfg->line_out_pins[0]) {
12121 err = add_control(spec, ALC_CTL_WIDGET_VOL,
12122 "Speaker Playback Volume",
12123 HDA_COMPOSE_AMP_VAL(0x02, 3, 0,
12124 HDA_OUTPUT));
12125 if (err < 0)
12126 return err;
12127 }
12128 if (nid == 0x16) {
12129 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
12130 "Speaker Playback Switch",
12131 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
12132 HDA_OUTPUT));
12133 if (err < 0)
12134 return err;
12135 } else {
12136 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
12137 "Speaker Playback Switch",
12138 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
12139 HDA_OUTPUT));
12140 if (err < 0)
12141 return err;
12142 }
12143 }
12144 nid = cfg->hp_pins[0];
12145 if (nid) {
12146 /* spec->multiout.hp_nid = 2; */
12147 if (!cfg->line_out_pins[0] && !cfg->speaker_pins[0]) {
12148 err = add_control(spec, ALC_CTL_WIDGET_VOL,
12149 "Headphone Playback Volume",
12150 HDA_COMPOSE_AMP_VAL(0x02, 3, 0,
12151 HDA_OUTPUT));
12152 if (err < 0)
12153 return err;
12154 }
12155 if (nid == 0x16) {
12156 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
12157 "Headphone Playback Switch",
12158 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
12159 HDA_OUTPUT));
12160 if (err < 0)
12161 return err;
12162 } else {
12163 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
12164 "Headphone Playback Switch",
12165 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
12166 HDA_OUTPUT));
12167 if (err < 0)
12168 return err;
12169 }
12170 }
12171 return 0;
12172}
12173
Takashi Iwaiee956e02008-10-31 17:16:31 +010012174static int alc269_auto_create_analog_input_ctls(struct alc_spec *spec,
12175 const struct auto_pin_cfg *cfg)
12176{
12177 int err;
12178
12179 err = alc880_auto_create_analog_input_ctls(spec, cfg);
12180 if (err < 0)
12181 return err;
12182 /* digital-mic input pin is excluded in alc880_auto_create..()
12183 * because it's under 0x18
12184 */
12185 if (cfg->input_pins[AUTO_PIN_MIC] == 0x12 ||
12186 cfg->input_pins[AUTO_PIN_FRONT_MIC] == 0x12) {
12187 struct hda_input_mux *imux = &spec->private_imux;
12188 imux->items[imux->num_items].label = "Int Mic";
12189 imux->items[imux->num_items].index = 0x05;
12190 imux->num_items++;
12191 }
12192 return 0;
12193}
Kailang Yangf6a92242007-12-13 16:52:54 +010012194
12195#ifdef CONFIG_SND_HDA_POWER_SAVE
12196#define alc269_loopbacks alc880_loopbacks
12197#endif
12198
12199/* pcm configuration: identiacal with ALC880 */
12200#define alc269_pcm_analog_playback alc880_pcm_analog_playback
12201#define alc269_pcm_analog_capture alc880_pcm_analog_capture
12202#define alc269_pcm_digital_playback alc880_pcm_digital_playback
12203#define alc269_pcm_digital_capture alc880_pcm_digital_capture
12204
12205/*
12206 * BIOS auto configuration
12207 */
12208static int alc269_parse_auto_config(struct hda_codec *codec)
12209{
12210 struct alc_spec *spec = codec->spec;
Takashi Iwai2005af22008-08-20 18:38:26 +020012211 int i, err;
Kailang Yangf6a92242007-12-13 16:52:54 +010012212 static hda_nid_t alc269_ignore[] = { 0x1d, 0 };
12213
12214 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
12215 alc269_ignore);
12216 if (err < 0)
12217 return err;
12218
12219 err = alc269_auto_create_multi_out_ctls(spec, &spec->autocfg);
12220 if (err < 0)
12221 return err;
12222 err = alc269_auto_create_analog_input_ctls(spec, &spec->autocfg);
12223 if (err < 0)
12224 return err;
12225
12226 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
12227
12228 if (spec->autocfg.dig_out_pin)
12229 spec->multiout.dig_out_nid = ALC269_DIGOUT_NID;
12230
Takashi Iwai603c4012008-07-30 15:01:44 +020012231 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010012232 add_mixer(spec, spec->kctls.list);
Kailang Yangf6a92242007-12-13 16:52:54 +010012233
Takashi Iwai2005af22008-08-20 18:38:26 +020012234 /* create a beep mixer control if the pin 0x1d isn't assigned */
12235 for (i = 0; i < ARRAY_SIZE(spec->autocfg.input_pins); i++)
12236 if (spec->autocfg.input_pins[i] == 0x1d)
12237 break;
12238 if (i >= ARRAY_SIZE(spec->autocfg.input_pins))
Takashi Iwaid88897e2008-10-31 15:01:37 +010012239 add_mixer(spec, alc269_beep_mixer);
Takashi Iwai2005af22008-08-20 18:38:26 +020012240
Takashi Iwaid88897e2008-10-31 15:01:37 +010012241 add_verb(spec, alc269_init_verbs);
Kailang Yangf6a92242007-12-13 16:52:54 +010012242 spec->num_mux_defs = 1;
12243 spec->input_mux = &spec->private_imux;
Takashi Iwaie01bf502008-08-21 16:25:07 +020012244 /* set default input source */
12245 snd_hda_codec_write_cache(codec, alc269_capsrc_nids[0],
12246 0, AC_VERB_SET_CONNECT_SEL,
12247 spec->input_mux->items[0].index);
Kailang Yangf6a92242007-12-13 16:52:54 +010012248
12249 err = alc_auto_add_mic_boost(codec);
12250 if (err < 0)
12251 return err;
12252
Takashi Iwaif9e336f2008-10-31 16:37:07 +010012253 if (!spec->cap_mixer)
12254 set_capture_mixer(spec);
Kailang Yangf53281e2008-07-18 12:36:43 +020012255
Takashi Iwaie044c392008-10-27 16:56:24 +010012256 store_pin_configs(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010012257 return 1;
12258}
12259
12260#define alc269_auto_init_multi_out alc882_auto_init_multi_out
12261#define alc269_auto_init_hp_out alc882_auto_init_hp_out
12262#define alc269_auto_init_analog_input alc882_auto_init_analog_input
12263
12264
12265/* init callback for auto-configuration model -- overriding the default init */
12266static void alc269_auto_init(struct hda_codec *codec)
12267{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012268 struct alc_spec *spec = codec->spec;
Kailang Yangf6a92242007-12-13 16:52:54 +010012269 alc269_auto_init_multi_out(codec);
12270 alc269_auto_init_hp_out(codec);
12271 alc269_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012272 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020012273 alc_inithook(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010012274}
12275
12276/*
12277 * configuration and preset
12278 */
12279static const char *alc269_models[ALC269_MODEL_LAST] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020012280 [ALC269_BASIC] = "basic",
Takashi Iwai2922c9a2008-08-27 18:12:42 +020012281 [ALC269_QUANTA_FL1] = "quanta",
12282 [ALC269_ASUS_EEEPC_P703] = "eeepc-p703",
Takashi Iwai26f5df22008-11-03 17:39:46 +010012283 [ALC269_ASUS_EEEPC_P901] = "eeepc-p901",
Tony Vroon64154832008-11-06 15:08:49 +000012284 [ALC269_FUJITSU] = "fujitsu",
12285 [ALC269_LIFEBOOK] = "lifebook"
Kailang Yangf6a92242007-12-13 16:52:54 +010012286};
12287
12288static struct snd_pci_quirk alc269_cfg_tbl[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020012289 SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_QUANTA_FL1),
Kailang Yangf53281e2008-07-18 12:36:43 +020012290 SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A",
12291 ALC269_ASUS_EEEPC_P703),
12292 SND_PCI_QUIRK(0x1043, 0x831a, "ASUS Eeepc P901",
12293 ALC269_ASUS_EEEPC_P901),
Kailang Yang60db6b52008-08-26 13:13:00 +020012294 SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101",
12295 ALC269_ASUS_EEEPC_P901),
Takashi Iwai26f5df22008-11-03 17:39:46 +010012296 SND_PCI_QUIRK(0x1734, 0x115d, "FSC Amilo", ALC269_FUJITSU),
Tony Vroon64154832008-11-06 15:08:49 +000012297 SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook ICH9M-based", ALC269_LIFEBOOK),
Kailang Yangf6a92242007-12-13 16:52:54 +010012298 {}
12299};
12300
12301static struct alc_config_preset alc269_presets[] = {
12302 [ALC269_BASIC] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010012303 .mixers = { alc269_base_mixer },
Kailang Yangf6a92242007-12-13 16:52:54 +010012304 .init_verbs = { alc269_init_verbs },
12305 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
12306 .dac_nids = alc269_dac_nids,
12307 .hp_nid = 0x03,
12308 .num_channel_mode = ARRAY_SIZE(alc269_modes),
12309 .channel_mode = alc269_modes,
12310 .input_mux = &alc269_capture_source,
12311 },
Kailang Yang60db6b52008-08-26 13:13:00 +020012312 [ALC269_QUANTA_FL1] = {
12313 .mixers = { alc269_quanta_fl1_mixer },
12314 .init_verbs = { alc269_init_verbs, alc269_quanta_fl1_verbs },
12315 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
12316 .dac_nids = alc269_dac_nids,
12317 .hp_nid = 0x03,
12318 .num_channel_mode = ARRAY_SIZE(alc269_modes),
12319 .channel_mode = alc269_modes,
12320 .input_mux = &alc269_capture_source,
12321 .unsol_event = alc269_quanta_fl1_unsol_event,
12322 .init_hook = alc269_quanta_fl1_init_hook,
12323 },
Kailang Yangf53281e2008-07-18 12:36:43 +020012324 [ALC269_ASUS_EEEPC_P703] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010012325 .mixers = { alc269_eeepc_mixer },
12326 .cap_mixer = alc269_epc_capture_mixer,
Kailang Yangf53281e2008-07-18 12:36:43 +020012327 .init_verbs = { alc269_init_verbs,
12328 alc269_eeepc_amic_init_verbs },
12329 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
12330 .dac_nids = alc269_dac_nids,
12331 .hp_nid = 0x03,
12332 .num_channel_mode = ARRAY_SIZE(alc269_modes),
12333 .channel_mode = alc269_modes,
12334 .input_mux = &alc269_eeepc_amic_capture_source,
12335 .unsol_event = alc269_eeepc_amic_unsol_event,
12336 .init_hook = alc269_eeepc_amic_inithook,
12337 },
12338 [ALC269_ASUS_EEEPC_P901] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010012339 .mixers = { alc269_eeepc_mixer },
12340 .cap_mixer = alc269_epc_capture_mixer,
Kailang Yangf53281e2008-07-18 12:36:43 +020012341 .init_verbs = { alc269_init_verbs,
12342 alc269_eeepc_dmic_init_verbs },
12343 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
12344 .dac_nids = alc269_dac_nids,
12345 .hp_nid = 0x03,
12346 .num_channel_mode = ARRAY_SIZE(alc269_modes),
12347 .channel_mode = alc269_modes,
12348 .input_mux = &alc269_eeepc_dmic_capture_source,
12349 .unsol_event = alc269_eeepc_dmic_unsol_event,
12350 .init_hook = alc269_eeepc_dmic_inithook,
12351 },
Takashi Iwai26f5df22008-11-03 17:39:46 +010012352 [ALC269_FUJITSU] = {
12353 .mixers = { alc269_fujitsu_mixer, alc269_beep_mixer },
12354 .cap_mixer = alc269_epc_capture_mixer,
12355 .init_verbs = { alc269_init_verbs,
12356 alc269_eeepc_dmic_init_verbs },
12357 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
12358 .dac_nids = alc269_dac_nids,
12359 .hp_nid = 0x03,
12360 .num_channel_mode = ARRAY_SIZE(alc269_modes),
12361 .channel_mode = alc269_modes,
12362 .input_mux = &alc269_eeepc_dmic_capture_source,
12363 .unsol_event = alc269_eeepc_dmic_unsol_event,
12364 .init_hook = alc269_eeepc_dmic_inithook,
12365 },
Tony Vroon64154832008-11-06 15:08:49 +000012366 [ALC269_LIFEBOOK] = {
12367 .mixers = { alc269_lifebook_mixer },
12368 .init_verbs = { alc269_init_verbs, alc269_lifebook_verbs },
12369 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
12370 .dac_nids = alc269_dac_nids,
12371 .hp_nid = 0x03,
12372 .num_channel_mode = ARRAY_SIZE(alc269_modes),
12373 .channel_mode = alc269_modes,
12374 .input_mux = &alc269_capture_source,
12375 .unsol_event = alc269_lifebook_unsol_event,
12376 .init_hook = alc269_lifebook_init_hook,
12377 },
Kailang Yangf6a92242007-12-13 16:52:54 +010012378};
12379
12380static int patch_alc269(struct hda_codec *codec)
12381{
12382 struct alc_spec *spec;
12383 int board_config;
12384 int err;
12385
12386 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
12387 if (spec == NULL)
12388 return -ENOMEM;
12389
12390 codec->spec = spec;
12391
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020012392 alc_fix_pll_init(codec, 0x20, 0x04, 15);
12393
Kailang Yangf6a92242007-12-13 16:52:54 +010012394 board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST,
12395 alc269_models,
12396 alc269_cfg_tbl);
12397
12398 if (board_config < 0) {
12399 printk(KERN_INFO "hda_codec: Unknown model for ALC269, "
12400 "trying auto-probe from BIOS...\n");
12401 board_config = ALC269_AUTO;
12402 }
12403
12404 if (board_config == ALC269_AUTO) {
12405 /* automatic parse from the BIOS config */
12406 err = alc269_parse_auto_config(codec);
12407 if (err < 0) {
12408 alc_free(codec);
12409 return err;
12410 } else if (!err) {
12411 printk(KERN_INFO
12412 "hda_codec: Cannot set up configuration "
12413 "from BIOS. Using base mode...\n");
12414 board_config = ALC269_BASIC;
12415 }
12416 }
12417
12418 if (board_config != ALC269_AUTO)
12419 setup_preset(spec, &alc269_presets[board_config]);
12420
12421 spec->stream_name_analog = "ALC269 Analog";
12422 spec->stream_analog_playback = &alc269_pcm_analog_playback;
12423 spec->stream_analog_capture = &alc269_pcm_analog_capture;
12424
12425 spec->stream_name_digital = "ALC269 Digital";
12426 spec->stream_digital_playback = &alc269_pcm_digital_playback;
12427 spec->stream_digital_capture = &alc269_pcm_digital_capture;
12428
12429 spec->adc_nids = alc269_adc_nids;
12430 spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids);
Takashi Iwaie01bf502008-08-21 16:25:07 +020012431 spec->capsrc_nids = alc269_capsrc_nids;
Takashi Iwaif9e336f2008-10-31 16:37:07 +010012432 if (!spec->cap_mixer)
12433 set_capture_mixer(spec);
Kailang Yangf6a92242007-12-13 16:52:54 +010012434
12435 codec->patch_ops = alc_patch_ops;
12436 if (board_config == ALC269_AUTO)
12437 spec->init_hook = alc269_auto_init;
12438#ifdef CONFIG_SND_HDA_POWER_SAVE
12439 if (!spec->loopback.amplist)
12440 spec->loopback.amplist = alc269_loopbacks;
12441#endif
12442
12443 return 0;
12444}
12445
12446/*
Kailang Yangdf694da2005-12-05 19:42:22 +010012447 * ALC861 channel source setting (2/6 channel selection for 3-stack)
12448 */
12449
12450/*
12451 * set the path ways for 2 channel output
12452 * need to set the codec line out and mic 1 pin widgets to inputs
12453 */
12454static struct hda_verb alc861_threestack_ch2_init[] = {
12455 /* set pin widget 1Ah (line in) for input */
12456 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012457 /* set pin widget 18h (mic1/2) for input, for mic also enable
12458 * the vref
12459 */
Kailang Yangdf694da2005-12-05 19:42:22 +010012460 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12461
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012462 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
12463#if 0
12464 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
12465 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
12466#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010012467 { } /* end */
12468};
12469/*
12470 * 6ch mode
12471 * need to set the codec line out and mic 1 pin widgets to outputs
12472 */
12473static struct hda_verb alc861_threestack_ch6_init[] = {
12474 /* set pin widget 1Ah (line in) for output (Back Surround)*/
12475 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12476 /* set pin widget 18h (mic1) for output (CLFE)*/
12477 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12478
12479 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012480 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010012481
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012482 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
12483#if 0
12484 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
12485 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
12486#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010012487 { } /* end */
12488};
12489
12490static struct hda_channel_mode alc861_threestack_modes[2] = {
12491 { 2, alc861_threestack_ch2_init },
12492 { 6, alc861_threestack_ch6_init },
12493};
Takashi Iwai22309c32006-08-09 16:57:28 +020012494/* Set mic1 as input and unmute the mixer */
12495static struct hda_verb alc861_uniwill_m31_ch2_init[] = {
12496 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12497 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
12498 { } /* end */
12499};
12500/* Set mic1 as output and mute mixer */
12501static struct hda_verb alc861_uniwill_m31_ch4_init[] = {
12502 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12503 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
12504 { } /* end */
12505};
12506
12507static struct hda_channel_mode alc861_uniwill_m31_modes[2] = {
12508 { 2, alc861_uniwill_m31_ch2_init },
12509 { 4, alc861_uniwill_m31_ch4_init },
12510};
Kailang Yangdf694da2005-12-05 19:42:22 +010012511
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012512/* Set mic1 and line-in as input and unmute the mixer */
12513static struct hda_verb alc861_asus_ch2_init[] = {
12514 /* set pin widget 1Ah (line in) for input */
12515 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012516 /* set pin widget 18h (mic1/2) for input, for mic also enable
12517 * the vref
12518 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012519 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12520
12521 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
12522#if 0
12523 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
12524 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
12525#endif
12526 { } /* end */
12527};
12528/* Set mic1 nad line-in as output and mute mixer */
12529static struct hda_verb alc861_asus_ch6_init[] = {
12530 /* set pin widget 1Ah (line in) for output (Back Surround)*/
12531 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12532 /* { 0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
12533 /* set pin widget 18h (mic1) for output (CLFE)*/
12534 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12535 /* { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
12536 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
12537 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
12538
12539 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
12540#if 0
12541 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
12542 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
12543#endif
12544 { } /* end */
12545};
12546
12547static struct hda_channel_mode alc861_asus_modes[2] = {
12548 { 2, alc861_asus_ch2_init },
12549 { 6, alc861_asus_ch6_init },
12550};
12551
Kailang Yangdf694da2005-12-05 19:42:22 +010012552/* patch-ALC861 */
12553
12554static struct snd_kcontrol_new alc861_base_mixer[] = {
12555 /* output mixer control */
12556 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
12557 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
12558 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
12559 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
12560 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
12561
12562 /*Input mixer control */
12563 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
12564 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
12565 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
12566 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
12567 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
12568 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
12569 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
12570 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
12571 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
12572 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012573
Kailang Yangdf694da2005-12-05 19:42:22 +010012574 { } /* end */
12575};
12576
12577static struct snd_kcontrol_new alc861_3ST_mixer[] = {
12578 /* output mixer control */
12579 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
12580 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
12581 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
12582 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
12583 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
12584
12585 /* Input mixer control */
12586 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
12587 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
12588 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
12589 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
12590 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
12591 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
12592 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
12593 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
12594 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
12595 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012596
Kailang Yangdf694da2005-12-05 19:42:22 +010012597 {
12598 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12599 .name = "Channel Mode",
12600 .info = alc_ch_mode_info,
12601 .get = alc_ch_mode_get,
12602 .put = alc_ch_mode_put,
12603 .private_value = ARRAY_SIZE(alc861_threestack_modes),
12604 },
12605 { } /* end */
Tobin Davisa53d1ae2006-10-17 12:00:28 +020012606};
12607
Takashi Iwaid1d985f2006-11-23 19:27:12 +010012608static struct snd_kcontrol_new alc861_toshiba_mixer[] = {
Tobin Davisa53d1ae2006-10-17 12:00:28 +020012609 /* output mixer control */
12610 HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT),
12611 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
12612 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
Kailang Yangea1fb292008-08-26 12:58:38 +020012613
Tobin Davisa53d1ae2006-10-17 12:00:28 +020012614 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012615};
Tobin Davisa53d1ae2006-10-17 12:00:28 +020012616
Takashi Iwai22309c32006-08-09 16:57:28 +020012617static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = {
12618 /* output mixer control */
12619 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
12620 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
12621 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
12622 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
12623 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
12624
12625 /* Input mixer control */
12626 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
12627 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
12628 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
12629 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
12630 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
12631 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
12632 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
12633 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
12634 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
12635 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012636
Takashi Iwai22309c32006-08-09 16:57:28 +020012637 {
12638 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12639 .name = "Channel Mode",
12640 .info = alc_ch_mode_info,
12641 .get = alc_ch_mode_get,
12642 .put = alc_ch_mode_put,
12643 .private_value = ARRAY_SIZE(alc861_uniwill_m31_modes),
12644 },
12645 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012646};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012647
12648static struct snd_kcontrol_new alc861_asus_mixer[] = {
12649 /* output mixer control */
12650 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
12651 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
12652 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
12653 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
12654 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
12655
12656 /* Input mixer control */
12657 HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
12658 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT),
12659 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
12660 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
12661 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
12662 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
12663 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
12664 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
12665 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012666 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_OUTPUT),
12667
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012668 {
12669 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12670 .name = "Channel Mode",
12671 .info = alc_ch_mode_info,
12672 .get = alc_ch_mode_get,
12673 .put = alc_ch_mode_put,
12674 .private_value = ARRAY_SIZE(alc861_asus_modes),
12675 },
12676 { }
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010012677};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012678
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010012679/* additional mixer */
Takashi Iwaid1d985f2006-11-23 19:27:12 +010012680static struct snd_kcontrol_new alc861_asus_laptop_mixer[] = {
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010012681 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
12682 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
12683 HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x23, 0x0, HDA_OUTPUT),
12684 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x23, 0x0, HDA_OUTPUT),
12685 { }
12686};
12687
Kailang Yangdf694da2005-12-05 19:42:22 +010012688/*
12689 * generic initialization of ADC, input mixers and output mixers
12690 */
12691static struct hda_verb alc861_base_init_verbs[] = {
12692 /*
12693 * Unmute ADC0 and set the default input to mic-in
12694 */
12695 /* port-A for surround (rear panel) */
12696 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12697 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x00 },
12698 /* port-B for mic-in (rear panel) with vref */
12699 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12700 /* port-C for line-in (rear panel) */
12701 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
12702 /* port-D for Front */
12703 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12704 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
12705 /* port-E for HP out (front panel) */
12706 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
12707 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010012708 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010012709 /* port-F for mic-in (front panel) with vref */
12710 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12711 /* port-G for CLFE (rear panel) */
12712 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12713 { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x00 },
12714 /* port-H for side (rear panel) */
12715 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12716 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x00 },
12717 /* CD-in */
12718 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
12719 /* route front mic to ADC1*/
12720 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
12721 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020012722
Kailang Yangdf694da2005-12-05 19:42:22 +010012723 /* Unmute DAC0~3 & spdif out*/
12724 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12725 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12726 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12727 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12728 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020012729
Kailang Yangdf694da2005-12-05 19:42:22 +010012730 /* Unmute Mixer 14 (mic) 1c (Line in)*/
12731 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12732 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12733 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12734 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020012735
Kailang Yangdf694da2005-12-05 19:42:22 +010012736 /* Unmute Stereo Mixer 15 */
12737 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12738 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12739 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012740 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010012741
12742 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12743 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12744 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12745 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12746 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12747 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12748 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12749 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012750 /* hp used DAC 3 (Front) */
12751 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010012752 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
12753
12754 { }
12755};
12756
12757static struct hda_verb alc861_threestack_init_verbs[] = {
12758 /*
12759 * Unmute ADC0 and set the default input to mic-in
12760 */
12761 /* port-A for surround (rear panel) */
12762 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
12763 /* port-B for mic-in (rear panel) with vref */
12764 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12765 /* port-C for line-in (rear panel) */
12766 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
12767 /* port-D for Front */
12768 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12769 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
12770 /* port-E for HP out (front panel) */
12771 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
12772 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010012773 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010012774 /* port-F for mic-in (front panel) with vref */
12775 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12776 /* port-G for CLFE (rear panel) */
12777 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
12778 /* port-H for side (rear panel) */
12779 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
12780 /* CD-in */
12781 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
12782 /* route front mic to ADC1*/
12783 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
12784 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12785 /* Unmute DAC0~3 & spdif out*/
12786 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12787 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12788 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12789 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12790 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020012791
Kailang Yangdf694da2005-12-05 19:42:22 +010012792 /* Unmute Mixer 14 (mic) 1c (Line in)*/
12793 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12794 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12795 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12796 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020012797
Kailang Yangdf694da2005-12-05 19:42:22 +010012798 /* Unmute Stereo Mixer 15 */
12799 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12800 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12801 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012802 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010012803
12804 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12805 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12806 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12807 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12808 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12809 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12810 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12811 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012812 /* hp used DAC 3 (Front) */
12813 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010012814 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
12815 { }
12816};
Takashi Iwai22309c32006-08-09 16:57:28 +020012817
12818static struct hda_verb alc861_uniwill_m31_init_verbs[] = {
12819 /*
12820 * Unmute ADC0 and set the default input to mic-in
12821 */
12822 /* port-A for surround (rear panel) */
12823 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
12824 /* port-B for mic-in (rear panel) with vref */
12825 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12826 /* port-C for line-in (rear panel) */
12827 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
12828 /* port-D for Front */
12829 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12830 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
12831 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012832 /* this has to be set to VREF80 */
12833 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Takashi Iwai22309c32006-08-09 16:57:28 +020012834 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010012835 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai22309c32006-08-09 16:57:28 +020012836 /* port-F for mic-in (front panel) with vref */
12837 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12838 /* port-G for CLFE (rear panel) */
12839 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
12840 /* port-H for side (rear panel) */
12841 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
12842 /* CD-in */
12843 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
12844 /* route front mic to ADC1*/
12845 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
12846 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12847 /* Unmute DAC0~3 & spdif out*/
12848 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12849 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12850 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12851 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12852 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020012853
Takashi Iwai22309c32006-08-09 16:57:28 +020012854 /* Unmute Mixer 14 (mic) 1c (Line in)*/
12855 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12856 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12857 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12858 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020012859
Takashi Iwai22309c32006-08-09 16:57:28 +020012860 /* Unmute Stereo Mixer 15 */
12861 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12862 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12863 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012864 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Takashi Iwai22309c32006-08-09 16:57:28 +020012865
12866 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12867 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12868 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12869 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12870 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12871 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12872 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12873 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012874 /* hp used DAC 3 (Front) */
12875 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Takashi Iwai22309c32006-08-09 16:57:28 +020012876 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
12877 { }
12878};
12879
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012880static struct hda_verb alc861_asus_init_verbs[] = {
12881 /*
12882 * Unmute ADC0 and set the default input to mic-in
12883 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012884 /* port-A for surround (rear panel)
12885 * according to codec#0 this is the HP jack
12886 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012887 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* was 0x00 */
12888 /* route front PCM to HP */
12889 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x01 },
12890 /* port-B for mic-in (rear panel) with vref */
12891 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12892 /* port-C for line-in (rear panel) */
12893 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
12894 /* port-D for Front */
12895 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12896 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
12897 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012898 /* this has to be set to VREF80 */
12899 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012900 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010012901 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012902 /* port-F for mic-in (front panel) with vref */
12903 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12904 /* port-G for CLFE (rear panel) */
12905 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12906 /* port-H for side (rear panel) */
12907 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12908 /* CD-in */
12909 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
12910 /* route front mic to ADC1*/
12911 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
12912 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12913 /* Unmute DAC0~3 & spdif out*/
12914 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12915 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12916 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12917 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12918 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12919 /* Unmute Mixer 14 (mic) 1c (Line in)*/
12920 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12921 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12922 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12923 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020012924
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012925 /* Unmute Stereo Mixer 15 */
12926 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12927 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12928 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012929 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012930
12931 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12932 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12933 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12934 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12935 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12936 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12937 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12938 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012939 /* hp used DAC 3 (Front) */
12940 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012941 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
12942 { }
12943};
12944
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010012945/* additional init verbs for ASUS laptops */
12946static struct hda_verb alc861_asus_laptop_init_verbs[] = {
12947 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x45 }, /* HP-out */
12948 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2) }, /* mute line-in */
12949 { }
12950};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012951
Kailang Yangdf694da2005-12-05 19:42:22 +010012952/*
12953 * generic initialization of ADC, input mixers and output mixers
12954 */
12955static struct hda_verb alc861_auto_init_verbs[] = {
12956 /*
12957 * Unmute ADC0 and set the default input to mic-in
12958 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012959 /* {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, */
Kailang Yangdf694da2005-12-05 19:42:22 +010012960 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020012961
Kailang Yangdf694da2005-12-05 19:42:22 +010012962 /* Unmute DAC0~3 & spdif out*/
12963 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12964 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12965 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12966 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12967 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020012968
Kailang Yangdf694da2005-12-05 19:42:22 +010012969 /* Unmute Mixer 14 (mic) 1c (Line in)*/
12970 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12971 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12972 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12973 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020012974
Kailang Yangdf694da2005-12-05 19:42:22 +010012975 /* Unmute Stereo Mixer 15 */
12976 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12977 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12978 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
12979 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c},
12980
12981 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12982 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12983 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12984 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12985 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12986 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12987 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12988 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12989
12990 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12991 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012992 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
12993 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010012994 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12995 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012996 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
12997 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010012998
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012999 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, /* set Mic 1 */
Kailang Yangdf694da2005-12-05 19:42:22 +010013000
13001 { }
13002};
13003
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013004static struct hda_verb alc861_toshiba_init_verbs[] = {
13005 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013006
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013007 { }
13008};
13009
13010/* toggle speaker-output according to the hp-jack state */
13011static void alc861_toshiba_automute(struct hda_codec *codec)
13012{
13013 unsigned int present;
13014
13015 present = snd_hda_codec_read(codec, 0x0f, 0,
13016 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020013017 snd_hda_codec_amp_stereo(codec, 0x16, HDA_INPUT, 0,
13018 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
13019 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_INPUT, 3,
13020 HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE);
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013021}
13022
13023static void alc861_toshiba_unsol_event(struct hda_codec *codec,
13024 unsigned int res)
13025{
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013026 if ((res >> 26) == ALC880_HP_EVENT)
13027 alc861_toshiba_automute(codec);
13028}
13029
Kailang Yangdf694da2005-12-05 19:42:22 +010013030/* pcm configuration: identiacal with ALC880 */
13031#define alc861_pcm_analog_playback alc880_pcm_analog_playback
13032#define alc861_pcm_analog_capture alc880_pcm_analog_capture
13033#define alc861_pcm_digital_playback alc880_pcm_digital_playback
13034#define alc861_pcm_digital_capture alc880_pcm_digital_capture
13035
13036
13037#define ALC861_DIGOUT_NID 0x07
13038
13039static struct hda_channel_mode alc861_8ch_modes[1] = {
13040 { 8, NULL }
13041};
13042
13043static hda_nid_t alc861_dac_nids[4] = {
13044 /* front, surround, clfe, side */
13045 0x03, 0x06, 0x05, 0x04
13046};
13047
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013048static hda_nid_t alc660_dac_nids[3] = {
13049 /* front, clfe, surround */
13050 0x03, 0x05, 0x06
13051};
13052
Kailang Yangdf694da2005-12-05 19:42:22 +010013053static hda_nid_t alc861_adc_nids[1] = {
13054 /* ADC0-2 */
13055 0x08,
13056};
13057
13058static struct hda_input_mux alc861_capture_source = {
13059 .num_items = 5,
13060 .items = {
13061 { "Mic", 0x0 },
13062 { "Front Mic", 0x3 },
13063 { "Line", 0x1 },
13064 { "CD", 0x4 },
13065 { "Mixer", 0x5 },
13066 },
13067};
13068
13069/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013070static int alc861_auto_fill_dac_nids(struct alc_spec *spec,
13071 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010013072{
13073 int i;
13074 hda_nid_t nid;
13075
13076 spec->multiout.dac_nids = spec->private_dac_nids;
13077 for (i = 0; i < cfg->line_outs; i++) {
13078 nid = cfg->line_out_pins[i];
13079 if (nid) {
13080 if (i >= ARRAY_SIZE(alc861_dac_nids))
13081 continue;
13082 spec->multiout.dac_nids[i] = alc861_dac_nids[i];
13083 }
13084 }
13085 spec->multiout.num_dacs = cfg->line_outs;
13086 return 0;
13087}
13088
13089/* add playback controls from the parsed DAC table */
13090static int alc861_auto_create_multi_out_ctls(struct alc_spec *spec,
13091 const struct auto_pin_cfg *cfg)
13092{
13093 char name[32];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013094 static const char *chname[4] = {
13095 "Front", "Surround", NULL /*CLFE*/, "Side"
13096 };
Kailang Yangdf694da2005-12-05 19:42:22 +010013097 hda_nid_t nid;
13098 int i, idx, err;
13099
13100 for (i = 0; i < cfg->line_outs; i++) {
13101 nid = spec->multiout.dac_nids[i];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013102 if (!nid)
Kailang Yangdf694da2005-12-05 19:42:22 +010013103 continue;
13104 if (nid == 0x05) {
13105 /* Center/LFE */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013106 err = add_control(spec, ALC_CTL_BIND_MUTE,
13107 "Center Playback Switch",
13108 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
13109 HDA_OUTPUT));
13110 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010013111 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013112 err = add_control(spec, ALC_CTL_BIND_MUTE,
13113 "LFE Playback Switch",
13114 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
13115 HDA_OUTPUT));
13116 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010013117 return err;
13118 } else {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013119 for (idx = 0; idx < ARRAY_SIZE(alc861_dac_nids) - 1;
13120 idx++)
Kailang Yangdf694da2005-12-05 19:42:22 +010013121 if (nid == alc861_dac_nids[idx])
13122 break;
13123 sprintf(name, "%s Playback Switch", chname[idx]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013124 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
13125 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
13126 HDA_OUTPUT));
13127 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010013128 return err;
13129 }
13130 }
13131 return 0;
13132}
13133
13134static int alc861_auto_create_hp_ctls(struct alc_spec *spec, hda_nid_t pin)
13135{
13136 int err;
13137 hda_nid_t nid;
13138
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013139 if (!pin)
Kailang Yangdf694da2005-12-05 19:42:22 +010013140 return 0;
13141
13142 if ((pin >= 0x0b && pin <= 0x10) || pin == 0x1f || pin == 0x20) {
13143 nid = 0x03;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013144 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
13145 "Headphone Playback Switch",
13146 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
13147 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010013148 return err;
13149 spec->multiout.hp_nid = nid;
13150 }
13151 return 0;
13152}
13153
13154/* create playback/capture controls for input pins */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013155static int alc861_auto_create_analog_input_ctls(struct alc_spec *spec,
13156 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010013157{
Kailang Yangdf694da2005-12-05 19:42:22 +010013158 struct hda_input_mux *imux = &spec->private_imux;
13159 int i, err, idx, idx1;
13160
13161 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013162 switch (cfg->input_pins[i]) {
Kailang Yangdf694da2005-12-05 19:42:22 +010013163 case 0x0c:
13164 idx1 = 1;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013165 idx = 2; /* Line In */
Kailang Yangdf694da2005-12-05 19:42:22 +010013166 break;
13167 case 0x0f:
13168 idx1 = 2;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013169 idx = 2; /* Line In */
Kailang Yangdf694da2005-12-05 19:42:22 +010013170 break;
13171 case 0x0d:
13172 idx1 = 0;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013173 idx = 1; /* Mic In */
Kailang Yangdf694da2005-12-05 19:42:22 +010013174 break;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013175 case 0x10:
Kailang Yangdf694da2005-12-05 19:42:22 +010013176 idx1 = 3;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013177 idx = 1; /* Mic In */
Kailang Yangdf694da2005-12-05 19:42:22 +010013178 break;
13179 case 0x11:
13180 idx1 = 4;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013181 idx = 0; /* CD */
Kailang Yangdf694da2005-12-05 19:42:22 +010013182 break;
13183 default:
13184 continue;
13185 }
13186
Takashi Iwai4a471b72005-12-07 13:56:29 +010013187 err = new_analog_input(spec, cfg->input_pins[i],
13188 auto_pin_cfg_labels[i], idx, 0x15);
Kailang Yangdf694da2005-12-05 19:42:22 +010013189 if (err < 0)
13190 return err;
13191
Takashi Iwai4a471b72005-12-07 13:56:29 +010013192 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
Kailang Yangdf694da2005-12-05 19:42:22 +010013193 imux->items[imux->num_items].index = idx1;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013194 imux->num_items++;
Kailang Yangdf694da2005-12-05 19:42:22 +010013195 }
13196 return 0;
13197}
13198
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013199static void alc861_auto_set_output_and_unmute(struct hda_codec *codec,
13200 hda_nid_t nid,
Kailang Yangdf694da2005-12-05 19:42:22 +010013201 int pin_type, int dac_idx)
13202{
Jacek Luczak564c5be2008-05-03 18:41:23 +020013203 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
13204 pin_type);
13205 snd_hda_codec_write(codec, dac_idx, 0, AC_VERB_SET_AMP_GAIN_MUTE,
13206 AMP_OUT_UNMUTE);
Kailang Yangdf694da2005-12-05 19:42:22 +010013207}
13208
13209static void alc861_auto_init_multi_out(struct hda_codec *codec)
13210{
13211 struct alc_spec *spec = codec->spec;
13212 int i;
13213
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013214 alc_subsystem_id(codec, 0x0e, 0x0f, 0x0b);
Kailang Yangdf694da2005-12-05 19:42:22 +010013215 for (i = 0; i < spec->autocfg.line_outs; i++) {
13216 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020013217 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangdf694da2005-12-05 19:42:22 +010013218 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020013219 alc861_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013220 spec->multiout.dac_nids[i]);
Kailang Yangdf694da2005-12-05 19:42:22 +010013221 }
13222}
13223
13224static void alc861_auto_init_hp_out(struct hda_codec *codec)
13225{
13226 struct alc_spec *spec = codec->spec;
13227 hda_nid_t pin;
13228
Takashi Iwaieb06ed82006-09-20 17:10:27 +020013229 pin = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010013230 if (pin) /* connect to front */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013231 alc861_auto_set_output_and_unmute(codec, pin, PIN_HP,
13232 spec->multiout.dac_nids[0]);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013233 pin = spec->autocfg.speaker_pins[0];
13234 if (pin)
13235 alc861_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Kailang Yangdf694da2005-12-05 19:42:22 +010013236}
13237
13238static void alc861_auto_init_analog_input(struct hda_codec *codec)
13239{
13240 struct alc_spec *spec = codec->spec;
13241 int i;
13242
13243 for (i = 0; i < AUTO_PIN_LAST; i++) {
13244 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013245 if (nid >= 0x0c && nid <= 0x11) {
13246 snd_hda_codec_write(codec, nid, 0,
13247 AC_VERB_SET_PIN_WIDGET_CONTROL,
13248 i <= AUTO_PIN_FRONT_MIC ?
13249 PIN_VREF80 : PIN_IN);
Kailang Yangdf694da2005-12-05 19:42:22 +010013250 }
13251 }
13252}
13253
13254/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013255/* return 1 if successful, 0 if the proper config is not found,
13256 * or a negative error code
13257 */
Kailang Yangdf694da2005-12-05 19:42:22 +010013258static int alc861_parse_auto_config(struct hda_codec *codec)
13259{
13260 struct alc_spec *spec = codec->spec;
13261 int err;
13262 static hda_nid_t alc861_ignore[] = { 0x1d, 0 };
13263
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013264 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
13265 alc861_ignore);
13266 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010013267 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013268 if (!spec->autocfg.line_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +010013269 return 0; /* can't find valid BIOS pin config */
13270
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013271 err = alc861_auto_fill_dac_nids(spec, &spec->autocfg);
13272 if (err < 0)
13273 return err;
13274 err = alc861_auto_create_multi_out_ctls(spec, &spec->autocfg);
13275 if (err < 0)
13276 return err;
13277 err = alc861_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
13278 if (err < 0)
13279 return err;
13280 err = alc861_auto_create_analog_input_ctls(spec, &spec->autocfg);
13281 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010013282 return err;
13283
13284 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
13285
13286 if (spec->autocfg.dig_out_pin)
13287 spec->multiout.dig_out_nid = ALC861_DIGOUT_NID;
13288
Takashi Iwai603c4012008-07-30 15:01:44 +020013289 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010013290 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +010013291
Takashi Iwaid88897e2008-10-31 15:01:37 +010013292 add_verb(spec, alc861_auto_init_verbs);
Kailang Yangdf694da2005-12-05 19:42:22 +010013293
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020013294 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +010013295 spec->input_mux = &spec->private_imux;
13296
13297 spec->adc_nids = alc861_adc_nids;
13298 spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids);
Takashi Iwaif9e336f2008-10-31 16:37:07 +010013299 set_capture_mixer(spec);
Kailang Yangdf694da2005-12-05 19:42:22 +010013300
Takashi Iwaie044c392008-10-27 16:56:24 +010013301 store_pin_configs(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010013302 return 1;
13303}
13304
Takashi Iwaiae6b8132006-03-03 16:47:17 +010013305/* additional initialization for auto-configuration model */
13306static void alc861_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010013307{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013308 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010013309 alc861_auto_init_multi_out(codec);
13310 alc861_auto_init_hp_out(codec);
13311 alc861_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013312 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020013313 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010013314}
13315
Takashi Iwaicb53c622007-08-10 17:21:45 +020013316#ifdef CONFIG_SND_HDA_POWER_SAVE
13317static struct hda_amp_list alc861_loopbacks[] = {
13318 { 0x15, HDA_INPUT, 0 },
13319 { 0x15, HDA_INPUT, 1 },
13320 { 0x15, HDA_INPUT, 2 },
13321 { 0x15, HDA_INPUT, 3 },
13322 { } /* end */
13323};
13324#endif
13325
Kailang Yangdf694da2005-12-05 19:42:22 +010013326
13327/*
13328 * configuration and preset
13329 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010013330static const char *alc861_models[ALC861_MODEL_LAST] = {
13331 [ALC861_3ST] = "3stack",
13332 [ALC660_3ST] = "3stack-660",
13333 [ALC861_3ST_DIG] = "3stack-dig",
13334 [ALC861_6ST_DIG] = "6stack-dig",
13335 [ALC861_UNIWILL_M31] = "uniwill-m31",
13336 [ALC861_TOSHIBA] = "toshiba",
13337 [ALC861_ASUS] = "asus",
13338 [ALC861_ASUS_LAPTOP] = "asus-laptop",
13339 [ALC861_AUTO] = "auto",
13340};
13341
13342static struct snd_pci_quirk alc861_cfg_tbl[] = {
Takashi Iwai687a47b2007-01-10 11:25:58 +010013343 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010013344 SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP),
13345 SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP),
13346 SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013347 SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP),
Kailang Yang83c34212007-07-05 11:43:05 +020013348 SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS P1-AH2", ALC861_3ST_DIG),
Tobin Davisad5e7732007-01-08 10:57:32 +010013349 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA),
Takashi Iwai341d4eb2007-07-09 17:53:18 +020013350 /* FIXME: the entry below breaks Toshiba A100 (model=auto works!)
13351 * Any other models that need this preset?
13352 */
13353 /* SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), */
Claudio Matsuokaef64adb2007-07-14 00:26:16 +020013354 SND_PCI_QUIRK(0x1462, 0x7254, "HP dx2200 (MSI MS-7254)", ALC861_3ST),
13355 SND_PCI_QUIRK(0x1462, 0x7297, "HP dx2250 (MSI MS-7297)", ALC861_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013356 SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31),
13357 SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31),
13358 SND_PCI_QUIRK(0x1584, 0x9075, "Airis Praxis N1212", ALC861_ASUS_LAPTOP),
13359 /* FIXME: the below seems conflict */
13360 /* SND_PCI_QUIRK(0x1584, 0x9075, "Uniwill", ALC861_UNIWILL_M31), */
13361 SND_PCI_QUIRK(0x1849, 0x0660, "Asrock 939SLI32", ALC660_3ST),
13362 SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST),
Kailang Yangdf694da2005-12-05 19:42:22 +010013363 {}
13364};
13365
13366static struct alc_config_preset alc861_presets[] = {
13367 [ALC861_3ST] = {
13368 .mixers = { alc861_3ST_mixer },
13369 .init_verbs = { alc861_threestack_init_verbs },
13370 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
13371 .dac_nids = alc861_dac_nids,
13372 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
13373 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020013374 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010013375 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13376 .adc_nids = alc861_adc_nids,
13377 .input_mux = &alc861_capture_source,
13378 },
13379 [ALC861_3ST_DIG] = {
13380 .mixers = { alc861_base_mixer },
13381 .init_verbs = { alc861_threestack_init_verbs },
13382 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
13383 .dac_nids = alc861_dac_nids,
13384 .dig_out_nid = ALC861_DIGOUT_NID,
13385 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
13386 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020013387 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010013388 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13389 .adc_nids = alc861_adc_nids,
13390 .input_mux = &alc861_capture_source,
13391 },
13392 [ALC861_6ST_DIG] = {
13393 .mixers = { alc861_base_mixer },
13394 .init_verbs = { alc861_base_init_verbs },
13395 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
13396 .dac_nids = alc861_dac_nids,
13397 .dig_out_nid = ALC861_DIGOUT_NID,
13398 .num_channel_mode = ARRAY_SIZE(alc861_8ch_modes),
13399 .channel_mode = alc861_8ch_modes,
13400 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13401 .adc_nids = alc861_adc_nids,
13402 .input_mux = &alc861_capture_source,
13403 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013404 [ALC660_3ST] = {
13405 .mixers = { alc861_3ST_mixer },
13406 .init_verbs = { alc861_threestack_init_verbs },
13407 .num_dacs = ARRAY_SIZE(alc660_dac_nids),
13408 .dac_nids = alc660_dac_nids,
13409 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
13410 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020013411 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013412 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13413 .adc_nids = alc861_adc_nids,
13414 .input_mux = &alc861_capture_source,
13415 },
Takashi Iwai22309c32006-08-09 16:57:28 +020013416 [ALC861_UNIWILL_M31] = {
13417 .mixers = { alc861_uniwill_m31_mixer },
13418 .init_verbs = { alc861_uniwill_m31_init_verbs },
13419 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
13420 .dac_nids = alc861_dac_nids,
13421 .dig_out_nid = ALC861_DIGOUT_NID,
13422 .num_channel_mode = ARRAY_SIZE(alc861_uniwill_m31_modes),
13423 .channel_mode = alc861_uniwill_m31_modes,
13424 .need_dac_fix = 1,
13425 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13426 .adc_nids = alc861_adc_nids,
13427 .input_mux = &alc861_capture_source,
13428 },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013429 [ALC861_TOSHIBA] = {
13430 .mixers = { alc861_toshiba_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013431 .init_verbs = { alc861_base_init_verbs,
13432 alc861_toshiba_init_verbs },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013433 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
13434 .dac_nids = alc861_dac_nids,
13435 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
13436 .channel_mode = alc883_3ST_2ch_modes,
13437 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13438 .adc_nids = alc861_adc_nids,
13439 .input_mux = &alc861_capture_source,
13440 .unsol_event = alc861_toshiba_unsol_event,
13441 .init_hook = alc861_toshiba_automute,
13442 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013443 [ALC861_ASUS] = {
13444 .mixers = { alc861_asus_mixer },
13445 .init_verbs = { alc861_asus_init_verbs },
13446 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
13447 .dac_nids = alc861_dac_nids,
13448 .dig_out_nid = ALC861_DIGOUT_NID,
13449 .num_channel_mode = ARRAY_SIZE(alc861_asus_modes),
13450 .channel_mode = alc861_asus_modes,
13451 .need_dac_fix = 1,
13452 .hp_nid = 0x06,
13453 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13454 .adc_nids = alc861_adc_nids,
13455 .input_mux = &alc861_capture_source,
13456 },
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010013457 [ALC861_ASUS_LAPTOP] = {
13458 .mixers = { alc861_toshiba_mixer, alc861_asus_laptop_mixer },
13459 .init_verbs = { alc861_asus_init_verbs,
13460 alc861_asus_laptop_init_verbs },
13461 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
13462 .dac_nids = alc861_dac_nids,
13463 .dig_out_nid = ALC861_DIGOUT_NID,
13464 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
13465 .channel_mode = alc883_3ST_2ch_modes,
13466 .need_dac_fix = 1,
13467 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13468 .adc_nids = alc861_adc_nids,
13469 .input_mux = &alc861_capture_source,
13470 },
13471};
Kailang Yangdf694da2005-12-05 19:42:22 +010013472
13473
13474static int patch_alc861(struct hda_codec *codec)
13475{
13476 struct alc_spec *spec;
13477 int board_config;
13478 int err;
13479
Robert P. J. Daydc041e02006-12-19 14:44:15 +010013480 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010013481 if (spec == NULL)
13482 return -ENOMEM;
13483
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013484 codec->spec = spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010013485
Takashi Iwaif5fcc132006-11-24 17:07:44 +010013486 board_config = snd_hda_check_board_config(codec, ALC861_MODEL_LAST,
13487 alc861_models,
13488 alc861_cfg_tbl);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013489
Takashi Iwaif5fcc132006-11-24 17:07:44 +010013490 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013491 printk(KERN_INFO "hda_codec: Unknown model for ALC861, "
13492 "trying auto-probe from BIOS...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010013493 board_config = ALC861_AUTO;
13494 }
13495
13496 if (board_config == ALC861_AUTO) {
13497 /* automatic parse from the BIOS config */
13498 err = alc861_parse_auto_config(codec);
13499 if (err < 0) {
13500 alc_free(codec);
13501 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013502 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013503 printk(KERN_INFO
13504 "hda_codec: Cannot set up configuration "
13505 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010013506 board_config = ALC861_3ST_DIG;
13507 }
13508 }
13509
13510 if (board_config != ALC861_AUTO)
13511 setup_preset(spec, &alc861_presets[board_config]);
13512
13513 spec->stream_name_analog = "ALC861 Analog";
13514 spec->stream_analog_playback = &alc861_pcm_analog_playback;
13515 spec->stream_analog_capture = &alc861_pcm_analog_capture;
13516
13517 spec->stream_name_digital = "ALC861 Digital";
13518 spec->stream_digital_playback = &alc861_pcm_digital_playback;
13519 spec->stream_digital_capture = &alc861_pcm_digital_capture;
13520
Takashi Iwai2134ea42008-01-10 16:53:55 +010013521 spec->vmaster_nid = 0x03;
13522
Kailang Yangdf694da2005-12-05 19:42:22 +010013523 codec->patch_ops = alc_patch_ops;
13524 if (board_config == ALC861_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +010013525 spec->init_hook = alc861_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020013526#ifdef CONFIG_SND_HDA_POWER_SAVE
13527 if (!spec->loopback.amplist)
13528 spec->loopback.amplist = alc861_loopbacks;
13529#endif
Kailang Yangea1fb292008-08-26 12:58:38 +020013530
Kailang Yangdf694da2005-12-05 19:42:22 +010013531 return 0;
13532}
13533
13534/*
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013535 * ALC861-VD support
13536 *
13537 * Based on ALC882
13538 *
13539 * In addition, an independent DAC
13540 */
13541#define ALC861VD_DIGOUT_NID 0x06
13542
13543static hda_nid_t alc861vd_dac_nids[4] = {
13544 /* front, surr, clfe, side surr */
13545 0x02, 0x03, 0x04, 0x05
13546};
13547
13548/* dac_nids for ALC660vd are in a different order - according to
13549 * Realtek's driver.
13550 * This should probably tesult in a different mixer for 6stack models
13551 * of ALC660vd codecs, but for now there is only 3stack mixer
13552 * - and it is the same as in 861vd.
13553 * adc_nids in ALC660vd are (is) the same as in 861vd
13554 */
13555static hda_nid_t alc660vd_dac_nids[3] = {
13556 /* front, rear, clfe, rear_surr */
13557 0x02, 0x04, 0x03
13558};
13559
13560static hda_nid_t alc861vd_adc_nids[1] = {
13561 /* ADC0 */
13562 0x09,
13563};
13564
Takashi Iwaie1406342008-02-11 18:32:32 +010013565static hda_nid_t alc861vd_capsrc_nids[1] = { 0x22 };
13566
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013567/* input MUX */
13568/* FIXME: should be a matrix-type input source selection */
13569static struct hda_input_mux alc861vd_capture_source = {
13570 .num_items = 4,
13571 .items = {
13572 { "Mic", 0x0 },
13573 { "Front Mic", 0x1 },
13574 { "Line", 0x2 },
13575 { "CD", 0x4 },
13576 },
13577};
13578
Kailang Yang272a5272007-05-14 11:00:38 +020013579static struct hda_input_mux alc861vd_dallas_capture_source = {
Tobin Davisb419f342008-03-07 11:57:51 +010013580 .num_items = 2,
Kailang Yang272a5272007-05-14 11:00:38 +020013581 .items = {
Tobin Davisb419f342008-03-07 11:57:51 +010013582 { "Ext Mic", 0x0 },
13583 { "Int Mic", 0x1 },
Kailang Yang272a5272007-05-14 11:00:38 +020013584 },
13585};
13586
Kailang Yangd1a991a2007-08-15 16:21:59 +020013587static struct hda_input_mux alc861vd_hp_capture_source = {
13588 .num_items = 2,
13589 .items = {
13590 { "Front Mic", 0x0 },
13591 { "ATAPI Mic", 0x1 },
13592 },
13593};
13594
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013595/*
13596 * 2ch mode
13597 */
13598static struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = {
13599 { 2, NULL }
13600};
13601
13602/*
13603 * 6ch mode
13604 */
13605static struct hda_verb alc861vd_6stack_ch6_init[] = {
13606 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
13607 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
13608 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
13609 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
13610 { } /* end */
13611};
13612
13613/*
13614 * 8ch mode
13615 */
13616static struct hda_verb alc861vd_6stack_ch8_init[] = {
13617 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
13618 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
13619 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
13620 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
13621 { } /* end */
13622};
13623
13624static struct hda_channel_mode alc861vd_6stack_modes[2] = {
13625 { 6, alc861vd_6stack_ch6_init },
13626 { 8, alc861vd_6stack_ch8_init },
13627};
13628
13629static struct snd_kcontrol_new alc861vd_chmode_mixer[] = {
13630 {
13631 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13632 .name = "Channel Mode",
13633 .info = alc_ch_mode_info,
13634 .get = alc_ch_mode_get,
13635 .put = alc_ch_mode_put,
13636 },
13637 { } /* end */
13638};
13639
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013640/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
13641 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
13642 */
13643static struct snd_kcontrol_new alc861vd_6st_mixer[] = {
13644 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13645 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
13646
13647 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
13648 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
13649
13650 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0,
13651 HDA_OUTPUT),
13652 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0,
13653 HDA_OUTPUT),
13654 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
13655 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
13656
13657 HDA_CODEC_VOLUME("Side Playback Volume", 0x05, 0x0, HDA_OUTPUT),
13658 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
13659
13660 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
13661
13662 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13663 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13664 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13665
13666 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
13667 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
13668 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
13669
13670 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
13671 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
13672
13673 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
13674 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
13675
13676 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
13677 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
13678
13679 { } /* end */
13680};
13681
13682static struct snd_kcontrol_new alc861vd_3st_mixer[] = {
13683 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13684 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
13685
13686 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
13687
13688 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13689 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13690 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13691
13692 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
13693 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
13694 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
13695
13696 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
13697 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
13698
13699 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
13700 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
13701
13702 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
13703 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
13704
13705 { } /* end */
13706};
13707
Kailang Yangbdd148a2007-05-08 15:19:08 +020013708static struct snd_kcontrol_new alc861vd_lenovo_mixer[] = {
13709 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13710 /*HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),*/
13711 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
13712
13713 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
13714
13715 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13716 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13717 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13718
13719 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
13720 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
13721 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
13722
13723 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
13724 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
13725
13726 { } /* end */
13727};
13728
Tobin Davisb419f342008-03-07 11:57:51 +010013729/* Pin assignment: Speaker=0x14, HP = 0x15,
13730 * Ext Mic=0x18, Int Mic = 0x19, CD = 0x1c, PC Beep = 0x1d
Kailang Yang272a5272007-05-14 11:00:38 +020013731 */
13732static struct snd_kcontrol_new alc861vd_dallas_mixer[] = {
Tobin Davisb419f342008-03-07 11:57:51 +010013733 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13734 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020013735 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
13736 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
Tobin Davisb419f342008-03-07 11:57:51 +010013737 HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
13738 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13739 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13740 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
13741 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
13742 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
13743 HDA_CODEC_VOLUME("PC Beep Volume", 0x0b, 0x05, HDA_INPUT),
13744 HDA_CODEC_MUTE("PC Beep Switch", 0x0b, 0x05, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020013745 { } /* end */
13746};
13747
Kailang Yangd1a991a2007-08-15 16:21:59 +020013748/* Pin assignment: Speaker=0x14, Line-out = 0x15,
13749 * Front Mic=0x18, ATAPI Mic = 0x19,
13750 */
13751static struct snd_kcontrol_new alc861vd_hp_mixer[] = {
13752 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13753 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
13754 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
13755 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
13756 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13757 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13758 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
13759 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangea1fb292008-08-26 12:58:38 +020013760
Kailang Yangd1a991a2007-08-15 16:21:59 +020013761 { } /* end */
13762};
13763
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013764/*
13765 * generic initialization of ADC, input mixers and output mixers
13766 */
13767static struct hda_verb alc861vd_volume_init_verbs[] = {
13768 /*
13769 * Unmute ADC0 and set the default input to mic-in
13770 */
13771 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
13772 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13773
13774 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of
13775 * the analog-loopback mixer widget
13776 */
13777 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020013778 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13779 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13780 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
13781 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
13782 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013783
13784 /* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yangbdd148a2007-05-08 15:19:08 +020013785 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13786 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13787 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013788 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013789
13790 /*
13791 * Set up output mixers (0x02 - 0x05)
13792 */
13793 /* set vol=0 to output mixers */
13794 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13795 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13796 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13797 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13798
13799 /* set up input amps for analog loopback */
13800 /* Amp Indices: DAC = 0, mixer = 1 */
13801 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13802 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13803 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13804 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13805 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13806 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13807 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13808 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13809
13810 { }
13811};
13812
13813/*
13814 * 3-stack pin configuration:
13815 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
13816 */
13817static struct hda_verb alc861vd_3stack_init_verbs[] = {
13818 /*
13819 * Set pin mode and muting
13820 */
13821 /* set front pin widgets 0x14 for output */
13822 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13823 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13824 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
13825
13826 /* Mic (rear) pin: input vref at 80% */
13827 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
13828 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13829 /* Front Mic pin: input vref at 80% */
13830 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
13831 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13832 /* Line In pin: input */
13833 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13834 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13835 /* Line-2 In: Headphone output (output 0 - 0x0c) */
13836 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13837 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13838 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
13839 /* CD pin widget for input */
13840 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13841
13842 { }
13843};
13844
13845/*
13846 * 6-stack pin configuration:
13847 */
13848static struct hda_verb alc861vd_6stack_init_verbs[] = {
13849 /*
13850 * Set pin mode and muting
13851 */
13852 /* set front pin widgets 0x14 for output */
13853 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13854 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13855 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
13856
13857 /* Rear Pin: output 1 (0x0d) */
13858 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13859 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13860 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
13861 /* CLFE Pin: output 2 (0x0e) */
13862 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13863 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13864 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
13865 /* Side Pin: output 3 (0x0f) */
13866 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13867 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13868 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
13869
13870 /* Mic (rear) pin: input vref at 80% */
13871 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
13872 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13873 /* Front Mic pin: input vref at 80% */
13874 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
13875 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13876 /* Line In pin: input */
13877 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13878 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13879 /* Line-2 In: Headphone output (output 0 - 0x0c) */
13880 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13881 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13882 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
13883 /* CD pin widget for input */
13884 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13885
13886 { }
13887};
13888
Kailang Yangbdd148a2007-05-08 15:19:08 +020013889static struct hda_verb alc861vd_eapd_verbs[] = {
13890 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
13891 { }
13892};
13893
Kailang Yangf9423e72008-05-27 12:32:25 +020013894static struct hda_verb alc660vd_eapd_verbs[] = {
13895 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
13896 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
13897 { }
13898};
13899
Kailang Yangbdd148a2007-05-08 15:19:08 +020013900static struct hda_verb alc861vd_lenovo_unsol_verbs[] = {
13901 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13902 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13903 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
13904 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Kailang Yangea1fb292008-08-26 12:58:38 +020013905 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
Kailang Yangbdd148a2007-05-08 15:19:08 +020013906 {}
13907};
13908
13909/* toggle speaker-output according to the hp-jack state */
13910static void alc861vd_lenovo_hp_automute(struct hda_codec *codec)
13911{
13912 unsigned int present;
13913 unsigned char bits;
13914
13915 present = snd_hda_codec_read(codec, 0x1b, 0,
13916 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020013917 bits = present ? HDA_AMP_MUTE : 0;
13918 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
13919 HDA_AMP_MUTE, bits);
Kailang Yangbdd148a2007-05-08 15:19:08 +020013920}
13921
13922static void alc861vd_lenovo_mic_automute(struct hda_codec *codec)
13923{
13924 unsigned int present;
13925 unsigned char bits;
13926
13927 present = snd_hda_codec_read(codec, 0x18, 0,
13928 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020013929 bits = present ? HDA_AMP_MUTE : 0;
13930 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
13931 HDA_AMP_MUTE, bits);
Kailang Yangbdd148a2007-05-08 15:19:08 +020013932}
13933
13934static void alc861vd_lenovo_automute(struct hda_codec *codec)
13935{
13936 alc861vd_lenovo_hp_automute(codec);
13937 alc861vd_lenovo_mic_automute(codec);
13938}
13939
13940static void alc861vd_lenovo_unsol_event(struct hda_codec *codec,
13941 unsigned int res)
13942{
13943 switch (res >> 26) {
13944 case ALC880_HP_EVENT:
13945 alc861vd_lenovo_hp_automute(codec);
13946 break;
13947 case ALC880_MIC_EVENT:
13948 alc861vd_lenovo_mic_automute(codec);
13949 break;
13950 }
13951}
13952
Kailang Yang272a5272007-05-14 11:00:38 +020013953static struct hda_verb alc861vd_dallas_verbs[] = {
13954 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13955 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13956 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13957 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13958
13959 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13960 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13961 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13962 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13963 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13964 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13965 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13966 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020013967
Kailang Yang272a5272007-05-14 11:00:38 +020013968 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13969 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13970 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13971 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13972 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13973 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13974 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13975 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13976
13977 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
13978 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13979 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
13980 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13981 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13982 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13983 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13984 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13985
13986 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13987 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
13988 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
13989 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
13990
13991 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020013992 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yang272a5272007-05-14 11:00:38 +020013993 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
13994
13995 { } /* end */
13996};
13997
13998/* toggle speaker-output according to the hp-jack state */
13999static void alc861vd_dallas_automute(struct hda_codec *codec)
14000{
14001 unsigned int present;
14002
14003 present = snd_hda_codec_read(codec, 0x15, 0,
14004 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020014005 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
14006 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +020014007}
14008
14009static void alc861vd_dallas_unsol_event(struct hda_codec *codec, unsigned int res)
14010{
14011 if ((res >> 26) == ALC880_HP_EVENT)
14012 alc861vd_dallas_automute(codec);
14013}
14014
Takashi Iwaicb53c622007-08-10 17:21:45 +020014015#ifdef CONFIG_SND_HDA_POWER_SAVE
14016#define alc861vd_loopbacks alc880_loopbacks
14017#endif
14018
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014019/* pcm configuration: identiacal with ALC880 */
14020#define alc861vd_pcm_analog_playback alc880_pcm_analog_playback
14021#define alc861vd_pcm_analog_capture alc880_pcm_analog_capture
14022#define alc861vd_pcm_digital_playback alc880_pcm_digital_playback
14023#define alc861vd_pcm_digital_capture alc880_pcm_digital_capture
14024
14025/*
14026 * configuration and preset
14027 */
14028static const char *alc861vd_models[ALC861VD_MODEL_LAST] = {
14029 [ALC660VD_3ST] = "3stack-660",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020014030 [ALC660VD_3ST_DIG] = "3stack-660-digout",
Takashi Iwai13c94742008-11-05 08:06:08 +010014031 [ALC660VD_ASUS_V1S] = "asus-v1s",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014032 [ALC861VD_3ST] = "3stack",
14033 [ALC861VD_3ST_DIG] = "3stack-digout",
14034 [ALC861VD_6ST_DIG] = "6stack-digout",
Kailang Yangbdd148a2007-05-08 15:19:08 +020014035 [ALC861VD_LENOVO] = "lenovo",
Kailang Yang272a5272007-05-14 11:00:38 +020014036 [ALC861VD_DALLAS] = "dallas",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020014037 [ALC861VD_HP] = "hp",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014038 [ALC861VD_AUTO] = "auto",
14039};
14040
14041static struct snd_pci_quirk alc861vd_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +010014042 SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST),
14043 SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP),
Takashi Iwai07e038b2007-02-15 18:23:41 +010014044 SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014045 SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),
Takashi Iwai13c94742008-11-05 08:06:08 +010014046 SND_PCI_QUIRK(0x1043, 0x1633, "Asus V1Sn", ALC660VD_ASUS_V1S),
Mike Crash6963f842007-06-25 12:12:51 +020014047 SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014048 SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010014049 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO),
Takashi Iwai38baf5a2007-08-16 17:52:43 +020014050 /*SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS),*/ /*lenovo*/
Kailang Yang272a5272007-05-14 11:00:38 +020014051 SND_PCI_QUIRK(0x1179, 0xff01, "DALLAS", ALC861VD_DALLAS),
Takashi Iwai542d7c62007-08-16 18:57:30 +020014052 SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO),
Tobin Davisb419f342008-03-07 11:57:51 +010014053 SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_DALLAS),
Takashi Iwai39c5d412007-08-15 16:24:17 +020014054 SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010014055 SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo", ALC861VD_LENOVO),
14056 SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo 3000 C200", ALC861VD_LENOVO),
Takashi Iwaibe321a892008-07-07 16:04:04 +020014057 SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 N200", ALC861VD_LENOVO),
Tobin Davis625dc0b2007-07-30 21:42:10 +020014058 SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014059 {}
14060};
14061
14062static struct alc_config_preset alc861vd_presets[] = {
14063 [ALC660VD_3ST] = {
14064 .mixers = { alc861vd_3st_mixer },
14065 .init_verbs = { alc861vd_volume_init_verbs,
14066 alc861vd_3stack_init_verbs },
14067 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
14068 .dac_nids = alc660vd_dac_nids,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014069 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14070 .channel_mode = alc861vd_3stack_2ch_modes,
14071 .input_mux = &alc861vd_capture_source,
14072 },
Mike Crash6963f842007-06-25 12:12:51 +020014073 [ALC660VD_3ST_DIG] = {
14074 .mixers = { alc861vd_3st_mixer },
14075 .init_verbs = { alc861vd_volume_init_verbs,
14076 alc861vd_3stack_init_verbs },
14077 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
14078 .dac_nids = alc660vd_dac_nids,
14079 .dig_out_nid = ALC861VD_DIGOUT_NID,
Mike Crash6963f842007-06-25 12:12:51 +020014080 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14081 .channel_mode = alc861vd_3stack_2ch_modes,
14082 .input_mux = &alc861vd_capture_source,
14083 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014084 [ALC861VD_3ST] = {
14085 .mixers = { alc861vd_3st_mixer },
14086 .init_verbs = { alc861vd_volume_init_verbs,
14087 alc861vd_3stack_init_verbs },
14088 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
14089 .dac_nids = alc861vd_dac_nids,
14090 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14091 .channel_mode = alc861vd_3stack_2ch_modes,
14092 .input_mux = &alc861vd_capture_source,
14093 },
14094 [ALC861VD_3ST_DIG] = {
14095 .mixers = { alc861vd_3st_mixer },
14096 .init_verbs = { alc861vd_volume_init_verbs,
14097 alc861vd_3stack_init_verbs },
14098 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
14099 .dac_nids = alc861vd_dac_nids,
14100 .dig_out_nid = ALC861VD_DIGOUT_NID,
14101 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14102 .channel_mode = alc861vd_3stack_2ch_modes,
14103 .input_mux = &alc861vd_capture_source,
14104 },
14105 [ALC861VD_6ST_DIG] = {
14106 .mixers = { alc861vd_6st_mixer, alc861vd_chmode_mixer },
14107 .init_verbs = { alc861vd_volume_init_verbs,
14108 alc861vd_6stack_init_verbs },
14109 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
14110 .dac_nids = alc861vd_dac_nids,
14111 .dig_out_nid = ALC861VD_DIGOUT_NID,
14112 .num_channel_mode = ARRAY_SIZE(alc861vd_6stack_modes),
14113 .channel_mode = alc861vd_6stack_modes,
14114 .input_mux = &alc861vd_capture_source,
14115 },
Kailang Yangbdd148a2007-05-08 15:19:08 +020014116 [ALC861VD_LENOVO] = {
14117 .mixers = { alc861vd_lenovo_mixer },
14118 .init_verbs = { alc861vd_volume_init_verbs,
14119 alc861vd_3stack_init_verbs,
14120 alc861vd_eapd_verbs,
14121 alc861vd_lenovo_unsol_verbs },
14122 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
14123 .dac_nids = alc660vd_dac_nids,
Kailang Yangbdd148a2007-05-08 15:19:08 +020014124 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14125 .channel_mode = alc861vd_3stack_2ch_modes,
14126 .input_mux = &alc861vd_capture_source,
14127 .unsol_event = alc861vd_lenovo_unsol_event,
14128 .init_hook = alc861vd_lenovo_automute,
14129 },
Kailang Yang272a5272007-05-14 11:00:38 +020014130 [ALC861VD_DALLAS] = {
14131 .mixers = { alc861vd_dallas_mixer },
14132 .init_verbs = { alc861vd_dallas_verbs },
14133 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
14134 .dac_nids = alc861vd_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +020014135 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14136 .channel_mode = alc861vd_3stack_2ch_modes,
14137 .input_mux = &alc861vd_dallas_capture_source,
14138 .unsol_event = alc861vd_dallas_unsol_event,
14139 .init_hook = alc861vd_dallas_automute,
Kailang Yangd1a991a2007-08-15 16:21:59 +020014140 },
14141 [ALC861VD_HP] = {
14142 .mixers = { alc861vd_hp_mixer },
14143 .init_verbs = { alc861vd_dallas_verbs, alc861vd_eapd_verbs },
14144 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
14145 .dac_nids = alc861vd_dac_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020014146 .dig_out_nid = ALC861VD_DIGOUT_NID,
Kailang Yangd1a991a2007-08-15 16:21:59 +020014147 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14148 .channel_mode = alc861vd_3stack_2ch_modes,
14149 .input_mux = &alc861vd_hp_capture_source,
14150 .unsol_event = alc861vd_dallas_unsol_event,
14151 .init_hook = alc861vd_dallas_automute,
Kailang Yangea1fb292008-08-26 12:58:38 +020014152 },
Takashi Iwai13c94742008-11-05 08:06:08 +010014153 [ALC660VD_ASUS_V1S] = {
14154 .mixers = { alc861vd_lenovo_mixer },
14155 .init_verbs = { alc861vd_volume_init_verbs,
14156 alc861vd_3stack_init_verbs,
14157 alc861vd_eapd_verbs,
14158 alc861vd_lenovo_unsol_verbs },
14159 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
14160 .dac_nids = alc660vd_dac_nids,
14161 .dig_out_nid = ALC861VD_DIGOUT_NID,
14162 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14163 .channel_mode = alc861vd_3stack_2ch_modes,
14164 .input_mux = &alc861vd_capture_source,
14165 .unsol_event = alc861vd_lenovo_unsol_event,
14166 .init_hook = alc861vd_lenovo_automute,
14167 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014168};
14169
14170/*
14171 * BIOS auto configuration
14172 */
14173static void alc861vd_auto_set_output_and_unmute(struct hda_codec *codec,
14174 hda_nid_t nid, int pin_type, int dac_idx)
14175{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014176 alc_set_pin_output(codec, nid, pin_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014177}
14178
14179static void alc861vd_auto_init_multi_out(struct hda_codec *codec)
14180{
14181 struct alc_spec *spec = codec->spec;
14182 int i;
14183
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014184 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014185 for (i = 0; i <= HDA_SIDE; i++) {
14186 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020014187 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014188 if (nid)
14189 alc861vd_auto_set_output_and_unmute(codec, nid,
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020014190 pin_type, i);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014191 }
14192}
14193
14194
14195static void alc861vd_auto_init_hp_out(struct hda_codec *codec)
14196{
14197 struct alc_spec *spec = codec->spec;
14198 hda_nid_t pin;
14199
14200 pin = spec->autocfg.hp_pins[0];
14201 if (pin) /* connect to front and use dac 0 */
14202 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014203 pin = spec->autocfg.speaker_pins[0];
14204 if (pin)
14205 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014206}
14207
14208#define alc861vd_is_input_pin(nid) alc880_is_input_pin(nid)
14209#define ALC861VD_PIN_CD_NID ALC880_PIN_CD_NID
14210
14211static void alc861vd_auto_init_analog_input(struct hda_codec *codec)
14212{
14213 struct alc_spec *spec = codec->spec;
14214 int i;
14215
14216 for (i = 0; i < AUTO_PIN_LAST; i++) {
14217 hda_nid_t nid = spec->autocfg.input_pins[i];
14218 if (alc861vd_is_input_pin(nid)) {
14219 snd_hda_codec_write(codec, nid, 0,
14220 AC_VERB_SET_PIN_WIDGET_CONTROL,
14221 i <= AUTO_PIN_FRONT_MIC ?
14222 PIN_VREF80 : PIN_IN);
14223 if (nid != ALC861VD_PIN_CD_NID)
14224 snd_hda_codec_write(codec, nid, 0,
14225 AC_VERB_SET_AMP_GAIN_MUTE,
14226 AMP_OUT_MUTE);
14227 }
14228 }
14229}
14230
Takashi Iwaif511b012008-08-15 16:46:42 +020014231#define alc861vd_auto_init_input_src alc882_auto_init_input_src
14232
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014233#define alc861vd_idx_to_mixer_vol(nid) ((nid) + 0x02)
14234#define alc861vd_idx_to_mixer_switch(nid) ((nid) + 0x0c)
14235
14236/* add playback controls from the parsed DAC table */
14237/* Based on ALC880 version. But ALC861VD has separate,
14238 * different NIDs for mute/unmute switch and volume control */
14239static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
14240 const struct auto_pin_cfg *cfg)
14241{
14242 char name[32];
14243 static const char *chname[4] = {"Front", "Surround", "CLFE", "Side"};
14244 hda_nid_t nid_v, nid_s;
14245 int i, err;
14246
14247 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014248 if (!spec->multiout.dac_nids[i])
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014249 continue;
14250 nid_v = alc861vd_idx_to_mixer_vol(
14251 alc880_dac_to_idx(
14252 spec->multiout.dac_nids[i]));
14253 nid_s = alc861vd_idx_to_mixer_switch(
14254 alc880_dac_to_idx(
14255 spec->multiout.dac_nids[i]));
14256
14257 if (i == 2) {
14258 /* Center/LFE */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014259 err = add_control(spec, ALC_CTL_WIDGET_VOL,
14260 "Center Playback Volume",
14261 HDA_COMPOSE_AMP_VAL(nid_v, 1, 0,
14262 HDA_OUTPUT));
14263 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014264 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014265 err = add_control(spec, ALC_CTL_WIDGET_VOL,
14266 "LFE Playback Volume",
14267 HDA_COMPOSE_AMP_VAL(nid_v, 2, 0,
14268 HDA_OUTPUT));
14269 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014270 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014271 err = add_control(spec, ALC_CTL_BIND_MUTE,
14272 "Center Playback Switch",
14273 HDA_COMPOSE_AMP_VAL(nid_s, 1, 2,
14274 HDA_INPUT));
14275 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014276 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014277 err = add_control(spec, ALC_CTL_BIND_MUTE,
14278 "LFE Playback Switch",
14279 HDA_COMPOSE_AMP_VAL(nid_s, 2, 2,
14280 HDA_INPUT));
14281 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014282 return err;
14283 } else {
14284 sprintf(name, "%s Playback Volume", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014285 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
14286 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0,
14287 HDA_OUTPUT));
14288 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014289 return err;
14290 sprintf(name, "%s Playback Switch", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014291 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
Kailang Yangbdd148a2007-05-08 15:19:08 +020014292 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014293 HDA_INPUT));
14294 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014295 return err;
14296 }
14297 }
14298 return 0;
14299}
14300
14301/* add playback controls for speaker and HP outputs */
14302/* Based on ALC880 version. But ALC861VD has separate,
14303 * different NIDs for mute/unmute switch and volume control */
14304static int alc861vd_auto_create_extra_out(struct alc_spec *spec,
14305 hda_nid_t pin, const char *pfx)
14306{
14307 hda_nid_t nid_v, nid_s;
14308 int err;
14309 char name[32];
14310
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014311 if (!pin)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014312 return 0;
14313
14314 if (alc880_is_fixed_pin(pin)) {
14315 nid_v = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
14316 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014317 if (!spec->multiout.hp_nid)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014318 spec->multiout.hp_nid = nid_v;
14319 else
14320 spec->multiout.extra_out_nid[0] = nid_v;
14321 /* control HP volume/switch on the output mixer amp */
14322 nid_v = alc861vd_idx_to_mixer_vol(
14323 alc880_fixed_pin_idx(pin));
14324 nid_s = alc861vd_idx_to_mixer_switch(
14325 alc880_fixed_pin_idx(pin));
14326
14327 sprintf(name, "%s Playback Volume", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014328 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
14329 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0, HDA_OUTPUT));
14330 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014331 return err;
14332 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014333 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
14334 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2, HDA_INPUT));
14335 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014336 return err;
14337 } else if (alc880_is_multi_pin(pin)) {
14338 /* set manual connection */
14339 /* we have only a switch on HP-out PIN */
14340 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014341 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
14342 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
14343 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014344 return err;
14345 }
14346 return 0;
14347}
14348
14349/* parse the BIOS configuration and set up the alc_spec
14350 * return 1 if successful, 0 if the proper config is not found,
14351 * or a negative error code
14352 * Based on ALC880 version - had to change it to override
14353 * alc880_auto_create_extra_out and alc880_auto_create_multi_out_ctls */
14354static int alc861vd_parse_auto_config(struct hda_codec *codec)
14355{
14356 struct alc_spec *spec = codec->spec;
14357 int err;
14358 static hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
14359
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014360 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
14361 alc861vd_ignore);
14362 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014363 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014364 if (!spec->autocfg.line_outs)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014365 return 0; /* can't find valid BIOS pin config */
14366
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014367 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
14368 if (err < 0)
14369 return err;
14370 err = alc861vd_auto_create_multi_out_ctls(spec, &spec->autocfg);
14371 if (err < 0)
14372 return err;
14373 err = alc861vd_auto_create_extra_out(spec,
14374 spec->autocfg.speaker_pins[0],
14375 "Speaker");
14376 if (err < 0)
14377 return err;
14378 err = alc861vd_auto_create_extra_out(spec,
14379 spec->autocfg.hp_pins[0],
14380 "Headphone");
14381 if (err < 0)
14382 return err;
14383 err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg);
14384 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014385 return err;
14386
14387 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
14388
14389 if (spec->autocfg.dig_out_pin)
14390 spec->multiout.dig_out_nid = ALC861VD_DIGOUT_NID;
14391
Takashi Iwai603c4012008-07-30 15:01:44 +020014392 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010014393 add_mixer(spec, spec->kctls.list);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014394
Takashi Iwaid88897e2008-10-31 15:01:37 +010014395 add_verb(spec, alc861vd_volume_init_verbs);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014396
14397 spec->num_mux_defs = 1;
14398 spec->input_mux = &spec->private_imux;
14399
Takashi Iwai776e1842007-08-29 15:07:11 +020014400 err = alc_auto_add_mic_boost(codec);
14401 if (err < 0)
14402 return err;
14403
Takashi Iwaie044c392008-10-27 16:56:24 +010014404 store_pin_configs(codec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014405 return 1;
14406}
14407
14408/* additional initialization for auto-configuration model */
14409static void alc861vd_auto_init(struct hda_codec *codec)
14410{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014411 struct alc_spec *spec = codec->spec;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014412 alc861vd_auto_init_multi_out(codec);
14413 alc861vd_auto_init_hp_out(codec);
14414 alc861vd_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020014415 alc861vd_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014416 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020014417 alc_inithook(codec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014418}
14419
14420static int patch_alc861vd(struct hda_codec *codec)
14421{
14422 struct alc_spec *spec;
14423 int err, board_config;
14424
14425 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
14426 if (spec == NULL)
14427 return -ENOMEM;
14428
14429 codec->spec = spec;
14430
14431 board_config = snd_hda_check_board_config(codec, ALC861VD_MODEL_LAST,
14432 alc861vd_models,
14433 alc861vd_cfg_tbl);
14434
14435 if (board_config < 0 || board_config >= ALC861VD_MODEL_LAST) {
14436 printk(KERN_INFO "hda_codec: Unknown model for ALC660VD/"
14437 "ALC861VD, trying auto-probe from BIOS...\n");
14438 board_config = ALC861VD_AUTO;
14439 }
14440
14441 if (board_config == ALC861VD_AUTO) {
14442 /* automatic parse from the BIOS config */
14443 err = alc861vd_parse_auto_config(codec);
14444 if (err < 0) {
14445 alc_free(codec);
14446 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014447 } else if (!err) {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014448 printk(KERN_INFO
14449 "hda_codec: Cannot set up configuration "
14450 "from BIOS. Using base mode...\n");
14451 board_config = ALC861VD_3ST;
14452 }
14453 }
14454
14455 if (board_config != ALC861VD_AUTO)
14456 setup_preset(spec, &alc861vd_presets[board_config]);
14457
Kailang Yang2f893282008-05-27 12:14:47 +020014458 if (codec->vendor_id == 0x10ec0660) {
14459 spec->stream_name_analog = "ALC660-VD Analog";
14460 spec->stream_name_digital = "ALC660-VD Digital";
Kailang Yangf9423e72008-05-27 12:32:25 +020014461 /* always turn on EAPD */
Takashi Iwaid88897e2008-10-31 15:01:37 +010014462 add_verb(spec, alc660vd_eapd_verbs);
Kailang Yang2f893282008-05-27 12:14:47 +020014463 } else {
14464 spec->stream_name_analog = "ALC861VD Analog";
14465 spec->stream_name_digital = "ALC861VD Digital";
14466 }
14467
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014468 spec->stream_analog_playback = &alc861vd_pcm_analog_playback;
14469 spec->stream_analog_capture = &alc861vd_pcm_analog_capture;
14470
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014471 spec->stream_digital_playback = &alc861vd_pcm_digital_playback;
14472 spec->stream_digital_capture = &alc861vd_pcm_digital_capture;
14473
14474 spec->adc_nids = alc861vd_adc_nids;
14475 spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids);
Takashi Iwaie1406342008-02-11 18:32:32 +010014476 spec->capsrc_nids = alc861vd_capsrc_nids;
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010014477 spec->is_mix_capture = 1;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014478
Takashi Iwaif9e336f2008-10-31 16:37:07 +010014479 set_capture_mixer(spec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014480
Takashi Iwai2134ea42008-01-10 16:53:55 +010014481 spec->vmaster_nid = 0x02;
14482
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014483 codec->patch_ops = alc_patch_ops;
14484
14485 if (board_config == ALC861VD_AUTO)
14486 spec->init_hook = alc861vd_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020014487#ifdef CONFIG_SND_HDA_POWER_SAVE
14488 if (!spec->loopback.amplist)
14489 spec->loopback.amplist = alc861vd_loopbacks;
14490#endif
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014491
14492 return 0;
14493}
14494
14495/*
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014496 * ALC662 support
14497 *
14498 * ALC662 is almost identical with ALC880 but has cleaner and more flexible
14499 * configuration. Each pin widget can choose any input DACs and a mixer.
14500 * Each ADC is connected from a mixer of all inputs. This makes possible
14501 * 6-channel independent captures.
14502 *
14503 * In addition, an independent DAC for the multi-playback (not used in this
14504 * driver yet).
14505 */
14506#define ALC662_DIGOUT_NID 0x06
14507#define ALC662_DIGIN_NID 0x0a
14508
14509static hda_nid_t alc662_dac_nids[4] = {
14510 /* front, rear, clfe, rear_surr */
14511 0x02, 0x03, 0x04
14512};
14513
14514static hda_nid_t alc662_adc_nids[1] = {
14515 /* ADC1-2 */
14516 0x09,
14517};
Takashi Iwaie1406342008-02-11 18:32:32 +010014518
Kailang Yang77a261b2008-02-19 11:38:05 +010014519static hda_nid_t alc662_capsrc_nids[1] = { 0x22 };
Takashi Iwaie1406342008-02-11 18:32:32 +010014520
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014521/* input MUX */
14522/* FIXME: should be a matrix-type input source selection */
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014523static struct hda_input_mux alc662_capture_source = {
14524 .num_items = 4,
14525 .items = {
14526 { "Mic", 0x0 },
14527 { "Front Mic", 0x1 },
14528 { "Line", 0x2 },
14529 { "CD", 0x4 },
14530 },
14531};
14532
14533static struct hda_input_mux alc662_lenovo_101e_capture_source = {
14534 .num_items = 2,
14535 .items = {
14536 { "Mic", 0x1 },
14537 { "Line", 0x2 },
14538 },
14539};
Kailang Yang291702f2007-10-16 14:28:03 +020014540
14541static struct hda_input_mux alc662_eeepc_capture_source = {
14542 .num_items = 2,
14543 .items = {
14544 { "i-Mic", 0x1 },
14545 { "e-Mic", 0x0 },
14546 },
14547};
14548
Kailang Yang6dda9f42008-05-27 12:05:31 +020014549static struct hda_input_mux alc663_capture_source = {
14550 .num_items = 3,
14551 .items = {
14552 { "Mic", 0x0 },
14553 { "Front Mic", 0x1 },
14554 { "Line", 0x2 },
14555 },
14556};
14557
14558static struct hda_input_mux alc663_m51va_capture_source = {
14559 .num_items = 2,
14560 .items = {
14561 { "Ext-Mic", 0x0 },
14562 { "D-Mic", 0x9 },
14563 },
14564};
14565
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014566/*
14567 * 2ch mode
14568 */
14569static struct hda_channel_mode alc662_3ST_2ch_modes[1] = {
14570 { 2, NULL }
14571};
14572
14573/*
14574 * 2ch mode
14575 */
14576static struct hda_verb alc662_3ST_ch2_init[] = {
14577 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
14578 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
14579 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
14580 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
14581 { } /* end */
14582};
14583
14584/*
14585 * 6ch mode
14586 */
14587static struct hda_verb alc662_3ST_ch6_init[] = {
14588 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14589 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
14590 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
14591 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14592 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
14593 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
14594 { } /* end */
14595};
14596
14597static struct hda_channel_mode alc662_3ST_6ch_modes[2] = {
14598 { 2, alc662_3ST_ch2_init },
14599 { 6, alc662_3ST_ch6_init },
14600};
14601
14602/*
14603 * 2ch mode
14604 */
14605static struct hda_verb alc662_sixstack_ch6_init[] = {
14606 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
14607 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
14608 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14609 { } /* end */
14610};
14611
14612/*
14613 * 6ch mode
14614 */
14615static struct hda_verb alc662_sixstack_ch8_init[] = {
14616 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14617 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14618 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14619 { } /* end */
14620};
14621
14622static struct hda_channel_mode alc662_5stack_modes[2] = {
14623 { 2, alc662_sixstack_ch6_init },
14624 { 6, alc662_sixstack_ch8_init },
14625};
14626
14627/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
14628 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
14629 */
14630
14631static struct snd_kcontrol_new alc662_base_mixer[] = {
14632 /* output mixer control */
14633 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010014634 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014635 HDA_CODEC_VOLUME("Surround Playback Volume", 0x3, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010014636 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014637 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
14638 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010014639 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
14640 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014641 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
14642
14643 /*Input mixer control */
14644 HDA_CODEC_VOLUME("CD Playback Volume", 0xb, 0x4, HDA_INPUT),
14645 HDA_CODEC_MUTE("CD Playback Switch", 0xb, 0x4, HDA_INPUT),
14646 HDA_CODEC_VOLUME("Line Playback Volume", 0xb, 0x02, HDA_INPUT),
14647 HDA_CODEC_MUTE("Line Playback Switch", 0xb, 0x02, HDA_INPUT),
14648 HDA_CODEC_VOLUME("Mic Playback Volume", 0xb, 0x0, HDA_INPUT),
14649 HDA_CODEC_MUTE("Mic Playback Switch", 0xb, 0x0, HDA_INPUT),
14650 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0xb, 0x01, HDA_INPUT),
14651 HDA_CODEC_MUTE("Front Mic Playback Switch", 0xb, 0x01, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014652 { } /* end */
14653};
14654
14655static struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = {
14656 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010014657 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014658 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
14659 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
14660 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
14661 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
14662 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
14663 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14664 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14665 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14666 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14667 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
14668 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014669 { } /* end */
14670};
14671
14672static struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = {
14673 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010014674 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014675 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010014676 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014677 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
14678 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010014679 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
14680 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014681 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
14682 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
14683 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
14684 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
14685 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
14686 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14687 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14688 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14689 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14690 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
14691 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014692 { } /* end */
14693};
14694
14695static struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = {
14696 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14697 HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010014698 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x03, 0x0, HDA_OUTPUT),
14699 HDA_BIND_MUTE("Speaker Playback Switch", 0x03, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014700 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
14701 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
14702 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
14703 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14704 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014705 { } /* end */
14706};
14707
Kailang Yang291702f2007-10-16 14:28:03 +020014708static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = {
Takashi Iwai86cd9292008-01-28 18:09:56 +010014709 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang291702f2007-10-16 14:28:03 +020014710
Herton Ronaldo Krzesinskib4818492008-02-23 11:34:12 +010014711 HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14712 HDA_CODEC_MUTE("Line-Out Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yang291702f2007-10-16 14:28:03 +020014713
14714 HDA_CODEC_VOLUME("e-Mic Boost", 0x18, 0, HDA_INPUT),
14715 HDA_CODEC_VOLUME("e-Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14716 HDA_CODEC_MUTE("e-Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14717
14718 HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT),
14719 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14720 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14721 { } /* end */
14722};
14723
Kailang Yang8c427222008-01-10 13:03:59 +010014724static struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = {
Takashi Iwai31bffaa2008-02-27 16:10:44 +010014725 HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14726 HDA_CODEC_MUTE("Line-Out Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010014727 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
14728 HDA_BIND_MUTE("Surround Playback Switch", 0x03, 2, HDA_INPUT),
14729 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
14730 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
14731 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x04, 1, 2, HDA_INPUT),
14732 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x04, 2, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010014733 HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010014734 HDA_BIND_MUTE("MuteCtrl Playback Switch", 0x0c, 2, HDA_INPUT),
14735 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
14736 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
14737 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14738 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14739 { } /* end */
14740};
14741
Kailang Yangf1d4e282008-08-26 14:03:29 +020014742static struct hda_bind_ctls alc663_asus_bind_master_vol = {
14743 .ops = &snd_hda_bind_vol,
14744 .values = {
14745 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
14746 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
14747 0
14748 },
14749};
14750
14751static struct hda_bind_ctls alc663_asus_one_bind_switch = {
14752 .ops = &snd_hda_bind_sw,
14753 .values = {
14754 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
14755 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
14756 0
14757 },
14758};
14759
Kailang Yang6dda9f42008-05-27 12:05:31 +020014760static struct snd_kcontrol_new alc663_m51va_mixer[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020014761 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
14762 HDA_BIND_SW("Master Playback Switch", &alc663_asus_one_bind_switch),
14763 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14764 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14765 { } /* end */
14766};
14767
14768static struct hda_bind_ctls alc663_asus_tree_bind_switch = {
14769 .ops = &snd_hda_bind_sw,
14770 .values = {
14771 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
14772 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
14773 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
14774 0
14775 },
14776};
14777
14778static struct snd_kcontrol_new alc663_two_hp_m1_mixer[] = {
14779 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
14780 HDA_BIND_SW("Master Playback Switch", &alc663_asus_tree_bind_switch),
14781 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14782 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14783 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14784 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14785
14786 { } /* end */
14787};
14788
14789static struct hda_bind_ctls alc663_asus_four_bind_switch = {
14790 .ops = &snd_hda_bind_sw,
14791 .values = {
14792 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
14793 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
14794 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
14795 0
14796 },
14797};
14798
14799static struct snd_kcontrol_new alc663_two_hp_m2_mixer[] = {
14800 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
14801 HDA_BIND_SW("Master Playback Switch", &alc663_asus_four_bind_switch),
14802 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14803 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14804 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14805 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14806 { } /* end */
14807};
14808
14809static struct snd_kcontrol_new alc662_1bjd_mixer[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020014810 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14811 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020014812 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
14813 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14814 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14815 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14816 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14817 { } /* end */
14818};
14819
14820static struct hda_bind_ctls alc663_asus_two_bind_master_vol = {
14821 .ops = &snd_hda_bind_vol,
14822 .values = {
14823 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
14824 HDA_COMPOSE_AMP_VAL(0x04, 3, 0, HDA_OUTPUT),
14825 0
14826 },
14827};
14828
14829static struct hda_bind_ctls alc663_asus_two_bind_switch = {
14830 .ops = &snd_hda_bind_sw,
14831 .values = {
14832 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
14833 HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT),
14834 0
14835 },
14836};
14837
14838static struct snd_kcontrol_new alc663_asus_21jd_clfe_mixer[] = {
14839 HDA_BIND_VOL("Master Playback Volume",
14840 &alc663_asus_two_bind_master_vol),
14841 HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
14842 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020014843 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
14844 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14845 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020014846 { } /* end */
14847};
14848
14849static struct snd_kcontrol_new alc663_asus_15jd_clfe_mixer[] = {
14850 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
14851 HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
14852 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
14853 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
14854 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14855 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020014856 { } /* end */
14857};
14858
14859static struct snd_kcontrol_new alc663_g71v_mixer[] = {
14860 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14861 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
14862 HDA_CODEC_VOLUME("Front Playback Volume", 0x03, 0x0, HDA_OUTPUT),
14863 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
14864 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
14865
14866 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14867 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14868 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14869 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14870 { } /* end */
14871};
14872
14873static struct snd_kcontrol_new alc663_g50v_mixer[] = {
14874 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14875 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
14876 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
14877
14878 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14879 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14880 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14881 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14882 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
14883 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
14884 { } /* end */
14885};
14886
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014887static struct snd_kcontrol_new alc662_chmode_mixer[] = {
14888 {
14889 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
14890 .name = "Channel Mode",
14891 .info = alc_ch_mode_info,
14892 .get = alc_ch_mode_get,
14893 .put = alc_ch_mode_put,
14894 },
14895 { } /* end */
14896};
14897
14898static struct hda_verb alc662_init_verbs[] = {
14899 /* ADC: mute amp left and right */
14900 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14901 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
14902 /* Front mixer: unmute input/output amp left and right (volume = 0) */
14903
Takashi Iwaicb53c622007-08-10 17:21:45 +020014904 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14905 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
14906 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
14907 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
14908 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014909
Kailang Yangb60dd392007-09-20 12:50:29 +020014910 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14911 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14912 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14913 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14914 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14915 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014916
14917 /* Front Pin: output 0 (0x0c) */
14918 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14919 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14920
14921 /* Rear Pin: output 1 (0x0d) */
14922 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14923 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14924
14925 /* CLFE Pin: output 2 (0x0e) */
14926 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14927 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14928
14929 /* Mic (rear) pin: input vref at 80% */
14930 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14931 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14932 /* Front Mic pin: input vref at 80% */
14933 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14934 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14935 /* Line In pin: input */
14936 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14937 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14938 /* Line-2 In: Headphone output (output 0 - 0x0c) */
14939 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14940 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14941 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
14942 /* CD pin widget for input */
14943 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14944
14945 /* FIXME: use matrix-type input source selection */
14946 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
14947 /* Input mixer */
14948 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14949 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14950 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
14951 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Kailang Yang291702f2007-10-16 14:28:03 +020014952
14953 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14954 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14955 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
14956 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Kailang Yang6dda9f42008-05-27 12:05:31 +020014957
14958 /* always trun on EAPD */
14959 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
14960 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
14961
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014962 { }
14963};
14964
14965static struct hda_verb alc662_sue_init_verbs[] = {
14966 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
14967 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
Kailang Yang291702f2007-10-16 14:28:03 +020014968 {}
14969};
14970
14971static struct hda_verb alc662_eeepc_sue_init_verbs[] = {
14972 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14973 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14974 {}
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014975};
14976
Kailang Yang8c427222008-01-10 13:03:59 +010014977/* Set Unsolicited Event*/
14978static struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = {
14979 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14980 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14981 {}
14982};
14983
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014984/*
14985 * generic initialization of ADC, input mixers and output mixers
14986 */
14987static struct hda_verb alc662_auto_init_verbs[] = {
14988 /*
14989 * Unmute ADC and set the default input to mic-in
14990 */
14991 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
14992 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14993
14994 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
14995 * mixer widget
14996 * Note: PASD motherboards uses the Line In 2 as the input for front
14997 * panel mic (mic 2)
14998 */
14999 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020015000 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15001 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15002 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
15003 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
15004 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015005
15006 /*
15007 * Set up output mixers (0x0c - 0x0f)
15008 */
15009 /* set vol=0 to output mixers */
15010 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
15011 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
15012 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
15013
15014 /* set up input amps for analog loopback */
15015 /* Amp Indices: DAC = 0, mixer = 1 */
Kailang Yangb60dd392007-09-20 12:50:29 +020015016 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15017 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15018 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15019 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15020 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15021 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015022
15023
15024 /* FIXME: use matrix-type input source selection */
15025 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
15026 /* Input mixer */
15027 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangd1a991a2007-08-15 16:21:59 +020015028 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015029 { }
15030};
15031
Takashi Iwai24fb9172008-09-02 14:48:20 +020015032/* additional verbs for ALC663 */
15033static struct hda_verb alc663_auto_init_verbs[] = {
15034 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15035 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15036 { }
15037};
15038
Kailang Yang6dda9f42008-05-27 12:05:31 +020015039static struct hda_verb alc663_m51va_init_verbs[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020015040 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15041 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yang6dda9f42008-05-27 12:05:31 +020015042 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15043 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangf1d4e282008-08-26 14:03:29 +020015044 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
15045 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15046 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
Kailang Yang6dda9f42008-05-27 12:05:31 +020015047 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15048 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15049 {}
15050};
15051
Kailang Yangf1d4e282008-08-26 14:03:29 +020015052static struct hda_verb alc663_21jd_amic_init_verbs[] = {
15053 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15054 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15055 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
15056 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15057 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15058 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15059 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15060 {}
15061};
15062
15063static struct hda_verb alc662_1bjd_amic_init_verbs[] = {
15064 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15065 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15066 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15067 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
15068 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15069 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15070 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15071 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15072 {}
15073};
15074
15075static struct hda_verb alc663_15jd_amic_init_verbs[] = {
15076 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15077 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15078 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
15079 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15080 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15081 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15082 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15083 {}
15084};
15085
15086static struct hda_verb alc663_two_hp_amic_m1_init_verbs[] = {
15087 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15088 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15089 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15090 {0x21, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */
15091 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15092 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15093 {0x15, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */
15094 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15095 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15096 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15097 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15098 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15099 {}
15100};
15101
15102static struct hda_verb alc663_two_hp_amic_m2_init_verbs[] = {
15103 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15104 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15105 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15106 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
15107 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15108 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15109 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
15110 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15111 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15112 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15113 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15114 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15115 {}
15116};
15117
Kailang Yang6dda9f42008-05-27 12:05:31 +020015118static struct hda_verb alc663_g71v_init_verbs[] = {
15119 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15120 /* {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
15121 /* {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, */ /* Headphone */
15122
15123 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15124 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15125 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
15126
15127 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
15128 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_MIC_EVENT},
15129 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
15130 {}
15131};
15132
15133static struct hda_verb alc663_g50v_init_verbs[] = {
15134 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15135 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15136 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
15137
15138 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15139 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15140 {}
15141};
15142
Kailang Yangf1d4e282008-08-26 14:03:29 +020015143static struct hda_verb alc662_ecs_init_verbs[] = {
15144 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
15145 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15146 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15147 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15148 {}
15149};
15150
Kailang Yangf1d4e282008-08-26 14:03:29 +020015151static struct snd_kcontrol_new alc662_auto_capture_mixer[] = {
15152 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
15153 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
15154 { } /* end */
15155};
15156
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015157static void alc662_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
15158{
15159 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015160 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015161
15162 present = snd_hda_codec_read(codec, 0x14, 0,
15163 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020015164 bits = present ? HDA_AMP_MUTE : 0;
15165 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
15166 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015167}
15168
15169static void alc662_lenovo_101e_all_automute(struct hda_codec *codec)
15170{
15171 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015172 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015173
15174 present = snd_hda_codec_read(codec, 0x1b, 0,
15175 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020015176 bits = present ? HDA_AMP_MUTE : 0;
15177 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
15178 HDA_AMP_MUTE, bits);
15179 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
15180 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015181}
15182
15183static void alc662_lenovo_101e_unsol_event(struct hda_codec *codec,
15184 unsigned int res)
15185{
15186 if ((res >> 26) == ALC880_HP_EVENT)
15187 alc662_lenovo_101e_all_automute(codec);
15188 if ((res >> 26) == ALC880_FRONT_EVENT)
15189 alc662_lenovo_101e_ispeaker_automute(codec);
15190}
15191
Kailang Yang291702f2007-10-16 14:28:03 +020015192static void alc662_eeepc_mic_automute(struct hda_codec *codec)
15193{
15194 unsigned int present;
15195
15196 present = snd_hda_codec_read(codec, 0x18, 0,
15197 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
15198 snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
15199 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
15200 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
15201 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
15202 snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
15203 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
15204 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
15205 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
15206}
15207
15208/* unsolicited event for HP jack sensing */
15209static void alc662_eeepc_unsol_event(struct hda_codec *codec,
15210 unsigned int res)
15211{
15212 if ((res >> 26) == ALC880_HP_EVENT)
15213 alc262_hippo1_automute( codec );
15214
15215 if ((res >> 26) == ALC880_MIC_EVENT)
15216 alc662_eeepc_mic_automute(codec);
15217}
15218
15219static void alc662_eeepc_inithook(struct hda_codec *codec)
15220{
15221 alc262_hippo1_automute( codec );
15222 alc662_eeepc_mic_automute(codec);
15223}
15224
Kailang Yang8c427222008-01-10 13:03:59 +010015225static void alc662_eeepc_ep20_automute(struct hda_codec *codec)
15226{
15227 unsigned int mute;
15228 unsigned int present;
15229
15230 snd_hda_codec_read(codec, 0x14, 0, AC_VERB_SET_PIN_SENSE, 0);
15231 present = snd_hda_codec_read(codec, 0x14, 0,
15232 AC_VERB_GET_PIN_SENSE, 0);
15233 present = (present & 0x80000000) != 0;
15234 if (present) {
15235 /* mute internal speaker */
15236 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +020015237 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yang8c427222008-01-10 13:03:59 +010015238 } else {
15239 /* unmute internal speaker if necessary */
15240 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
15241 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +020015242 HDA_AMP_MUTE, mute);
Kailang Yang8c427222008-01-10 13:03:59 +010015243 }
15244}
15245
15246/* unsolicited event for HP jack sensing */
15247static void alc662_eeepc_ep20_unsol_event(struct hda_codec *codec,
15248 unsigned int res)
15249{
15250 if ((res >> 26) == ALC880_HP_EVENT)
15251 alc662_eeepc_ep20_automute(codec);
15252}
15253
15254static void alc662_eeepc_ep20_inithook(struct hda_codec *codec)
15255{
15256 alc662_eeepc_ep20_automute(codec);
15257}
15258
Kailang Yang6dda9f42008-05-27 12:05:31 +020015259static void alc663_m51va_speaker_automute(struct hda_codec *codec)
15260{
15261 unsigned int present;
15262 unsigned char bits;
15263
15264 present = snd_hda_codec_read(codec, 0x21, 0,
Kailang Yangf1d4e282008-08-26 14:03:29 +020015265 AC_VERB_GET_PIN_SENSE, 0)
15266 & AC_PINSENSE_PRESENCE;
Kailang Yang6dda9f42008-05-27 12:05:31 +020015267 bits = present ? HDA_AMP_MUTE : 0;
Kailang Yangf1d4e282008-08-26 14:03:29 +020015268 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
15269 AMP_IN_MUTE(0), bits);
15270 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
15271 AMP_IN_MUTE(0), bits);
15272}
15273
15274static void alc663_21jd_two_speaker_automute(struct hda_codec *codec)
15275{
15276 unsigned int present;
15277 unsigned char bits;
15278
15279 present = snd_hda_codec_read(codec, 0x21, 0,
15280 AC_VERB_GET_PIN_SENSE, 0)
15281 & AC_PINSENSE_PRESENCE;
15282 bits = present ? HDA_AMP_MUTE : 0;
15283 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
15284 AMP_IN_MUTE(0), bits);
15285 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
15286 AMP_IN_MUTE(0), bits);
15287 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0,
15288 AMP_IN_MUTE(0), bits);
15289 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1,
15290 AMP_IN_MUTE(0), bits);
15291}
15292
15293static void alc663_15jd_two_speaker_automute(struct hda_codec *codec)
15294{
15295 unsigned int present;
15296 unsigned char bits;
15297
15298 present = snd_hda_codec_read(codec, 0x15, 0,
15299 AC_VERB_GET_PIN_SENSE, 0)
15300 & AC_PINSENSE_PRESENCE;
15301 bits = present ? HDA_AMP_MUTE : 0;
15302 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
15303 AMP_IN_MUTE(0), bits);
15304 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
15305 AMP_IN_MUTE(0), bits);
15306 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0,
15307 AMP_IN_MUTE(0), bits);
15308 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1,
15309 AMP_IN_MUTE(0), bits);
15310}
15311
15312static void alc662_f5z_speaker_automute(struct hda_codec *codec)
15313{
15314 unsigned int present;
15315 unsigned char bits;
15316
15317 present = snd_hda_codec_read(codec, 0x1b, 0,
15318 AC_VERB_GET_PIN_SENSE, 0)
15319 & AC_PINSENSE_PRESENCE;
15320 bits = present ? 0 : PIN_OUT;
15321 snd_hda_codec_write(codec, 0x14, 0,
15322 AC_VERB_SET_PIN_WIDGET_CONTROL, bits);
15323}
15324
15325static void alc663_two_hp_m1_speaker_automute(struct hda_codec *codec)
15326{
15327 unsigned int present1, present2;
15328
15329 present1 = snd_hda_codec_read(codec, 0x21, 0,
15330 AC_VERB_GET_PIN_SENSE, 0)
15331 & AC_PINSENSE_PRESENCE;
15332 present2 = snd_hda_codec_read(codec, 0x15, 0,
15333 AC_VERB_GET_PIN_SENSE, 0)
15334 & AC_PINSENSE_PRESENCE;
15335
15336 if (present1 || present2) {
15337 snd_hda_codec_write_cache(codec, 0x14, 0,
15338 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
15339 } else {
15340 snd_hda_codec_write_cache(codec, 0x14, 0,
15341 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
15342 }
15343}
15344
15345static void alc663_two_hp_m2_speaker_automute(struct hda_codec *codec)
15346{
15347 unsigned int present1, present2;
15348
15349 present1 = snd_hda_codec_read(codec, 0x1b, 0,
15350 AC_VERB_GET_PIN_SENSE, 0)
15351 & AC_PINSENSE_PRESENCE;
15352 present2 = snd_hda_codec_read(codec, 0x15, 0,
15353 AC_VERB_GET_PIN_SENSE, 0)
15354 & AC_PINSENSE_PRESENCE;
15355
15356 if (present1 || present2) {
15357 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
15358 AMP_IN_MUTE(0), AMP_IN_MUTE(0));
15359 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
15360 AMP_IN_MUTE(0), AMP_IN_MUTE(0));
15361 } else {
15362 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
15363 AMP_IN_MUTE(0), 0);
15364 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
15365 AMP_IN_MUTE(0), 0);
15366 }
Kailang Yang6dda9f42008-05-27 12:05:31 +020015367}
15368
15369static void alc663_m51va_mic_automute(struct hda_codec *codec)
15370{
15371 unsigned int present;
15372
15373 present = snd_hda_codec_read(codec, 0x18, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +020015374 AC_VERB_GET_PIN_SENSE, 0)
15375 & AC_PINSENSE_PRESENCE;
Kailang Yang6dda9f42008-05-27 12:05:31 +020015376 snd_hda_codec_write_cache(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangea1fb292008-08-26 12:58:38 +020015377 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
Kailang Yang6dda9f42008-05-27 12:05:31 +020015378 snd_hda_codec_write_cache(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangea1fb292008-08-26 12:58:38 +020015379 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
Kailang Yang6dda9f42008-05-27 12:05:31 +020015380 snd_hda_codec_write_cache(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangea1fb292008-08-26 12:58:38 +020015381 0x7000 | (0x09 << 8) | (present ? 0x80 : 0));
Kailang Yang6dda9f42008-05-27 12:05:31 +020015382 snd_hda_codec_write_cache(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangea1fb292008-08-26 12:58:38 +020015383 0x7000 | (0x09 << 8) | (present ? 0x80 : 0));
Kailang Yang6dda9f42008-05-27 12:05:31 +020015384}
15385
15386static void alc663_m51va_unsol_event(struct hda_codec *codec,
15387 unsigned int res)
15388{
15389 switch (res >> 26) {
15390 case ALC880_HP_EVENT:
15391 alc663_m51va_speaker_automute(codec);
15392 break;
15393 case ALC880_MIC_EVENT:
15394 alc663_m51va_mic_automute(codec);
15395 break;
15396 }
15397}
15398
15399static void alc663_m51va_inithook(struct hda_codec *codec)
15400{
15401 alc663_m51va_speaker_automute(codec);
15402 alc663_m51va_mic_automute(codec);
15403}
15404
Kailang Yangf1d4e282008-08-26 14:03:29 +020015405/* ***************** Mode1 ******************************/
15406static void alc663_mode1_unsol_event(struct hda_codec *codec,
15407 unsigned int res)
15408{
15409 switch (res >> 26) {
15410 case ALC880_HP_EVENT:
15411 alc663_m51va_speaker_automute(codec);
15412 break;
15413 case ALC880_MIC_EVENT:
15414 alc662_eeepc_mic_automute(codec);
15415 break;
15416 }
15417}
15418
15419static void alc663_mode1_inithook(struct hda_codec *codec)
15420{
15421 alc663_m51va_speaker_automute(codec);
15422 alc662_eeepc_mic_automute(codec);
15423}
15424/* ***************** Mode2 ******************************/
15425static void alc662_mode2_unsol_event(struct hda_codec *codec,
15426 unsigned int res)
15427{
15428 switch (res >> 26) {
15429 case ALC880_HP_EVENT:
15430 alc662_f5z_speaker_automute(codec);
15431 break;
15432 case ALC880_MIC_EVENT:
15433 alc662_eeepc_mic_automute(codec);
15434 break;
15435 }
15436}
15437
15438static void alc662_mode2_inithook(struct hda_codec *codec)
15439{
15440 alc662_f5z_speaker_automute(codec);
15441 alc662_eeepc_mic_automute(codec);
15442}
15443/* ***************** Mode3 ******************************/
15444static void alc663_mode3_unsol_event(struct hda_codec *codec,
15445 unsigned int res)
15446{
15447 switch (res >> 26) {
15448 case ALC880_HP_EVENT:
15449 alc663_two_hp_m1_speaker_automute(codec);
15450 break;
15451 case ALC880_MIC_EVENT:
15452 alc662_eeepc_mic_automute(codec);
15453 break;
15454 }
15455}
15456
15457static void alc663_mode3_inithook(struct hda_codec *codec)
15458{
15459 alc663_two_hp_m1_speaker_automute(codec);
15460 alc662_eeepc_mic_automute(codec);
15461}
15462/* ***************** Mode4 ******************************/
15463static void alc663_mode4_unsol_event(struct hda_codec *codec,
15464 unsigned int res)
15465{
15466 switch (res >> 26) {
15467 case ALC880_HP_EVENT:
15468 alc663_21jd_two_speaker_automute(codec);
15469 break;
15470 case ALC880_MIC_EVENT:
15471 alc662_eeepc_mic_automute(codec);
15472 break;
15473 }
15474}
15475
15476static void alc663_mode4_inithook(struct hda_codec *codec)
15477{
15478 alc663_21jd_two_speaker_automute(codec);
15479 alc662_eeepc_mic_automute(codec);
15480}
15481/* ***************** Mode5 ******************************/
15482static void alc663_mode5_unsol_event(struct hda_codec *codec,
15483 unsigned int res)
15484{
15485 switch (res >> 26) {
15486 case ALC880_HP_EVENT:
15487 alc663_15jd_two_speaker_automute(codec);
15488 break;
15489 case ALC880_MIC_EVENT:
15490 alc662_eeepc_mic_automute(codec);
15491 break;
15492 }
15493}
15494
15495static void alc663_mode5_inithook(struct hda_codec *codec)
15496{
15497 alc663_15jd_two_speaker_automute(codec);
15498 alc662_eeepc_mic_automute(codec);
15499}
15500/* ***************** Mode6 ******************************/
15501static void alc663_mode6_unsol_event(struct hda_codec *codec,
15502 unsigned int res)
15503{
15504 switch (res >> 26) {
15505 case ALC880_HP_EVENT:
15506 alc663_two_hp_m2_speaker_automute(codec);
15507 break;
15508 case ALC880_MIC_EVENT:
15509 alc662_eeepc_mic_automute(codec);
15510 break;
15511 }
15512}
15513
15514static void alc663_mode6_inithook(struct hda_codec *codec)
15515{
15516 alc663_two_hp_m2_speaker_automute(codec);
15517 alc662_eeepc_mic_automute(codec);
15518}
15519
Kailang Yang6dda9f42008-05-27 12:05:31 +020015520static void alc663_g71v_hp_automute(struct hda_codec *codec)
15521{
15522 unsigned int present;
15523 unsigned char bits;
15524
15525 present = snd_hda_codec_read(codec, 0x21, 0,
15526 AC_VERB_GET_PIN_SENSE, 0)
15527 & AC_PINSENSE_PRESENCE;
15528 bits = present ? HDA_AMP_MUTE : 0;
15529 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
15530 HDA_AMP_MUTE, bits);
15531 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
15532 HDA_AMP_MUTE, bits);
15533}
15534
15535static void alc663_g71v_front_automute(struct hda_codec *codec)
15536{
15537 unsigned int present;
15538 unsigned char bits;
15539
15540 present = snd_hda_codec_read(codec, 0x15, 0,
15541 AC_VERB_GET_PIN_SENSE, 0)
15542 & AC_PINSENSE_PRESENCE;
15543 bits = present ? HDA_AMP_MUTE : 0;
15544 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
15545 HDA_AMP_MUTE, bits);
15546}
15547
15548static void alc663_g71v_unsol_event(struct hda_codec *codec,
15549 unsigned int res)
15550{
15551 switch (res >> 26) {
15552 case ALC880_HP_EVENT:
15553 alc663_g71v_hp_automute(codec);
15554 break;
15555 case ALC880_FRONT_EVENT:
15556 alc663_g71v_front_automute(codec);
15557 break;
15558 case ALC880_MIC_EVENT:
15559 alc662_eeepc_mic_automute(codec);
15560 break;
15561 }
15562}
15563
15564static void alc663_g71v_inithook(struct hda_codec *codec)
15565{
15566 alc663_g71v_front_automute(codec);
15567 alc663_g71v_hp_automute(codec);
15568 alc662_eeepc_mic_automute(codec);
15569}
15570
15571static void alc663_g50v_unsol_event(struct hda_codec *codec,
15572 unsigned int res)
15573{
15574 switch (res >> 26) {
15575 case ALC880_HP_EVENT:
15576 alc663_m51va_speaker_automute(codec);
15577 break;
15578 case ALC880_MIC_EVENT:
15579 alc662_eeepc_mic_automute(codec);
15580 break;
15581 }
15582}
15583
15584static void alc663_g50v_inithook(struct hda_codec *codec)
15585{
15586 alc663_m51va_speaker_automute(codec);
15587 alc662_eeepc_mic_automute(codec);
15588}
15589
Kailang Yangf1d4e282008-08-26 14:03:29 +020015590/* bind hp and internal speaker mute (with plug check) */
15591static int alc662_ecs_master_sw_put(struct snd_kcontrol *kcontrol,
15592 struct snd_ctl_elem_value *ucontrol)
15593{
15594 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
15595 long *valp = ucontrol->value.integer.value;
15596 int change;
15597
15598 change = snd_hda_codec_amp_update(codec, 0x1b, 0, HDA_OUTPUT, 0,
15599 HDA_AMP_MUTE,
15600 valp[0] ? 0 : HDA_AMP_MUTE);
15601 change |= snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0,
15602 HDA_AMP_MUTE,
15603 valp[1] ? 0 : HDA_AMP_MUTE);
15604 if (change)
15605 alc262_hippo1_automute(codec);
15606 return change;
15607}
15608
15609static struct snd_kcontrol_new alc662_ecs_mixer[] = {
15610 HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15611 {
15612 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
15613 .name = "Master Playback Switch",
15614 .info = snd_hda_mixer_amp_switch_info,
15615 .get = snd_hda_mixer_amp_switch_get,
15616 .put = alc662_ecs_master_sw_put,
15617 .private_value = HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
15618 },
15619
15620 HDA_CODEC_VOLUME("e-Mic/LineIn Boost", 0x18, 0, HDA_INPUT),
15621 HDA_CODEC_VOLUME("e-Mic/LineIn Playback Volume", 0x0b, 0x0, HDA_INPUT),
15622 HDA_CODEC_MUTE("e-Mic/LineIn Playback Switch", 0x0b, 0x0, HDA_INPUT),
15623
15624 HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT),
15625 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15626 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
15627 { } /* end */
15628};
15629
Takashi Iwaicb53c622007-08-10 17:21:45 +020015630#ifdef CONFIG_SND_HDA_POWER_SAVE
15631#define alc662_loopbacks alc880_loopbacks
15632#endif
15633
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015634
15635/* pcm configuration: identiacal with ALC880 */
15636#define alc662_pcm_analog_playback alc880_pcm_analog_playback
15637#define alc662_pcm_analog_capture alc880_pcm_analog_capture
15638#define alc662_pcm_digital_playback alc880_pcm_digital_playback
15639#define alc662_pcm_digital_capture alc880_pcm_digital_capture
15640
15641/*
15642 * configuration and preset
15643 */
15644static const char *alc662_models[ALC662_MODEL_LAST] = {
15645 [ALC662_3ST_2ch_DIG] = "3stack-dig",
15646 [ALC662_3ST_6ch_DIG] = "3stack-6ch-dig",
15647 [ALC662_3ST_6ch] = "3stack-6ch",
15648 [ALC662_5ST_DIG] = "6stack-dig",
15649 [ALC662_LENOVO_101E] = "lenovo-101e",
Takashi Iwaib995d762007-10-17 10:41:06 +020015650 [ALC662_ASUS_EEEPC_P701] = "eeepc-p701",
Kailang Yang8c427222008-01-10 13:03:59 +010015651 [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20",
Kailang Yangf1d4e282008-08-26 14:03:29 +020015652 [ALC662_ECS] = "ecs",
Kailang Yang6dda9f42008-05-27 12:05:31 +020015653 [ALC663_ASUS_M51VA] = "m51va",
15654 [ALC663_ASUS_G71V] = "g71v",
15655 [ALC663_ASUS_H13] = "h13",
15656 [ALC663_ASUS_G50V] = "g50v",
Kailang Yangf1d4e282008-08-26 14:03:29 +020015657 [ALC663_ASUS_MODE1] = "asus-mode1",
15658 [ALC662_ASUS_MODE2] = "asus-mode2",
15659 [ALC663_ASUS_MODE3] = "asus-mode3",
15660 [ALC663_ASUS_MODE4] = "asus-mode4",
15661 [ALC663_ASUS_MODE5] = "asus-mode5",
15662 [ALC663_ASUS_MODE6] = "asus-mode6",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015663 [ALC662_AUTO] = "auto",
15664};
15665
15666static struct snd_pci_quirk alc662_cfg_tbl[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020015667 SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M51VA", ALC663_ASUS_M51VA),
Kailang Yang80ffe862008-10-15 11:23:27 +020015668 SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS G50V", ALC663_ASUS_G50V),
Herton Ronaldo Krzesinski3da23ca2008-03-14 12:52:59 +010015669 SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG),
Kailang Yang291702f2007-10-16 14:28:03 +020015670 SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701),
Kailang Yang8c427222008-01-10 13:03:59 +010015671 SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20),
Kailang Yangf1d4e282008-08-26 14:03:29 +020015672 SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC663_ASUS_MODE1),
15673 SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M50Vr", ALC663_ASUS_MODE1),
15674 SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC663_ASUS_MODE1),
15675 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC663_ASUS_MODE1),
15676 SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC663_ASUS_MODE1),
15677 SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS NB", ALC663_ASUS_MODE1),
15678 SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC663_ASUS_MODE1),
15679 SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC663_ASUS_MODE1),
15680 SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC663_ASUS_MODE1),
Kailang Yang80ffe862008-10-15 11:23:27 +020015681 SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC663_ASUS_MODE1),
Kailang Yangf1d4e282008-08-26 14:03:29 +020015682 SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_ASUS_MODE2),
15683 SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_ASUS_MODE2),
15684 SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_ASUS_MODE2),
15685 SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_ASUS_MODE2),
15686 SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_ASUS_MODE2),
15687 SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_ASUS_MODE2),
15688 SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_ASUS_MODE2),
15689 SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_ASUS_MODE2),
15690 SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_ASUS_MODE2),
15691 SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_ASUS_MODE2),
15692 SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_ASUS_MODE2),
15693 SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_ASUS_MODE2),
15694 SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC663_ASUS_MODE3),
15695 SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC663_ASUS_MODE3),
15696 SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC663_ASUS_MODE3),
15697 SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC663_ASUS_MODE3),
15698 SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC663_ASUS_MODE3),
15699 SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC663_ASUS_MODE4),
15700 SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC663_ASUS_MODE5),
15701 SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC663_ASUS_MODE6),
15702 SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC663_ASUS_MODE6),
15703 SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC663_ASUS_MODE6),
Herton Ronaldo Krzesinski95fe5f22008-09-26 23:48:45 -030015704 SND_PCI_QUIRK(0x105b, 0x0d47, "Foxconn 45CMX/45GMX/45CMX-K",
15705 ALC662_3ST_6ch_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010015706 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E),
Kailang Yangf1d4e282008-08-26 14:03:29 +020015707 SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_ECS),
15708 SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS),
Herton Ronaldo Krzesinskicb559742008-09-26 23:47:45 -030015709 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L",
15710 ALC662_3ST_6ch_DIG),
Vedran Miletic19c009a2008-09-29 20:29:25 +020015711 SND_PCI_QUIRK(0x1565, 0x820f, "Biostar TA780G M2+", ALC662_3ST_6ch_DIG),
Takashi Iwai238713d2008-10-05 10:57:39 +020015712 SND_PCI_QUIRK(0x1849, 0x3662, "ASROCK K10N78FullHD-hSLI R3.0",
Vedran Miletic19c009a2008-09-29 20:29:25 +020015713 ALC662_3ST_6ch_DIG),
Kailang Yang6dda9f42008-05-27 12:05:31 +020015714 SND_PCI_QUIRK(0x1854, 0x2000, "ASUS H13-2000", ALC663_ASUS_H13),
15715 SND_PCI_QUIRK(0x1854, 0x2001, "ASUS H13-2001", ALC663_ASUS_H13),
15716 SND_PCI_QUIRK(0x1854, 0x2002, "ASUS H13-2002", ALC663_ASUS_H13),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015717 {}
15718};
15719
15720static struct alc_config_preset alc662_presets[] = {
15721 [ALC662_3ST_2ch_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015722 .mixers = { alc662_3ST_2ch_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015723 .init_verbs = { alc662_init_verbs },
15724 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15725 .dac_nids = alc662_dac_nids,
15726 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015727 .dig_in_nid = ALC662_DIGIN_NID,
15728 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15729 .channel_mode = alc662_3ST_2ch_modes,
15730 .input_mux = &alc662_capture_source,
15731 },
15732 [ALC662_3ST_6ch_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015733 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015734 .init_verbs = { alc662_init_verbs },
15735 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15736 .dac_nids = alc662_dac_nids,
15737 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015738 .dig_in_nid = ALC662_DIGIN_NID,
15739 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
15740 .channel_mode = alc662_3ST_6ch_modes,
15741 .need_dac_fix = 1,
15742 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015743 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015744 [ALC662_3ST_6ch] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015745 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015746 .init_verbs = { alc662_init_verbs },
15747 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15748 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015749 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
15750 .channel_mode = alc662_3ST_6ch_modes,
15751 .need_dac_fix = 1,
15752 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015753 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015754 [ALC662_5ST_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015755 .mixers = { alc662_base_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015756 .init_verbs = { alc662_init_verbs },
15757 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15758 .dac_nids = alc662_dac_nids,
15759 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015760 .dig_in_nid = ALC662_DIGIN_NID,
15761 .num_channel_mode = ARRAY_SIZE(alc662_5stack_modes),
15762 .channel_mode = alc662_5stack_modes,
15763 .input_mux = &alc662_capture_source,
15764 },
15765 [ALC662_LENOVO_101E] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015766 .mixers = { alc662_lenovo_101e_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015767 .init_verbs = { alc662_init_verbs, alc662_sue_init_verbs },
15768 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15769 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015770 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15771 .channel_mode = alc662_3ST_2ch_modes,
15772 .input_mux = &alc662_lenovo_101e_capture_source,
15773 .unsol_event = alc662_lenovo_101e_unsol_event,
15774 .init_hook = alc662_lenovo_101e_all_automute,
15775 },
Kailang Yang291702f2007-10-16 14:28:03 +020015776 [ALC662_ASUS_EEEPC_P701] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015777 .mixers = { alc662_eeepc_p701_mixer },
Kailang Yang291702f2007-10-16 14:28:03 +020015778 .init_verbs = { alc662_init_verbs,
15779 alc662_eeepc_sue_init_verbs },
15780 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15781 .dac_nids = alc662_dac_nids,
Kailang Yang291702f2007-10-16 14:28:03 +020015782 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15783 .channel_mode = alc662_3ST_2ch_modes,
15784 .input_mux = &alc662_eeepc_capture_source,
15785 .unsol_event = alc662_eeepc_unsol_event,
15786 .init_hook = alc662_eeepc_inithook,
15787 },
Kailang Yang8c427222008-01-10 13:03:59 +010015788 [ALC662_ASUS_EEEPC_EP20] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015789 .mixers = { alc662_eeepc_ep20_mixer,
Kailang Yang8c427222008-01-10 13:03:59 +010015790 alc662_chmode_mixer },
15791 .init_verbs = { alc662_init_verbs,
15792 alc662_eeepc_ep20_sue_init_verbs },
15793 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15794 .dac_nids = alc662_dac_nids,
Kailang Yang8c427222008-01-10 13:03:59 +010015795 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
15796 .channel_mode = alc662_3ST_6ch_modes,
15797 .input_mux = &alc662_lenovo_101e_capture_source,
15798 .unsol_event = alc662_eeepc_ep20_unsol_event,
15799 .init_hook = alc662_eeepc_ep20_inithook,
15800 },
Kailang Yangf1d4e282008-08-26 14:03:29 +020015801 [ALC662_ECS] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015802 .mixers = { alc662_ecs_mixer },
Kailang Yangf1d4e282008-08-26 14:03:29 +020015803 .init_verbs = { alc662_init_verbs,
15804 alc662_ecs_init_verbs },
15805 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15806 .dac_nids = alc662_dac_nids,
15807 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15808 .channel_mode = alc662_3ST_2ch_modes,
15809 .input_mux = &alc662_eeepc_capture_source,
15810 .unsol_event = alc662_eeepc_unsol_event,
15811 .init_hook = alc662_eeepc_inithook,
15812 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020015813 [ALC663_ASUS_M51VA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015814 .mixers = { alc663_m51va_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020015815 .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
15816 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15817 .dac_nids = alc662_dac_nids,
15818 .dig_out_nid = ALC662_DIGOUT_NID,
15819 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15820 .channel_mode = alc662_3ST_2ch_modes,
15821 .input_mux = &alc663_m51va_capture_source,
15822 .unsol_event = alc663_m51va_unsol_event,
15823 .init_hook = alc663_m51va_inithook,
15824 },
15825 [ALC663_ASUS_G71V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015826 .mixers = { alc663_g71v_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020015827 .init_verbs = { alc662_init_verbs, alc663_g71v_init_verbs },
15828 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15829 .dac_nids = alc662_dac_nids,
15830 .dig_out_nid = ALC662_DIGOUT_NID,
15831 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15832 .channel_mode = alc662_3ST_2ch_modes,
15833 .input_mux = &alc662_eeepc_capture_source,
15834 .unsol_event = alc663_g71v_unsol_event,
15835 .init_hook = alc663_g71v_inithook,
15836 },
15837 [ALC663_ASUS_H13] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015838 .mixers = { alc663_m51va_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020015839 .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
15840 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15841 .dac_nids = alc662_dac_nids,
15842 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15843 .channel_mode = alc662_3ST_2ch_modes,
15844 .input_mux = &alc663_m51va_capture_source,
15845 .unsol_event = alc663_m51va_unsol_event,
15846 .init_hook = alc663_m51va_inithook,
15847 },
15848 [ALC663_ASUS_G50V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015849 .mixers = { alc663_g50v_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020015850 .init_verbs = { alc662_init_verbs, alc663_g50v_init_verbs },
15851 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15852 .dac_nids = alc662_dac_nids,
15853 .dig_out_nid = ALC662_DIGOUT_NID,
15854 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
15855 .channel_mode = alc662_3ST_6ch_modes,
15856 .input_mux = &alc663_capture_source,
15857 .unsol_event = alc663_g50v_unsol_event,
15858 .init_hook = alc663_g50v_inithook,
15859 },
Kailang Yangf1d4e282008-08-26 14:03:29 +020015860 [ALC663_ASUS_MODE1] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015861 .mixers = { alc663_m51va_mixer },
15862 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020015863 .init_verbs = { alc662_init_verbs,
15864 alc663_21jd_amic_init_verbs },
15865 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15866 .hp_nid = 0x03,
15867 .dac_nids = alc662_dac_nids,
15868 .dig_out_nid = ALC662_DIGOUT_NID,
15869 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15870 .channel_mode = alc662_3ST_2ch_modes,
15871 .input_mux = &alc662_eeepc_capture_source,
15872 .unsol_event = alc663_mode1_unsol_event,
15873 .init_hook = alc663_mode1_inithook,
15874 },
15875 [ALC662_ASUS_MODE2] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015876 .mixers = { alc662_1bjd_mixer },
15877 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020015878 .init_verbs = { alc662_init_verbs,
15879 alc662_1bjd_amic_init_verbs },
15880 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15881 .dac_nids = alc662_dac_nids,
15882 .dig_out_nid = ALC662_DIGOUT_NID,
15883 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15884 .channel_mode = alc662_3ST_2ch_modes,
15885 .input_mux = &alc662_eeepc_capture_source,
15886 .unsol_event = alc662_mode2_unsol_event,
15887 .init_hook = alc662_mode2_inithook,
15888 },
15889 [ALC663_ASUS_MODE3] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015890 .mixers = { alc663_two_hp_m1_mixer },
15891 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020015892 .init_verbs = { alc662_init_verbs,
15893 alc663_two_hp_amic_m1_init_verbs },
15894 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15895 .hp_nid = 0x03,
15896 .dac_nids = alc662_dac_nids,
15897 .dig_out_nid = ALC662_DIGOUT_NID,
15898 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15899 .channel_mode = alc662_3ST_2ch_modes,
15900 .input_mux = &alc662_eeepc_capture_source,
15901 .unsol_event = alc663_mode3_unsol_event,
15902 .init_hook = alc663_mode3_inithook,
15903 },
15904 [ALC663_ASUS_MODE4] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015905 .mixers = { alc663_asus_21jd_clfe_mixer },
15906 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020015907 .init_verbs = { alc662_init_verbs,
15908 alc663_21jd_amic_init_verbs},
15909 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15910 .hp_nid = 0x03,
15911 .dac_nids = alc662_dac_nids,
15912 .dig_out_nid = ALC662_DIGOUT_NID,
15913 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15914 .channel_mode = alc662_3ST_2ch_modes,
15915 .input_mux = &alc662_eeepc_capture_source,
15916 .unsol_event = alc663_mode4_unsol_event,
15917 .init_hook = alc663_mode4_inithook,
15918 },
15919 [ALC663_ASUS_MODE5] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015920 .mixers = { alc663_asus_15jd_clfe_mixer },
15921 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020015922 .init_verbs = { alc662_init_verbs,
15923 alc663_15jd_amic_init_verbs },
15924 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15925 .hp_nid = 0x03,
15926 .dac_nids = alc662_dac_nids,
15927 .dig_out_nid = ALC662_DIGOUT_NID,
15928 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15929 .channel_mode = alc662_3ST_2ch_modes,
15930 .input_mux = &alc662_eeepc_capture_source,
15931 .unsol_event = alc663_mode5_unsol_event,
15932 .init_hook = alc663_mode5_inithook,
15933 },
15934 [ALC663_ASUS_MODE6] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015935 .mixers = { alc663_two_hp_m2_mixer },
15936 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020015937 .init_verbs = { alc662_init_verbs,
15938 alc663_two_hp_amic_m2_init_verbs },
15939 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15940 .hp_nid = 0x03,
15941 .dac_nids = alc662_dac_nids,
15942 .dig_out_nid = ALC662_DIGOUT_NID,
15943 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15944 .channel_mode = alc662_3ST_2ch_modes,
15945 .input_mux = &alc662_eeepc_capture_source,
15946 .unsol_event = alc663_mode6_unsol_event,
15947 .init_hook = alc663_mode6_inithook,
15948 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015949};
15950
15951
15952/*
15953 * BIOS auto configuration
15954 */
15955
15956/* add playback controls from the parsed DAC table */
15957static int alc662_auto_create_multi_out_ctls(struct alc_spec *spec,
15958 const struct auto_pin_cfg *cfg)
15959{
15960 char name[32];
15961 static const char *chname[4] = {
15962 "Front", "Surround", NULL /*CLFE*/, "Side"
15963 };
15964 hda_nid_t nid;
15965 int i, err;
15966
15967 for (i = 0; i < cfg->line_outs; i++) {
15968 if (!spec->multiout.dac_nids[i])
15969 continue;
Kailang Yangb60dd392007-09-20 12:50:29 +020015970 nid = alc880_idx_to_dac(i);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015971 if (i == 2) {
15972 /* Center/LFE */
15973 err = add_control(spec, ALC_CTL_WIDGET_VOL,
15974 "Center Playback Volume",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015975 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
15976 HDA_OUTPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015977 if (err < 0)
15978 return err;
15979 err = add_control(spec, ALC_CTL_WIDGET_VOL,
15980 "LFE Playback Volume",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015981 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
15982 HDA_OUTPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015983 if (err < 0)
15984 return err;
Herton Ronaldo Krzesinskib69ce012008-09-18 16:41:49 -030015985 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015986 "Center Playback Switch",
Herton Ronaldo Krzesinskib69ce012008-09-18 16:41:49 -030015987 HDA_COMPOSE_AMP_VAL(0x0e, 1, 0,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015988 HDA_INPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015989 if (err < 0)
15990 return err;
Herton Ronaldo Krzesinskib69ce012008-09-18 16:41:49 -030015991 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015992 "LFE Playback Switch",
Herton Ronaldo Krzesinskib69ce012008-09-18 16:41:49 -030015993 HDA_COMPOSE_AMP_VAL(0x0e, 2, 0,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015994 HDA_INPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015995 if (err < 0)
15996 return err;
15997 } else {
15998 sprintf(name, "%s Playback Volume", chname[i]);
15999 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016000 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
16001 HDA_OUTPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016002 if (err < 0)
16003 return err;
16004 sprintf(name, "%s Playback Switch", chname[i]);
Herton Ronaldo Krzesinskib69ce012008-09-18 16:41:49 -030016005 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
16006 HDA_COMPOSE_AMP_VAL(alc880_idx_to_mixer(i),
16007 3, 0, HDA_INPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016008 if (err < 0)
16009 return err;
16010 }
16011 }
16012 return 0;
16013}
16014
16015/* add playback controls for speaker and HP outputs */
16016static int alc662_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
16017 const char *pfx)
16018{
16019 hda_nid_t nid;
16020 int err;
16021 char name[32];
16022
16023 if (!pin)
16024 return 0;
16025
Takashi Iwai24fb9172008-09-02 14:48:20 +020016026 if (pin == 0x17) {
16027 /* ALC663 has a mono output pin on 0x17 */
16028 sprintf(name, "%s Playback Switch", pfx);
16029 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
16030 HDA_COMPOSE_AMP_VAL(pin, 2, 0, HDA_OUTPUT));
16031 return err;
16032 }
16033
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016034 if (alc880_is_fixed_pin(pin)) {
16035 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
16036 /* printk("DAC nid=%x\n",nid); */
16037 /* specify the DAC as the extra output */
16038 if (!spec->multiout.hp_nid)
16039 spec->multiout.hp_nid = nid;
16040 else
16041 spec->multiout.extra_out_nid[0] = nid;
16042 /* control HP volume/switch on the output mixer amp */
16043 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
16044 sprintf(name, "%s Playback Volume", pfx);
16045 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
16046 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
16047 if (err < 0)
16048 return err;
16049 sprintf(name, "%s Playback Switch", pfx);
16050 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
16051 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
16052 if (err < 0)
16053 return err;
16054 } else if (alc880_is_multi_pin(pin)) {
16055 /* set manual connection */
16056 /* we have only a switch on HP-out PIN */
16057 sprintf(name, "%s Playback Switch", pfx);
16058 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
16059 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
16060 if (err < 0)
16061 return err;
16062 }
16063 return 0;
16064}
16065
16066/* create playback/capture controls for input pins */
16067static int alc662_auto_create_analog_input_ctls(struct alc_spec *spec,
16068 const struct auto_pin_cfg *cfg)
16069{
16070 struct hda_input_mux *imux = &spec->private_imux;
16071 int i, err, idx;
16072
16073 for (i = 0; i < AUTO_PIN_LAST; i++) {
16074 if (alc880_is_input_pin(cfg->input_pins[i])) {
16075 idx = alc880_input_pin_idx(cfg->input_pins[i]);
16076 err = new_analog_input(spec, cfg->input_pins[i],
16077 auto_pin_cfg_labels[i],
16078 idx, 0x0b);
16079 if (err < 0)
16080 return err;
16081 imux->items[imux->num_items].label =
16082 auto_pin_cfg_labels[i];
16083 imux->items[imux->num_items].index =
16084 alc880_input_pin_idx(cfg->input_pins[i]);
16085 imux->num_items++;
16086 }
16087 }
16088 return 0;
16089}
16090
16091static void alc662_auto_set_output_and_unmute(struct hda_codec *codec,
16092 hda_nid_t nid, int pin_type,
16093 int dac_idx)
16094{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016095 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016096 /* need the manual connection? */
16097 if (alc880_is_multi_pin(nid)) {
16098 struct alc_spec *spec = codec->spec;
16099 int idx = alc880_multi_pin_idx(nid);
16100 snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
16101 AC_VERB_SET_CONNECT_SEL,
16102 alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
16103 }
16104}
16105
16106static void alc662_auto_init_multi_out(struct hda_codec *codec)
16107{
16108 struct alc_spec *spec = codec->spec;
16109 int i;
16110
Kailang Yang8c427222008-01-10 13:03:59 +010016111 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016112 for (i = 0; i <= HDA_SIDE; i++) {
16113 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020016114 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016115 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020016116 alc662_auto_set_output_and_unmute(codec, nid, pin_type,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016117 i);
16118 }
16119}
16120
16121static void alc662_auto_init_hp_out(struct hda_codec *codec)
16122{
16123 struct alc_spec *spec = codec->spec;
16124 hda_nid_t pin;
16125
16126 pin = spec->autocfg.hp_pins[0];
16127 if (pin) /* connect to front */
16128 /* use dac 0 */
16129 alc662_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016130 pin = spec->autocfg.speaker_pins[0];
16131 if (pin)
16132 alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016133}
16134
16135#define alc662_is_input_pin(nid) alc880_is_input_pin(nid)
16136#define ALC662_PIN_CD_NID ALC880_PIN_CD_NID
16137
16138static void alc662_auto_init_analog_input(struct hda_codec *codec)
16139{
16140 struct alc_spec *spec = codec->spec;
16141 int i;
16142
16143 for (i = 0; i < AUTO_PIN_LAST; i++) {
16144 hda_nid_t nid = spec->autocfg.input_pins[i];
16145 if (alc662_is_input_pin(nid)) {
16146 snd_hda_codec_write(codec, nid, 0,
16147 AC_VERB_SET_PIN_WIDGET_CONTROL,
16148 (i <= AUTO_PIN_FRONT_MIC ?
16149 PIN_VREF80 : PIN_IN));
16150 if (nid != ALC662_PIN_CD_NID)
16151 snd_hda_codec_write(codec, nid, 0,
16152 AC_VERB_SET_AMP_GAIN_MUTE,
16153 AMP_OUT_MUTE);
16154 }
16155 }
16156}
16157
Takashi Iwaif511b012008-08-15 16:46:42 +020016158#define alc662_auto_init_input_src alc882_auto_init_input_src
16159
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016160static int alc662_parse_auto_config(struct hda_codec *codec)
16161{
16162 struct alc_spec *spec = codec->spec;
16163 int err;
16164 static hda_nid_t alc662_ignore[] = { 0x1d, 0 };
16165
16166 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
16167 alc662_ignore);
16168 if (err < 0)
16169 return err;
16170 if (!spec->autocfg.line_outs)
16171 return 0; /* can't find valid BIOS pin config */
16172
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016173 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
16174 if (err < 0)
16175 return err;
16176 err = alc662_auto_create_multi_out_ctls(spec, &spec->autocfg);
16177 if (err < 0)
16178 return err;
16179 err = alc662_auto_create_extra_out(spec,
16180 spec->autocfg.speaker_pins[0],
16181 "Speaker");
16182 if (err < 0)
16183 return err;
16184 err = alc662_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
16185 "Headphone");
16186 if (err < 0)
16187 return err;
16188 err = alc662_auto_create_analog_input_ctls(spec, &spec->autocfg);
16189 if (err < 0)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016190 return err;
16191
16192 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
16193
16194 if (spec->autocfg.dig_out_pin)
16195 spec->multiout.dig_out_nid = ALC880_DIGOUT_NID;
16196
Takashi Iwai603c4012008-07-30 15:01:44 +020016197 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010016198 add_mixer(spec, spec->kctls.list);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016199
16200 spec->num_mux_defs = 1;
16201 spec->input_mux = &spec->private_imux;
Kailang Yangea1fb292008-08-26 12:58:38 +020016202
Takashi Iwaid88897e2008-10-31 15:01:37 +010016203 add_verb(spec, alc662_auto_init_verbs);
Takashi Iwai24fb9172008-09-02 14:48:20 +020016204 if (codec->vendor_id == 0x10ec0663)
Takashi Iwaid88897e2008-10-31 15:01:37 +010016205 add_verb(spec, alc663_auto_init_verbs);
Takashi Iwaiee979a142008-09-02 15:42:20 +020016206
16207 err = alc_auto_add_mic_boost(codec);
16208 if (err < 0)
16209 return err;
16210
Takashi Iwaie044c392008-10-27 16:56:24 +010016211 store_pin_configs(codec);
Takashi Iwai8c87286f2007-06-19 12:11:16 +020016212 return 1;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016213}
16214
16215/* additional initialization for auto-configuration model */
16216static void alc662_auto_init(struct hda_codec *codec)
16217{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016218 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016219 alc662_auto_init_multi_out(codec);
16220 alc662_auto_init_hp_out(codec);
16221 alc662_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020016222 alc662_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016223 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020016224 alc_inithook(codec);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016225}
16226
16227static int patch_alc662(struct hda_codec *codec)
16228{
16229 struct alc_spec *spec;
16230 int err, board_config;
16231
16232 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
16233 if (!spec)
16234 return -ENOMEM;
16235
16236 codec->spec = spec;
16237
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020016238 alc_fix_pll_init(codec, 0x20, 0x04, 15);
16239
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016240 board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST,
16241 alc662_models,
16242 alc662_cfg_tbl);
16243 if (board_config < 0) {
16244 printk(KERN_INFO "hda_codec: Unknown model for ALC662, "
16245 "trying auto-probe from BIOS...\n");
16246 board_config = ALC662_AUTO;
16247 }
16248
16249 if (board_config == ALC662_AUTO) {
16250 /* automatic parse from the BIOS config */
16251 err = alc662_parse_auto_config(codec);
16252 if (err < 0) {
16253 alc_free(codec);
16254 return err;
Takashi Iwai8c87286f2007-06-19 12:11:16 +020016255 } else if (!err) {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016256 printk(KERN_INFO
16257 "hda_codec: Cannot set up configuration "
16258 "from BIOS. Using base mode...\n");
16259 board_config = ALC662_3ST_2ch_DIG;
16260 }
16261 }
16262
16263 if (board_config != ALC662_AUTO)
16264 setup_preset(spec, &alc662_presets[board_config]);
16265
Kailang Yang6dda9f42008-05-27 12:05:31 +020016266 if (codec->vendor_id == 0x10ec0663) {
16267 spec->stream_name_analog = "ALC663 Analog";
16268 spec->stream_name_digital = "ALC663 Digital";
Kailang Yang01afd412008-10-15 11:22:09 +020016269 } else if (codec->vendor_id == 0x10ec0272) {
16270 spec->stream_name_analog = "ALC272 Analog";
16271 spec->stream_name_digital = "ALC272 Digital";
Kailang Yang6dda9f42008-05-27 12:05:31 +020016272 } else {
16273 spec->stream_name_analog = "ALC662 Analog";
16274 spec->stream_name_digital = "ALC662 Digital";
16275 }
16276
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016277 spec->stream_analog_playback = &alc662_pcm_analog_playback;
16278 spec->stream_analog_capture = &alc662_pcm_analog_capture;
16279
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016280 spec->stream_digital_playback = &alc662_pcm_digital_playback;
16281 spec->stream_digital_capture = &alc662_pcm_digital_capture;
16282
Takashi Iwaie1406342008-02-11 18:32:32 +010016283 spec->adc_nids = alc662_adc_nids;
16284 spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids);
16285 spec->capsrc_nids = alc662_capsrc_nids;
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010016286 spec->is_mix_capture = 1;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016287
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016288 if (!spec->cap_mixer)
16289 set_capture_mixer(spec);
16290
Takashi Iwai2134ea42008-01-10 16:53:55 +010016291 spec->vmaster_nid = 0x02;
16292
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016293 codec->patch_ops = alc_patch_ops;
16294 if (board_config == ALC662_AUTO)
16295 spec->init_hook = alc662_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020016296#ifdef CONFIG_SND_HDA_POWER_SAVE
16297 if (!spec->loopback.amplist)
16298 spec->loopback.amplist = alc662_loopbacks;
16299#endif
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016300
16301 return 0;
16302}
16303
16304/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070016305 * patch entries
16306 */
16307struct hda_codec_preset snd_hda_preset_realtek[] = {
16308 { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
Kailang Yangdf694da2005-12-05 19:42:22 +010016309 { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
Kailang Yangf6a92242007-12-13 16:52:54 +010016310 { .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 },
Kailang Yanga361d842007-06-05 12:30:55 +020016311 { .id = 0x10ec0268, .name = "ALC268", .patch = patch_alc268 },
Kailang Yangf6a92242007-12-13 16:52:54 +010016312 { .id = 0x10ec0269, .name = "ALC269", .patch = patch_alc269 },
Kailang Yang01afd412008-10-15 11:22:09 +020016313 { .id = 0x10ec0272, .name = "ALC272", .patch = patch_alc662 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016314 { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016315 .patch = patch_alc861 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016316 { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
16317 { .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 },
16318 { .id = 0x10ec0862, .name = "ALC861-VD", .patch = patch_alc861vd },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016319 { .id = 0x10ec0662, .rev = 0x100002, .name = "ALC662 rev2",
16320 .patch = patch_alc883 },
16321 { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1",
16322 .patch = patch_alc662 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020016323 { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016324 { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070016325 { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020016326 { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc883 },
Clive Messer669faba2008-09-30 15:49:13 +020016327 { .id = 0x10ec0885, .rev = 0x100101, .name = "ALC889A",
16328 .patch = patch_alc882 }, /* should be patch_alc883() in future */
Takashi Iwaicb308f92008-04-16 14:13:29 +020016329 { .id = 0x10ec0885, .rev = 0x100103, .name = "ALC889A",
Takashi Iwai7943a8a2008-04-16 17:29:09 +020016330 .patch = patch_alc882 }, /* should be patch_alc883() in future */
Kailang Yangdf694da2005-12-05 19:42:22 +010016331 { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
Kailang Yanga385a522008-10-15 11:20:21 +020016332 { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc883 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020016333 { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc883 },
Kailang Yang44426082008-10-15 11:18:05 +020016334 { .id = 0x10ec0888, .rev = 0x100101, .name = "ALC1200",
16335 .patch = patch_alc883 },
Kailang Yangf6a92242007-12-13 16:52:54 +010016336 { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc883 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070016337 {} /* terminator */
16338};