blob: d748d19f1632671e3ae3bd4ad88ec64490e12b5e [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,
Kailang Yangdf694da2005-12-05 19:42:22 +0100106 ALC262_AUTO,
107 ALC262_MODEL_LAST /* last tag */
108};
109
Kailang Yanga361d842007-06-05 12:30:55 +0200110/* ALC268 models */
111enum {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +0200112 ALC267_QUANTA_IL1,
Kailang Yanga361d842007-06-05 12:30:55 +0200113 ALC268_3ST,
Kailang Yangd1a991a2007-08-15 16:21:59 +0200114 ALC268_TOSHIBA,
Takashi Iwaid2738092007-08-16 14:59:45 +0200115 ALC268_ACER,
Kailang Yang8ef355d2008-08-26 13:10:22 +0200116 ALC268_ACER_ASPIRE_ONE,
Takashi Iwai3866f0b2008-01-15 12:37:42 +0100117 ALC268_DELL,
Mirco Tischlerf12462c2008-02-04 12:33:59 +0100118 ALC268_ZEPTO,
Jonathan Woithe86c53bd2008-01-08 12:33:19 +0100119#ifdef CONFIG_SND_DEBUG
120 ALC268_TEST,
121#endif
Kailang Yanga361d842007-06-05 12:30:55 +0200122 ALC268_AUTO,
123 ALC268_MODEL_LAST /* last tag */
124};
125
Kailang Yangf6a92242007-12-13 16:52:54 +0100126/* ALC269 models */
127enum {
128 ALC269_BASIC,
Kailang Yang60db6b52008-08-26 13:13:00 +0200129 ALC269_QUANTA_FL1,
Kailang Yangf53281e2008-07-18 12:36:43 +0200130 ALC269_ASUS_EEEPC_P703,
131 ALC269_ASUS_EEEPC_P901,
Kailang Yangf6a92242007-12-13 16:52:54 +0100132 ALC269_AUTO,
133 ALC269_MODEL_LAST /* last tag */
134};
135
Kailang Yangdf694da2005-12-05 19:42:22 +0100136/* ALC861 models */
137enum {
138 ALC861_3ST,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200139 ALC660_3ST,
Kailang Yangdf694da2005-12-05 19:42:22 +0100140 ALC861_3ST_DIG,
141 ALC861_6ST_DIG,
Takashi Iwai22309c32006-08-09 16:57:28 +0200142 ALC861_UNIWILL_M31,
Tobin Davisa53d1ae2006-10-17 12:00:28 +0200143 ALC861_TOSHIBA,
Mariusz Domanski7cdbff92006-10-23 13:42:56 +0200144 ALC861_ASUS,
Takashi Iwai56bb0ca2006-11-22 11:52:52 +0100145 ALC861_ASUS_LAPTOP,
Kailang Yangdf694da2005-12-05 19:42:22 +0100146 ALC861_AUTO,
147 ALC861_MODEL_LAST,
148};
149
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100150/* ALC861-VD models */
151enum {
152 ALC660VD_3ST,
Mike Crash6963f842007-06-25 12:12:51 +0200153 ALC660VD_3ST_DIG,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100154 ALC861VD_3ST,
155 ALC861VD_3ST_DIG,
156 ALC861VD_6ST_DIG,
Kailang Yangbdd148a2007-05-08 15:19:08 +0200157 ALC861VD_LENOVO,
Kailang Yang272a5272007-05-14 11:00:38 +0200158 ALC861VD_DALLAS,
Kailang Yangd1a991a2007-08-15 16:21:59 +0200159 ALC861VD_HP,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100160 ALC861VD_AUTO,
161 ALC861VD_MODEL_LAST,
162};
163
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200164/* ALC662 models */
165enum {
166 ALC662_3ST_2ch_DIG,
167 ALC662_3ST_6ch_DIG,
168 ALC662_3ST_6ch,
169 ALC662_5ST_DIG,
170 ALC662_LENOVO_101E,
Kailang Yang291702f2007-10-16 14:28:03 +0200171 ALC662_ASUS_EEEPC_P701,
Kailang Yang8c427222008-01-10 13:03:59 +0100172 ALC662_ASUS_EEEPC_EP20,
Kailang Yang6dda9f42008-05-27 12:05:31 +0200173 ALC663_ASUS_M51VA,
174 ALC663_ASUS_G71V,
175 ALC663_ASUS_H13,
176 ALC663_ASUS_G50V,
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200177 ALC662_AUTO,
178 ALC662_MODEL_LAST,
179};
180
Kailang Yangdf694da2005-12-05 19:42:22 +0100181/* ALC882 models */
182enum {
183 ALC882_3ST_DIG,
184 ALC882_6ST_DIG,
Takashi Iwai4b146cb2006-07-28 14:42:36 +0200185 ALC882_ARIMA,
Kailang Yangbdd148a2007-05-08 15:19:08 +0200186 ALC882_W2JC,
Kailang Yang272a5272007-05-14 11:00:38 +0200187 ALC882_TARGA,
188 ALC882_ASUS_A7J,
Takashi Iwai914759b2007-09-06 14:52:04 +0200189 ALC882_ASUS_A7M,
Tobin Davis9102cd12006-12-15 10:02:12 +0100190 ALC885_MACPRO,
Takashi Iwai87350ad2007-08-16 18:19:38 +0200191 ALC885_MBP3,
Nicola Fagnanic54728d2007-07-19 23:28:52 +0200192 ALC885_IMAC24,
Kailang Yang272a5272007-05-14 11:00:38 +0200193 ALC882_AUTO,
Kailang Yangdf694da2005-12-05 19:42:22 +0100194 ALC882_MODEL_LAST,
195};
196
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200197/* ALC883 models */
198enum {
199 ALC883_3ST_2ch_DIG,
200 ALC883_3ST_6ch_DIG,
201 ALC883_3ST_6ch,
202 ALC883_6ST_DIG,
Kailang Yangccc656c2006-10-17 12:32:26 +0200203 ALC883_TARGA_DIG,
204 ALC883_TARGA_2ch_DIG,
Vladimir Avdoninbab282b92006-08-22 13:31:58 +0200205 ALC883_ACER,
Tobin Davis2880a862007-08-07 11:50:26 +0200206 ALC883_ACER_ASPIRE,
Tobin Davisc07584c2006-10-13 12:32:16 +0200207 ALC883_MEDION,
Kailang Yangea1fb292008-08-26 12:58:38 +0200208 ALC883_MEDION_MD2,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +0100209 ALC883_LAPTOP_EAPD,
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200210 ALC883_LENOVO_101E_2ch,
Kailang Yang272a5272007-05-14 11:00:38 +0200211 ALC883_LENOVO_NB0763,
Kailang Yang189609a2007-08-20 11:31:23 +0200212 ALC888_LENOVO_MS7195_DIG,
Kailang Yange2757d52008-08-26 13:17:46 +0200213 ALC888_LENOVO_SKY,
Kailang Yangea1fb292008-08-26 12:58:38 +0200214 ALC883_HAIER_W66,
Claudio Matsuoka4723c022007-07-13 14:36:19 +0200215 ALC888_3ST_HP,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +0100216 ALC888_6ST_DELL,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +0100217 ALC883_MITAC,
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +0100218 ALC883_CLEVO_M720,
Jiang zhefb97dc62008-03-06 11:07:11 +0100219 ALC883_FUJITSU_PI2515,
Jiang zhe17bba1b2008-06-04 12:11:07 +0200220 ALC883_3ST_6ch_INTEL,
Kailang Yange2757d52008-08-26 13:17:46 +0200221 ALC888_ASUS_M90V,
222 ALC888_ASUS_EEE1601,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200223 ALC883_AUTO,
224 ALC883_MODEL_LAST,
225};
226
Kailang Yangdf694da2005-12-05 19:42:22 +0100227/* for GPIO Poll */
228#define GPIO_MASK 0x03
229
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230struct alc_spec {
231 /* codec parameterization */
Kailang Yangdf694da2005-12-05 19:42:22 +0100232 struct snd_kcontrol_new *mixers[5]; /* mixer arrays */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233 unsigned int num_mixers;
234
Kailang Yangdf694da2005-12-05 19:42:22 +0100235 const struct hda_verb *init_verbs[5]; /* initialization verbs
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200236 * don't forget NULL
237 * termination!
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200238 */
239 unsigned int num_init_verbs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240
Takashi Iwai16ded522005-06-10 19:58:24 +0200241 char *stream_name_analog; /* analog PCM stream */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 struct hda_pcm_stream *stream_analog_playback;
243 struct hda_pcm_stream *stream_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +0100244 struct hda_pcm_stream *stream_analog_alt_playback;
245 struct hda_pcm_stream *stream_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200247 char *stream_name_digital; /* digital PCM stream */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 struct hda_pcm_stream *stream_digital_playback;
249 struct hda_pcm_stream *stream_digital_capture;
250
251 /* playback */
Takashi Iwai16ded522005-06-10 19:58:24 +0200252 struct hda_multi_out multiout; /* playback set-up
253 * max_channels, dacs must be set
254 * dig_out_nid and hp_nid are optional
255 */
Takashi Iwai63300792008-01-24 15:31:36 +0100256 hda_nid_t alt_dac_nid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257
258 /* capture */
259 unsigned int num_adc_nids;
260 hda_nid_t *adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100261 hda_nid_t *capsrc_nids;
Takashi Iwai16ded522005-06-10 19:58:24 +0200262 hda_nid_t dig_in_nid; /* digital-in NID; optional */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263
264 /* capture source */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200265 unsigned int num_mux_defs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266 const struct hda_input_mux *input_mux;
267 unsigned int cur_mux[3];
268
269 /* channel model */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100270 const struct hda_channel_mode *channel_mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 int num_channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200272 int need_dac_fix;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273
274 /* PCM information */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100275 struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */
Takashi Iwai41e41f12005-06-08 14:48:49 +0200276
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200277 /* dynamic controls, init_verbs and input_mux */
278 struct auto_pin_cfg autocfg;
279 unsigned int num_kctl_alloc, num_kctl_used;
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100280 struct snd_kcontrol_new *kctl_alloc;
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200281 struct hda_input_mux private_imux;
Takashi Iwai41923e42007-10-22 17:20:10 +0200282 hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
Takashi Iwai834be882006-03-01 14:16:17 +0100283
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100284 /* hooks */
285 void (*init_hook)(struct hda_codec *codec);
286 void (*unsol_event)(struct hda_codec *codec, unsigned int res);
287
Takashi Iwai834be882006-03-01 14:16:17 +0100288 /* for pin sensing */
289 unsigned int sense_updated: 1;
290 unsigned int jack_present: 1;
Takashi Iwaibec15c32008-01-28 18:16:30 +0100291 unsigned int master_sw: 1;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200292
Takashi Iwai2134ea42008-01-10 16:53:55 +0100293 /* for virtual master */
294 hda_nid_t vmaster_nid;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200295#ifdef CONFIG_SND_HDA_POWER_SAVE
296 struct hda_loopback_check loopback;
297#endif
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +0200298
299 /* for PLL fix */
300 hda_nid_t pll_nid;
301 unsigned int pll_coef_idx, pll_coef_bit;
Kailang Yangdf694da2005-12-05 19:42:22 +0100302};
303
304/*
305 * configuration template - to be copied to the spec instance
306 */
307struct alc_config_preset {
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200308 struct snd_kcontrol_new *mixers[5]; /* should be identical size
309 * with spec
310 */
Kailang Yangdf694da2005-12-05 19:42:22 +0100311 const struct hda_verb *init_verbs[5];
312 unsigned int num_dacs;
313 hda_nid_t *dac_nids;
314 hda_nid_t dig_out_nid; /* optional */
315 hda_nid_t hp_nid; /* optional */
316 unsigned int num_adc_nids;
317 hda_nid_t *adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100318 hda_nid_t *capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +0100319 hda_nid_t dig_in_nid;
320 unsigned int num_channel_mode;
321 const struct hda_channel_mode *channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200322 int need_dac_fix;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200323 unsigned int num_mux_defs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100324 const struct hda_input_mux *input_mux;
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100325 void (*unsol_event)(struct hda_codec *, unsigned int);
326 void (*init_hook)(struct hda_codec *);
Takashi Iwaicb53c622007-08-10 17:21:45 +0200327#ifdef CONFIG_SND_HDA_POWER_SAVE
328 struct hda_amp_list *loopbacks;
329#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330};
331
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332
333/*
334 * input MUX handling
335 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200336static int alc_mux_enum_info(struct snd_kcontrol *kcontrol,
337 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338{
339 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
340 struct alc_spec *spec = codec->spec;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200341 unsigned int mux_idx = snd_ctl_get_ioffidx(kcontrol, &uinfo->id);
342 if (mux_idx >= spec->num_mux_defs)
343 mux_idx = 0;
344 return snd_hda_input_mux_info(&spec->input_mux[mux_idx], uinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345}
346
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200347static int alc_mux_enum_get(struct snd_kcontrol *kcontrol,
348 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349{
350 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
351 struct alc_spec *spec = codec->spec;
352 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
353
354 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
355 return 0;
356}
357
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200358static int alc_mux_enum_put(struct snd_kcontrol *kcontrol,
359 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360{
361 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
362 struct alc_spec *spec = codec->spec;
363 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200364 unsigned int mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx;
Takashi Iwaie1406342008-02-11 18:32:32 +0100365 hda_nid_t nid = spec->capsrc_nids ?
366 spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx];
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200367 return snd_hda_input_mux_put(codec, &spec->input_mux[mux_idx], ucontrol,
Takashi Iwaie1406342008-02-11 18:32:32 +0100368 nid, &spec->cur_mux[adc_idx]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369}
370
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200371
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372/*
373 * channel mode setting
374 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200375static int alc_ch_mode_info(struct snd_kcontrol *kcontrol,
376 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377{
378 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
379 struct alc_spec *spec = codec->spec;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100380 return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode,
381 spec->num_channel_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382}
383
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200384static int alc_ch_mode_get(struct snd_kcontrol *kcontrol,
385 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386{
387 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
388 struct alc_spec *spec = codec->spec;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100389 return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200390 spec->num_channel_mode,
391 spec->multiout.max_channels);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392}
393
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200394static int alc_ch_mode_put(struct snd_kcontrol *kcontrol,
395 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396{
397 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
398 struct alc_spec *spec = codec->spec;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200399 int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
400 spec->num_channel_mode,
401 &spec->multiout.max_channels);
Takashi Iwaibd2033f2006-10-10 19:49:31 +0200402 if (err >= 0 && spec->need_dac_fix)
Takashi Iwai4e195a72006-07-28 14:47:34 +0200403 spec->multiout.num_dacs = spec->multiout.max_channels / 2;
404 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405}
406
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407/*
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100408 * Control the mode of pin widget settings via the mixer. "pc" is used
Kailang Yangea1fb292008-08-26 12:58:38 +0200409 * instead of "%" to avoid consequences of accidently treating the % as
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100410 * being part of a format specifier. Maximum allowed length of a value is
411 * 63 characters plus NULL terminator.
Jonathan Woithe7cf51e482006-02-09 12:01:26 +0100412 *
413 * Note: some retasking pin complexes seem to ignore requests for input
414 * states other than HiZ (eg: PIN_VREFxx) and revert to HiZ if any of these
415 * are requested. Therefore order this list so that this behaviour will not
416 * cause problems when mixer clients move through the enum sequentially.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200417 * NIDs 0x0f and 0x10 have been observed to have this behaviour as of
418 * March 2006.
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200419 */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100420static char *alc_pin_mode_names[] = {
Jonathan Woithe7cf51e482006-02-09 12:01:26 +0100421 "Mic 50pc bias", "Mic 80pc bias",
422 "Line in", "Line out", "Headphone out",
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100423};
424static unsigned char alc_pin_mode_values[] = {
Jonathan Woithe7cf51e482006-02-09 12:01:26 +0100425 PIN_VREF50, PIN_VREF80, PIN_IN, PIN_OUT, PIN_HP,
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100426};
427/* The control can present all 5 options, or it can limit the options based
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200428 * in the pin being assumed to be exclusively an input or an output pin. In
429 * addition, "input" pins may or may not process the mic bias option
430 * depending on actual widget capability (NIDs 0x0f and 0x10 don't seem to
431 * accept requests for bias as of chip versions up to March 2006) and/or
432 * wiring in the computer.
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100433 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200434#define ALC_PIN_DIR_IN 0x00
435#define ALC_PIN_DIR_OUT 0x01
436#define ALC_PIN_DIR_INOUT 0x02
437#define ALC_PIN_DIR_IN_NOMICBIAS 0x03
438#define ALC_PIN_DIR_INOUT_NOMICBIAS 0x04
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100439
Kailang Yangea1fb292008-08-26 12:58:38 +0200440/* Info about the pin modes supported by the different pin direction modes.
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100441 * For each direction the minimum and maximum values are given.
442 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200443static signed char alc_pin_mode_dir_info[5][2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100444 { 0, 2 }, /* ALC_PIN_DIR_IN */
445 { 3, 4 }, /* ALC_PIN_DIR_OUT */
446 { 0, 4 }, /* ALC_PIN_DIR_INOUT */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200447 { 2, 2 }, /* ALC_PIN_DIR_IN_NOMICBIAS */
448 { 2, 4 }, /* ALC_PIN_DIR_INOUT_NOMICBIAS */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100449};
450#define alc_pin_mode_min(_dir) (alc_pin_mode_dir_info[_dir][0])
451#define alc_pin_mode_max(_dir) (alc_pin_mode_dir_info[_dir][1])
452#define alc_pin_mode_n_items(_dir) \
453 (alc_pin_mode_max(_dir)-alc_pin_mode_min(_dir)+1)
454
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200455static int alc_pin_mode_info(struct snd_kcontrol *kcontrol,
456 struct snd_ctl_elem_info *uinfo)
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200457{
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100458 unsigned int item_num = uinfo->value.enumerated.item;
459 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
460
461 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200462 uinfo->count = 1;
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100463 uinfo->value.enumerated.items = alc_pin_mode_n_items(dir);
464
465 if (item_num<alc_pin_mode_min(dir) || item_num>alc_pin_mode_max(dir))
466 item_num = alc_pin_mode_min(dir);
467 strcpy(uinfo->value.enumerated.name, alc_pin_mode_names[item_num]);
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200468 return 0;
469}
470
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200471static int alc_pin_mode_get(struct snd_kcontrol *kcontrol,
472 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200473{
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100474 unsigned int i;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200475 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
476 hda_nid_t nid = kcontrol->private_value & 0xffff;
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100477 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200478 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200479 unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
480 AC_VERB_GET_PIN_WIDGET_CONTROL,
481 0x00);
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200482
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100483 /* Find enumerated value for current pinctl setting */
484 i = alc_pin_mode_min(dir);
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200485 while (alc_pin_mode_values[i] != pinctl && i <= alc_pin_mode_max(dir))
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100486 i++;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200487 *valp = i <= alc_pin_mode_max(dir) ? i: alc_pin_mode_min(dir);
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100488 return 0;
489}
490
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200491static int alc_pin_mode_put(struct snd_kcontrol *kcontrol,
492 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100493{
494 signed int change;
495 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
496 hda_nid_t nid = kcontrol->private_value & 0xffff;
497 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
498 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200499 unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
500 AC_VERB_GET_PIN_WIDGET_CONTROL,
501 0x00);
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100502
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200503 if (val < alc_pin_mode_min(dir) || val > alc_pin_mode_max(dir))
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100504 val = alc_pin_mode_min(dir);
505
506 change = pinctl != alc_pin_mode_values[val];
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100507 if (change) {
508 /* Set pin mode to that requested */
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200509 snd_hda_codec_write_cache(codec, nid, 0,
510 AC_VERB_SET_PIN_WIDGET_CONTROL,
511 alc_pin_mode_values[val]);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100512
Kailang Yangea1fb292008-08-26 12:58:38 +0200513 /* Also enable the retasking pin's input/output as required
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100514 * for the requested pin mode. Enum values of 2 or less are
515 * input modes.
516 *
517 * Dynamically switching the input/output buffers probably
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200518 * reduces noise slightly (particularly on input) so we'll
519 * do it. However, having both input and output buffers
520 * enabled simultaneously doesn't seem to be problematic if
521 * this turns out to be necessary in the future.
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100522 */
523 if (val <= 2) {
Takashi Iwai47fd8302007-08-10 17:11:07 +0200524 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
525 HDA_AMP_MUTE, HDA_AMP_MUTE);
526 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
527 HDA_AMP_MUTE, 0);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100528 } else {
Takashi Iwai47fd8302007-08-10 17:11:07 +0200529 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
530 HDA_AMP_MUTE, HDA_AMP_MUTE);
531 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
532 HDA_AMP_MUTE, 0);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100533 }
534 }
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200535 return change;
536}
537
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100538#define ALC_PIN_MODE(xname, nid, dir) \
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200539 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100540 .info = alc_pin_mode_info, \
541 .get = alc_pin_mode_get, \
542 .put = alc_pin_mode_put, \
543 .private_value = nid | (dir<<16) }
Kailang Yangdf694da2005-12-05 19:42:22 +0100544
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100545/* A switch control for ALC260 GPIO pins. Multiple GPIOs can be ganged
546 * together using a mask with more than one bit set. This control is
547 * currently used only by the ALC260 test model. At this stage they are not
548 * needed for any "production" models.
549 */
550#ifdef CONFIG_SND_DEBUG
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200551#define alc_gpio_data_info snd_ctl_boolean_mono_info
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200552
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200553static int alc_gpio_data_get(struct snd_kcontrol *kcontrol,
554 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100555{
556 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
557 hda_nid_t nid = kcontrol->private_value & 0xffff;
558 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
559 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200560 unsigned int val = snd_hda_codec_read(codec, nid, 0,
561 AC_VERB_GET_GPIO_DATA, 0x00);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100562
563 *valp = (val & mask) != 0;
564 return 0;
565}
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200566static int alc_gpio_data_put(struct snd_kcontrol *kcontrol,
567 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100568{
569 signed int change;
570 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
571 hda_nid_t nid = kcontrol->private_value & 0xffff;
572 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
573 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200574 unsigned int gpio_data = snd_hda_codec_read(codec, nid, 0,
575 AC_VERB_GET_GPIO_DATA,
576 0x00);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100577
578 /* Set/unset the masked GPIO bit(s) as needed */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200579 change = (val == 0 ? 0 : mask) != (gpio_data & mask);
580 if (val == 0)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100581 gpio_data &= ~mask;
582 else
583 gpio_data |= mask;
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200584 snd_hda_codec_write_cache(codec, nid, 0,
585 AC_VERB_SET_GPIO_DATA, gpio_data);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100586
587 return change;
588}
589#define ALC_GPIO_DATA_SWITCH(xname, nid, mask) \
590 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
591 .info = alc_gpio_data_info, \
592 .get = alc_gpio_data_get, \
593 .put = alc_gpio_data_put, \
594 .private_value = nid | (mask<<16) }
595#endif /* CONFIG_SND_DEBUG */
596
Jonathan Woithe92621f12006-02-28 11:47:47 +0100597/* A switch control to allow the enabling of the digital IO pins on the
598 * ALC260. This is incredibly simplistic; the intention of this control is
599 * to provide something in the test model allowing digital outputs to be
600 * identified if present. If models are found which can utilise these
601 * outputs a more complete mixer control can be devised for those models if
602 * necessary.
603 */
604#ifdef CONFIG_SND_DEBUG
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200605#define alc_spdif_ctrl_info snd_ctl_boolean_mono_info
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200606
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200607static int alc_spdif_ctrl_get(struct snd_kcontrol *kcontrol,
608 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe92621f12006-02-28 11:47:47 +0100609{
610 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
611 hda_nid_t nid = kcontrol->private_value & 0xffff;
612 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
613 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200614 unsigned int val = snd_hda_codec_read(codec, nid, 0,
Andrew Paprocki3982d172007-12-19 12:13:44 +0100615 AC_VERB_GET_DIGI_CONVERT_1, 0x00);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100616
617 *valp = (val & mask) != 0;
618 return 0;
619}
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200620static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol,
621 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe92621f12006-02-28 11:47:47 +0100622{
623 signed int change;
624 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
625 hda_nid_t nid = kcontrol->private_value & 0xffff;
626 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
627 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200628 unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
Andrew Paprocki3982d172007-12-19 12:13:44 +0100629 AC_VERB_GET_DIGI_CONVERT_1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200630 0x00);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100631
632 /* Set/unset the masked control bit(s) as needed */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200633 change = (val == 0 ? 0 : mask) != (ctrl_data & mask);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100634 if (val==0)
635 ctrl_data &= ~mask;
636 else
637 ctrl_data |= mask;
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200638 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
639 ctrl_data);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100640
641 return change;
642}
643#define ALC_SPDIF_CTRL_SWITCH(xname, nid, mask) \
644 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
645 .info = alc_spdif_ctrl_info, \
646 .get = alc_spdif_ctrl_get, \
647 .put = alc_spdif_ctrl_put, \
648 .private_value = nid | (mask<<16) }
649#endif /* CONFIG_SND_DEBUG */
650
Jonathan Woithef8225f62008-01-08 12:16:54 +0100651/* A switch control to allow the enabling EAPD digital outputs on the ALC26x.
652 * Again, this is only used in the ALC26x test models to help identify when
653 * the EAPD line must be asserted for features to work.
654 */
655#ifdef CONFIG_SND_DEBUG
656#define alc_eapd_ctrl_info snd_ctl_boolean_mono_info
657
658static int alc_eapd_ctrl_get(struct snd_kcontrol *kcontrol,
659 struct snd_ctl_elem_value *ucontrol)
660{
661 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
662 hda_nid_t nid = kcontrol->private_value & 0xffff;
663 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
664 long *valp = ucontrol->value.integer.value;
665 unsigned int val = snd_hda_codec_read(codec, nid, 0,
666 AC_VERB_GET_EAPD_BTLENABLE, 0x00);
667
668 *valp = (val & mask) != 0;
669 return 0;
670}
671
672static int alc_eapd_ctrl_put(struct snd_kcontrol *kcontrol,
673 struct snd_ctl_elem_value *ucontrol)
674{
675 int change;
676 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
677 hda_nid_t nid = kcontrol->private_value & 0xffff;
678 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
679 long val = *ucontrol->value.integer.value;
680 unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
681 AC_VERB_GET_EAPD_BTLENABLE,
682 0x00);
683
684 /* Set/unset the masked control bit(s) as needed */
685 change = (!val ? 0 : mask) != (ctrl_data & mask);
686 if (!val)
687 ctrl_data &= ~mask;
688 else
689 ctrl_data |= mask;
690 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
691 ctrl_data);
692
693 return change;
694}
695
696#define ALC_EAPD_CTRL_SWITCH(xname, nid, mask) \
697 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
698 .info = alc_eapd_ctrl_info, \
699 .get = alc_eapd_ctrl_get, \
700 .put = alc_eapd_ctrl_put, \
701 .private_value = nid | (mask<<16) }
702#endif /* CONFIG_SND_DEBUG */
703
Kailang Yangdf694da2005-12-05 19:42:22 +0100704/*
705 * set up from the preset table
706 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200707static void setup_preset(struct alc_spec *spec,
708 const struct alc_config_preset *preset)
Kailang Yangdf694da2005-12-05 19:42:22 +0100709{
710 int i;
711
712 for (i = 0; i < ARRAY_SIZE(preset->mixers) && preset->mixers[i]; i++)
713 spec->mixers[spec->num_mixers++] = preset->mixers[i];
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200714 for (i = 0; i < ARRAY_SIZE(preset->init_verbs) && preset->init_verbs[i];
715 i++)
716 spec->init_verbs[spec->num_init_verbs++] =
717 preset->init_verbs[i];
Kailang Yangea1fb292008-08-26 12:58:38 +0200718
Kailang Yangdf694da2005-12-05 19:42:22 +0100719 spec->channel_mode = preset->channel_mode;
720 spec->num_channel_mode = preset->num_channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200721 spec->need_dac_fix = preset->need_dac_fix;
Kailang Yangdf694da2005-12-05 19:42:22 +0100722
723 spec->multiout.max_channels = spec->channel_mode[0].channels;
724
725 spec->multiout.num_dacs = preset->num_dacs;
726 spec->multiout.dac_nids = preset->dac_nids;
727 spec->multiout.dig_out_nid = preset->dig_out_nid;
728 spec->multiout.hp_nid = preset->hp_nid;
Kailang Yangea1fb292008-08-26 12:58:38 +0200729
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200730 spec->num_mux_defs = preset->num_mux_defs;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200731 if (!spec->num_mux_defs)
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200732 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +0100733 spec->input_mux = preset->input_mux;
734
735 spec->num_adc_nids = preset->num_adc_nids;
736 spec->adc_nids = preset->adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100737 spec->capsrc_nids = preset->capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +0100738 spec->dig_in_nid = preset->dig_in_nid;
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100739
740 spec->unsol_event = preset->unsol_event;
741 spec->init_hook = preset->init_hook;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200742#ifdef CONFIG_SND_HDA_POWER_SAVE
743 spec->loopback.amplist = preset->loopbacks;
744#endif
Kailang Yangdf694da2005-12-05 19:42:22 +0100745}
746
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200747/* Enable GPIO mask and set output */
748static struct hda_verb alc_gpio1_init_verbs[] = {
749 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
750 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
751 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
752 { }
753};
754
755static struct hda_verb alc_gpio2_init_verbs[] = {
756 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
757 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
758 {0x01, AC_VERB_SET_GPIO_DATA, 0x02},
759 { }
760};
761
Kailang Yangbdd148a2007-05-08 15:19:08 +0200762static struct hda_verb alc_gpio3_init_verbs[] = {
763 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
764 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
765 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
766 { }
767};
768
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +0200769/*
770 * Fix hardware PLL issue
771 * On some codecs, the analog PLL gating control must be off while
772 * the default value is 1.
773 */
774static void alc_fix_pll(struct hda_codec *codec)
775{
776 struct alc_spec *spec = codec->spec;
777 unsigned int val;
778
779 if (!spec->pll_nid)
780 return;
781 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
782 spec->pll_coef_idx);
783 val = snd_hda_codec_read(codec, spec->pll_nid, 0,
784 AC_VERB_GET_PROC_COEF, 0);
785 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
786 spec->pll_coef_idx);
787 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_PROC_COEF,
788 val & ~(1 << spec->pll_coef_bit));
789}
790
791static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
792 unsigned int coef_idx, unsigned int coef_bit)
793{
794 struct alc_spec *spec = codec->spec;
795 spec->pll_nid = nid;
796 spec->pll_coef_idx = coef_idx;
797 spec->pll_coef_bit = coef_bit;
798 alc_fix_pll(codec);
799}
800
Kailang Yangc9b58002007-10-16 14:30:01 +0200801static void alc_sku_automute(struct hda_codec *codec)
802{
803 struct alc_spec *spec = codec->spec;
Kailang Yangc9b58002007-10-16 14:30:01 +0200804 unsigned int present;
805 unsigned int hp_nid = spec->autocfg.hp_pins[0];
806 unsigned int sp_nid = spec->autocfg.speaker_pins[0];
807
808 /* need to execute and sync at first */
809 snd_hda_codec_read(codec, hp_nid, 0, AC_VERB_SET_PIN_SENSE, 0);
810 present = snd_hda_codec_read(codec, hp_nid, 0,
811 AC_VERB_GET_PIN_SENSE, 0);
812 spec->jack_present = (present & 0x80000000) != 0;
Takashi Iwaif6c7e542008-02-12 18:32:23 +0100813 snd_hda_codec_write(codec, sp_nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
814 spec->jack_present ? 0 : PIN_OUT);
Kailang Yangc9b58002007-10-16 14:30:01 +0200815}
816
817/* unsolicited event for HP jack sensing */
818static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res)
819{
820 if (codec->vendor_id == 0x10ec0880)
821 res >>= 28;
822 else
823 res >>= 26;
824 if (res != ALC880_HP_EVENT)
825 return;
826
827 alc_sku_automute(codec);
828}
829
Kailang Yangf9423e72008-05-27 12:32:25 +0200830/* additional initialization for ALC888 variants */
831static void alc888_coef_init(struct hda_codec *codec)
832{
833 unsigned int tmp;
834
835 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0);
836 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
837 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
838 if ((tmp & 0xf0) == 2)
839 /* alc888S-VC */
840 snd_hda_codec_read(codec, 0x20, 0,
841 AC_VERB_SET_PROC_COEF, 0x830);
842 else
843 /* alc888-VB */
844 snd_hda_codec_read(codec, 0x20, 0,
845 AC_VERB_SET_PROC_COEF, 0x3030);
846}
847
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200848/* 32-bit subsystem ID for BIOS loading in HD Audio codec.
849 * 31 ~ 16 : Manufacture ID
850 * 15 ~ 8 : SKU ID
851 * 7 ~ 0 : Assembly ID
852 * port-A --> pin 39/41, port-E --> pin 14/15, port-D --> pin 35/36
853 */
854static void alc_subsystem_id(struct hda_codec *codec,
855 unsigned int porta, unsigned int porte,
856 unsigned int portd)
857{
Kailang Yangc9b58002007-10-16 14:30:01 +0200858 unsigned int ass, tmp, i;
859 unsigned nid;
860 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200861
Kailang Yangc9b58002007-10-16 14:30:01 +0200862 ass = codec->subsystem_id & 0xffff;
863 if ((ass != codec->bus->pci->subsystem_device) && (ass & 1))
864 goto do_sku;
865
Kailang Yangea1fb292008-08-26 12:58:38 +0200866 /*
Kailang Yangc9b58002007-10-16 14:30:01 +0200867 * 31~30 : port conetcivity
868 * 29~21 : reserve
869 * 20 : PCBEEP input
870 * 19~16 : Check sum (15:1)
871 * 15~1 : Custom
872 * 0 : override
873 */
874 nid = 0x1d;
875 if (codec->vendor_id == 0x10ec0260)
876 nid = 0x17;
877 ass = snd_hda_codec_read(codec, nid, 0,
878 AC_VERB_GET_CONFIG_DEFAULT, 0);
879 if (!(ass & 1) && !(ass & 0x100000))
880 return;
881 if ((ass >> 30) != 1) /* no physical connection */
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200882 return;
883
Kailang Yangc9b58002007-10-16 14:30:01 +0200884 /* check sum */
885 tmp = 0;
886 for (i = 1; i < 16; i++) {
Kailang Yang8c427222008-01-10 13:03:59 +0100887 if ((ass >> i) & 1)
Kailang Yangc9b58002007-10-16 14:30:01 +0200888 tmp++;
889 }
890 if (((ass >> 16) & 0xf) != tmp)
891 return;
892do_sku:
893 /*
894 * 0 : override
895 * 1 : Swap Jack
896 * 2 : 0 --> Desktop, 1 --> Laptop
897 * 3~5 : External Amplifier control
898 * 7~6 : Reserved
899 */
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200900 tmp = (ass & 0x38) >> 3; /* external Amp control */
901 switch (tmp) {
902 case 1:
903 snd_hda_sequence_write(codec, alc_gpio1_init_verbs);
904 break;
905 case 3:
906 snd_hda_sequence_write(codec, alc_gpio2_init_verbs);
907 break;
Kailang Yangbdd148a2007-05-08 15:19:08 +0200908 case 7:
909 snd_hda_sequence_write(codec, alc_gpio3_init_verbs);
910 break;
Kailang Yangc9b58002007-10-16 14:30:01 +0200911 case 5: /* set EAPD output high */
Kailang Yangbdd148a2007-05-08 15:19:08 +0200912 switch (codec->vendor_id) {
Kailang Yangc9b58002007-10-16 14:30:01 +0200913 case 0x10ec0260:
914 snd_hda_codec_write(codec, 0x0f, 0,
915 AC_VERB_SET_EAPD_BTLENABLE, 2);
916 snd_hda_codec_write(codec, 0x10, 0,
917 AC_VERB_SET_EAPD_BTLENABLE, 2);
918 break;
919 case 0x10ec0262:
Kailang Yangbdd148a2007-05-08 15:19:08 +0200920 case 0x10ec0267:
921 case 0x10ec0268:
Kailang Yangc9b58002007-10-16 14:30:01 +0200922 case 0x10ec0269:
Kailang Yangf9423e72008-05-27 12:32:25 +0200923 case 0x10ec0660:
924 case 0x10ec0662:
925 case 0x10ec0663:
Kailang Yangc9b58002007-10-16 14:30:01 +0200926 case 0x10ec0862:
Takashi Iwai20a3a052008-05-23 17:52:53 +0200927 case 0x10ec0889:
Kailang Yangbdd148a2007-05-08 15:19:08 +0200928 snd_hda_codec_write(codec, 0x14, 0,
929 AC_VERB_SET_EAPD_BTLENABLE, 2);
930 snd_hda_codec_write(codec, 0x15, 0,
931 AC_VERB_SET_EAPD_BTLENABLE, 2);
Kailang Yangc9b58002007-10-16 14:30:01 +0200932 break;
Kailang Yangbdd148a2007-05-08 15:19:08 +0200933 }
Kailang Yangc9b58002007-10-16 14:30:01 +0200934 switch (codec->vendor_id) {
935 case 0x10ec0260:
936 snd_hda_codec_write(codec, 0x1a, 0,
937 AC_VERB_SET_COEF_INDEX, 7);
938 tmp = snd_hda_codec_read(codec, 0x1a, 0,
939 AC_VERB_GET_PROC_COEF, 0);
940 snd_hda_codec_write(codec, 0x1a, 0,
941 AC_VERB_SET_COEF_INDEX, 7);
942 snd_hda_codec_write(codec, 0x1a, 0,
943 AC_VERB_SET_PROC_COEF,
944 tmp | 0x2010);
945 break;
946 case 0x10ec0262:
947 case 0x10ec0880:
948 case 0x10ec0882:
949 case 0x10ec0883:
950 case 0x10ec0885:
Takashi Iwai20a3a052008-05-23 17:52:53 +0200951 case 0x10ec0889:
Kailang Yangc9b58002007-10-16 14:30:01 +0200952 snd_hda_codec_write(codec, 0x20, 0,
953 AC_VERB_SET_COEF_INDEX, 7);
954 tmp = snd_hda_codec_read(codec, 0x20, 0,
955 AC_VERB_GET_PROC_COEF, 0);
956 snd_hda_codec_write(codec, 0x20, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +0200957 AC_VERB_SET_COEF_INDEX, 7);
Kailang Yangc9b58002007-10-16 14:30:01 +0200958 snd_hda_codec_write(codec, 0x20, 0,
959 AC_VERB_SET_PROC_COEF,
960 tmp | 0x2010);
961 break;
Kailang Yangf9423e72008-05-27 12:32:25 +0200962 case 0x10ec0888:
Takashi Iwai1082c742008-08-22 15:24:22 +0200963 /*alc888_coef_init(codec);*/ /* called in alc_init() */
Kailang Yangf9423e72008-05-27 12:32:25 +0200964 break;
Kailang Yangc9b58002007-10-16 14:30:01 +0200965 case 0x10ec0267:
966 case 0x10ec0268:
967 snd_hda_codec_write(codec, 0x20, 0,
968 AC_VERB_SET_COEF_INDEX, 7);
969 tmp = snd_hda_codec_read(codec, 0x20, 0,
970 AC_VERB_GET_PROC_COEF, 0);
971 snd_hda_codec_write(codec, 0x20, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +0200972 AC_VERB_SET_COEF_INDEX, 7);
Kailang Yangc9b58002007-10-16 14:30:01 +0200973 snd_hda_codec_write(codec, 0x20, 0,
974 AC_VERB_SET_PROC_COEF,
975 tmp | 0x3000);
976 break;
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200977 }
Kailang Yangc9b58002007-10-16 14:30:01 +0200978 default:
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200979 break;
980 }
Kailang Yangea1fb292008-08-26 12:58:38 +0200981
Kailang Yang8c427222008-01-10 13:03:59 +0100982 /* is laptop or Desktop and enable the function "Mute internal speaker
Kailang Yangc9b58002007-10-16 14:30:01 +0200983 * when the external headphone out jack is plugged"
984 */
Kailang Yang8c427222008-01-10 13:03:59 +0100985 if (!(ass & 0x8000))
Kailang Yangc9b58002007-10-16 14:30:01 +0200986 return;
987 /*
988 * 10~8 : Jack location
989 * 12~11: Headphone out -> 00: PortA, 01: PortE, 02: PortD, 03: Resvered
990 * 14~13: Resvered
991 * 15 : 1 --> enable the function "Mute internal speaker
992 * when the external headphone out jack is plugged"
993 */
994 if (!spec->autocfg.speaker_pins[0]) {
Kailang Yang8c427222008-01-10 13:03:59 +0100995 if (spec->autocfg.line_out_pins[0])
Kailang Yangc9b58002007-10-16 14:30:01 +0200996 spec->autocfg.speaker_pins[0] =
Kailang Yang8c427222008-01-10 13:03:59 +0100997 spec->autocfg.line_out_pins[0];
Kailang Yangc9b58002007-10-16 14:30:01 +0200998 else
999 return;
1000 }
1001
1002 if (!spec->autocfg.hp_pins[0]) {
1003 tmp = (ass >> 11) & 0x3; /* HP to chassis */
1004 if (tmp == 0)
1005 spec->autocfg.hp_pins[0] = porta;
1006 else if (tmp == 1)
1007 spec->autocfg.hp_pins[0] = porte;
1008 else if (tmp == 2)
1009 spec->autocfg.hp_pins[0] = portd;
1010 else
1011 return;
1012 }
1013
1014 snd_hda_codec_write(codec, spec->autocfg.hp_pins[0], 0,
1015 AC_VERB_SET_UNSOLICITED_ENABLE,
1016 AC_USRSP_EN | ALC880_HP_EVENT);
Kailang Yangea1fb292008-08-26 12:58:38 +02001017
Kailang Yangc9b58002007-10-16 14:30:01 +02001018 spec->unsol_event = alc_sku_unsol_event;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001019}
1020
Takashi Iwai41e41f12005-06-08 14:48:49 +02001021/*
Takashi Iwaif95474e2007-07-10 00:47:43 +02001022 * Fix-up pin default configurations
1023 */
1024
1025struct alc_pincfg {
1026 hda_nid_t nid;
1027 u32 val;
1028};
1029
1030static void alc_fix_pincfg(struct hda_codec *codec,
1031 const struct snd_pci_quirk *quirk,
1032 const struct alc_pincfg **pinfix)
1033{
1034 const struct alc_pincfg *cfg;
1035
1036 quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk);
1037 if (!quirk)
1038 return;
1039
1040 cfg = pinfix[quirk->value];
1041 for (; cfg->nid; cfg++) {
1042 int i;
1043 u32 val = cfg->val;
1044 for (i = 0; i < 4; i++) {
1045 snd_hda_codec_write(codec, cfg->nid, 0,
1046 AC_VERB_SET_CONFIG_DEFAULT_BYTES_0 + i,
1047 val & 0xff);
1048 val >>= 8;
1049 }
1050 }
1051}
1052
1053/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001054 * ALC880 3-stack model
1055 *
1056 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0e)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001057 * Pin assignment: Front = 0x14, Line-In/Surr = 0x1a, Mic/CLFE = 0x18,
1058 * F-Mic = 0x1b, HP = 0x19
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 */
1060
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001061static hda_nid_t alc880_dac_nids[4] = {
1062 /* front, rear, clfe, rear_surr */
1063 0x02, 0x05, 0x04, 0x03
1064};
1065
1066static hda_nid_t alc880_adc_nids[3] = {
1067 /* ADC0-2 */
1068 0x07, 0x08, 0x09,
1069};
1070
1071/* The datasheet says the node 0x07 is connected from inputs,
1072 * but it shows zero connection in the real implementation on some devices.
Kailang Yangdf694da2005-12-05 19:42:22 +01001073 * Note: this is a 915GAV bug, fixed on 915GLV
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001075static hda_nid_t alc880_adc_nids_alt[2] = {
1076 /* ADC1-2 */
1077 0x08, 0x09,
1078};
1079
1080#define ALC880_DIGOUT_NID 0x06
1081#define ALC880_DIGIN_NID 0x0a
1082
1083static struct hda_input_mux alc880_capture_source = {
1084 .num_items = 4,
1085 .items = {
1086 { "Mic", 0x0 },
1087 { "Front Mic", 0x3 },
1088 { "Line", 0x2 },
1089 { "CD", 0x4 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001091};
1092
1093/* channel source setting (2/6 channel selection for 3-stack) */
1094/* 2ch mode */
1095static struct hda_verb alc880_threestack_ch2_init[] = {
1096 /* set line-in to input, mute it */
1097 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
1098 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1099 /* set mic-in to input vref 80%, mute it */
1100 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1101 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 { } /* end */
1103};
1104
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001105/* 6ch mode */
1106static struct hda_verb alc880_threestack_ch6_init[] = {
1107 /* set line-in to output, unmute it */
1108 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1109 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1110 /* set mic-in to output, unmute it */
1111 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1112 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1113 { } /* end */
1114};
1115
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001116static struct hda_channel_mode alc880_threestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001117 { 2, alc880_threestack_ch2_init },
1118 { 6, alc880_threestack_ch6_init },
1119};
1120
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001121static struct snd_kcontrol_new alc880_three_stack_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02001122 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001123 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02001124 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001125 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02001126 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1127 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001128 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1129 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1131 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1132 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1133 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1134 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1135 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1136 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
1137 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
1138 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
1139 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001141 {
1142 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1143 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01001144 .info = alc_ch_mode_info,
1145 .get = alc_ch_mode_get,
1146 .put = alc_ch_mode_put,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001147 },
1148 { } /* end */
1149};
1150
1151/* capture mixer elements */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001152static struct snd_kcontrol_new alc880_capture_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001153 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
1154 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
1155 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT),
1156 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT),
1157 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT),
1158 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT),
1159 {
1160 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1161 /* The multiple "Capture Source" controls confuse alsamixer
1162 * So call somewhat different..
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001163 */
1164 /* .name = "Capture Source", */
1165 .name = "Input Source",
1166 .count = 3,
1167 .info = alc_mux_enum_info,
1168 .get = alc_mux_enum_get,
1169 .put = alc_mux_enum_put,
1170 },
1171 { } /* end */
1172};
1173
1174/* capture mixer elements (in case NID 0x07 not available) */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001175static struct snd_kcontrol_new alc880_capture_alt_mixer[] = {
Takashi Iwai71fe7b82005-05-25 18:11:40 +02001176 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
1177 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
1178 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
1179 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180 {
1181 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1182 /* The multiple "Capture Source" controls confuse alsamixer
1183 * So call somewhat different..
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 */
1185 /* .name = "Capture Source", */
1186 .name = "Input Source",
1187 .count = 2,
1188 .info = alc_mux_enum_info,
1189 .get = alc_mux_enum_get,
1190 .put = alc_mux_enum_put,
1191 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192 { } /* end */
1193};
1194
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001195
1196
1197/*
1198 * ALC880 5-stack model
1199 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001200 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0d),
1201 * Side = 0x02 (0xd)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001202 * Pin assignment: Front = 0x14, Surr = 0x17, CLFE = 0x16
1203 * Line-In/Side = 0x1a, Mic = 0x18, F-Mic = 0x1b, HP = 0x19
1204 */
1205
1206/* additional mixers to alc880_three_stack_mixer */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001207static struct snd_kcontrol_new alc880_five_stack_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001208 HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001209 HDA_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210 { } /* end */
1211};
1212
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001213/* channel source setting (6/8 channel selection for 5-stack) */
1214/* 6ch mode */
1215static struct hda_verb alc880_fivestack_ch6_init[] = {
1216 /* set line-in to input, mute it */
1217 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
1218 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02001219 { } /* end */
1220};
1221
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001222/* 8ch mode */
1223static struct hda_verb alc880_fivestack_ch8_init[] = {
1224 /* set line-in to output, unmute it */
1225 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1226 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1227 { } /* end */
1228};
1229
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001230static struct hda_channel_mode alc880_fivestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001231 { 6, alc880_fivestack_ch6_init },
1232 { 8, alc880_fivestack_ch8_init },
1233};
1234
1235
1236/*
1237 * ALC880 6-stack model
1238 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001239 * DAC: Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e),
1240 * Side = 0x05 (0x0f)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001241 * Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, Side = 0x17,
1242 * Mic = 0x18, F-Mic = 0x19, Line = 0x1a, HP = 0x1b
1243 */
1244
1245static hda_nid_t alc880_6st_dac_nids[4] = {
1246 /* front, rear, clfe, rear_surr */
1247 0x02, 0x03, 0x04, 0x05
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02001248};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001249
1250static struct hda_input_mux alc880_6stack_capture_source = {
1251 .num_items = 4,
1252 .items = {
1253 { "Mic", 0x0 },
1254 { "Front Mic", 0x1 },
1255 { "Line", 0x2 },
1256 { "CD", 0x4 },
1257 },
1258};
1259
1260/* fixed 8-channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001261static struct hda_channel_mode alc880_sixstack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001262 { 8, NULL },
1263};
1264
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001265static struct snd_kcontrol_new alc880_six_stack_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001266 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001267 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001268 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001269 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001270 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1271 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001272 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1273 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001274 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001275 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001276 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1277 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1278 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1279 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1280 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1281 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1282 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1283 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
1284 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
1285 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001286 {
1287 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1288 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01001289 .info = alc_ch_mode_info,
1290 .get = alc_ch_mode_get,
1291 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02001292 },
1293 { } /* end */
1294};
1295
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001296
1297/*
1298 * ALC880 W810 model
1299 *
1300 * W810 has rear IO for:
1301 * Front (DAC 02)
1302 * Surround (DAC 03)
1303 * Center/LFE (DAC 04)
1304 * Digital out (06)
1305 *
1306 * The system also has a pair of internal speakers, and a headphone jack.
1307 * These are both connected to Line2 on the codec, hence to DAC 02.
Kailang Yangea1fb292008-08-26 12:58:38 +02001308 *
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001309 * There is a variable resistor to control the speaker or headphone
1310 * volume. This is a hardware-only device without a software API.
1311 *
1312 * Plugging headphones in will disable the internal speakers. This is
1313 * implemented in hardware, not via the driver using jack sense. In
1314 * a similar fashion, plugging into the rear socket marked "front" will
1315 * disable both the speakers and headphones.
1316 *
1317 * For input, there's a microphone jack, and an "audio in" jack.
1318 * These may not do anything useful with this driver yet, because I
1319 * haven't setup any initialization verbs for these yet...
1320 */
1321
1322static hda_nid_t alc880_w810_dac_nids[3] = {
1323 /* front, rear/surround, clfe */
1324 0x02, 0x03, 0x04
1325};
1326
1327/* fixed 6 channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001328static struct hda_channel_mode alc880_w810_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001329 { 6, NULL }
1330};
1331
1332/* Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, HP = 0x1b */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001333static struct snd_kcontrol_new alc880_w810_base_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001334 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001335 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001336 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001337 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001338 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1339 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001340 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1341 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001342 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
1343 { } /* end */
1344};
1345
1346
1347/*
1348 * Z710V model
1349 *
1350 * DAC: Front = 0x02 (0x0c), HP = 0x03 (0x0d)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001351 * Pin assignment: Front = 0x14, HP = 0x15, Mic = 0x18, Mic2 = 0x19(?),
1352 * Line = 0x1a
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001353 */
1354
1355static hda_nid_t alc880_z71v_dac_nids[1] = {
1356 0x02
1357};
1358#define ALC880_Z71V_HP_DAC 0x03
1359
1360/* fixed 2 channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001361static struct hda_channel_mode alc880_2_jack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001362 { 2, NULL }
1363};
1364
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001365static struct snd_kcontrol_new alc880_z71v_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001366 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001367 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001368 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001369 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001370 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1371 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1372 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1373 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1374 { } /* end */
1375};
1376
1377
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001378/*
1379 * ALC880 F1734 model
1380 *
1381 * DAC: HP = 0x02 (0x0c), Front = 0x03 (0x0d)
1382 * Pin assignment: HP = 0x14, Front = 0x15, Mic = 0x18
1383 */
1384
1385static hda_nid_t alc880_f1734_dac_nids[1] = {
1386 0x03
1387};
1388#define ALC880_F1734_HP_DAC 0x02
1389
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001390static struct snd_kcontrol_new alc880_f1734_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001391 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001392 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01001393 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1394 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001395 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1396 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Takashi Iwai937b4162008-02-11 14:52:36 +01001397 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1398 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001399 { } /* end */
1400};
1401
Takashi Iwai937b4162008-02-11 14:52:36 +01001402static struct hda_input_mux alc880_f1734_capture_source = {
1403 .num_items = 2,
1404 .items = {
1405 { "Mic", 0x1 },
1406 { "CD", 0x4 },
1407 },
1408};
1409
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001410
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001411/*
1412 * ALC880 ASUS model
1413 *
1414 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
1415 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
1416 * Mic = 0x18, Line = 0x1a
1417 */
1418
1419#define alc880_asus_dac_nids alc880_w810_dac_nids /* identical with w810 */
1420#define alc880_asus_modes alc880_threestack_modes /* 2/6 channel mode */
1421
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001422static struct snd_kcontrol_new alc880_asus_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001423 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001424 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001425 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001426 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001427 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1428 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001429 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1430 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001431 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1432 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1433 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1434 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1435 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1436 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001437 {
1438 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1439 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01001440 .info = alc_ch_mode_info,
1441 .get = alc_ch_mode_get,
1442 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02001443 },
1444 { } /* end */
1445};
1446
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001447/*
1448 * ALC880 ASUS W1V model
1449 *
1450 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
1451 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
1452 * Mic = 0x18, Line = 0x1a, Line2 = 0x1b
1453 */
1454
1455/* additional mixers to alc880_asus_mixer */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001456static struct snd_kcontrol_new alc880_asus_w1v_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001457 HDA_CODEC_VOLUME("Line2 Playback Volume", 0x0b, 0x03, HDA_INPUT),
1458 HDA_CODEC_MUTE("Line2 Playback Switch", 0x0b, 0x03, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001459 { } /* end */
1460};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001461
Takashi Iwai3c10a9d2005-08-23 20:02:27 +02001462/* additional mixers to alc880_asus_mixer */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001463static struct snd_kcontrol_new alc880_pcbeep_mixer[] = {
Takashi Iwai3c10a9d2005-08-23 20:02:27 +02001464 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
1465 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
1466 { } /* end */
1467};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001468
Kailang Yangdf694da2005-12-05 19:42:22 +01001469/* TCL S700 */
1470static struct snd_kcontrol_new alc880_tcl_s700_mixer[] = {
1471 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1472 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
1473 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
1474 HDA_CODEC_VOLUME("CD Playback Volume", 0x0B, 0x04, HDA_INPUT),
1475 HDA_CODEC_MUTE("CD Playback Switch", 0x0B, 0x04, HDA_INPUT),
1476 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0B, 0x0, HDA_INPUT),
1477 HDA_CODEC_MUTE("Mic Playback Switch", 0x0B, 0x0, HDA_INPUT),
1478 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
1479 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
1480 {
1481 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1482 /* The multiple "Capture Source" controls confuse alsamixer
1483 * So call somewhat different..
Kailang Yangdf694da2005-12-05 19:42:22 +01001484 */
1485 /* .name = "Capture Source", */
1486 .name = "Input Source",
1487 .count = 1,
1488 .info = alc_mux_enum_info,
1489 .get = alc_mux_enum_get,
1490 .put = alc_mux_enum_put,
1491 },
1492 { } /* end */
1493};
1494
Kailang Yangccc656c2006-10-17 12:32:26 +02001495/* Uniwill */
1496static struct snd_kcontrol_new alc880_uniwill_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01001497 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1498 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
1499 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1500 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02001501 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1502 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
1503 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1504 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
1505 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1506 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1507 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1508 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1509 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1510 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1511 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1512 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
1513 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
1514 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
1515 {
1516 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1517 .name = "Channel Mode",
1518 .info = alc_ch_mode_info,
1519 .get = alc_ch_mode_get,
1520 .put = alc_ch_mode_put,
1521 },
1522 { } /* end */
1523};
1524
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01001525static struct snd_kcontrol_new alc880_fujitsu_mixer[] = {
1526 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1527 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
1528 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1529 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
1530 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1531 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1532 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1533 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1534 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1535 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
1536 { } /* end */
1537};
1538
Kailang Yangccc656c2006-10-17 12:32:26 +02001539static struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01001540 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1541 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
1542 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1543 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02001544 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1545 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1546 { } /* end */
1547};
1548
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549/*
Takashi Iwai2134ea42008-01-10 16:53:55 +01001550 * virtual master controls
1551 */
1552
1553/*
1554 * slave controls for virtual master
1555 */
1556static const char *alc_slave_vols[] = {
1557 "Front Playback Volume",
1558 "Surround Playback Volume",
1559 "Center Playback Volume",
1560 "LFE Playback Volume",
1561 "Side Playback Volume",
1562 "Headphone Playback Volume",
1563 "Speaker Playback Volume",
1564 "Mono Playback Volume",
Takashi Iwai2134ea42008-01-10 16:53:55 +01001565 "Line-Out Playback Volume",
1566 NULL,
1567};
1568
1569static const char *alc_slave_sws[] = {
1570 "Front Playback Switch",
1571 "Surround Playback Switch",
1572 "Center Playback Switch",
1573 "LFE Playback Switch",
1574 "Side Playback Switch",
1575 "Headphone Playback Switch",
1576 "Speaker Playback Switch",
1577 "Mono Playback Switch",
Takashi Iwaiedb54a52008-01-29 12:47:02 +01001578 "IEC958 Playback Switch",
Takashi Iwai2134ea42008-01-10 16:53:55 +01001579 NULL,
1580};
1581
1582/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001583 * build control elements
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584 */
1585static int alc_build_controls(struct hda_codec *codec)
1586{
1587 struct alc_spec *spec = codec->spec;
1588 int err;
1589 int i;
1590
1591 for (i = 0; i < spec->num_mixers; i++) {
1592 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
1593 if (err < 0)
1594 return err;
1595 }
1596
1597 if (spec->multiout.dig_out_nid) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001598 err = snd_hda_create_spdif_out_ctls(codec,
1599 spec->multiout.dig_out_nid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600 if (err < 0)
1601 return err;
Takashi Iwai9a081602008-02-12 18:37:26 +01001602 err = snd_hda_create_spdif_share_sw(codec,
1603 &spec->multiout);
1604 if (err < 0)
1605 return err;
1606 spec->multiout.share_spdif = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607 }
1608 if (spec->dig_in_nid) {
1609 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
1610 if (err < 0)
1611 return err;
1612 }
Takashi Iwai2134ea42008-01-10 16:53:55 +01001613
1614 /* if we have no master control, let's create it */
1615 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001616 unsigned int vmaster_tlv[4];
Takashi Iwai2134ea42008-01-10 16:53:55 +01001617 snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001618 HDA_OUTPUT, vmaster_tlv);
Takashi Iwai2134ea42008-01-10 16:53:55 +01001619 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001620 vmaster_tlv, alc_slave_vols);
Takashi Iwai2134ea42008-01-10 16:53:55 +01001621 if (err < 0)
1622 return err;
1623 }
1624 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
1625 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
1626 NULL, alc_slave_sws);
1627 if (err < 0)
1628 return err;
1629 }
1630
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 return 0;
1632}
1633
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001634
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635/*
1636 * initialize the codec volumes, etc
1637 */
1638
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001639/*
1640 * generic initialization of ADC, input mixers and output mixers
1641 */
1642static struct hda_verb alc880_volume_init_verbs[] = {
1643 /*
1644 * Unmute ADC0-2 and set the default input to mic-in
1645 */
Takashi Iwai71fe7b82005-05-25 18:11:40 +02001646 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001647 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02001648 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001649 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02001650 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001651 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001653 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
1654 * mixer widget
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001655 * Note: PASD motherboards uses the Line In 2 as the input for front
1656 * panel mic (mic 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001658 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02001659 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1660 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
1661 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
1662 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
1663 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
1664 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
1665 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001667 /*
1668 * Set up output mixers (0x0c - 0x0f)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001670 /* set vol=0 to output mixers */
1671 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1672 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1673 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1674 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1675 /* set up input amps for analog loopback */
1676 /* Amp Indices: DAC = 0, mixer = 1 */
Takashi Iwai05acb862005-06-10 19:50:25 +02001677 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1678 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02001679 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1680 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02001681 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1682 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02001683 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1684 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685
1686 { }
1687};
1688
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001689/*
1690 * 3-stack pin configuration:
1691 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
1692 */
1693static struct hda_verb alc880_pin_3stack_init_verbs[] = {
1694 /*
1695 * preset connection lists of input pins
1696 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
1697 */
1698 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
1699 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1700 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
1701
1702 /*
1703 * Set pin mode and muting
1704 */
1705 /* set front pin widgets 0x14 for output */
1706 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1707 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1708 /* Mic1 (rear panel) pin widget for input and vref at 80% */
1709 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1710 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1711 /* Mic2 (as headphone out) for HP output */
1712 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1713 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1714 /* Line In pin widget for input */
1715 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1716 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1717 /* Line2 (as front mic) pin widget for input and vref at 80% */
1718 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1719 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1720 /* CD pin widget for input */
1721 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1722
1723 { }
1724};
1725
1726/*
1727 * 5-stack pin configuration:
1728 * front = 0x14, surround = 0x17, clfe = 0x16, mic = 0x18, HP = 0x19,
1729 * line-in/side = 0x1a, f-mic = 0x1b
1730 */
1731static struct hda_verb alc880_pin_5stack_init_verbs[] = {
1732 /*
1733 * preset connection lists of input pins
1734 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
1735 */
1736 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1737 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/side */
1738
1739 /*
1740 * Set pin mode and muting
1741 */
1742 /* set pin widgets 0x14-0x17 for output */
Takashi Iwai05acb862005-06-10 19:50:25 +02001743 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1744 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1745 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1746 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001747 /* unmute pins for output (no gain on this amp) */
1748 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1749 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1750 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1751 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1752
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02001754 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001755 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1756 /* Mic2 (as headphone out) for HP output */
1757 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02001758 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001759 /* Line In pin widget for input */
1760 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1761 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1762 /* Line2 (as front mic) pin widget for input and vref at 80% */
1763 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1764 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1765 /* CD pin widget for input */
1766 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767
1768 { }
1769};
1770
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001771/*
1772 * W810 pin configuration:
1773 * front = 0x14, surround = 0x15, clfe = 0x16, HP = 0x1b
1774 */
1775static struct hda_verb alc880_pin_w810_init_verbs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776 /* hphone/speaker input selector: front DAC */
1777 {0x13, AC_VERB_SET_CONNECT_SEL, 0x0},
1778
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001779 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1780 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1781 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1782 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1783 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1784 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1785
1786 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02001787 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789 { }
1790};
1791
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001792/*
1793 * Z71V pin configuration:
1794 * Speaker-out = 0x14, HP = 0x15, Mic = 0x18, Line-in = 0x1a, Mic2 = 0x1b (?)
1795 */
1796static struct hda_verb alc880_pin_z71v_init_verbs[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02001797 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001798 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai05acb862005-06-10 19:50:25 +02001799 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001800 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02001801
Takashi Iwai16ded522005-06-10 19:58:24 +02001802 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001803 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02001804 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001805 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02001806
1807 { }
1808};
1809
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001810/*
1811 * 6-stack pin configuration:
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001812 * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18,
1813 * f-mic = 0x19, line = 0x1a, HP = 0x1b
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001814 */
1815static struct hda_verb alc880_pin_6stack_init_verbs[] = {
1816 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1817
Takashi Iwai16ded522005-06-10 19:58:24 +02001818 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001819 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001820 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001821 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001822 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001823 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001824 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001825 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1826
Takashi Iwai16ded522005-06-10 19:58:24 +02001827 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001828 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001829 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001830 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001831 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001832 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001833 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai16ded522005-06-10 19:58:24 +02001834 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001835 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangea1fb292008-08-26 12:58:38 +02001836
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001837 { }
1838};
Takashi Iwai16ded522005-06-10 19:58:24 +02001839
Kailang Yangccc656c2006-10-17 12:32:26 +02001840/*
1841 * Uniwill pin configuration:
1842 * HP = 0x14, InternalSpeaker = 0x15, mic = 0x18, internal mic = 0x19,
1843 * line = 0x1a
1844 */
1845static struct hda_verb alc880_uniwill_init_verbs[] = {
1846 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1847
1848 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1849 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1850 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1851 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1852 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1853 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1854 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1855 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1856 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1857 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1858 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1859 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1860 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1861 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1862
1863 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1864 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1865 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1866 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1867 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1868 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1869 /* {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, */
1870 /* {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
1871 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1872
1873 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
1874 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
1875
1876 { }
1877};
1878
1879/*
1880* Uniwill P53
Kailang Yangea1fb292008-08-26 12:58:38 +02001881* HP = 0x14, InternalSpeaker = 0x15, mic = 0x19,
Kailang Yangccc656c2006-10-17 12:32:26 +02001882 */
1883static struct hda_verb alc880_uniwill_p53_init_verbs[] = {
1884 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1885
1886 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1887 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1888 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1889 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1890 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1891 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1892 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1893 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1894 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1895 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1896 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1897 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1898
1899 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1900 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1901 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1902 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1903 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1904 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1905
1906 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
1907 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_DCVOL_EVENT},
1908
1909 { }
1910};
1911
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01001912static struct hda_verb alc880_beep_init_verbs[] = {
1913 { 0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) },
1914 { }
1915};
1916
Kailang Yangccc656c2006-10-17 12:32:26 +02001917/* toggle speaker-output according to the hp-jack state */
Takashi Iwai458a4fa2007-05-05 12:18:40 +02001918static void alc880_uniwill_hp_automute(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02001919{
1920 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02001921 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02001922
1923 present = snd_hda_codec_read(codec, 0x14, 0,
1924 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02001925 bits = present ? HDA_AMP_MUTE : 0;
1926 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
1927 HDA_AMP_MUTE, bits);
1928 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
1929 HDA_AMP_MUTE, bits);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02001930}
1931
1932/* auto-toggle front mic */
1933static void alc880_uniwill_mic_automute(struct hda_codec *codec)
1934{
1935 unsigned int present;
1936 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02001937
1938 present = snd_hda_codec_read(codec, 0x18, 0,
1939 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02001940 bits = present ? HDA_AMP_MUTE : 0;
1941 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02001942}
1943
1944static void alc880_uniwill_automute(struct hda_codec *codec)
1945{
1946 alc880_uniwill_hp_automute(codec);
1947 alc880_uniwill_mic_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02001948}
1949
1950static void alc880_uniwill_unsol_event(struct hda_codec *codec,
1951 unsigned int res)
1952{
1953 /* Looks like the unsol event is incompatible with the standard
1954 * definition. 4bit tag is placed at 28 bit!
1955 */
Takashi Iwai458a4fa2007-05-05 12:18:40 +02001956 switch (res >> 28) {
1957 case ALC880_HP_EVENT:
1958 alc880_uniwill_hp_automute(codec);
1959 break;
1960 case ALC880_MIC_EVENT:
1961 alc880_uniwill_mic_automute(codec);
1962 break;
1963 }
Kailang Yangccc656c2006-10-17 12:32:26 +02001964}
1965
1966static void alc880_uniwill_p53_hp_automute(struct hda_codec *codec)
1967{
1968 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02001969 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02001970
1971 present = snd_hda_codec_read(codec, 0x14, 0,
1972 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02001973 bits = present ? HDA_AMP_MUTE : 0;
Jiang zhe64654c22008-04-14 13:26:21 +02001974 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, HDA_AMP_MUTE, bits);
Kailang Yangccc656c2006-10-17 12:32:26 +02001975}
1976
1977static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec)
1978{
1979 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02001980
Kailang Yangccc656c2006-10-17 12:32:26 +02001981 present = snd_hda_codec_read(codec, 0x21, 0,
Takashi Iwai47fd8302007-08-10 17:11:07 +02001982 AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
1983 present &= HDA_AMP_VOLMASK;
1984 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0,
1985 HDA_AMP_VOLMASK, present);
1986 snd_hda_codec_amp_stereo(codec, 0x0d, HDA_OUTPUT, 0,
1987 HDA_AMP_VOLMASK, present);
Kailang Yangccc656c2006-10-17 12:32:26 +02001988}
Takashi Iwai47fd8302007-08-10 17:11:07 +02001989
Kailang Yangccc656c2006-10-17 12:32:26 +02001990static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec,
1991 unsigned int res)
1992{
1993 /* Looks like the unsol event is incompatible with the standard
1994 * definition. 4bit tag is placed at 28 bit!
1995 */
1996 if ((res >> 28) == ALC880_HP_EVENT)
1997 alc880_uniwill_p53_hp_automute(codec);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02001998 if ((res >> 28) == ALC880_DCVOL_EVENT)
Kailang Yangccc656c2006-10-17 12:32:26 +02001999 alc880_uniwill_p53_dcvol_automute(codec);
2000}
2001
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002002/*
2003 * F1734 pin configuration:
2004 * HP = 0x14, speaker-out = 0x15, mic = 0x18
2005 */
2006static struct hda_verb alc880_pin_f1734_init_verbs[] = {
Michael Gruberee7a9c72008-03-10 11:30:59 +01002007 {0x07, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002008 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
2009 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
2010 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
2011 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
2012
2013 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2014 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2015 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2016 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2017
2018 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2019 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Michael Gruberee7a9c72008-03-10 11:30:59 +01002020 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002021 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2022 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2023 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2024 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2025 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2026 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02002027
Takashi Iwai937b4162008-02-11 14:52:36 +01002028 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
2029 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_DCVOL_EVENT},
2030
Takashi Iwai16ded522005-06-10 19:58:24 +02002031 { }
2032};
2033
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002034/*
2035 * ASUS pin configuration:
2036 * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a
2037 */
2038static struct hda_verb alc880_pin_asus_init_verbs[] = {
2039 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
2040 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
2041 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
2042 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
2043
2044 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2045 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2046 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2047 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2048 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2049 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2050 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2051 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2052
2053 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2054 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2055 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2056 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2057 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2058 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2059 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2060 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2061 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangea1fb292008-08-26 12:58:38 +02002062
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002063 { }
2064};
2065
2066/* Enable GPIO mask and set output */
Kailang Yangbc9f98a2007-04-12 13:06:07 +02002067#define alc880_gpio1_init_verbs alc_gpio1_init_verbs
2068#define alc880_gpio2_init_verbs alc_gpio2_init_verbs
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002069
Kailang Yangdf694da2005-12-05 19:42:22 +01002070/* Clevo m520g init */
2071static struct hda_verb alc880_pin_clevo_init_verbs[] = {
2072 /* headphone output */
2073 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
2074 /* line-out */
2075 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2076 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2077 /* Line-in */
2078 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2079 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2080 /* CD */
2081 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2082 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2083 /* Mic1 (rear panel) */
2084 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2085 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2086 /* Mic2 (front panel) */
2087 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2088 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2089 /* headphone */
2090 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2091 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2092 /* change to EAPD mode */
2093 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
2094 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
2095
2096 { }
2097};
2098
2099static struct hda_verb alc880_pin_tcl_S700_init_verbs[] = {
Takashi Iwai4b146cb2006-07-28 14:42:36 +02002100 /* change to EAPD mode */
2101 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
2102 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
2103
Kailang Yangdf694da2005-12-05 19:42:22 +01002104 /* Headphone output */
2105 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2106 /* Front output*/
2107 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2108 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
2109
2110 /* Line In pin widget for input */
2111 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2112 /* CD pin widget for input */
2113 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2114 /* Mic1 (rear panel) pin widget for input and vref at 80% */
2115 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2116
2117 /* change to EAPD mode */
2118 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
2119 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
2120
2121 { }
2122};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002123
2124/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002125 * LG m1 express dual
2126 *
2127 * Pin assignment:
2128 * Rear Line-In/Out (blue): 0x14
2129 * Build-in Mic-In: 0x15
2130 * Speaker-out: 0x17
2131 * HP-Out (green): 0x1b
2132 * Mic-In/Out (red): 0x19
2133 * SPDIF-Out: 0x1e
2134 */
2135
2136/* To make 5.1 output working (green=Front, blue=Surr, red=CLFE) */
2137static hda_nid_t alc880_lg_dac_nids[3] = {
2138 0x05, 0x02, 0x03
2139};
2140
2141/* seems analog CD is not working */
2142static struct hda_input_mux alc880_lg_capture_source = {
2143 .num_items = 3,
2144 .items = {
2145 { "Mic", 0x1 },
2146 { "Line", 0x5 },
2147 { "Internal Mic", 0x6 },
2148 },
2149};
2150
2151/* 2,4,6 channel modes */
2152static struct hda_verb alc880_lg_ch2_init[] = {
2153 /* set line-in and mic-in to input */
2154 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2155 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2156 { }
2157};
2158
2159static struct hda_verb alc880_lg_ch4_init[] = {
2160 /* set line-in to out and mic-in to input */
2161 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
2162 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2163 { }
2164};
2165
2166static struct hda_verb alc880_lg_ch6_init[] = {
2167 /* set line-in and mic-in to output */
2168 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
2169 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
2170 { }
2171};
2172
2173static struct hda_channel_mode alc880_lg_ch_modes[3] = {
2174 { 2, alc880_lg_ch2_init },
2175 { 4, alc880_lg_ch4_init },
2176 { 6, alc880_lg_ch6_init },
2177};
2178
2179static struct snd_kcontrol_new alc880_lg_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01002180 HDA_CODEC_VOLUME("Front Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
2181 HDA_BIND_MUTE("Front Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002182 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2183 HDA_BIND_MUTE("Surround Playback Switch", 0x0c, 2, HDA_INPUT),
2184 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
2185 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
2186 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
2187 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
2188 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2189 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
2190 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x06, HDA_INPUT),
2191 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x06, HDA_INPUT),
2192 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x07, HDA_INPUT),
2193 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x07, HDA_INPUT),
2194 {
2195 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2196 .name = "Channel Mode",
2197 .info = alc_ch_mode_info,
2198 .get = alc_ch_mode_get,
2199 .put = alc_ch_mode_put,
2200 },
2201 { } /* end */
2202};
2203
2204static struct hda_verb alc880_lg_init_verbs[] = {
2205 /* set capture source to mic-in */
2206 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2207 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2208 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2209 /* mute all amp mixer inputs */
2210 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02002211 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
2212 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002213 /* line-in to input */
2214 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2215 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2216 /* built-in mic */
2217 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2218 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2219 /* speaker-out */
2220 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2221 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2222 /* mic-in to input */
2223 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
2224 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2225 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2226 /* HP-out */
2227 {0x13, AC_VERB_SET_CONNECT_SEL, 0x03},
2228 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2229 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2230 /* jack sense */
2231 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | 0x1},
2232 { }
2233};
2234
2235/* toggle speaker-output according to the hp-jack state */
2236static void alc880_lg_automute(struct hda_codec *codec)
2237{
2238 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002239 unsigned char bits;
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002240
2241 present = snd_hda_codec_read(codec, 0x1b, 0,
2242 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02002243 bits = present ? HDA_AMP_MUTE : 0;
2244 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
2245 HDA_AMP_MUTE, bits);
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002246}
2247
2248static void alc880_lg_unsol_event(struct hda_codec *codec, unsigned int res)
2249{
2250 /* Looks like the unsol event is incompatible with the standard
2251 * definition. 4bit tag is placed at 28 bit!
2252 */
2253 if ((res >> 28) == 0x01)
2254 alc880_lg_automute(codec);
2255}
2256
2257/*
Takashi Iwaid6815182006-03-23 16:06:23 +01002258 * LG LW20
2259 *
2260 * Pin assignment:
2261 * Speaker-out: 0x14
2262 * Mic-In: 0x18
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02002263 * Built-in Mic-In: 0x19
2264 * Line-In: 0x1b
2265 * HP-Out: 0x1a
Takashi Iwaid6815182006-03-23 16:06:23 +01002266 * SPDIF-Out: 0x1e
2267 */
2268
Takashi Iwaid6815182006-03-23 16:06:23 +01002269static struct hda_input_mux alc880_lg_lw_capture_source = {
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02002270 .num_items = 3,
Takashi Iwaid6815182006-03-23 16:06:23 +01002271 .items = {
2272 { "Mic", 0x0 },
2273 { "Internal Mic", 0x1 },
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02002274 { "Line In", 0x2 },
Takashi Iwaid6815182006-03-23 16:06:23 +01002275 },
2276};
2277
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002278#define alc880_lg_lw_modes alc880_threestack_modes
2279
Takashi Iwaid6815182006-03-23 16:06:23 +01002280static struct snd_kcontrol_new alc880_lg_lw_mixer[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002281 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2282 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
2283 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
2284 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
2285 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2286 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
2287 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2288 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
2289 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2290 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaid6815182006-03-23 16:06:23 +01002291 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2292 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2293 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
2294 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002295 {
2296 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2297 .name = "Channel Mode",
2298 .info = alc_ch_mode_info,
2299 .get = alc_ch_mode_get,
2300 .put = alc_ch_mode_put,
2301 },
Takashi Iwaid6815182006-03-23 16:06:23 +01002302 { } /* end */
2303};
2304
2305static struct hda_verb alc880_lg_lw_init_verbs[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002306 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2307 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
2308 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
2309
Takashi Iwaid6815182006-03-23 16:06:23 +01002310 /* set capture source to mic-in */
2311 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2312 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2313 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02002314 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaid6815182006-03-23 16:06:23 +01002315 /* speaker-out */
2316 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2317 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2318 /* HP-out */
Takashi Iwaid6815182006-03-23 16:06:23 +01002319 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2320 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2321 /* mic-in to input */
2322 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2323 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2324 /* built-in mic */
2325 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2326 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2327 /* jack sense */
2328 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | 0x1},
2329 { }
2330};
2331
2332/* toggle speaker-output according to the hp-jack state */
2333static void alc880_lg_lw_automute(struct hda_codec *codec)
2334{
2335 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002336 unsigned char bits;
Takashi Iwaid6815182006-03-23 16:06:23 +01002337
2338 present = snd_hda_codec_read(codec, 0x1b, 0,
2339 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02002340 bits = present ? HDA_AMP_MUTE : 0;
2341 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
2342 HDA_AMP_MUTE, bits);
Takashi Iwaid6815182006-03-23 16:06:23 +01002343}
2344
2345static void alc880_lg_lw_unsol_event(struct hda_codec *codec, unsigned int res)
2346{
2347 /* Looks like the unsol event is incompatible with the standard
2348 * definition. 4bit tag is placed at 28 bit!
2349 */
2350 if ((res >> 28) == 0x01)
2351 alc880_lg_lw_automute(codec);
2352}
2353
Takashi Iwaidf99cd32008-04-25 15:25:04 +02002354static struct snd_kcontrol_new alc880_medion_rim_mixer[] = {
2355 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2356 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
2357 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2358 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2359 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2360 HDA_CODEC_MUTE("Internal Playback Switch", 0x0b, 0x1, HDA_INPUT),
2361 { } /* end */
2362};
2363
2364static struct hda_input_mux alc880_medion_rim_capture_source = {
2365 .num_items = 2,
2366 .items = {
2367 { "Mic", 0x0 },
2368 { "Internal Mic", 0x1 },
2369 },
2370};
2371
2372static struct hda_verb alc880_medion_rim_init_verbs[] = {
2373 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2374
2375 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2376 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2377
2378 /* Mic1 (rear panel) pin widget for input and vref at 80% */
2379 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2380 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2381 /* Mic2 (as headphone out) for HP output */
2382 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2383 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2384 /* Internal Speaker */
2385 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2386 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2387
2388 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
2389 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
2390
2391 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
2392 { }
2393};
2394
2395/* toggle speaker-output according to the hp-jack state */
2396static void alc880_medion_rim_automute(struct hda_codec *codec)
2397{
2398 unsigned int present;
2399 unsigned char bits;
2400
2401 present = snd_hda_codec_read(codec, 0x14, 0,
2402 AC_VERB_GET_PIN_SENSE, 0)
2403 & AC_PINSENSE_PRESENCE;
2404 bits = present ? HDA_AMP_MUTE : 0;
2405 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
2406 HDA_AMP_MUTE, bits);
2407 if (present)
2408 snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0);
2409 else
2410 snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 2);
2411}
2412
2413static void alc880_medion_rim_unsol_event(struct hda_codec *codec,
2414 unsigned int res)
2415{
2416 /* Looks like the unsol event is incompatible with the standard
2417 * definition. 4bit tag is placed at 28 bit!
2418 */
2419 if ((res >> 28) == ALC880_HP_EVENT)
2420 alc880_medion_rim_automute(codec);
2421}
2422
Takashi Iwaicb53c622007-08-10 17:21:45 +02002423#ifdef CONFIG_SND_HDA_POWER_SAVE
2424static struct hda_amp_list alc880_loopbacks[] = {
2425 { 0x0b, HDA_INPUT, 0 },
2426 { 0x0b, HDA_INPUT, 1 },
2427 { 0x0b, HDA_INPUT, 2 },
2428 { 0x0b, HDA_INPUT, 3 },
2429 { 0x0b, HDA_INPUT, 4 },
2430 { } /* end */
2431};
2432
2433static struct hda_amp_list alc880_lg_loopbacks[] = {
2434 { 0x0b, HDA_INPUT, 1 },
2435 { 0x0b, HDA_INPUT, 6 },
2436 { 0x0b, HDA_INPUT, 7 },
2437 { } /* end */
2438};
2439#endif
2440
Takashi Iwaid6815182006-03-23 16:06:23 +01002441/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002442 * Common callbacks
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002443 */
Takashi Iwai16ded522005-06-10 19:58:24 +02002444
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445static int alc_init(struct hda_codec *codec)
2446{
2447 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002448 unsigned int i;
2449
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02002450 alc_fix_pll(codec);
Takashi Iwai1082c742008-08-22 15:24:22 +02002451 if (codec->vendor_id == 0x10ec0888)
2452 alc888_coef_init(codec);
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02002453
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002454 for (i = 0; i < spec->num_init_verbs; i++)
2455 snd_hda_sequence_write(codec, spec->init_verbs[i]);
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002456
2457 if (spec->init_hook)
2458 spec->init_hook(codec);
2459
Linus Torvalds1da177e2005-04-16 15:20:36 -07002460 return 0;
2461}
2462
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002463static void alc_unsol_event(struct hda_codec *codec, unsigned int res)
2464{
2465 struct alc_spec *spec = codec->spec;
2466
2467 if (spec->unsol_event)
2468 spec->unsol_event(codec, res);
2469}
2470
Takashi Iwaicb53c622007-08-10 17:21:45 +02002471#ifdef CONFIG_SND_HDA_POWER_SAVE
2472static int alc_check_power_status(struct hda_codec *codec, hda_nid_t nid)
2473{
2474 struct alc_spec *spec = codec->spec;
2475 return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
2476}
2477#endif
2478
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479/*
2480 * Analog playback callbacks
2481 */
2482static int alc880_playback_pcm_open(struct hda_pcm_stream *hinfo,
2483 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002484 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002485{
2486 struct alc_spec *spec = codec->spec;
Takashi Iwai9a081602008-02-12 18:37:26 +01002487 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
2488 hinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002489}
2490
2491static int alc880_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
2492 struct hda_codec *codec,
2493 unsigned int stream_tag,
2494 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002495 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002496{
2497 struct alc_spec *spec = codec->spec;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002498 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
2499 stream_tag, format, substream);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500}
2501
2502static int alc880_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
2503 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002504 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002505{
2506 struct alc_spec *spec = codec->spec;
2507 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
2508}
2509
2510/*
2511 * Digital out
2512 */
2513static int alc880_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
2514 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002515 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002516{
2517 struct alc_spec *spec = codec->spec;
2518 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
2519}
2520
Takashi Iwai6b97eb42007-04-05 14:51:48 +02002521static int alc880_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
2522 struct hda_codec *codec,
2523 unsigned int stream_tag,
2524 unsigned int format,
2525 struct snd_pcm_substream *substream)
2526{
2527 struct alc_spec *spec = codec->spec;
2528 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
2529 stream_tag, format, substream);
2530}
2531
Linus Torvalds1da177e2005-04-16 15:20:36 -07002532static int alc880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
2533 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002534 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002535{
2536 struct alc_spec *spec = codec->spec;
2537 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
2538}
2539
2540/*
2541 * Analog capture
2542 */
Takashi Iwai63300792008-01-24 15:31:36 +01002543static int alc880_alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002544 struct hda_codec *codec,
2545 unsigned int stream_tag,
2546 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002547 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002548{
2549 struct alc_spec *spec = codec->spec;
2550
Takashi Iwai63300792008-01-24 15:31:36 +01002551 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1],
Linus Torvalds1da177e2005-04-16 15:20:36 -07002552 stream_tag, 0, format);
2553 return 0;
2554}
2555
Takashi Iwai63300792008-01-24 15:31:36 +01002556static int alc880_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002557 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002558 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002559{
2560 struct alc_spec *spec = codec->spec;
2561
Takashi Iwai888afa12008-03-18 09:57:50 +01002562 snd_hda_codec_cleanup_stream(codec,
2563 spec->adc_nids[substream->number + 1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002564 return 0;
2565}
2566
2567
2568/*
2569 */
2570static struct hda_pcm_stream alc880_pcm_analog_playback = {
2571 .substreams = 1,
2572 .channels_min = 2,
2573 .channels_max = 8,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002574 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002575 .ops = {
2576 .open = alc880_playback_pcm_open,
2577 .prepare = alc880_playback_pcm_prepare,
2578 .cleanup = alc880_playback_pcm_cleanup
2579 },
2580};
2581
2582static struct hda_pcm_stream alc880_pcm_analog_capture = {
Takashi Iwai63300792008-01-24 15:31:36 +01002583 .substreams = 1,
2584 .channels_min = 2,
2585 .channels_max = 2,
2586 /* NID is set in alc_build_pcms */
2587};
2588
2589static struct hda_pcm_stream alc880_pcm_analog_alt_playback = {
2590 .substreams = 1,
2591 .channels_min = 2,
2592 .channels_max = 2,
2593 /* NID is set in alc_build_pcms */
2594};
2595
2596static struct hda_pcm_stream alc880_pcm_analog_alt_capture = {
2597 .substreams = 2, /* can be overridden */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002598 .channels_min = 2,
2599 .channels_max = 2,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002600 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002601 .ops = {
Takashi Iwai63300792008-01-24 15:31:36 +01002602 .prepare = alc880_alt_capture_pcm_prepare,
2603 .cleanup = alc880_alt_capture_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604 },
2605};
2606
2607static struct hda_pcm_stream alc880_pcm_digital_playback = {
2608 .substreams = 1,
2609 .channels_min = 2,
2610 .channels_max = 2,
2611 /* NID is set in alc_build_pcms */
2612 .ops = {
2613 .open = alc880_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02002614 .close = alc880_dig_playback_pcm_close,
2615 .prepare = alc880_dig_playback_pcm_prepare
Linus Torvalds1da177e2005-04-16 15:20:36 -07002616 },
2617};
2618
2619static struct hda_pcm_stream alc880_pcm_digital_capture = {
2620 .substreams = 1,
2621 .channels_min = 2,
2622 .channels_max = 2,
2623 /* NID is set in alc_build_pcms */
2624};
2625
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01002626/* Used by alc_build_pcms to flag that a PCM has no playback stream */
Takashi Iwai63300792008-01-24 15:31:36 +01002627static struct hda_pcm_stream alc_pcm_null_stream = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01002628 .substreams = 0,
2629 .channels_min = 0,
2630 .channels_max = 0,
2631};
2632
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633static int alc_build_pcms(struct hda_codec *codec)
2634{
2635 struct alc_spec *spec = codec->spec;
2636 struct hda_pcm *info = spec->pcm_rec;
2637 int i;
2638
2639 codec->num_pcms = 1;
2640 codec->pcm_info = info;
2641
2642 info->name = spec->stream_name_analog;
Takashi Iwai4a471b72005-12-07 13:56:29 +01002643 if (spec->stream_analog_playback) {
Takashi Iwaida3cec32008-08-08 17:12:14 +02002644 if (snd_BUG_ON(!spec->multiout.dac_nids))
2645 return -EINVAL;
Takashi Iwai4a471b72005-12-07 13:56:29 +01002646 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
2647 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
2648 }
2649 if (spec->stream_analog_capture) {
Takashi Iwaida3cec32008-08-08 17:12:14 +02002650 if (snd_BUG_ON(!spec->adc_nids))
2651 return -EINVAL;
Takashi Iwai4a471b72005-12-07 13:56:29 +01002652 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
2653 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
2654 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655
Takashi Iwai4a471b72005-12-07 13:56:29 +01002656 if (spec->channel_mode) {
2657 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0;
2658 for (i = 0; i < spec->num_channel_mode; i++) {
2659 if (spec->channel_mode[i].channels > info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max) {
2660 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->channel_mode[i].channels;
2661 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002662 }
2663 }
2664
Takashi Iwaie08a0072006-09-07 17:52:14 +02002665 /* SPDIF for stream index #1 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002666 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
Takashi Iwaie08a0072006-09-07 17:52:14 +02002667 codec->num_pcms = 2;
Takashi Iwaic06134d2006-10-11 18:49:13 +02002668 info = spec->pcm_rec + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669 info->name = spec->stream_name_digital;
Takashi Iwai7ba72ba2008-02-06 14:03:20 +01002670 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Takashi Iwai4a471b72005-12-07 13:56:29 +01002671 if (spec->multiout.dig_out_nid &&
2672 spec->stream_digital_playback) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002673 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_digital_playback);
2674 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
2675 }
Takashi Iwai4a471b72005-12-07 13:56:29 +01002676 if (spec->dig_in_nid &&
2677 spec->stream_digital_capture) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_digital_capture);
2679 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
2680 }
Takashi Iwai963f8032008-08-11 10:04:40 +02002681 /* FIXME: do we need this for all Realtek codec models? */
2682 codec->spdif_status_reset = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683 }
2684
Takashi Iwaie08a0072006-09-07 17:52:14 +02002685 /* If the use of more than one ADC is requested for the current
2686 * model, configure a second analog capture-only PCM.
2687 */
2688 /* Additional Analaog capture for index #2 */
Takashi Iwai63300792008-01-24 15:31:36 +01002689 if ((spec->alt_dac_nid && spec->stream_analog_alt_playback) ||
2690 (spec->num_adc_nids > 1 && spec->stream_analog_alt_capture)) {
Takashi Iwaie08a0072006-09-07 17:52:14 +02002691 codec->num_pcms = 3;
Takashi Iwaic06134d2006-10-11 18:49:13 +02002692 info = spec->pcm_rec + 2;
Takashi Iwaie08a0072006-09-07 17:52:14 +02002693 info->name = spec->stream_name_analog;
Takashi Iwai63300792008-01-24 15:31:36 +01002694 if (spec->alt_dac_nid) {
2695 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
2696 *spec->stream_analog_alt_playback;
2697 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
2698 spec->alt_dac_nid;
2699 } else {
2700 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
2701 alc_pcm_null_stream;
2702 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
2703 }
2704 if (spec->num_adc_nids > 1) {
2705 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
2706 *spec->stream_analog_alt_capture;
2707 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
2708 spec->adc_nids[1];
2709 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams =
2710 spec->num_adc_nids - 1;
2711 } else {
2712 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
2713 alc_pcm_null_stream;
2714 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0;
Takashi Iwaie08a0072006-09-07 17:52:14 +02002715 }
2716 }
2717
Linus Torvalds1da177e2005-04-16 15:20:36 -07002718 return 0;
2719}
2720
2721static void alc_free(struct hda_codec *codec)
2722{
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002723 struct alc_spec *spec = codec->spec;
2724 unsigned int i;
2725
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002726 if (!spec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002727 return;
2728
2729 if (spec->kctl_alloc) {
2730 for (i = 0; i < spec->num_kctl_used; i++)
2731 kfree(spec->kctl_alloc[i].name);
2732 kfree(spec->kctl_alloc);
2733 }
2734 kfree(spec);
Takashi Iwai7943a8a2008-04-16 17:29:09 +02002735 codec->spec = NULL; /* to be sure */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002736}
2737
2738/*
2739 */
2740static struct hda_codec_ops alc_patch_ops = {
2741 .build_controls = alc_build_controls,
2742 .build_pcms = alc_build_pcms,
2743 .init = alc_init,
2744 .free = alc_free,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002745 .unsol_event = alc_unsol_event,
Takashi Iwaicb53c622007-08-10 17:21:45 +02002746#ifdef CONFIG_SND_HDA_POWER_SAVE
2747 .check_power_status = alc_check_power_status,
2748#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002749};
2750
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002751
2752/*
2753 * Test configuration for debugging
2754 *
2755 * Almost all inputs/outputs are enabled. I/O pins can be configured via
2756 * enum controls.
2757 */
2758#ifdef CONFIG_SND_DEBUG
2759static hda_nid_t alc880_test_dac_nids[4] = {
2760 0x02, 0x03, 0x04, 0x05
2761};
2762
2763static struct hda_input_mux alc880_test_capture_source = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002764 .num_items = 7,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002765 .items = {
2766 { "In-1", 0x0 },
2767 { "In-2", 0x1 },
2768 { "In-3", 0x2 },
2769 { "In-4", 0x3 },
2770 { "CD", 0x4 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002771 { "Front", 0x5 },
2772 { "Surround", 0x6 },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002773 },
2774};
2775
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002776static struct hda_channel_mode alc880_test_modes[4] = {
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002777 { 2, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02002778 { 4, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002779 { 6, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02002780 { 8, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002781};
2782
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002783static int alc_test_pin_ctl_info(struct snd_kcontrol *kcontrol,
2784 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002785{
2786 static char *texts[] = {
2787 "N/A", "Line Out", "HP Out",
2788 "In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%"
2789 };
2790 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2791 uinfo->count = 1;
2792 uinfo->value.enumerated.items = 8;
2793 if (uinfo->value.enumerated.item >= 8)
2794 uinfo->value.enumerated.item = 7;
2795 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
2796 return 0;
2797}
2798
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002799static int alc_test_pin_ctl_get(struct snd_kcontrol *kcontrol,
2800 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002801{
2802 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2803 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
2804 unsigned int pin_ctl, item = 0;
2805
2806 pin_ctl = snd_hda_codec_read(codec, nid, 0,
2807 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
2808 if (pin_ctl & AC_PINCTL_OUT_EN) {
2809 if (pin_ctl & AC_PINCTL_HP_EN)
2810 item = 2;
2811 else
2812 item = 1;
2813 } else if (pin_ctl & AC_PINCTL_IN_EN) {
2814 switch (pin_ctl & AC_PINCTL_VREFEN) {
2815 case AC_PINCTL_VREF_HIZ: item = 3; break;
2816 case AC_PINCTL_VREF_50: item = 4; break;
2817 case AC_PINCTL_VREF_GRD: item = 5; break;
2818 case AC_PINCTL_VREF_80: item = 6; break;
2819 case AC_PINCTL_VREF_100: item = 7; break;
2820 }
2821 }
2822 ucontrol->value.enumerated.item[0] = item;
2823 return 0;
2824}
2825
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002826static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol,
2827 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002828{
2829 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2830 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
2831 static unsigned int ctls[] = {
2832 0, AC_PINCTL_OUT_EN, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN,
2833 AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ,
2834 AC_PINCTL_IN_EN | AC_PINCTL_VREF_50,
2835 AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD,
2836 AC_PINCTL_IN_EN | AC_PINCTL_VREF_80,
2837 AC_PINCTL_IN_EN | AC_PINCTL_VREF_100,
2838 };
2839 unsigned int old_ctl, new_ctl;
2840
2841 old_ctl = snd_hda_codec_read(codec, nid, 0,
2842 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
2843 new_ctl = ctls[ucontrol->value.enumerated.item[0]];
2844 if (old_ctl != new_ctl) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002845 int val;
2846 snd_hda_codec_write_cache(codec, nid, 0,
2847 AC_VERB_SET_PIN_WIDGET_CONTROL,
2848 new_ctl);
Takashi Iwai47fd8302007-08-10 17:11:07 +02002849 val = ucontrol->value.enumerated.item[0] >= 3 ?
2850 HDA_AMP_MUTE : 0;
2851 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
2852 HDA_AMP_MUTE, val);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002853 return 1;
2854 }
2855 return 0;
2856}
2857
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002858static int alc_test_pin_src_info(struct snd_kcontrol *kcontrol,
2859 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002860{
2861 static char *texts[] = {
2862 "Front", "Surround", "CLFE", "Side"
2863 };
2864 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2865 uinfo->count = 1;
2866 uinfo->value.enumerated.items = 4;
2867 if (uinfo->value.enumerated.item >= 4)
2868 uinfo->value.enumerated.item = 3;
2869 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
2870 return 0;
2871}
2872
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002873static int alc_test_pin_src_get(struct snd_kcontrol *kcontrol,
2874 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002875{
2876 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2877 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
2878 unsigned int sel;
2879
2880 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0);
2881 ucontrol->value.enumerated.item[0] = sel & 3;
2882 return 0;
2883}
2884
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002885static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol,
2886 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002887{
2888 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2889 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
2890 unsigned int sel;
2891
2892 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3;
2893 if (ucontrol->value.enumerated.item[0] != sel) {
2894 sel = ucontrol->value.enumerated.item[0] & 3;
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002895 snd_hda_codec_write_cache(codec, nid, 0,
2896 AC_VERB_SET_CONNECT_SEL, sel);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002897 return 1;
2898 }
2899 return 0;
2900}
2901
2902#define PIN_CTL_TEST(xname,nid) { \
2903 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2904 .name = xname, \
2905 .info = alc_test_pin_ctl_info, \
2906 .get = alc_test_pin_ctl_get, \
2907 .put = alc_test_pin_ctl_put, \
2908 .private_value = nid \
2909 }
2910
2911#define PIN_SRC_TEST(xname,nid) { \
2912 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2913 .name = xname, \
2914 .info = alc_test_pin_src_info, \
2915 .get = alc_test_pin_src_get, \
2916 .put = alc_test_pin_src_put, \
2917 .private_value = nid \
2918 }
2919
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002920static struct snd_kcontrol_new alc880_test_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02002921 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2922 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2923 HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
2924 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002925 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
2926 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
2927 HDA_BIND_MUTE("CLFE Playback Switch", 0x0e, 2, HDA_INPUT),
2928 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002929 PIN_CTL_TEST("Front Pin Mode", 0x14),
2930 PIN_CTL_TEST("Surround Pin Mode", 0x15),
2931 PIN_CTL_TEST("CLFE Pin Mode", 0x16),
2932 PIN_CTL_TEST("Side Pin Mode", 0x17),
2933 PIN_CTL_TEST("In-1 Pin Mode", 0x18),
2934 PIN_CTL_TEST("In-2 Pin Mode", 0x19),
2935 PIN_CTL_TEST("In-3 Pin Mode", 0x1a),
2936 PIN_CTL_TEST("In-4 Pin Mode", 0x1b),
2937 PIN_SRC_TEST("In-1 Pin Source", 0x18),
2938 PIN_SRC_TEST("In-2 Pin Source", 0x19),
2939 PIN_SRC_TEST("In-3 Pin Source", 0x1a),
2940 PIN_SRC_TEST("In-4 Pin Source", 0x1b),
2941 HDA_CODEC_VOLUME("In-1 Playback Volume", 0x0b, 0x0, HDA_INPUT),
2942 HDA_CODEC_MUTE("In-1 Playback Switch", 0x0b, 0x0, HDA_INPUT),
2943 HDA_CODEC_VOLUME("In-2 Playback Volume", 0x0b, 0x1, HDA_INPUT),
2944 HDA_CODEC_MUTE("In-2 Playback Switch", 0x0b, 0x1, HDA_INPUT),
2945 HDA_CODEC_VOLUME("In-3 Playback Volume", 0x0b, 0x2, HDA_INPUT),
2946 HDA_CODEC_MUTE("In-3 Playback Switch", 0x0b, 0x2, HDA_INPUT),
2947 HDA_CODEC_VOLUME("In-4 Playback Volume", 0x0b, 0x3, HDA_INPUT),
2948 HDA_CODEC_MUTE("In-4 Playback Switch", 0x0b, 0x3, HDA_INPUT),
2949 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x4, HDA_INPUT),
2950 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x4, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002951 {
2952 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2953 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01002954 .info = alc_ch_mode_info,
2955 .get = alc_ch_mode_get,
2956 .put = alc_ch_mode_put,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002957 },
2958 { } /* end */
2959};
2960
2961static struct hda_verb alc880_test_init_verbs[] = {
2962 /* Unmute inputs of 0x0c - 0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02002963 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2964 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2965 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2966 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2967 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2968 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2969 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2970 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002971 /* Vol output for 0x0c-0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02002972 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2973 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2974 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2975 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002976 /* Set output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02002977 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2978 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2979 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2980 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002981 /* Unmute output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02002982 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2983 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2984 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2985 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002986 /* Set input pins 0x18-0x1c */
Takashi Iwai16ded522005-06-10 19:58:24 +02002987 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2988 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwai05acb862005-06-10 19:50:25 +02002989 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2990 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2991 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002992 /* Mute input pins 0x18-0x1b */
Takashi Iwai05acb862005-06-10 19:50:25 +02002993 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2994 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2995 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2996 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002997 /* ADC set up */
Takashi Iwai05acb862005-06-10 19:50:25 +02002998 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002999 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02003000 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003001 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02003002 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003003 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02003004 /* Analog input/passthru */
3005 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3006 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
3007 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
3008 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
3009 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003010 { }
3011};
3012#endif
3013
Linus Torvalds1da177e2005-04-16 15:20:36 -07003014/*
3015 */
3016
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003017static const char *alc880_models[ALC880_MODEL_LAST] = {
3018 [ALC880_3ST] = "3stack",
3019 [ALC880_TCL_S700] = "tcl",
3020 [ALC880_3ST_DIG] = "3stack-digout",
3021 [ALC880_CLEVO] = "clevo",
3022 [ALC880_5ST] = "5stack",
3023 [ALC880_5ST_DIG] = "5stack-digout",
3024 [ALC880_W810] = "w810",
3025 [ALC880_Z71V] = "z71v",
3026 [ALC880_6ST] = "6stack",
3027 [ALC880_6ST_DIG] = "6stack-digout",
3028 [ALC880_ASUS] = "asus",
3029 [ALC880_ASUS_W1V] = "asus-w1v",
3030 [ALC880_ASUS_DIG] = "asus-dig",
3031 [ALC880_ASUS_DIG2] = "asus-dig2",
3032 [ALC880_UNIWILL_DIG] = "uniwill",
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003033 [ALC880_UNIWILL_P53] = "uniwill-p53",
3034 [ALC880_FUJITSU] = "fujitsu",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003035 [ALC880_F1734] = "F1734",
3036 [ALC880_LG] = "lg",
3037 [ALC880_LG_LW] = "lg-lw",
Takashi Iwaidf99cd32008-04-25 15:25:04 +02003038 [ALC880_MEDION_RIM] = "medion",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003039#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003040 [ALC880_TEST] = "test",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003041#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003042 [ALC880_AUTO] = "auto",
3043};
3044
3045static struct snd_pci_quirk alc880_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003046 SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003047 SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG),
3048 SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST),
3049 SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_3ST_DIG),
3050 SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_6ST_DIG),
3051 SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_6ST_DIG),
3052 SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_6ST_DIG),
3053 SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_3ST_DIG),
3054 SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003055 SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_6ST_DIG),
3056 SND_PCI_QUIRK(0x103c, 0x2a09, "HP", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003057 SND_PCI_QUIRK(0x1043, 0x10b3, "ASUS W1V", ALC880_ASUS_W1V),
3058 SND_PCI_QUIRK(0x1043, 0x10c2, "ASUS W6A", ALC880_ASUS_DIG),
3059 SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS Wxx", ALC880_ASUS_DIG),
3060 SND_PCI_QUIRK(0x1043, 0x1113, "ASUS", ALC880_ASUS_DIG),
3061 SND_PCI_QUIRK(0x1043, 0x1123, "ASUS", ALC880_ASUS_DIG),
3062 SND_PCI_QUIRK(0x1043, 0x1173, "ASUS", ALC880_ASUS_DIG),
3063 SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_Z71V),
3064 /* SND_PCI_QUIRK(0x1043, 0x1964, "ASUS", ALC880_ASUS_DIG), */
3065 SND_PCI_QUIRK(0x1043, 0x1973, "ASUS", ALC880_ASUS_DIG),
3066 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS", ALC880_ASUS_DIG),
Travis Place186c3112008-05-20 11:54:41 +02003067 SND_PCI_QUIRK(0x1043, 0x814e, "ASUS P5GD1 w/SPDIF", ALC880_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003068 SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG),
3069 SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST),
3070 SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003071 SND_PCI_QUIRK(0x1043, 0, "ASUS", ALC880_ASUS), /* default ASUS */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003072 SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003073 SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST),
3074 SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003075 SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_5ST),
3076 SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003077 SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_6ST_DIG),
3078 SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_6ST_DIG),
3079 SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_6ST_DIG),
3080 SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003081 SND_PCI_QUIRK(0x1558, 0x0520, "Clevo m520G", ALC880_CLEVO),
3082 SND_PCI_QUIRK(0x1558, 0x0660, "Clevo m655n", ALC880_CLEVO),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003083 SND_PCI_QUIRK(0x1558, 0x5401, "ASUS", ALC880_ASUS_DIG2),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003084 SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003085 SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_UNIWILL_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003086 SND_PCI_QUIRK(0x1584, 0x9054, "Uniwlll", ALC880_F1734),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003087 SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL),
3088 SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003089 SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810),
Takashi Iwaidf99cd32008-04-25 15:25:04 +02003090 SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_MEDION_RIM),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003091 SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003092 SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003093 SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734),
Travis Place1d116042008-06-23 11:42:30 +02003094 SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FUJITSU),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003095 SND_PCI_QUIRK(0x1734, 0x10ac, "FSC", ALC880_UNIWILL),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003096 SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003097 SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003098 SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG),
3099 SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003100 SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003101 SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700),
3102 SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG), /* broken BIOS */
3103 SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG),
3104 SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003105 SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_5ST_DIG),
3106 SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003107 SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003108 SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003109 SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_3ST_DIG),
3110 SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003111 SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_5ST_DIG),
3112 SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_5ST_DIG),
3113 SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003114 SND_PCI_QUIRK(0x8086, 0, "Intel mobo", ALC880_3ST), /* default Intel */
3115 SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG),
3116 SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003117 {}
3118};
3119
Takashi Iwai16ded522005-06-10 19:58:24 +02003120/*
Kailang Yangdf694da2005-12-05 19:42:22 +01003121 * ALC880 codec presets
Takashi Iwai16ded522005-06-10 19:58:24 +02003122 */
Takashi Iwai16ded522005-06-10 19:58:24 +02003123static struct alc_config_preset alc880_presets[] = {
3124 [ALC880_3ST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003125 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003126 .init_verbs = { alc880_volume_init_verbs,
3127 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003128 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02003129 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003130 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
3131 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003132 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003133 .input_mux = &alc880_capture_source,
3134 },
3135 [ALC880_3ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003136 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003137 .init_verbs = { alc880_volume_init_verbs,
3138 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003139 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02003140 .dac_nids = alc880_dac_nids,
3141 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003142 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
3143 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003144 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003145 .input_mux = &alc880_capture_source,
3146 },
Kailang Yangdf694da2005-12-05 19:42:22 +01003147 [ALC880_TCL_S700] = {
3148 .mixers = { alc880_tcl_s700_mixer },
3149 .init_verbs = { alc880_volume_init_verbs,
3150 alc880_pin_tcl_S700_init_verbs,
3151 alc880_gpio2_init_verbs },
3152 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3153 .dac_nids = alc880_dac_nids,
3154 .hp_nid = 0x03,
3155 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3156 .channel_mode = alc880_2_jack_modes,
3157 .input_mux = &alc880_capture_source,
3158 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003159 [ALC880_5ST] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003160 .mixers = { alc880_three_stack_mixer,
3161 alc880_five_stack_mixer},
3162 .init_verbs = { alc880_volume_init_verbs,
3163 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003164 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3165 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003166 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
3167 .channel_mode = alc880_fivestack_modes,
3168 .input_mux = &alc880_capture_source,
3169 },
3170 [ALC880_5ST_DIG] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003171 .mixers = { alc880_three_stack_mixer,
3172 alc880_five_stack_mixer },
3173 .init_verbs = { alc880_volume_init_verbs,
3174 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003175 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3176 .dac_nids = alc880_dac_nids,
3177 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003178 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
3179 .channel_mode = alc880_fivestack_modes,
3180 .input_mux = &alc880_capture_source,
3181 },
Takashi Iwaib6482d42005-06-27 15:32:43 +02003182 [ALC880_6ST] = {
3183 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003184 .init_verbs = { alc880_volume_init_verbs,
3185 alc880_pin_6stack_init_verbs },
Takashi Iwaib6482d42005-06-27 15:32:43 +02003186 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
3187 .dac_nids = alc880_6st_dac_nids,
3188 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
3189 .channel_mode = alc880_sixstack_modes,
3190 .input_mux = &alc880_6stack_capture_source,
3191 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003192 [ALC880_6ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003193 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003194 .init_verbs = { alc880_volume_init_verbs,
3195 alc880_pin_6stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003196 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
3197 .dac_nids = alc880_6st_dac_nids,
3198 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003199 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
3200 .channel_mode = alc880_sixstack_modes,
3201 .input_mux = &alc880_6stack_capture_source,
3202 },
3203 [ALC880_W810] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003204 .mixers = { alc880_w810_base_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003205 .init_verbs = { alc880_volume_init_verbs,
3206 alc880_pin_w810_init_verbs,
Takashi Iwaib0af0de2005-06-21 14:49:19 +02003207 alc880_gpio2_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003208 .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids),
3209 .dac_nids = alc880_w810_dac_nids,
3210 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003211 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
3212 .channel_mode = alc880_w810_modes,
3213 .input_mux = &alc880_capture_source,
3214 },
3215 [ALC880_Z71V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003216 .mixers = { alc880_z71v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003217 .init_verbs = { alc880_volume_init_verbs,
3218 alc880_pin_z71v_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003219 .num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids),
3220 .dac_nids = alc880_z71v_dac_nids,
3221 .dig_out_nid = ALC880_DIGOUT_NID,
3222 .hp_nid = 0x03,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003223 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3224 .channel_mode = alc880_2_jack_modes,
Takashi Iwai16ded522005-06-10 19:58:24 +02003225 .input_mux = &alc880_capture_source,
3226 },
3227 [ALC880_F1734] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003228 .mixers = { alc880_f1734_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003229 .init_verbs = { alc880_volume_init_verbs,
3230 alc880_pin_f1734_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003231 .num_dacs = ARRAY_SIZE(alc880_f1734_dac_nids),
3232 .dac_nids = alc880_f1734_dac_nids,
3233 .hp_nid = 0x02,
3234 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3235 .channel_mode = alc880_2_jack_modes,
Takashi Iwai937b4162008-02-11 14:52:36 +01003236 .input_mux = &alc880_f1734_capture_source,
3237 .unsol_event = alc880_uniwill_p53_unsol_event,
3238 .init_hook = alc880_uniwill_p53_hp_automute,
Takashi Iwai16ded522005-06-10 19:58:24 +02003239 },
3240 [ALC880_ASUS] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003241 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003242 .init_verbs = { alc880_volume_init_verbs,
3243 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003244 alc880_gpio1_init_verbs },
3245 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3246 .dac_nids = alc880_asus_dac_nids,
3247 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3248 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003249 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003250 .input_mux = &alc880_capture_source,
3251 },
3252 [ALC880_ASUS_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003253 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003254 .init_verbs = { alc880_volume_init_verbs,
3255 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003256 alc880_gpio1_init_verbs },
3257 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3258 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003259 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003260 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3261 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003262 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003263 .input_mux = &alc880_capture_source,
3264 },
Kailang Yangdf694da2005-12-05 19:42:22 +01003265 [ALC880_ASUS_DIG2] = {
3266 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003267 .init_verbs = { alc880_volume_init_verbs,
3268 alc880_pin_asus_init_verbs,
Kailang Yangdf694da2005-12-05 19:42:22 +01003269 alc880_gpio2_init_verbs }, /* use GPIO2 */
3270 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3271 .dac_nids = alc880_asus_dac_nids,
3272 .dig_out_nid = ALC880_DIGOUT_NID,
3273 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3274 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003275 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01003276 .input_mux = &alc880_capture_source,
3277 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003278 [ALC880_ASUS_W1V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003279 .mixers = { alc880_asus_mixer, alc880_asus_w1v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003280 .init_verbs = { alc880_volume_init_verbs,
3281 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003282 alc880_gpio1_init_verbs },
3283 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3284 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003285 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003286 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3287 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003288 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003289 .input_mux = &alc880_capture_source,
3290 },
3291 [ALC880_UNIWILL_DIG] = {
Takashi Iwai3c10a9d2005-08-23 20:02:27 +02003292 .mixers = { alc880_asus_mixer, alc880_pcbeep_mixer },
Kailang Yangccc656c2006-10-17 12:32:26 +02003293 .init_verbs = { alc880_volume_init_verbs,
3294 alc880_pin_asus_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003295 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3296 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003297 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003298 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3299 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003300 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003301 .input_mux = &alc880_capture_source,
3302 },
Kailang Yangccc656c2006-10-17 12:32:26 +02003303 [ALC880_UNIWILL] = {
3304 .mixers = { alc880_uniwill_mixer },
3305 .init_verbs = { alc880_volume_init_verbs,
3306 alc880_uniwill_init_verbs },
3307 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3308 .dac_nids = alc880_asus_dac_nids,
3309 .dig_out_nid = ALC880_DIGOUT_NID,
3310 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
3311 .channel_mode = alc880_threestack_modes,
3312 .need_dac_fix = 1,
3313 .input_mux = &alc880_capture_source,
3314 .unsol_event = alc880_uniwill_unsol_event,
3315 .init_hook = alc880_uniwill_automute,
3316 },
3317 [ALC880_UNIWILL_P53] = {
3318 .mixers = { alc880_uniwill_p53_mixer },
3319 .init_verbs = { alc880_volume_init_verbs,
3320 alc880_uniwill_p53_init_verbs },
3321 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3322 .dac_nids = alc880_asus_dac_nids,
3323 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003324 .channel_mode = alc880_threestack_modes,
3325 .input_mux = &alc880_capture_source,
3326 .unsol_event = alc880_uniwill_p53_unsol_event,
3327 .init_hook = alc880_uniwill_p53_hp_automute,
3328 },
3329 [ALC880_FUJITSU] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003330 .mixers = { alc880_fujitsu_mixer,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003331 alc880_pcbeep_mixer, },
3332 .init_verbs = { alc880_volume_init_verbs,
3333 alc880_uniwill_p53_init_verbs,
3334 alc880_beep_init_verbs },
3335 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3336 .dac_nids = alc880_dac_nids,
Takashi Iwaid53d7d92007-08-20 15:20:02 +02003337 .dig_out_nid = ALC880_DIGOUT_NID,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003338 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3339 .channel_mode = alc880_2_jack_modes,
Kailang Yangccc656c2006-10-17 12:32:26 +02003340 .input_mux = &alc880_capture_source,
3341 .unsol_event = alc880_uniwill_p53_unsol_event,
3342 .init_hook = alc880_uniwill_p53_hp_automute,
3343 },
Kailang Yangdf694da2005-12-05 19:42:22 +01003344 [ALC880_CLEVO] = {
3345 .mixers = { alc880_three_stack_mixer },
3346 .init_verbs = { alc880_volume_init_verbs,
3347 alc880_pin_clevo_init_verbs },
3348 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3349 .dac_nids = alc880_dac_nids,
3350 .hp_nid = 0x03,
3351 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
3352 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003353 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01003354 .input_mux = &alc880_capture_source,
3355 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003356 [ALC880_LG] = {
3357 .mixers = { alc880_lg_mixer },
3358 .init_verbs = { alc880_volume_init_verbs,
3359 alc880_lg_init_verbs },
3360 .num_dacs = ARRAY_SIZE(alc880_lg_dac_nids),
3361 .dac_nids = alc880_lg_dac_nids,
3362 .dig_out_nid = ALC880_DIGOUT_NID,
3363 .num_channel_mode = ARRAY_SIZE(alc880_lg_ch_modes),
3364 .channel_mode = alc880_lg_ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003365 .need_dac_fix = 1,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003366 .input_mux = &alc880_lg_capture_source,
3367 .unsol_event = alc880_lg_unsol_event,
3368 .init_hook = alc880_lg_automute,
Takashi Iwaicb53c622007-08-10 17:21:45 +02003369#ifdef CONFIG_SND_HDA_POWER_SAVE
3370 .loopbacks = alc880_lg_loopbacks,
3371#endif
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003372 },
Takashi Iwaid6815182006-03-23 16:06:23 +01003373 [ALC880_LG_LW] = {
3374 .mixers = { alc880_lg_lw_mixer },
3375 .init_verbs = { alc880_volume_init_verbs,
3376 alc880_lg_lw_init_verbs },
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003377 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwaid6815182006-03-23 16:06:23 +01003378 .dac_nids = alc880_dac_nids,
3379 .dig_out_nid = ALC880_DIGOUT_NID,
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003380 .num_channel_mode = ARRAY_SIZE(alc880_lg_lw_modes),
3381 .channel_mode = alc880_lg_lw_modes,
Takashi Iwaid6815182006-03-23 16:06:23 +01003382 .input_mux = &alc880_lg_lw_capture_source,
3383 .unsol_event = alc880_lg_lw_unsol_event,
3384 .init_hook = alc880_lg_lw_automute,
3385 },
Takashi Iwaidf99cd32008-04-25 15:25:04 +02003386 [ALC880_MEDION_RIM] = {
3387 .mixers = { alc880_medion_rim_mixer },
3388 .init_verbs = { alc880_volume_init_verbs,
3389 alc880_medion_rim_init_verbs,
3390 alc_gpio2_init_verbs },
3391 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3392 .dac_nids = alc880_dac_nids,
3393 .dig_out_nid = ALC880_DIGOUT_NID,
3394 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3395 .channel_mode = alc880_2_jack_modes,
3396 .input_mux = &alc880_medion_rim_capture_source,
3397 .unsol_event = alc880_medion_rim_unsol_event,
3398 .init_hook = alc880_medion_rim_automute,
3399 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003400#ifdef CONFIG_SND_DEBUG
3401 [ALC880_TEST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003402 .mixers = { alc880_test_mixer },
3403 .init_verbs = { alc880_test_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003404 .num_dacs = ARRAY_SIZE(alc880_test_dac_nids),
3405 .dac_nids = alc880_test_dac_nids,
3406 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003407 .num_channel_mode = ARRAY_SIZE(alc880_test_modes),
3408 .channel_mode = alc880_test_modes,
3409 .input_mux = &alc880_test_capture_source,
3410 },
3411#endif
3412};
3413
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003414/*
3415 * Automatic parse of I/O pins from the BIOS configuration
3416 */
3417
3418#define NUM_CONTROL_ALLOC 32
3419#define NUM_VERB_ALLOC 32
3420
3421enum {
3422 ALC_CTL_WIDGET_VOL,
3423 ALC_CTL_WIDGET_MUTE,
3424 ALC_CTL_BIND_MUTE,
3425};
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003426static struct snd_kcontrol_new alc880_control_templates[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003427 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
3428 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Takashi Iwai985be542005-11-02 18:26:49 +01003429 HDA_BIND_MUTE(NULL, 0, 0, 0),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003430};
3431
3432/* add dynamic controls */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003433static int add_control(struct alc_spec *spec, int type, const char *name,
3434 unsigned long val)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003435{
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003436 struct snd_kcontrol_new *knew;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003437
3438 if (spec->num_kctl_used >= spec->num_kctl_alloc) {
3439 int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
3440
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003441 /* array + terminator */
3442 knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL);
3443 if (!knew)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003444 return -ENOMEM;
3445 if (spec->kctl_alloc) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003446 memcpy(knew, spec->kctl_alloc,
3447 sizeof(*knew) * spec->num_kctl_alloc);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003448 kfree(spec->kctl_alloc);
3449 }
3450 spec->kctl_alloc = knew;
3451 spec->num_kctl_alloc = num;
3452 }
3453
3454 knew = &spec->kctl_alloc[spec->num_kctl_used];
3455 *knew = alc880_control_templates[type];
Paulo Marques543537b2005-06-23 00:09:02 -07003456 knew->name = kstrdup(name, GFP_KERNEL);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003457 if (!knew->name)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003458 return -ENOMEM;
3459 knew->private_value = val;
3460 spec->num_kctl_used++;
3461 return 0;
3462}
3463
3464#define alc880_is_fixed_pin(nid) ((nid) >= 0x14 && (nid) <= 0x17)
3465#define alc880_fixed_pin_idx(nid) ((nid) - 0x14)
3466#define alc880_is_multi_pin(nid) ((nid) >= 0x18)
3467#define alc880_multi_pin_idx(nid) ((nid) - 0x18)
3468#define alc880_is_input_pin(nid) ((nid) >= 0x18)
3469#define alc880_input_pin_idx(nid) ((nid) - 0x18)
3470#define alc880_idx_to_dac(nid) ((nid) + 0x02)
3471#define alc880_dac_to_idx(nid) ((nid) - 0x02)
3472#define alc880_idx_to_mixer(nid) ((nid) + 0x0c)
3473#define alc880_idx_to_selector(nid) ((nid) + 0x10)
3474#define ALC880_PIN_CD_NID 0x1c
3475
3476/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003477static int alc880_auto_fill_dac_nids(struct alc_spec *spec,
3478 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003479{
3480 hda_nid_t nid;
3481 int assigned[4];
3482 int i, j;
3483
3484 memset(assigned, 0, sizeof(assigned));
Takashi Iwaib0af0de2005-06-21 14:49:19 +02003485 spec->multiout.dac_nids = spec->private_dac_nids;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003486
3487 /* check the pins hardwired to audio widget */
3488 for (i = 0; i < cfg->line_outs; i++) {
3489 nid = cfg->line_out_pins[i];
3490 if (alc880_is_fixed_pin(nid)) {
3491 int idx = alc880_fixed_pin_idx(nid);
Libin Yang5014f192005-11-23 15:48:36 +01003492 spec->multiout.dac_nids[i] = alc880_idx_to_dac(idx);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003493 assigned[idx] = 1;
3494 }
3495 }
3496 /* left pins can be connect to any audio widget */
3497 for (i = 0; i < cfg->line_outs; i++) {
3498 nid = cfg->line_out_pins[i];
3499 if (alc880_is_fixed_pin(nid))
3500 continue;
3501 /* search for an empty channel */
3502 for (j = 0; j < cfg->line_outs; j++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003503 if (!assigned[j]) {
3504 spec->multiout.dac_nids[i] =
3505 alc880_idx_to_dac(j);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003506 assigned[j] = 1;
3507 break;
3508 }
3509 }
3510 }
3511 spec->multiout.num_dacs = cfg->line_outs;
3512 return 0;
3513}
3514
3515/* add playback controls from the parsed DAC table */
Kailang Yangdf694da2005-12-05 19:42:22 +01003516static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
3517 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003518{
3519 char name[32];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003520 static const char *chname[4] = {
3521 "Front", "Surround", NULL /*CLFE*/, "Side"
3522 };
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003523 hda_nid_t nid;
3524 int i, err;
3525
3526 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003527 if (!spec->multiout.dac_nids[i])
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003528 continue;
3529 nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i]));
3530 if (i == 2) {
3531 /* Center/LFE */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003532 err = add_control(spec, ALC_CTL_WIDGET_VOL,
3533 "Center Playback Volume",
3534 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
3535 HDA_OUTPUT));
3536 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003537 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003538 err = add_control(spec, ALC_CTL_WIDGET_VOL,
3539 "LFE Playback Volume",
3540 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
3541 HDA_OUTPUT));
3542 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003543 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003544 err = add_control(spec, ALC_CTL_BIND_MUTE,
3545 "Center Playback Switch",
3546 HDA_COMPOSE_AMP_VAL(nid, 1, 2,
3547 HDA_INPUT));
3548 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003549 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003550 err = add_control(spec, ALC_CTL_BIND_MUTE,
3551 "LFE Playback Switch",
3552 HDA_COMPOSE_AMP_VAL(nid, 2, 2,
3553 HDA_INPUT));
3554 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003555 return err;
3556 } else {
3557 sprintf(name, "%s Playback Volume", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003558 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
3559 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
3560 HDA_OUTPUT));
3561 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003562 return err;
3563 sprintf(name, "%s Playback Switch", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003564 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
3565 HDA_COMPOSE_AMP_VAL(nid, 3, 2,
3566 HDA_INPUT));
3567 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003568 return err;
3569 }
3570 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003571 return 0;
3572}
3573
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003574/* add playback controls for speaker and HP outputs */
3575static int alc880_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
3576 const char *pfx)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003577{
3578 hda_nid_t nid;
3579 int err;
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003580 char name[32];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003581
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003582 if (!pin)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003583 return 0;
3584
3585 if (alc880_is_fixed_pin(pin)) {
3586 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
Takashi Iwai82bc9552006-03-21 11:24:42 +01003587 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003588 if (!spec->multiout.hp_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003589 spec->multiout.hp_nid = nid;
Takashi Iwai82bc9552006-03-21 11:24:42 +01003590 else
3591 spec->multiout.extra_out_nid[0] = nid;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003592 /* control HP volume/switch on the output mixer amp */
3593 nid = alc880_idx_to_mixer(alc880_fixed_pin_idx(pin));
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003594 sprintf(name, "%s Playback Volume", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003595 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
3596 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
3597 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003598 return err;
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003599 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003600 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
3601 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
3602 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003603 return err;
3604 } else if (alc880_is_multi_pin(pin)) {
3605 /* set manual connection */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003606 /* we have only a switch on HP-out PIN */
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003607 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003608 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
3609 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
3610 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003611 return err;
3612 }
3613 return 0;
3614}
3615
3616/* create input playback/capture controls for the given pin */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003617static int new_analog_input(struct alc_spec *spec, hda_nid_t pin,
3618 const char *ctlname,
Kailang Yangdf694da2005-12-05 19:42:22 +01003619 int idx, hda_nid_t mix_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003620{
3621 char name[32];
Kailang Yangdf694da2005-12-05 19:42:22 +01003622 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003623
3624 sprintf(name, "%s Playback Volume", ctlname);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003625 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
3626 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
3627 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003628 return err;
3629 sprintf(name, "%s Playback Switch", ctlname);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003630 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
3631 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
3632 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003633 return err;
3634 return 0;
3635}
3636
3637/* create playback/capture controls for input pins */
Kailang Yangdf694da2005-12-05 19:42:22 +01003638static int alc880_auto_create_analog_input_ctls(struct alc_spec *spec,
3639 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003640{
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003641 struct hda_input_mux *imux = &spec->private_imux;
Kailang Yangdf694da2005-12-05 19:42:22 +01003642 int i, err, idx;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003643
3644 for (i = 0; i < AUTO_PIN_LAST; i++) {
3645 if (alc880_is_input_pin(cfg->input_pins[i])) {
Kailang Yangdf694da2005-12-05 19:42:22 +01003646 idx = alc880_input_pin_idx(cfg->input_pins[i]);
Takashi Iwai4a471b72005-12-07 13:56:29 +01003647 err = new_analog_input(spec, cfg->input_pins[i],
3648 auto_pin_cfg_labels[i],
Kailang Yangdf694da2005-12-05 19:42:22 +01003649 idx, 0x0b);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003650 if (err < 0)
3651 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003652 imux->items[imux->num_items].label =
3653 auto_pin_cfg_labels[i];
3654 imux->items[imux->num_items].index =
3655 alc880_input_pin_idx(cfg->input_pins[i]);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003656 imux->num_items++;
3657 }
3658 }
3659 return 0;
3660}
3661
Takashi Iwaif6c7e542008-02-12 18:32:23 +01003662static void alc_set_pin_output(struct hda_codec *codec, hda_nid_t nid,
3663 unsigned int pin_type)
3664{
3665 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
3666 pin_type);
3667 /* unmute pin */
Takashi Iwaid260cdf2008-02-13 17:19:35 +01003668 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
3669 AMP_OUT_UNMUTE);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01003670}
3671
Kailang Yangdf694da2005-12-05 19:42:22 +01003672static void alc880_auto_set_output_and_unmute(struct hda_codec *codec,
3673 hda_nid_t nid, int pin_type,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003674 int dac_idx)
3675{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01003676 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003677 /* need the manual connection? */
3678 if (alc880_is_multi_pin(nid)) {
3679 struct alc_spec *spec = codec->spec;
3680 int idx = alc880_multi_pin_idx(nid);
3681 snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
3682 AC_VERB_SET_CONNECT_SEL,
3683 alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
3684 }
3685}
3686
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02003687static int get_pin_type(int line_out_type)
3688{
3689 if (line_out_type == AUTO_PIN_HP_OUT)
3690 return PIN_HP;
3691 else
3692 return PIN_OUT;
3693}
3694
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003695static void alc880_auto_init_multi_out(struct hda_codec *codec)
3696{
3697 struct alc_spec *spec = codec->spec;
3698 int i;
Kailang Yangea1fb292008-08-26 12:58:38 +02003699
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003700 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003701 for (i = 0; i < spec->autocfg.line_outs; i++) {
3702 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02003703 int pin_type = get_pin_type(spec->autocfg.line_out_type);
3704 alc880_auto_set_output_and_unmute(codec, nid, pin_type, i);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003705 }
3706}
3707
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003708static void alc880_auto_init_extra_out(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003709{
3710 struct alc_spec *spec = codec->spec;
3711 hda_nid_t pin;
3712
Takashi Iwai82bc9552006-03-21 11:24:42 +01003713 pin = spec->autocfg.speaker_pins[0];
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003714 if (pin) /* connect to front */
3715 alc880_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003716 pin = spec->autocfg.hp_pins[0];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003717 if (pin) /* connect to front */
3718 alc880_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
3719}
3720
3721static void alc880_auto_init_analog_input(struct hda_codec *codec)
3722{
3723 struct alc_spec *spec = codec->spec;
3724 int i;
3725
3726 for (i = 0; i < AUTO_PIN_LAST; i++) {
3727 hda_nid_t nid = spec->autocfg.input_pins[i];
3728 if (alc880_is_input_pin(nid)) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003729 snd_hda_codec_write(codec, nid, 0,
3730 AC_VERB_SET_PIN_WIDGET_CONTROL,
3731 i <= AUTO_PIN_FRONT_MIC ?
3732 PIN_VREF80 : PIN_IN);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003733 if (nid != ALC880_PIN_CD_NID)
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003734 snd_hda_codec_write(codec, nid, 0,
3735 AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003736 AMP_OUT_MUTE);
3737 }
3738 }
3739}
3740
3741/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003742/* return 1 if successful, 0 if the proper config is not found,
3743 * or a negative error code
3744 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003745static int alc880_parse_auto_config(struct hda_codec *codec)
3746{
3747 struct alc_spec *spec = codec->spec;
3748 int err;
Kailang Yangdf694da2005-12-05 19:42:22 +01003749 static hda_nid_t alc880_ignore[] = { 0x1d, 0 };
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003750
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003751 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
3752 alc880_ignore);
3753 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003754 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003755 if (!spec->autocfg.line_outs)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003756 return 0; /* can't find valid BIOS pin config */
Kailang Yangdf694da2005-12-05 19:42:22 +01003757
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003758 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
3759 if (err < 0)
3760 return err;
3761 err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
3762 if (err < 0)
3763 return err;
3764 err = alc880_auto_create_extra_out(spec,
3765 spec->autocfg.speaker_pins[0],
3766 "Speaker");
3767 if (err < 0)
3768 return err;
3769 err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
3770 "Headphone");
3771 if (err < 0)
3772 return err;
3773 err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg);
3774 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003775 return err;
3776
3777 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
3778
3779 if (spec->autocfg.dig_out_pin)
3780 spec->multiout.dig_out_nid = ALC880_DIGOUT_NID;
3781 if (spec->autocfg.dig_in_pin)
3782 spec->dig_in_nid = ALC880_DIGIN_NID;
3783
3784 if (spec->kctl_alloc)
3785 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
3786
3787 spec->init_verbs[spec->num_init_verbs++] = alc880_volume_init_verbs;
3788
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003789 spec->num_mux_defs = 1;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003790 spec->input_mux = &spec->private_imux;
3791
3792 return 1;
3793}
3794
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003795/* additional initialization for auto-configuration model */
3796static void alc880_auto_init(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003797{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01003798 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003799 alc880_auto_init_multi_out(codec);
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003800 alc880_auto_init_extra_out(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003801 alc880_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01003802 if (spec->unsol_event)
3803 alc_sku_automute(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003804}
3805
3806/*
3807 * OK, here we have finally the patch for ALC880
3808 */
3809
Linus Torvalds1da177e2005-04-16 15:20:36 -07003810static int patch_alc880(struct hda_codec *codec)
3811{
3812 struct alc_spec *spec;
3813 int board_config;
Kailang Yangdf694da2005-12-05 19:42:22 +01003814 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003815
Takashi Iwaie560d8d2005-09-09 14:21:46 +02003816 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003817 if (spec == NULL)
3818 return -ENOMEM;
3819
3820 codec->spec = spec;
3821
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003822 board_config = snd_hda_check_board_config(codec, ALC880_MODEL_LAST,
3823 alc880_models,
3824 alc880_cfg_tbl);
3825 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003826 printk(KERN_INFO "hda_codec: Unknown model for ALC880, "
3827 "trying auto-probe from BIOS...\n");
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003828 board_config = ALC880_AUTO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003829 }
3830
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003831 if (board_config == ALC880_AUTO) {
3832 /* automatic parse from the BIOS config */
3833 err = alc880_parse_auto_config(codec);
3834 if (err < 0) {
3835 alc_free(codec);
3836 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003837 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003838 printk(KERN_INFO
3839 "hda_codec: Cannot set up configuration "
3840 "from BIOS. Using 3-stack mode...\n");
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003841 board_config = ALC880_3ST;
3842 }
3843 }
3844
Kailang Yangdf694da2005-12-05 19:42:22 +01003845 if (board_config != ALC880_AUTO)
3846 setup_preset(spec, &alc880_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003847
3848 spec->stream_name_analog = "ALC880 Analog";
3849 spec->stream_analog_playback = &alc880_pcm_analog_playback;
3850 spec->stream_analog_capture = &alc880_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01003851 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003852
3853 spec->stream_name_digital = "ALC880 Digital";
3854 spec->stream_digital_playback = &alc880_pcm_digital_playback;
3855 spec->stream_digital_capture = &alc880_pcm_digital_capture;
3856
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003857 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003858 /* check whether NID 0x07 is valid */
Takashi Iwai54d17402005-11-21 16:33:22 +01003859 unsigned int wcap = get_wcaps(codec, alc880_adc_nids[0]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003860 /* get type */
3861 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003862 if (wcap != AC_WID_AUD_IN) {
3863 spec->adc_nids = alc880_adc_nids_alt;
3864 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids_alt);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003865 spec->mixers[spec->num_mixers] =
3866 alc880_capture_alt_mixer;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003867 spec->num_mixers++;
3868 } else {
3869 spec->adc_nids = alc880_adc_nids;
3870 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids);
3871 spec->mixers[spec->num_mixers] = alc880_capture_mixer;
3872 spec->num_mixers++;
3873 }
3874 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003875
Takashi Iwai2134ea42008-01-10 16:53:55 +01003876 spec->vmaster_nid = 0x0c;
3877
Linus Torvalds1da177e2005-04-16 15:20:36 -07003878 codec->patch_ops = alc_patch_ops;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003879 if (board_config == ALC880_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003880 spec->init_hook = alc880_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02003881#ifdef CONFIG_SND_HDA_POWER_SAVE
3882 if (!spec->loopback.amplist)
3883 spec->loopback.amplist = alc880_loopbacks;
3884#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07003885
3886 return 0;
3887}
3888
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003889
Linus Torvalds1da177e2005-04-16 15:20:36 -07003890/*
3891 * ALC260 support
3892 */
3893
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003894static hda_nid_t alc260_dac_nids[1] = {
3895 /* front */
3896 0x02,
3897};
3898
3899static hda_nid_t alc260_adc_nids[1] = {
3900 /* ADC0 */
3901 0x04,
3902};
3903
Kailang Yangdf694da2005-12-05 19:42:22 +01003904static hda_nid_t alc260_adc_nids_alt[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003905 /* ADC1 */
3906 0x05,
3907};
3908
Kailang Yangdf694da2005-12-05 19:42:22 +01003909static hda_nid_t alc260_hp_adc_nids[2] = {
3910 /* ADC1, 0 */
3911 0x05, 0x04
3912};
3913
Jonathan Woithed57fdac2006-02-28 11:38:35 +01003914/* NIDs used when simultaneous access to both ADCs makes sense. Note that
3915 * alc260_capture_mixer assumes ADC0 (nid 0x04) is the first ADC.
3916 */
3917static hda_nid_t alc260_dual_adc_nids[2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01003918 /* ADC0, ADC1 */
3919 0x04, 0x05
3920};
3921
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003922#define ALC260_DIGOUT_NID 0x03
3923#define ALC260_DIGIN_NID 0x06
3924
3925static struct hda_input_mux alc260_capture_source = {
3926 .num_items = 4,
3927 .items = {
3928 { "Mic", 0x0 },
3929 { "Front Mic", 0x1 },
3930 { "Line", 0x2 },
3931 { "CD", 0x4 },
3932 },
3933};
3934
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01003935/* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003936 * headphone jack and the internal CD lines since these are the only pins at
3937 * which audio can appear. For flexibility, also allow the option of
3938 * recording the mixer output on the second ADC (ADC0 doesn't have a
3939 * connection to the mixer output).
Jonathan Woithea9430dd2005-09-16 19:12:48 +02003940 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003941static struct hda_input_mux alc260_fujitsu_capture_sources[2] = {
3942 {
3943 .num_items = 3,
3944 .items = {
3945 { "Mic/Line", 0x0 },
3946 { "CD", 0x4 },
3947 { "Headphone", 0x2 },
3948 },
Jonathan Woithea9430dd2005-09-16 19:12:48 +02003949 },
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003950 {
3951 .num_items = 4,
3952 .items = {
3953 { "Mic/Line", 0x0 },
3954 { "CD", 0x4 },
3955 { "Headphone", 0x2 },
3956 { "Mixer", 0x5 },
3957 },
3958 },
3959
Jonathan Woithea9430dd2005-09-16 19:12:48 +02003960};
3961
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003962/* Acer TravelMate(/Extensa/Aspire) notebooks have similar configuration to
3963 * the Fujitsu S702x, but jacks are marked differently.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01003964 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003965static struct hda_input_mux alc260_acer_capture_sources[2] = {
3966 {
3967 .num_items = 4,
3968 .items = {
3969 { "Mic", 0x0 },
3970 { "Line", 0x2 },
3971 { "CD", 0x4 },
3972 { "Headphone", 0x5 },
3973 },
3974 },
3975 {
3976 .num_items = 5,
3977 .items = {
3978 { "Mic", 0x0 },
3979 { "Line", 0x2 },
3980 { "CD", 0x4 },
3981 { "Headphone", 0x6 },
3982 { "Mixer", 0x5 },
3983 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01003984 },
3985};
Linus Torvalds1da177e2005-04-16 15:20:36 -07003986/*
3987 * This is just place-holder, so there's something for alc_build_pcms to look
3988 * at when it calculates the maximum number of channels. ALC260 has no mixer
3989 * element which allows changing the channel mode, so the verb list is
3990 * never used.
3991 */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01003992static struct hda_channel_mode alc260_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003993 { 2, NULL },
3994};
3995
Kailang Yangdf694da2005-12-05 19:42:22 +01003996
3997/* Mixer combinations
3998 *
3999 * basic: base_output + input + pc_beep + capture
4000 * HP: base_output + input + capture_alt
4001 * HP_3013: hp_3013 + input + capture
4002 * fujitsu: fujitsu + capture
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004003 * acer: acer + capture
Kailang Yangdf694da2005-12-05 19:42:22 +01004004 */
4005
4006static struct snd_kcontrol_new alc260_base_output_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02004007 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01004008 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01004009 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
4010 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
4011 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
4012 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
4013 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004014};
Kailang Yangdf694da2005-12-05 19:42:22 +01004015
4016static struct snd_kcontrol_new alc260_input_mixer[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004017 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4018 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
4019 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
4020 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
4021 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
4022 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
4023 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT),
4024 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004025 { } /* end */
4026};
4027
Kailang Yangdf694da2005-12-05 19:42:22 +01004028static struct snd_kcontrol_new alc260_pc_beep_mixer[] = {
4029 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x07, 0x05, HDA_INPUT),
4030 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x07, 0x05, HDA_INPUT),
4031 { } /* end */
4032};
4033
Takashi Iwaibec15c32008-01-28 18:16:30 +01004034/* update HP, line and mono out pins according to the master switch */
4035static void alc260_hp_master_update(struct hda_codec *codec,
4036 hda_nid_t hp, hda_nid_t line,
4037 hda_nid_t mono)
4038{
4039 struct alc_spec *spec = codec->spec;
4040 unsigned int val = spec->master_sw ? PIN_HP : 0;
4041 /* change HP and line-out pins */
4042 snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
4043 val);
4044 snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
4045 val);
4046 /* mono (speaker) depending on the HP jack sense */
4047 val = (val && !spec->jack_present) ? PIN_OUT : 0;
4048 snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
4049 val);
4050}
4051
4052static int alc260_hp_master_sw_get(struct snd_kcontrol *kcontrol,
4053 struct snd_ctl_elem_value *ucontrol)
4054{
4055 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4056 struct alc_spec *spec = codec->spec;
4057 *ucontrol->value.integer.value = spec->master_sw;
4058 return 0;
4059}
4060
4061static int alc260_hp_master_sw_put(struct snd_kcontrol *kcontrol,
4062 struct snd_ctl_elem_value *ucontrol)
4063{
4064 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4065 struct alc_spec *spec = codec->spec;
4066 int val = !!*ucontrol->value.integer.value;
4067 hda_nid_t hp, line, mono;
4068
4069 if (val == spec->master_sw)
4070 return 0;
4071 spec->master_sw = val;
4072 hp = (kcontrol->private_value >> 16) & 0xff;
4073 line = (kcontrol->private_value >> 8) & 0xff;
4074 mono = kcontrol->private_value & 0xff;
4075 alc260_hp_master_update(codec, hp, line, mono);
4076 return 1;
4077}
4078
4079static struct snd_kcontrol_new alc260_hp_output_mixer[] = {
4080 {
4081 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4082 .name = "Master Playback Switch",
4083 .info = snd_ctl_boolean_mono_info,
4084 .get = alc260_hp_master_sw_get,
4085 .put = alc260_hp_master_sw_put,
4086 .private_value = (0x0f << 16) | (0x10 << 8) | 0x11
4087 },
4088 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4089 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
4090 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
4091 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
4092 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
4093 HDA_OUTPUT),
4094 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2, HDA_INPUT),
4095 { } /* end */
4096};
4097
4098static struct hda_verb alc260_hp_unsol_verbs[] = {
4099 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
4100 {},
4101};
4102
4103static void alc260_hp_automute(struct hda_codec *codec)
4104{
4105 struct alc_spec *spec = codec->spec;
4106 unsigned int present;
4107
4108 present = snd_hda_codec_read(codec, 0x10, 0,
4109 AC_VERB_GET_PIN_SENSE, 0);
4110 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
4111 alc260_hp_master_update(codec, 0x0f, 0x10, 0x11);
4112}
4113
4114static void alc260_hp_unsol_event(struct hda_codec *codec, unsigned int res)
4115{
4116 if ((res >> 26) == ALC880_HP_EVENT)
4117 alc260_hp_automute(codec);
4118}
4119
Kailang Yangdf694da2005-12-05 19:42:22 +01004120static struct snd_kcontrol_new alc260_hp_3013_mixer[] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01004121 {
4122 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4123 .name = "Master Playback Switch",
4124 .info = snd_ctl_boolean_mono_info,
4125 .get = alc260_hp_master_sw_get,
4126 .put = alc260_hp_master_sw_put,
4127 .private_value = (0x10 << 16) | (0x15 << 8) | 0x11
4128 },
Kailang Yangdf694da2005-12-05 19:42:22 +01004129 HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT),
4130 HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT),
4131 HDA_CODEC_VOLUME("Aux-In Playback Volume", 0x07, 0x06, HDA_INPUT),
4132 HDA_CODEC_MUTE("Aux-In Playback Switch", 0x07, 0x06, HDA_INPUT),
4133 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4134 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01004135 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
4136 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02004137 { } /* end */
4138};
4139
Kailang Yang3f878302008-08-26 13:02:23 +02004140static struct hda_bind_ctls alc260_dc7600_bind_master_vol = {
4141 .ops = &snd_hda_bind_vol,
4142 .values = {
4143 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_OUTPUT),
4144 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_OUTPUT),
4145 HDA_COMPOSE_AMP_VAL(0x0a, 3, 0, HDA_OUTPUT),
4146 0
4147 },
4148};
4149
4150static struct hda_bind_ctls alc260_dc7600_bind_switch = {
4151 .ops = &snd_hda_bind_sw,
4152 .values = {
4153 HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT),
4154 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
4155 0
4156 },
4157};
4158
4159static struct snd_kcontrol_new alc260_hp_dc7600_mixer[] = {
4160 HDA_BIND_VOL("Master Playback Volume", &alc260_dc7600_bind_master_vol),
4161 HDA_BIND_SW("LineOut Playback Switch", &alc260_dc7600_bind_switch),
4162 HDA_CODEC_MUTE("Speaker Playback Switch", 0x0f, 0x0, HDA_OUTPUT),
4163 HDA_CODEC_MUTE("Headphone Playback Switch", 0x10, 0x0, HDA_OUTPUT),
4164 { } /* end */
4165};
4166
Takashi Iwaibec15c32008-01-28 18:16:30 +01004167static struct hda_verb alc260_hp_3013_unsol_verbs[] = {
4168 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
4169 {},
4170};
4171
4172static void alc260_hp_3013_automute(struct hda_codec *codec)
4173{
4174 struct alc_spec *spec = codec->spec;
4175 unsigned int present;
4176
4177 present = snd_hda_codec_read(codec, 0x15, 0,
4178 AC_VERB_GET_PIN_SENSE, 0);
4179 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
4180 alc260_hp_master_update(codec, 0x10, 0x15, 0x11);
4181}
4182
4183static void alc260_hp_3013_unsol_event(struct hda_codec *codec,
4184 unsigned int res)
4185{
4186 if ((res >> 26) == ALC880_HP_EVENT)
4187 alc260_hp_3013_automute(codec);
4188}
4189
Kailang Yang3f878302008-08-26 13:02:23 +02004190static void alc260_hp_3012_automute(struct hda_codec *codec)
4191{
4192 unsigned int present, bits;
4193
4194 present = snd_hda_codec_read(codec, 0x10, 0,
4195 AC_VERB_GET_PIN_SENSE, 0) & AC_PINSENSE_PRESENCE;
4196
4197 bits = present ? 0 : PIN_OUT;
4198 snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
4199 bits);
4200 snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
4201 bits);
4202 snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
4203 bits);
4204}
4205
4206static void alc260_hp_3012_unsol_event(struct hda_codec *codec,
4207 unsigned int res)
4208{
4209 if ((res >> 26) == ALC880_HP_EVENT)
4210 alc260_hp_3012_automute(codec);
4211}
4212
4213/* Fujitsu S702x series laptops. ALC260 pin usage: Mic/Line jack = 0x12,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004214 * HP jack = 0x14, CD audio = 0x16, internal speaker = 0x10.
4215 */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01004216static struct snd_kcontrol_new alc260_fujitsu_mixer[] = {
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004217 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01004218 HDA_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004219 ALC_PIN_MODE("Headphone Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004220 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4221 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
4222 HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT),
4223 HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004224 ALC_PIN_MODE("Mic/Line Jack Mode", 0x12, ALC_PIN_DIR_IN),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004225 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
4226 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01004227 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT),
4228 HDA_BIND_MUTE("Speaker Playback Switch", 0x09, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01004229 { } /* end */
4230};
4231
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004232/* Mixer for Acer TravelMate(/Extensa/Aspire) notebooks. Note that current
4233 * versions of the ALC260 don't act on requests to enable mic bias from NID
4234 * 0x0f (used to drive the headphone jack in these laptops). The ALC260
4235 * datasheet doesn't mention this restriction. At this stage it's not clear
4236 * whether this behaviour is intentional or is a hardware bug in chip
4237 * revisions available in early 2006. Therefore for now allow the
4238 * "Headphone Jack Mode" control to span all choices, but if it turns out
4239 * that the lack of mic bias for this NID is intentional we could change the
4240 * mode from ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
4241 *
4242 * In addition, Acer TravelMate(/Extensa/Aspire) notebooks in early 2006
4243 * don't appear to make the mic bias available from the "line" jack, even
4244 * though the NID used for this jack (0x14) can supply it. The theory is
4245 * that perhaps Acer have included blocking capacitors between the ALC260
4246 * and the output jack. If this turns out to be the case for all such
4247 * models the "Line Jack Mode" mode could be changed from ALC_PIN_DIR_INOUT
4248 * to ALC_PIN_DIR_INOUT_NOMICBIAS.
Jonathan Woithebd869482006-11-28 11:35:52 +01004249 *
4250 * The C20x Tablet series have a mono internal speaker which is controlled
4251 * via the chip's Mono sum widget and pin complex, so include the necessary
4252 * controls for such models. On models without a "mono speaker" the control
4253 * won't do anything.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004254 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004255static struct snd_kcontrol_new alc260_acer_mixer[] = {
4256 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4257 HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004258 ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01004259 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
Jonathan Woithebd869482006-11-28 11:35:52 +01004260 HDA_OUTPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01004261 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2,
Jonathan Woithebd869482006-11-28 11:35:52 +01004262 HDA_INPUT),
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004263 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4264 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
4265 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
4266 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
4267 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
4268 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
4269 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
4270 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
4271 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
4272 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
4273 { } /* end */
4274};
4275
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004276/* Packard bell V7900 ALC260 pin usage: HP = 0x0f, Mic jack = 0x12,
4277 * Line In jack = 0x14, CD audio = 0x16, pc beep = 0x17.
4278 */
4279static struct snd_kcontrol_new alc260_will_mixer[] = {
4280 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4281 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
4282 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
4283 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
4284 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
4285 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
4286 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
4287 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
4288 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4289 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
4290 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
4291 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
4292 { } /* end */
4293};
4294
4295/* Replacer 672V ALC260 pin usage: Mic jack = 0x12,
4296 * Line In jack = 0x14, ATAPI Mic = 0x13, speaker = 0x0f.
4297 */
4298static struct snd_kcontrol_new alc260_replacer_672v_mixer[] = {
4299 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4300 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
4301 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
4302 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
4303 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
4304 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x07, 0x1, HDA_INPUT),
4305 HDA_CODEC_MUTE("ATATI Mic Playback Switch", 0x07, 0x1, HDA_INPUT),
4306 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
4307 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
4308 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
4309 { } /* end */
4310};
4311
Kailang Yangdf694da2005-12-05 19:42:22 +01004312/* capture mixer elements */
4313static struct snd_kcontrol_new alc260_capture_mixer[] = {
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004314 HDA_CODEC_VOLUME("Capture Volume", 0x04, 0x0, HDA_INPUT),
4315 HDA_CODEC_MUTE("Capture Switch", 0x04, 0x0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01004316 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x05, 0x0, HDA_INPUT),
4317 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x05, 0x0, HDA_INPUT),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004318 {
4319 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Kailang Yangdf694da2005-12-05 19:42:22 +01004320 /* The multiple "Capture Source" controls confuse alsamixer
4321 * So call somewhat different..
Kailang Yangdf694da2005-12-05 19:42:22 +01004322 */
4323 /* .name = "Capture Source", */
4324 .name = "Input Source",
4325 .count = 2,
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004326 .info = alc_mux_enum_info,
4327 .get = alc_mux_enum_get,
4328 .put = alc_mux_enum_put,
4329 },
4330 { } /* end */
4331};
4332
Kailang Yangdf694da2005-12-05 19:42:22 +01004333static struct snd_kcontrol_new alc260_capture_alt_mixer[] = {
4334 HDA_CODEC_VOLUME("Capture Volume", 0x05, 0x0, HDA_INPUT),
4335 HDA_CODEC_MUTE("Capture Switch", 0x05, 0x0, HDA_INPUT),
4336 {
4337 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4338 /* The multiple "Capture Source" controls confuse alsamixer
4339 * So call somewhat different..
Kailang Yangdf694da2005-12-05 19:42:22 +01004340 */
4341 /* .name = "Capture Source", */
4342 .name = "Input Source",
4343 .count = 1,
4344 .info = alc_mux_enum_info,
4345 .get = alc_mux_enum_get,
4346 .put = alc_mux_enum_put,
4347 },
4348 { } /* end */
4349};
4350
4351/*
4352 * initialization verbs
4353 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004354static struct hda_verb alc260_init_verbs[] = {
4355 /* Line In pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02004356 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004357 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02004358 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004359 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02004360 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004361 /* Mic2 (front panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02004362 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004363 /* LINE-2 is used for line-out in rear */
Takashi Iwai05acb862005-06-10 19:50:25 +02004364 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004365 /* select line-out */
Jonathan Woithefd56f2d2006-01-24 10:35:46 +01004366 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004367 /* LINE-OUT pin */
Takashi Iwai05acb862005-06-10 19:50:25 +02004368 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004369 /* enable HP */
Takashi Iwai05acb862005-06-10 19:50:25 +02004370 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004371 /* enable Mono */
Takashi Iwai05acb862005-06-10 19:50:25 +02004372 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4373 /* mute capture amp left and right */
Takashi Iwai16ded522005-06-10 19:58:24 +02004374 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004375 /* set connection select to line in (default select for this ADC) */
4376 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai16ded522005-06-10 19:58:24 +02004377 /* mute capture amp left and right */
4378 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4379 /* set connection select to line in (default select for this ADC) */
4380 {0x05, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai05acb862005-06-10 19:50:25 +02004381 /* set vol=0 Line-Out mixer amp left and right */
4382 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4383 /* unmute pin widget amp left and right (no gain on this amp) */
4384 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4385 /* set vol=0 HP mixer amp left and right */
4386 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4387 /* unmute pin widget amp left and right (no gain on this amp) */
4388 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4389 /* set vol=0 Mono mixer amp left and right */
4390 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4391 /* unmute pin widget amp left and right (no gain on this amp) */
4392 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4393 /* unmute LINE-2 out pin */
4394 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004395 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
4396 * Line In 2 = 0x03
4397 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02004398 /* mute analog inputs */
4399 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4400 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4401 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4402 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4403 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004404 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
Takashi Iwai05acb862005-06-10 19:50:25 +02004405 /* mute Front out path */
4406 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4407 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4408 /* mute Headphone out path */
4409 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4410 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4411 /* mute Mono out path */
4412 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4413 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004414 { }
4415};
4416
Takashi Iwai474167d2006-05-17 17:17:43 +02004417#if 0 /* should be identical with alc260_init_verbs? */
Kailang Yangdf694da2005-12-05 19:42:22 +01004418static struct hda_verb alc260_hp_init_verbs[] = {
4419 /* Headphone and output */
4420 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
4421 /* mono output */
4422 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4423 /* Mic1 (rear panel) pin widget for input and vref at 80% */
4424 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4425 /* Mic2 (front panel) pin widget for input and vref at 80% */
4426 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4427 /* Line In pin widget for input */
4428 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4429 /* Line-2 pin widget for output */
4430 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4431 /* CD pin widget for input */
4432 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4433 /* unmute amp left and right */
4434 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
4435 /* set connection select to line in (default select for this ADC) */
4436 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
4437 /* unmute Line-Out mixer amp left and right (volume = 0) */
4438 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
4439 /* mute pin widget amp left and right (no gain on this amp) */
4440 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
4441 /* unmute HP mixer amp left and right (volume = 0) */
4442 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
4443 /* mute pin widget amp left and right (no gain on this amp) */
4444 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004445 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
4446 * Line In 2 = 0x03
4447 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02004448 /* mute analog inputs */
4449 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4450 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4451 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4452 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4453 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01004454 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
4455 /* Unmute Front out path */
4456 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4457 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4458 /* Unmute Headphone out path */
4459 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4460 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4461 /* Unmute Mono out path */
4462 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4463 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4464 { }
4465};
Takashi Iwai474167d2006-05-17 17:17:43 +02004466#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01004467
4468static struct hda_verb alc260_hp_3013_init_verbs[] = {
4469 /* Line out and output */
4470 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4471 /* mono output */
4472 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4473 /* Mic1 (rear panel) pin widget for input and vref at 80% */
4474 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4475 /* Mic2 (front panel) pin widget for input and vref at 80% */
4476 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4477 /* Line In pin widget for input */
4478 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4479 /* Headphone pin widget for output */
4480 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
4481 /* CD pin widget for input */
4482 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4483 /* unmute amp left and right */
4484 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
4485 /* set connection select to line in (default select for this ADC) */
4486 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
4487 /* unmute Line-Out mixer amp left and right (volume = 0) */
4488 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
4489 /* mute pin widget amp left and right (no gain on this amp) */
4490 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
4491 /* unmute HP mixer amp left and right (volume = 0) */
4492 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
4493 /* mute pin widget amp left and right (no gain on this amp) */
4494 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004495 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
4496 * Line In 2 = 0x03
4497 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02004498 /* mute analog inputs */
4499 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4500 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4501 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4502 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4503 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01004504 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
4505 /* Unmute Front out path */
4506 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4507 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4508 /* Unmute Headphone out path */
4509 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4510 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4511 /* Unmute Mono out path */
4512 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4513 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4514 { }
4515};
4516
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004517/* Initialisation sequence for ALC260 as configured in Fujitsu S702x
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004518 * laptops. ALC260 pin usage: Mic/Line jack = 0x12, HP jack = 0x14, CD
4519 * audio = 0x16, internal speaker = 0x10.
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004520 */
4521static struct hda_verb alc260_fujitsu_init_verbs[] = {
4522 /* Disable all GPIOs */
4523 {0x01, AC_VERB_SET_GPIO_MASK, 0},
4524 /* Internal speaker is connected to headphone pin */
4525 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4526 /* Headphone/Line-out jack connects to Line1 pin; make it an output */
4527 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Jonathan Woithef7ace402006-02-28 11:46:14 +01004528 /* Mic/Line-in jack is connected to mic1 pin, so make it an input */
4529 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4530 /* Ensure all other unused pins are disabled and muted. */
4531 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4532 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004533 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01004534 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004535 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01004536 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4537 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4538 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004539
Jonathan Woithef7ace402006-02-28 11:46:14 +01004540 /* Disable digital (SPDIF) pins */
4541 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
4542 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004543
Kailang Yangea1fb292008-08-26 12:58:38 +02004544 /* Ensure Line1 pin widget takes its input from the OUT1 sum bus
Jonathan Woithef7ace402006-02-28 11:46:14 +01004545 * when acting as an output.
4546 */
4547 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
4548
4549 /* Start with output sum widgets muted and their output gains at min */
Takashi Iwai8b33a5a2006-02-09 11:57:01 +01004550 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4551 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4552 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4553 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4554 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4555 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4556 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4557 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4558 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004559
Jonathan Woithef7ace402006-02-28 11:46:14 +01004560 /* Unmute HP pin widget amp left and right (no equiv mixer ctrl) */
4561 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4562 /* Unmute Line1 pin widget output buffer since it starts as an output.
4563 * If the pin mode is changed by the user the pin mode control will
4564 * take care of enabling the pin's input/output buffers as needed.
4565 * Therefore there's no need to enable the input buffer at this
4566 * stage.
Jonathan Woithecdcd9262006-02-28 11:36:42 +01004567 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01004568 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +02004569 /* Unmute input buffer of pin widget used for Line-in (no equiv
Jonathan Woithecdcd9262006-02-28 11:36:42 +01004570 * mixer ctrl)
4571 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01004572 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004573
Jonathan Woithef7ace402006-02-28 11:46:14 +01004574 /* Mute capture amp left and right */
4575 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +02004576 /* Set ADC connection select to match default mixer setting - line
Jonathan Woithef7ace402006-02-28 11:46:14 +01004577 * in (on mic1 pin)
4578 */
4579 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004580
Jonathan Woithef7ace402006-02-28 11:46:14 +01004581 /* Do the same for the second ADC: mute capture input amp and
4582 * set ADC connection to line in (on mic1 pin)
4583 */
4584 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4585 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004586
Jonathan Woithef7ace402006-02-28 11:46:14 +01004587 /* Mute all inputs to mixer widget (even unconnected ones) */
4588 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
4589 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
4590 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
4591 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
4592 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
4593 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
4594 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
4595 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
Takashi Iwai4a471b72005-12-07 13:56:29 +01004596
4597 { }
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004598};
4599
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004600/* Initialisation sequence for ALC260 as configured in Acer TravelMate and
4601 * similar laptops (adapted from Fujitsu init verbs).
4602 */
4603static struct hda_verb alc260_acer_init_verbs[] = {
4604 /* On TravelMate laptops, GPIO 0 enables the internal speaker and
4605 * the headphone jack. Turn this on and rely on the standard mute
4606 * methods whenever the user wants to turn these outputs off.
4607 */
4608 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
4609 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
4610 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
4611 /* Internal speaker/Headphone jack is connected to Line-out pin */
4612 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4613 /* Internal microphone/Mic jack is connected to Mic1 pin */
4614 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
4615 /* Line In jack is connected to Line1 pin */
4616 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Jonathan Woithebd869482006-11-28 11:35:52 +01004617 /* Some Acers (eg: C20x Tablets) use Mono pin for internal speaker */
4618 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004619 /* Ensure all other unused pins are disabled and muted. */
4620 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4621 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004622 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4623 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4624 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4625 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4626 /* Disable digital (SPDIF) pins */
4627 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
4628 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
4629
Kailang Yangea1fb292008-08-26 12:58:38 +02004630 /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004631 * bus when acting as outputs.
4632 */
4633 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
4634 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
4635
4636 /* Start with output sum widgets muted and their output gains at min */
4637 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4638 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4639 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4640 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4641 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4642 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4643 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4644 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4645 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4646
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004647 /* Unmute Line-out pin widget amp left and right
4648 * (no equiv mixer ctrl)
4649 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004650 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithebd869482006-11-28 11:35:52 +01004651 /* Unmute mono pin widget amp output (no equiv mixer ctrl) */
4652 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004653 /* Unmute Mic1 and Line1 pin widget input buffers since they start as
4654 * inputs. If the pin mode is changed by the user the pin mode control
4655 * will take care of enabling the pin's input/output buffers as needed.
4656 * Therefore there's no need to enable the input buffer at this
4657 * stage.
4658 */
4659 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4660 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4661
4662 /* Mute capture amp left and right */
4663 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4664 /* Set ADC connection select to match default mixer setting - mic
4665 * (on mic1 pin)
4666 */
4667 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
4668
4669 /* Do similar with the second ADC: mute capture input amp and
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004670 * set ADC connection to mic to match ALSA's default state.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004671 */
4672 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004673 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004674
4675 /* Mute all inputs to mixer widget (even unconnected ones) */
4676 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
4677 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
4678 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
4679 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
4680 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
4681 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
4682 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
4683 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
4684
4685 { }
4686};
4687
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004688static struct hda_verb alc260_will_verbs[] = {
4689 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4690 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x00},
4691 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
4692 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
4693 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
4694 {0x1a, AC_VERB_SET_PROC_COEF, 0x3040},
4695 {}
4696};
4697
4698static struct hda_verb alc260_replacer_672v_verbs[] = {
4699 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
4700 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
4701 {0x1a, AC_VERB_SET_PROC_COEF, 0x3050},
4702
4703 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
4704 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
4705 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
4706
4707 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
4708 {}
4709};
4710
4711/* toggle speaker-output according to the hp-jack state */
4712static void alc260_replacer_672v_automute(struct hda_codec *codec)
4713{
4714 unsigned int present;
4715
4716 /* speaker --> GPIO Data 0, hp or spdif --> GPIO data 1 */
4717 present = snd_hda_codec_read(codec, 0x0f, 0,
4718 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
4719 if (present) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02004720 snd_hda_codec_write_cache(codec, 0x01, 0,
4721 AC_VERB_SET_GPIO_DATA, 1);
4722 snd_hda_codec_write_cache(codec, 0x0f, 0,
4723 AC_VERB_SET_PIN_WIDGET_CONTROL,
4724 PIN_HP);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004725 } else {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02004726 snd_hda_codec_write_cache(codec, 0x01, 0,
4727 AC_VERB_SET_GPIO_DATA, 0);
4728 snd_hda_codec_write_cache(codec, 0x0f, 0,
4729 AC_VERB_SET_PIN_WIDGET_CONTROL,
4730 PIN_OUT);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004731 }
4732}
4733
4734static void alc260_replacer_672v_unsol_event(struct hda_codec *codec,
4735 unsigned int res)
4736{
4737 if ((res >> 26) == ALC880_HP_EVENT)
4738 alc260_replacer_672v_automute(codec);
4739}
4740
Kailang Yang3f878302008-08-26 13:02:23 +02004741static struct hda_verb alc260_hp_dc7600_verbs[] = {
4742 {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
4743 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
4744 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4745 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4746 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4747 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4748 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4749 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
4750 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
4751 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
4752 {}
4753};
4754
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004755/* Test configuration for debugging, modelled after the ALC880 test
4756 * configuration.
4757 */
4758#ifdef CONFIG_SND_DEBUG
4759static hda_nid_t alc260_test_dac_nids[1] = {
4760 0x02,
4761};
4762static hda_nid_t alc260_test_adc_nids[2] = {
4763 0x04, 0x05,
4764};
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004765/* For testing the ALC260, each input MUX needs its own definition since
Kailang Yangea1fb292008-08-26 12:58:38 +02004766 * the signal assignments are different. This assumes that the first ADC
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004767 * is NID 0x04.
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01004768 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004769static struct hda_input_mux alc260_test_capture_sources[2] = {
4770 {
4771 .num_items = 7,
4772 .items = {
4773 { "MIC1 pin", 0x0 },
4774 { "MIC2 pin", 0x1 },
4775 { "LINE1 pin", 0x2 },
4776 { "LINE2 pin", 0x3 },
4777 { "CD pin", 0x4 },
4778 { "LINE-OUT pin", 0x5 },
4779 { "HP-OUT pin", 0x6 },
4780 },
4781 },
4782 {
4783 .num_items = 8,
4784 .items = {
4785 { "MIC1 pin", 0x0 },
4786 { "MIC2 pin", 0x1 },
4787 { "LINE1 pin", 0x2 },
4788 { "LINE2 pin", 0x3 },
4789 { "CD pin", 0x4 },
4790 { "Mixer", 0x5 },
4791 { "LINE-OUT pin", 0x6 },
4792 { "HP-OUT pin", 0x7 },
4793 },
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004794 },
4795};
4796static struct snd_kcontrol_new alc260_test_mixer[] = {
4797 /* Output driver widgets */
4798 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
4799 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
4800 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x09, 0x0, HDA_OUTPUT),
4801 HDA_BIND_MUTE("LOUT2 Playback Switch", 0x09, 2, HDA_INPUT),
4802 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4803 HDA_BIND_MUTE("LOUT1 Playback Switch", 0x08, 2, HDA_INPUT),
4804
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004805 /* Modes for retasking pin widgets
4806 * Note: the ALC260 doesn't seem to act on requests to enable mic
4807 * bias from NIDs 0x0f and 0x10. The ALC260 datasheet doesn't
4808 * mention this restriction. At this stage it's not clear whether
4809 * this behaviour is intentional or is a hardware bug in chip
4810 * revisions available at least up until early 2006. Therefore for
4811 * now allow the "HP-OUT" and "LINE-OUT" Mode controls to span all
4812 * choices, but if it turns out that the lack of mic bias for these
4813 * NIDs is intentional we could change their modes from
4814 * ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
4815 */
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004816 ALC_PIN_MODE("HP-OUT pin mode", 0x10, ALC_PIN_DIR_INOUT),
4817 ALC_PIN_MODE("LINE-OUT pin mode", 0x0f, ALC_PIN_DIR_INOUT),
4818 ALC_PIN_MODE("LINE2 pin mode", 0x15, ALC_PIN_DIR_INOUT),
4819 ALC_PIN_MODE("LINE1 pin mode", 0x14, ALC_PIN_DIR_INOUT),
4820 ALC_PIN_MODE("MIC2 pin mode", 0x13, ALC_PIN_DIR_INOUT),
4821 ALC_PIN_MODE("MIC1 pin mode", 0x12, ALC_PIN_DIR_INOUT),
4822
4823 /* Loopback mixer controls */
4824 HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x07, 0x00, HDA_INPUT),
4825 HDA_CODEC_MUTE("MIC1 Playback Switch", 0x07, 0x00, HDA_INPUT),
4826 HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x07, 0x01, HDA_INPUT),
4827 HDA_CODEC_MUTE("MIC2 Playback Switch", 0x07, 0x01, HDA_INPUT),
4828 HDA_CODEC_VOLUME("LINE1 Playback Volume", 0x07, 0x02, HDA_INPUT),
4829 HDA_CODEC_MUTE("LINE1 Playback Switch", 0x07, 0x02, HDA_INPUT),
4830 HDA_CODEC_VOLUME("LINE2 Playback Volume", 0x07, 0x03, HDA_INPUT),
4831 HDA_CODEC_MUTE("LINE2 Playback Switch", 0x07, 0x03, HDA_INPUT),
4832 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4833 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
4834 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
4835 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
4836 HDA_CODEC_VOLUME("LINE-OUT loopback Playback Volume", 0x07, 0x06, HDA_INPUT),
4837 HDA_CODEC_MUTE("LINE-OUT loopback Playback Switch", 0x07, 0x06, HDA_INPUT),
4838 HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x07, 0x7, HDA_INPUT),
4839 HDA_CODEC_MUTE("HP-OUT loopback Playback Switch", 0x07, 0x7, HDA_INPUT),
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01004840
4841 /* Controls for GPIO pins, assuming they are configured as outputs */
4842 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
4843 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
4844 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
4845 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
4846
Jonathan Woithe92621f12006-02-28 11:47:47 +01004847 /* Switches to allow the digital IO pins to be enabled. The datasheet
4848 * is ambigious as to which NID is which; testing on laptops which
Kailang Yangea1fb292008-08-26 12:58:38 +02004849 * make this output available should provide clarification.
Jonathan Woithe92621f12006-02-28 11:47:47 +01004850 */
4851 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x03, 0x01),
4852 ALC_SPDIF_CTRL_SWITCH("SPDIF Capture Switch", 0x06, 0x01),
4853
Jonathan Woithef8225f62008-01-08 12:16:54 +01004854 /* A switch allowing EAPD to be enabled. Some laptops seem to use
4855 * this output to turn on an external amplifier.
4856 */
4857 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
4858 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
4859
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004860 { } /* end */
4861};
4862static struct hda_verb alc260_test_init_verbs[] = {
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01004863 /* Enable all GPIOs as outputs with an initial value of 0 */
4864 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f},
4865 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
4866 {0x01, AC_VERB_SET_GPIO_MASK, 0x0f},
4867
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004868 /* Enable retasking pins as output, initially without power amp */
4869 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4870 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4871 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4872 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4873 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4874 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4875
Jonathan Woithe92621f12006-02-28 11:47:47 +01004876 /* Disable digital (SPDIF) pins initially, but users can enable
4877 * them via a mixer switch. In the case of SPDIF-out, this initverb
4878 * payload also sets the generation to 0, output to be in "consumer"
4879 * PCM format, copyright asserted, no pre-emphasis and no validity
4880 * control.
4881 */
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004882 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
4883 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
4884
Kailang Yangea1fb292008-08-26 12:58:38 +02004885 /* Ensure mic1, mic2, line1 and line2 pin widgets take input from the
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004886 * OUT1 sum bus when acting as an output.
4887 */
4888 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
4889 {0x0c, AC_VERB_SET_CONNECT_SEL, 0},
4890 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
4891 {0x0e, AC_VERB_SET_CONNECT_SEL, 0},
4892
4893 /* Start with output sum widgets muted and their output gains at min */
4894 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4895 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4896 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4897 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4898 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4899 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4900 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4901 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4902 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4903
Jonathan Woithecdcd9262006-02-28 11:36:42 +01004904 /* Unmute retasking pin widget output buffers since the default
4905 * state appears to be output. As the pin mode is changed by the
4906 * user the pin mode control will take care of enabling the pin's
4907 * input/output buffers as needed.
4908 */
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004909 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4910 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4911 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4912 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4913 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4914 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4915 /* Also unmute the mono-out pin widget */
4916 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4917
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004918 /* Mute capture amp left and right */
4919 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithef7ace402006-02-28 11:46:14 +01004920 /* Set ADC connection select to match default mixer setting (mic1
4921 * pin)
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004922 */
4923 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
4924
4925 /* Do the same for the second ADC: mute capture input amp and
Jonathan Woithef7ace402006-02-28 11:46:14 +01004926 * set ADC connection to mic1 pin
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004927 */
4928 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4929 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
4930
4931 /* Mute all inputs to mixer widget (even unconnected ones) */
4932 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
4933 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
4934 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
4935 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
4936 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
4937 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
4938 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
4939 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
4940
4941 { }
4942};
4943#endif
4944
Takashi Iwai63300792008-01-24 15:31:36 +01004945#define alc260_pcm_analog_playback alc880_pcm_analog_alt_playback
4946#define alc260_pcm_analog_capture alc880_pcm_analog_capture
Linus Torvalds1da177e2005-04-16 15:20:36 -07004947
Takashi Iwaia3bcba32005-12-06 19:05:29 +01004948#define alc260_pcm_digital_playback alc880_pcm_digital_playback
4949#define alc260_pcm_digital_capture alc880_pcm_digital_capture
4950
Kailang Yangdf694da2005-12-05 19:42:22 +01004951/*
4952 * for BIOS auto-configuration
4953 */
4954
4955static int alc260_add_playback_controls(struct alc_spec *spec, hda_nid_t nid,
4956 const char *pfx)
4957{
4958 hda_nid_t nid_vol;
4959 unsigned long vol_val, sw_val;
4960 char name[32];
4961 int err;
4962
4963 if (nid >= 0x0f && nid < 0x11) {
4964 nid_vol = nid - 0x7;
4965 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
4966 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
4967 } else if (nid == 0x11) {
4968 nid_vol = nid - 0x7;
4969 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT);
4970 sw_val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
4971 } else if (nid >= 0x12 && nid <= 0x15) {
4972 nid_vol = 0x08;
4973 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
4974 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
4975 } else
4976 return 0; /* N/A */
Kailang Yangea1fb292008-08-26 12:58:38 +02004977
Kailang Yangdf694da2005-12-05 19:42:22 +01004978 snprintf(name, sizeof(name), "%s Playback Volume", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004979 err = add_control(spec, ALC_CTL_WIDGET_VOL, name, vol_val);
4980 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01004981 return err;
4982 snprintf(name, sizeof(name), "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004983 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, sw_val);
4984 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01004985 return err;
4986 return 1;
4987}
4988
4989/* add playback controls from the parsed DAC table */
4990static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec,
4991 const struct auto_pin_cfg *cfg)
4992{
4993 hda_nid_t nid;
4994 int err;
4995
4996 spec->multiout.num_dacs = 1;
4997 spec->multiout.dac_nids = spec->private_dac_nids;
4998 spec->multiout.dac_nids[0] = 0x02;
4999
5000 nid = cfg->line_out_pins[0];
5001 if (nid) {
5002 err = alc260_add_playback_controls(spec, nid, "Front");
5003 if (err < 0)
5004 return err;
5005 }
5006
Takashi Iwai82bc9552006-03-21 11:24:42 +01005007 nid = cfg->speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01005008 if (nid) {
5009 err = alc260_add_playback_controls(spec, nid, "Speaker");
5010 if (err < 0)
5011 return err;
5012 }
5013
Takashi Iwaieb06ed82006-09-20 17:10:27 +02005014 nid = cfg->hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01005015 if (nid) {
5016 err = alc260_add_playback_controls(spec, nid, "Headphone");
5017 if (err < 0)
5018 return err;
5019 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005020 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01005021}
5022
5023/* create playback/capture controls for input pins */
5024static int alc260_auto_create_analog_input_ctls(struct alc_spec *spec,
5025 const struct auto_pin_cfg *cfg)
5026{
Kailang Yangdf694da2005-12-05 19:42:22 +01005027 struct hda_input_mux *imux = &spec->private_imux;
5028 int i, err, idx;
5029
5030 for (i = 0; i < AUTO_PIN_LAST; i++) {
5031 if (cfg->input_pins[i] >= 0x12) {
5032 idx = cfg->input_pins[i] - 0x12;
Takashi Iwai4a471b72005-12-07 13:56:29 +01005033 err = new_analog_input(spec, cfg->input_pins[i],
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005034 auto_pin_cfg_labels[i], idx,
5035 0x07);
Kailang Yangdf694da2005-12-05 19:42:22 +01005036 if (err < 0)
5037 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005038 imux->items[imux->num_items].label =
5039 auto_pin_cfg_labels[i];
Kailang Yangdf694da2005-12-05 19:42:22 +01005040 imux->items[imux->num_items].index = idx;
5041 imux->num_items++;
5042 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005043 if (cfg->input_pins[i] >= 0x0f && cfg->input_pins[i] <= 0x10){
Kailang Yangdf694da2005-12-05 19:42:22 +01005044 idx = cfg->input_pins[i] - 0x09;
Takashi Iwai4a471b72005-12-07 13:56:29 +01005045 err = new_analog_input(spec, cfg->input_pins[i],
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005046 auto_pin_cfg_labels[i], idx,
5047 0x07);
Kailang Yangdf694da2005-12-05 19:42:22 +01005048 if (err < 0)
5049 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005050 imux->items[imux->num_items].label =
5051 auto_pin_cfg_labels[i];
Kailang Yangdf694da2005-12-05 19:42:22 +01005052 imux->items[imux->num_items].index = idx;
5053 imux->num_items++;
5054 }
5055 }
5056 return 0;
5057}
5058
5059static void alc260_auto_set_output_and_unmute(struct hda_codec *codec,
5060 hda_nid_t nid, int pin_type,
5061 int sel_idx)
5062{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005063 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01005064 /* need the manual connection? */
5065 if (nid >= 0x12) {
5066 int idx = nid - 0x12;
5067 snd_hda_codec_write(codec, idx + 0x0b, 0,
5068 AC_VERB_SET_CONNECT_SEL, sel_idx);
Kailang Yangdf694da2005-12-05 19:42:22 +01005069 }
5070}
5071
5072static void alc260_auto_init_multi_out(struct hda_codec *codec)
5073{
5074 struct alc_spec *spec = codec->spec;
5075 hda_nid_t nid;
5076
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005077 alc_subsystem_id(codec, 0x10, 0x15, 0x0f);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005078 nid = spec->autocfg.line_out_pins[0];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02005079 if (nid) {
5080 int pin_type = get_pin_type(spec->autocfg.line_out_type);
5081 alc260_auto_set_output_and_unmute(codec, nid, pin_type, 0);
5082 }
Kailang Yangea1fb292008-08-26 12:58:38 +02005083
Takashi Iwai82bc9552006-03-21 11:24:42 +01005084 nid = spec->autocfg.speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01005085 if (nid)
5086 alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
5087
Takashi Iwaieb06ed82006-09-20 17:10:27 +02005088 nid = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01005089 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02005090 alc260_auto_set_output_and_unmute(codec, nid, PIN_HP, 0);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005091}
Kailang Yangdf694da2005-12-05 19:42:22 +01005092
5093#define ALC260_PIN_CD_NID 0x16
5094static void alc260_auto_init_analog_input(struct hda_codec *codec)
5095{
5096 struct alc_spec *spec = codec->spec;
5097 int i;
5098
5099 for (i = 0; i < AUTO_PIN_LAST; i++) {
5100 hda_nid_t nid = spec->autocfg.input_pins[i];
5101 if (nid >= 0x12) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005102 snd_hda_codec_write(codec, nid, 0,
5103 AC_VERB_SET_PIN_WIDGET_CONTROL,
5104 i <= AUTO_PIN_FRONT_MIC ?
5105 PIN_VREF80 : PIN_IN);
Kailang Yangdf694da2005-12-05 19:42:22 +01005106 if (nid != ALC260_PIN_CD_NID)
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005107 snd_hda_codec_write(codec, nid, 0,
5108 AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangdf694da2005-12-05 19:42:22 +01005109 AMP_OUT_MUTE);
5110 }
5111 }
5112}
5113
5114/*
5115 * generic initialization of ADC, input mixers and output mixers
5116 */
5117static struct hda_verb alc260_volume_init_verbs[] = {
5118 /*
5119 * Unmute ADC0-1 and set the default input to mic-in
5120 */
5121 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
5122 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5123 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
5124 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +02005125
Kailang Yangdf694da2005-12-05 19:42:22 +01005126 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
5127 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005128 * Note: PASD motherboards uses the Line In 2 as the input for
5129 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01005130 */
5131 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02005132 /* mute analog inputs */
5133 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5134 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5135 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5136 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5137 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01005138
5139 /*
5140 * Set up output mixers (0x08 - 0x0a)
5141 */
5142 /* set vol=0 to output mixers */
5143 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5144 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5145 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5146 /* set up input amps for analog loopback */
5147 /* Amp Indices: DAC = 0, mixer = 1 */
5148 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5149 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5150 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5151 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5152 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5153 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +02005154
Kailang Yangdf694da2005-12-05 19:42:22 +01005155 { }
5156};
5157
5158static int alc260_parse_auto_config(struct hda_codec *codec)
5159{
5160 struct alc_spec *spec = codec->spec;
5161 unsigned int wcap;
5162 int err;
5163 static hda_nid_t alc260_ignore[] = { 0x17, 0 };
5164
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005165 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
5166 alc260_ignore);
5167 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01005168 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005169 err = alc260_auto_create_multi_out_ctls(spec, &spec->autocfg);
5170 if (err < 0)
Takashi Iwai4a471b72005-12-07 13:56:29 +01005171 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005172 if (!spec->kctl_alloc)
Kailang Yangdf694da2005-12-05 19:42:22 +01005173 return 0; /* can't find valid BIOS pin config */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005174 err = alc260_auto_create_analog_input_ctls(spec, &spec->autocfg);
5175 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01005176 return err;
5177
5178 spec->multiout.max_channels = 2;
5179
5180 if (spec->autocfg.dig_out_pin)
5181 spec->multiout.dig_out_nid = ALC260_DIGOUT_NID;
5182 if (spec->kctl_alloc)
5183 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
5184
5185 spec->init_verbs[spec->num_init_verbs++] = alc260_volume_init_verbs;
5186
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005187 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +01005188 spec->input_mux = &spec->private_imux;
5189
5190 /* check whether NID 0x04 is valid */
Takashi Iwai4a471b72005-12-07 13:56:29 +01005191 wcap = get_wcaps(codec, 0x04);
Kailang Yangdf694da2005-12-05 19:42:22 +01005192 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; /* get type */
Takashi Iwai67ebcb02008-02-19 15:03:57 +01005193 if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
Kailang Yangdf694da2005-12-05 19:42:22 +01005194 spec->adc_nids = alc260_adc_nids_alt;
5195 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt);
5196 spec->mixers[spec->num_mixers] = alc260_capture_alt_mixer;
Kailang Yangdf694da2005-12-05 19:42:22 +01005197 } else {
5198 spec->adc_nids = alc260_adc_nids;
5199 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids);
5200 spec->mixers[spec->num_mixers] = alc260_capture_mixer;
Kailang Yangdf694da2005-12-05 19:42:22 +01005201 }
Takashi Iwai4a471b72005-12-07 13:56:29 +01005202 spec->num_mixers++;
Kailang Yangdf694da2005-12-05 19:42:22 +01005203
5204 return 1;
5205}
5206
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005207/* additional initialization for auto-configuration model */
5208static void alc260_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01005209{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005210 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01005211 alc260_auto_init_multi_out(codec);
5212 alc260_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005213 if (spec->unsol_event)
5214 alc_sku_automute(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01005215}
5216
Takashi Iwaicb53c622007-08-10 17:21:45 +02005217#ifdef CONFIG_SND_HDA_POWER_SAVE
5218static struct hda_amp_list alc260_loopbacks[] = {
5219 { 0x07, HDA_INPUT, 0 },
5220 { 0x07, HDA_INPUT, 1 },
5221 { 0x07, HDA_INPUT, 2 },
5222 { 0x07, HDA_INPUT, 3 },
5223 { 0x07, HDA_INPUT, 4 },
5224 { } /* end */
5225};
5226#endif
5227
Kailang Yangdf694da2005-12-05 19:42:22 +01005228/*
5229 * ALC260 configurations
5230 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005231static const char *alc260_models[ALC260_MODEL_LAST] = {
5232 [ALC260_BASIC] = "basic",
5233 [ALC260_HP] = "hp",
5234 [ALC260_HP_3013] = "hp-3013",
5235 [ALC260_FUJITSU_S702X] = "fujitsu",
5236 [ALC260_ACER] = "acer",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005237 [ALC260_WILL] = "will",
5238 [ALC260_REPLACER_672V] = "replacer",
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005239#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005240 [ALC260_TEST] = "test",
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005241#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005242 [ALC260_AUTO] = "auto",
5243};
5244
5245static struct snd_pci_quirk alc260_cfg_tbl[] = {
Jonathan Woithebd869482006-11-28 11:35:52 +01005246 SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005247 SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER),
Takashi Iwai9720b712007-03-13 21:46:23 +01005248 SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013),
Takashi Iwaia8a5d062007-03-15 15:10:28 +01005249 SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_HP_3013),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005250 SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013),
Jaroslav Kysela34ec8a02008-07-10 14:49:19 +02005251 SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP_3013),
Kailang Yang3f878302008-08-26 13:02:23 +02005252 SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_DC7600),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005253 SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013),
5254 SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP),
5255 SND_PCI_QUIRK(0x103c, 0x3015, "HP", ALC260_HP),
5256 SND_PCI_QUIRK(0x103c, 0x3016, "HP", ALC260_HP),
5257 SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_BASIC),
5258 SND_PCI_QUIRK(0x104d, 0x81cc, "Sony VAIO", ALC260_BASIC),
5259 SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC),
5260 SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X),
5261 SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005262 SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_REPLACER_672V),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01005263 SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_WILL),
Takashi Iwai16ded522005-06-10 19:58:24 +02005264 {}
5265};
5266
Kailang Yangdf694da2005-12-05 19:42:22 +01005267static struct alc_config_preset alc260_presets[] = {
5268 [ALC260_BASIC] = {
5269 .mixers = { alc260_base_output_mixer,
5270 alc260_input_mixer,
5271 alc260_pc_beep_mixer,
5272 alc260_capture_mixer },
5273 .init_verbs = { alc260_init_verbs },
5274 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5275 .dac_nids = alc260_dac_nids,
5276 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
5277 .adc_nids = alc260_adc_nids,
5278 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5279 .channel_mode = alc260_modes,
5280 .input_mux = &alc260_capture_source,
5281 },
5282 [ALC260_HP] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01005283 .mixers = { alc260_hp_output_mixer,
Kailang Yangdf694da2005-12-05 19:42:22 +01005284 alc260_input_mixer,
5285 alc260_capture_alt_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01005286 .init_verbs = { alc260_init_verbs,
5287 alc260_hp_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01005288 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5289 .dac_nids = alc260_dac_nids,
5290 .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids),
5291 .adc_nids = alc260_hp_adc_nids,
5292 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5293 .channel_mode = alc260_modes,
5294 .input_mux = &alc260_capture_source,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005295 .unsol_event = alc260_hp_unsol_event,
5296 .init_hook = alc260_hp_automute,
Kailang Yangdf694da2005-12-05 19:42:22 +01005297 },
Kailang Yang3f878302008-08-26 13:02:23 +02005298 [ALC260_HP_DC7600] = {
5299 .mixers = { alc260_hp_dc7600_mixer,
5300 alc260_input_mixer,
5301 alc260_capture_alt_mixer },
5302 .init_verbs = { alc260_init_verbs,
5303 alc260_hp_dc7600_verbs },
5304 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5305 .dac_nids = alc260_dac_nids,
5306 .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids),
5307 .adc_nids = alc260_hp_adc_nids,
5308 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5309 .channel_mode = alc260_modes,
5310 .input_mux = &alc260_capture_source,
5311 .unsol_event = alc260_hp_3012_unsol_event,
5312 .init_hook = alc260_hp_3012_automute,
5313 },
Kailang Yangdf694da2005-12-05 19:42:22 +01005314 [ALC260_HP_3013] = {
5315 .mixers = { alc260_hp_3013_mixer,
5316 alc260_input_mixer,
5317 alc260_capture_alt_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01005318 .init_verbs = { alc260_hp_3013_init_verbs,
5319 alc260_hp_3013_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01005320 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5321 .dac_nids = alc260_dac_nids,
5322 .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids),
5323 .adc_nids = alc260_hp_adc_nids,
5324 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5325 .channel_mode = alc260_modes,
5326 .input_mux = &alc260_capture_source,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005327 .unsol_event = alc260_hp_3013_unsol_event,
5328 .init_hook = alc260_hp_3013_automute,
Kailang Yangdf694da2005-12-05 19:42:22 +01005329 },
5330 [ALC260_FUJITSU_S702X] = {
5331 .mixers = { alc260_fujitsu_mixer,
5332 alc260_capture_mixer },
5333 .init_verbs = { alc260_fujitsu_init_verbs },
5334 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5335 .dac_nids = alc260_dac_nids,
Jonathan Woithed57fdac2006-02-28 11:38:35 +01005336 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
5337 .adc_nids = alc260_dual_adc_nids,
Kailang Yangdf694da2005-12-05 19:42:22 +01005338 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5339 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005340 .num_mux_defs = ARRAY_SIZE(alc260_fujitsu_capture_sources),
5341 .input_mux = alc260_fujitsu_capture_sources,
Kailang Yangdf694da2005-12-05 19:42:22 +01005342 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005343 [ALC260_ACER] = {
5344 .mixers = { alc260_acer_mixer,
5345 alc260_capture_mixer },
5346 .init_verbs = { alc260_acer_init_verbs },
5347 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5348 .dac_nids = alc260_dac_nids,
5349 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
5350 .adc_nids = alc260_dual_adc_nids,
5351 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5352 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005353 .num_mux_defs = ARRAY_SIZE(alc260_acer_capture_sources),
5354 .input_mux = alc260_acer_capture_sources,
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005355 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005356 [ALC260_WILL] = {
5357 .mixers = { alc260_will_mixer,
5358 alc260_capture_mixer },
5359 .init_verbs = { alc260_init_verbs, alc260_will_verbs },
5360 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5361 .dac_nids = alc260_dac_nids,
5362 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
5363 .adc_nids = alc260_adc_nids,
5364 .dig_out_nid = ALC260_DIGOUT_NID,
5365 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5366 .channel_mode = alc260_modes,
5367 .input_mux = &alc260_capture_source,
5368 },
5369 [ALC260_REPLACER_672V] = {
5370 .mixers = { alc260_replacer_672v_mixer,
5371 alc260_capture_mixer },
5372 .init_verbs = { alc260_init_verbs, alc260_replacer_672v_verbs },
5373 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5374 .dac_nids = alc260_dac_nids,
5375 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
5376 .adc_nids = alc260_adc_nids,
5377 .dig_out_nid = ALC260_DIGOUT_NID,
5378 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5379 .channel_mode = alc260_modes,
5380 .input_mux = &alc260_capture_source,
5381 .unsol_event = alc260_replacer_672v_unsol_event,
5382 .init_hook = alc260_replacer_672v_automute,
5383 },
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005384#ifdef CONFIG_SND_DEBUG
5385 [ALC260_TEST] = {
5386 .mixers = { alc260_test_mixer,
5387 alc260_capture_mixer },
5388 .init_verbs = { alc260_test_init_verbs },
5389 .num_dacs = ARRAY_SIZE(alc260_test_dac_nids),
5390 .dac_nids = alc260_test_dac_nids,
5391 .num_adc_nids = ARRAY_SIZE(alc260_test_adc_nids),
5392 .adc_nids = alc260_test_adc_nids,
5393 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5394 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005395 .num_mux_defs = ARRAY_SIZE(alc260_test_capture_sources),
5396 .input_mux = alc260_test_capture_sources,
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005397 },
5398#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01005399};
5400
Linus Torvalds1da177e2005-04-16 15:20:36 -07005401static int patch_alc260(struct hda_codec *codec)
5402{
5403 struct alc_spec *spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01005404 int err, board_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005405
Takashi Iwaie560d8d2005-09-09 14:21:46 +02005406 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005407 if (spec == NULL)
5408 return -ENOMEM;
5409
5410 codec->spec = spec;
5411
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005412 board_config = snd_hda_check_board_config(codec, ALC260_MODEL_LAST,
5413 alc260_models,
5414 alc260_cfg_tbl);
5415 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02005416 snd_printd(KERN_INFO "hda_codec: Unknown model for ALC260, "
5417 "trying auto-probe from BIOS...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01005418 board_config = ALC260_AUTO;
Takashi Iwai16ded522005-06-10 19:58:24 +02005419 }
5420
Kailang Yangdf694da2005-12-05 19:42:22 +01005421 if (board_config == ALC260_AUTO) {
5422 /* automatic parse from the BIOS config */
5423 err = alc260_parse_auto_config(codec);
5424 if (err < 0) {
5425 alc_free(codec);
5426 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005427 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02005428 printk(KERN_INFO
5429 "hda_codec: Cannot set up configuration "
5430 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01005431 board_config = ALC260_BASIC;
5432 }
Takashi Iwai16ded522005-06-10 19:58:24 +02005433 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005434
Kailang Yangdf694da2005-12-05 19:42:22 +01005435 if (board_config != ALC260_AUTO)
5436 setup_preset(spec, &alc260_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005437
5438 spec->stream_name_analog = "ALC260 Analog";
5439 spec->stream_analog_playback = &alc260_pcm_analog_playback;
5440 spec->stream_analog_capture = &alc260_pcm_analog_capture;
5441
Takashi Iwaia3bcba32005-12-06 19:05:29 +01005442 spec->stream_name_digital = "ALC260 Digital";
5443 spec->stream_digital_playback = &alc260_pcm_digital_playback;
5444 spec->stream_digital_capture = &alc260_pcm_digital_capture;
5445
Takashi Iwai2134ea42008-01-10 16:53:55 +01005446 spec->vmaster_nid = 0x08;
5447
Linus Torvalds1da177e2005-04-16 15:20:36 -07005448 codec->patch_ops = alc_patch_ops;
Kailang Yangdf694da2005-12-05 19:42:22 +01005449 if (board_config == ALC260_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005450 spec->init_hook = alc260_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02005451#ifdef CONFIG_SND_HDA_POWER_SAVE
5452 if (!spec->loopback.amplist)
5453 spec->loopback.amplist = alc260_loopbacks;
5454#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005455
5456 return 0;
5457}
5458
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005459
Linus Torvalds1da177e2005-04-16 15:20:36 -07005460/*
5461 * ALC882 support
5462 *
5463 * ALC882 is almost identical with ALC880 but has cleaner and more flexible
5464 * configuration. Each pin widget can choose any input DACs and a mixer.
5465 * Each ADC is connected from a mixer of all inputs. This makes possible
5466 * 6-channel independent captures.
5467 *
5468 * In addition, an independent DAC for the multi-playback (not used in this
5469 * driver yet).
5470 */
Kailang Yangdf694da2005-12-05 19:42:22 +01005471#define ALC882_DIGOUT_NID 0x06
5472#define ALC882_DIGIN_NID 0x0a
Linus Torvalds1da177e2005-04-16 15:20:36 -07005473
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01005474static struct hda_channel_mode alc882_ch_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005475 { 8, NULL }
5476};
5477
5478static hda_nid_t alc882_dac_nids[4] = {
5479 /* front, rear, clfe, rear_surr */
5480 0x02, 0x03, 0x04, 0x05
5481};
5482
Kailang Yangdf694da2005-12-05 19:42:22 +01005483/* identical with ALC880 */
5484#define alc882_adc_nids alc880_adc_nids
5485#define alc882_adc_nids_alt alc880_adc_nids_alt
Linus Torvalds1da177e2005-04-16 15:20:36 -07005486
Takashi Iwaie1406342008-02-11 18:32:32 +01005487static hda_nid_t alc882_capsrc_nids[3] = { 0x24, 0x23, 0x22 };
5488static hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 };
5489
Linus Torvalds1da177e2005-04-16 15:20:36 -07005490/* input MUX */
5491/* FIXME: should be a matrix-type input source selection */
5492
5493static struct hda_input_mux alc882_capture_source = {
5494 .num_items = 4,
5495 .items = {
5496 { "Mic", 0x0 },
5497 { "Front Mic", 0x1 },
5498 { "Line", 0x2 },
5499 { "CD", 0x4 },
5500 },
5501};
Linus Torvalds1da177e2005-04-16 15:20:36 -07005502#define alc882_mux_enum_info alc_mux_enum_info
5503#define alc882_mux_enum_get alc_mux_enum_get
5504
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005505static int alc882_mux_enum_put(struct snd_kcontrol *kcontrol,
5506 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005507{
5508 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
5509 struct alc_spec *spec = codec->spec;
5510 const struct hda_input_mux *imux = spec->input_mux;
5511 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Takashi Iwai88c71a92008-02-14 17:27:17 +01005512 hda_nid_t nid = spec->capsrc_nids ?
5513 spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx];
Linus Torvalds1da177e2005-04-16 15:20:36 -07005514 unsigned int *cur_val = &spec->cur_mux[adc_idx];
5515 unsigned int i, idx;
5516
5517 idx = ucontrol->value.enumerated.item[0];
5518 if (idx >= imux->num_items)
5519 idx = imux->num_items - 1;
Takashi Iwai82beb8f2007-08-10 17:09:26 +02005520 if (*cur_val == idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005521 return 0;
5522 for (i = 0; i < imux->num_items; i++) {
Takashi Iwai47fd8302007-08-10 17:11:07 +02005523 unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE;
5524 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT,
Takashi Iwai82beb8f2007-08-10 17:09:26 +02005525 imux->items[i].index,
Takashi Iwai47fd8302007-08-10 17:11:07 +02005526 HDA_AMP_MUTE, v);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005527 }
5528 *cur_val = idx;
5529 return 1;
5530}
5531
Kailang Yangdf694da2005-12-05 19:42:22 +01005532/*
Kailang Yang272a5272007-05-14 11:00:38 +02005533 * 2ch mode
5534 */
5535static struct hda_verb alc882_3ST_ch2_init[] = {
5536 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
5537 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
5538 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
5539 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
5540 { } /* end */
5541};
5542
5543/*
5544 * 6ch mode
5545 */
5546static struct hda_verb alc882_3ST_ch6_init[] = {
5547 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5548 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
5549 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
5550 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5551 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
5552 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
5553 { } /* end */
5554};
5555
5556static struct hda_channel_mode alc882_3ST_6ch_modes[2] = {
5557 { 2, alc882_3ST_ch2_init },
5558 { 6, alc882_3ST_ch6_init },
5559};
5560
5561/*
Kailang Yangdf694da2005-12-05 19:42:22 +01005562 * 6ch mode
5563 */
5564static struct hda_verb alc882_sixstack_ch6_init[] = {
5565 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
5566 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5567 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5568 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5569 { } /* end */
5570};
5571
5572/*
5573 * 8ch mode
5574 */
5575static struct hda_verb alc882_sixstack_ch8_init[] = {
5576 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5577 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5578 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5579 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5580 { } /* end */
5581};
5582
5583static struct hda_channel_mode alc882_sixstack_modes[2] = {
5584 { 6, alc882_sixstack_ch6_init },
5585 { 8, alc882_sixstack_ch8_init },
5586};
5587
Takashi Iwai87350ad2007-08-16 18:19:38 +02005588/*
5589 * macbook pro ALC885 can switch LineIn to LineOut without loosing Mic
5590 */
5591
5592/*
5593 * 2ch mode
5594 */
5595static struct hda_verb alc885_mbp_ch2_init[] = {
5596 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
5597 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5598 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5599 { } /* end */
5600};
5601
5602/*
5603 * 6ch mode
5604 */
5605static struct hda_verb alc885_mbp_ch6_init[] = {
5606 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5607 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5608 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
5609 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5610 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5611 { } /* end */
5612};
5613
5614static struct hda_channel_mode alc885_mbp_6ch_modes[2] = {
5615 { 2, alc885_mbp_ch2_init },
5616 { 6, alc885_mbp_ch6_init },
5617};
5618
5619
Linus Torvalds1da177e2005-04-16 15:20:36 -07005620/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
5621 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
5622 */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01005623static struct snd_kcontrol_new alc882_base_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02005624 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005625 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02005626 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005627 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02005628 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
5629 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005630 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
5631 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02005632 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005633 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005634 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
5635 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5636 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5637 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5638 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5639 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01005640 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005641 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
5642 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01005643 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005644 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
5645 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
5646 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005647 { } /* end */
5648};
5649
Takashi Iwai87350ad2007-08-16 18:19:38 +02005650static struct snd_kcontrol_new alc885_mbp3_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01005651 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
5652 HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
5653 HDA_CODEC_MUTE ("Speaker Playback Switch", 0x14, 0x00, HDA_OUTPUT),
5654 HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
5655 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5656 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02005657 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
5658 HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01005659 HDA_CODEC_VOLUME("Line Boost", 0x1a, 0x00, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02005660 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT),
5661 { } /* end */
5662};
Kailang Yangbdd148a2007-05-08 15:19:08 +02005663static struct snd_kcontrol_new alc882_w2jc_mixer[] = {
5664 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5665 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
5666 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5667 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5668 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5669 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5670 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5671 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
5672 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
5673 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
5674 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
5675 { } /* end */
5676};
5677
Kailang Yang272a5272007-05-14 11:00:38 +02005678static struct snd_kcontrol_new alc882_targa_mixer[] = {
5679 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5680 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
5681 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
5682 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5683 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5684 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5685 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5686 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5687 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai96fe7cc82007-09-07 10:57:44 +02005688 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02005689 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
5690 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai96fe7cc82007-09-07 10:57:44 +02005691 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02005692 { } /* end */
5693};
5694
5695/* Pin assignment: Front=0x14, HP = 0x15, Front = 0x16, ???
5696 * Front Mic=0x18, Line In = 0x1a, Line In = 0x1b, CD = 0x1c
5697 */
5698static struct snd_kcontrol_new alc882_asus_a7j_mixer[] = {
5699 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5700 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
5701 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
5702 HDA_CODEC_MUTE("Mobile Front Playback Switch", 0x16, 0x0, HDA_OUTPUT),
5703 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5704 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5705 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5706 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5707 HDA_CODEC_VOLUME("Mobile Line Playback Volume", 0x0b, 0x03, HDA_INPUT),
5708 HDA_CODEC_MUTE("Mobile Line Playback Switch", 0x0b, 0x03, HDA_INPUT),
5709 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5710 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai96fe7cc82007-09-07 10:57:44 +02005711 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02005712 { } /* end */
5713};
5714
Takashi Iwai914759b2007-09-06 14:52:04 +02005715static struct snd_kcontrol_new alc882_asus_a7m_mixer[] = {
5716 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5717 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
5718 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
5719 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5720 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5721 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5722 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5723 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5724 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
5725 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
5726 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
5727 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
5728 { } /* end */
5729};
5730
Kailang Yangdf694da2005-12-05 19:42:22 +01005731static struct snd_kcontrol_new alc882_chmode_mixer[] = {
5732 {
5733 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5734 .name = "Channel Mode",
5735 .info = alc_ch_mode_info,
5736 .get = alc_ch_mode_get,
5737 .put = alc_ch_mode_put,
5738 },
5739 { } /* end */
5740};
5741
Linus Torvalds1da177e2005-04-16 15:20:36 -07005742static struct hda_verb alc882_init_verbs[] = {
5743 /* Front mixer: unmute input/output amp left and right (volume = 0) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005744 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5745 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5746 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005747 /* Rear mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02005748 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5749 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5750 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005751 /* CLFE mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02005752 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5753 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5754 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005755 /* Side mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02005756 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5757 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5758 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005759
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005760 /* Front Pin: output 0 (0x0c) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005761 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02005762 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005763 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005764 /* Rear Pin: output 1 (0x0d) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005765 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02005766 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005767 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005768 /* CLFE Pin: output 2 (0x0e) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005769 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02005770 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005771 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005772 /* Side Pin: output 3 (0x0f) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005773 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02005774 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005775 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005776 /* Mic (rear) pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02005777 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005778 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5779 /* Front Mic pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02005780 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005781 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5782 /* Line In pin: input */
Takashi Iwai05acb862005-06-10 19:50:25 +02005783 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005784 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5785 /* Line-2 In: Headphone output (output 0 - 0x0c) */
5786 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5787 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5788 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005789 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02005790 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005791
5792 /* FIXME: use matrix-type input source selection */
5793 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
5794 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
Takashi Iwai05acb862005-06-10 19:50:25 +02005795 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5796 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5797 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5798 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005799 /* Input mixer2 */
Takashi Iwai05acb862005-06-10 19:50:25 +02005800 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5801 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5802 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5803 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005804 /* Input mixer3 */
Takashi Iwai05acb862005-06-10 19:50:25 +02005805 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5806 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5807 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5808 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5809 /* ADC1: mute amp left and right */
5810 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02005811 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02005812 /* ADC2: mute amp left and right */
5813 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02005814 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02005815 /* ADC3: mute amp left and right */
5816 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02005817 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005818
5819 { }
5820};
5821
Takashi Iwai4b146cb2006-07-28 14:42:36 +02005822static struct hda_verb alc882_eapd_verbs[] = {
5823 /* change to EAPD mode */
5824 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01005825 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005826 { }
Takashi Iwai4b146cb2006-07-28 14:42:36 +02005827};
5828
Tobin Davis9102cd12006-12-15 10:02:12 +01005829/* Mac Pro test */
5830static struct snd_kcontrol_new alc882_macpro_mixer[] = {
5831 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5832 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
5833 HDA_CODEC_MUTE("Headphone Playback Switch", 0x18, 0x0, HDA_OUTPUT),
5834 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
5835 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
5836 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x02, HDA_INPUT),
5837 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x02, HDA_INPUT),
5838 { } /* end */
5839};
5840
5841static struct hda_verb alc882_macpro_init_verbs[] = {
5842 /* Front mixer: unmute input/output amp left and right (volume = 0) */
5843 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5844 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5845 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5846 /* Front Pin: output 0 (0x0c) */
5847 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5848 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5849 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
5850 /* Front Mic pin: input vref at 80% */
5851 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
5852 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5853 /* Speaker: output */
5854 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5855 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5856 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x04},
5857 /* Headphone output (output 0 - 0x0c) */
5858 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5859 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5860 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
5861
5862 /* FIXME: use matrix-type input source selection */
5863 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
5864 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
5865 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5866 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5867 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5868 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5869 /* Input mixer2 */
5870 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5871 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5872 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5873 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5874 /* Input mixer3 */
5875 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5876 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5877 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5878 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5879 /* ADC1: mute amp left and right */
5880 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5881 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
5882 /* ADC2: mute amp left and right */
5883 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5884 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
5885 /* ADC3: mute amp left and right */
5886 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5887 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
5888
5889 { }
5890};
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005891
Takashi Iwai87350ad2007-08-16 18:19:38 +02005892/* Macbook Pro rev3 */
5893static struct hda_verb alc885_mbp3_init_verbs[] = {
5894 /* Front mixer: unmute input/output amp left and right (volume = 0) */
5895 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5896 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5897 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5898 /* Rear mixer */
5899 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5900 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5901 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5902 /* Front Pin: output 0 (0x0c) */
5903 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5904 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5905 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
5906 /* HP Pin: output 0 (0x0d) */
5907 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
5908 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5909 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
5910 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
5911 /* Mic (rear) pin: input vref at 80% */
5912 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
5913 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5914 /* Front Mic pin: input vref at 80% */
5915 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
5916 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5917 /* Line In pin: use output 1 when in LineOut mode */
5918 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
5919 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5920 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
5921
5922 /* FIXME: use matrix-type input source selection */
5923 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
5924 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
5925 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5926 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5927 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5928 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5929 /* Input mixer2 */
5930 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5931 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5932 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5933 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5934 /* Input mixer3 */
5935 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5936 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5937 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5938 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5939 /* ADC1: mute amp left and right */
5940 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5941 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
5942 /* ADC2: mute amp left and right */
5943 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5944 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
5945 /* ADC3: mute amp left and right */
5946 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5947 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
5948
5949 { }
5950};
5951
Nicola Fagnanic54728d2007-07-19 23:28:52 +02005952/* iMac 24 mixer. */
5953static struct snd_kcontrol_new alc885_imac24_mixer[] = {
5954 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
5955 HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x00, HDA_INPUT),
5956 { } /* end */
5957};
5958
5959/* iMac 24 init verbs. */
5960static struct hda_verb alc885_imac24_init_verbs[] = {
5961 /* Internal speakers: output 0 (0x0c) */
5962 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5963 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5964 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
5965 /* Internal speakers: output 0 (0x0c) */
5966 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5967 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5968 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
5969 /* Headphone: output 0 (0x0c) */
5970 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5971 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5972 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
5973 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
5974 /* Front Mic: input vref at 80% */
5975 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
5976 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5977 { }
5978};
5979
5980/* Toggle speaker-output according to the hp-jack state */
5981static void alc885_imac24_automute(struct hda_codec *codec)
5982{
5983 unsigned int present;
5984
5985 present = snd_hda_codec_read(codec, 0x14, 0,
5986 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02005987 snd_hda_codec_amp_stereo(codec, 0x18, HDA_OUTPUT, 0,
5988 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
5989 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0,
5990 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Nicola Fagnanic54728d2007-07-19 23:28:52 +02005991}
5992
5993/* Processes unsolicited events. */
5994static void alc885_imac24_unsol_event(struct hda_codec *codec,
5995 unsigned int res)
5996{
5997 /* Headphone insertion or removal. */
5998 if ((res >> 26) == ALC880_HP_EVENT)
5999 alc885_imac24_automute(codec);
6000}
6001
Takashi Iwai87350ad2007-08-16 18:19:38 +02006002static void alc885_mbp3_automute(struct hda_codec *codec)
6003{
6004 unsigned int present;
6005
6006 present = snd_hda_codec_read(codec, 0x15, 0,
6007 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
6008 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
6009 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
6010 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
6011 HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE);
6012
6013}
6014static void alc885_mbp3_unsol_event(struct hda_codec *codec,
6015 unsigned int res)
6016{
6017 /* Headphone insertion or removal. */
6018 if ((res >> 26) == ALC880_HP_EVENT)
6019 alc885_mbp3_automute(codec);
6020}
6021
6022
Kailang Yang272a5272007-05-14 11:00:38 +02006023static struct hda_verb alc882_targa_verbs[] = {
6024 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6025 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6026
6027 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6028 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02006029
Kailang Yang272a5272007-05-14 11:00:38 +02006030 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
6031 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
6032 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
6033
6034 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
6035 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
6036 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
6037 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
6038 { } /* end */
6039};
6040
6041/* toggle speaker-output according to the hp-jack state */
6042static void alc882_targa_automute(struct hda_codec *codec)
6043{
6044 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02006045
Kailang Yang272a5272007-05-14 11:00:38 +02006046 present = snd_hda_codec_read(codec, 0x14, 0,
6047 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02006048 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
6049 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02006050 snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
6051 present ? 1 : 3);
Kailang Yang272a5272007-05-14 11:00:38 +02006052}
6053
6054static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res)
6055{
6056 /* Looks like the unsol event is incompatible with the standard
6057 * definition. 4bit tag is placed at 26 bit!
6058 */
6059 if (((res >> 26) == ALC880_HP_EVENT)) {
6060 alc882_targa_automute(codec);
6061 }
6062}
6063
6064static struct hda_verb alc882_asus_a7j_verbs[] = {
6065 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6066 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6067
6068 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6069 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6070 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02006071
Kailang Yang272a5272007-05-14 11:00:38 +02006072 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
6073 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
6074 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
6075
6076 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
6077 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
6078 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
6079 { } /* end */
6080};
6081
Takashi Iwai914759b2007-09-06 14:52:04 +02006082static struct hda_verb alc882_asus_a7m_verbs[] = {
6083 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6084 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6085
6086 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6087 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6088 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02006089
Takashi Iwai914759b2007-09-06 14:52:04 +02006090 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
6091 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
6092 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
6093
6094 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
6095 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
6096 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
6097 { } /* end */
6098};
6099
Tobin Davis9102cd12006-12-15 10:02:12 +01006100static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted)
6101{
6102 unsigned int gpiostate, gpiomask, gpiodir;
6103
6104 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
6105 AC_VERB_GET_GPIO_DATA, 0);
6106
6107 if (!muted)
6108 gpiostate |= (1 << pin);
6109 else
6110 gpiostate &= ~(1 << pin);
6111
6112 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
6113 AC_VERB_GET_GPIO_MASK, 0);
6114 gpiomask |= (1 << pin);
6115
6116 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
6117 AC_VERB_GET_GPIO_DIRECTION, 0);
6118 gpiodir |= (1 << pin);
6119
6120
6121 snd_hda_codec_write(codec, codec->afg, 0,
6122 AC_VERB_SET_GPIO_MASK, gpiomask);
6123 snd_hda_codec_write(codec, codec->afg, 0,
6124 AC_VERB_SET_GPIO_DIRECTION, gpiodir);
6125
6126 msleep(1);
6127
6128 snd_hda_codec_write(codec, codec->afg, 0,
6129 AC_VERB_SET_GPIO_DATA, gpiostate);
6130}
6131
Takashi Iwai7debbe52007-08-16 15:01:03 +02006132/* set up GPIO at initialization */
6133static void alc885_macpro_init_hook(struct hda_codec *codec)
6134{
6135 alc882_gpio_mute(codec, 0, 0);
6136 alc882_gpio_mute(codec, 1, 0);
6137}
6138
6139/* set up GPIO and update auto-muting at initialization */
6140static void alc885_imac24_init_hook(struct hda_codec *codec)
6141{
6142 alc885_macpro_init_hook(codec);
6143 alc885_imac24_automute(codec);
6144}
6145
Kailang Yangdf694da2005-12-05 19:42:22 +01006146/*
6147 * generic initialization of ADC, input mixers and output mixers
6148 */
6149static struct hda_verb alc882_auto_init_verbs[] = {
6150 /*
6151 * Unmute ADC0-2 and set the default input to mic-in
6152 */
6153 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
6154 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6155 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
6156 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6157 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
6158 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6159
Takashi Iwaicb53c622007-08-10 17:21:45 +02006160 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +01006161 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006162 * Note: PASD motherboards uses the Line In 2 as the input for
6163 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01006164 */
6165 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02006166 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6167 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6168 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6169 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6170 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01006171
6172 /*
6173 * Set up output mixers (0x0c - 0x0f)
6174 */
6175 /* set vol=0 to output mixers */
6176 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6177 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6178 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6179 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6180 /* set up input amps for analog loopback */
6181 /* Amp Indices: DAC = 0, mixer = 1 */
6182 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6183 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6184 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6185 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6186 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6187 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6188 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6189 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6190 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6191 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6192
6193 /* FIXME: use matrix-type input source selection */
6194 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
6195 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
6196 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6197 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
6198 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
6199 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
6200 /* Input mixer2 */
6201 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6202 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
6203 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
6204 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
6205 /* Input mixer3 */
6206 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6207 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
6208 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
6209 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
6210
6211 { }
6212};
6213
6214/* capture mixer elements */
6215static struct snd_kcontrol_new alc882_capture_alt_mixer[] = {
6216 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6217 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6218 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6219 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6220 {
6221 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6222 /* The multiple "Capture Source" controls confuse alsamixer
6223 * So call somewhat different..
Kailang Yangdf694da2005-12-05 19:42:22 +01006224 */
6225 /* .name = "Capture Source", */
6226 .name = "Input Source",
6227 .count = 2,
6228 .info = alc882_mux_enum_info,
6229 .get = alc882_mux_enum_get,
6230 .put = alc882_mux_enum_put,
6231 },
6232 { } /* end */
6233};
6234
6235static struct snd_kcontrol_new alc882_capture_mixer[] = {
6236 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
6237 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
6238 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT),
6239 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT),
6240 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT),
6241 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT),
6242 {
6243 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6244 /* The multiple "Capture Source" controls confuse alsamixer
6245 * So call somewhat different..
Kailang Yangdf694da2005-12-05 19:42:22 +01006246 */
6247 /* .name = "Capture Source", */
6248 .name = "Input Source",
6249 .count = 3,
6250 .info = alc882_mux_enum_info,
6251 .get = alc882_mux_enum_get,
6252 .put = alc882_mux_enum_put,
6253 },
6254 { } /* end */
6255};
6256
Takashi Iwaicb53c622007-08-10 17:21:45 +02006257#ifdef CONFIG_SND_HDA_POWER_SAVE
6258#define alc882_loopbacks alc880_loopbacks
6259#endif
6260
Kailang Yangdf694da2005-12-05 19:42:22 +01006261/* pcm configuration: identiacal with ALC880 */
6262#define alc882_pcm_analog_playback alc880_pcm_analog_playback
6263#define alc882_pcm_analog_capture alc880_pcm_analog_capture
6264#define alc882_pcm_digital_playback alc880_pcm_digital_playback
6265#define alc882_pcm_digital_capture alc880_pcm_digital_capture
6266
6267/*
6268 * configuration and preset
6269 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006270static const char *alc882_models[ALC882_MODEL_LAST] = {
6271 [ALC882_3ST_DIG] = "3stack-dig",
6272 [ALC882_6ST_DIG] = "6stack-dig",
6273 [ALC882_ARIMA] = "arima",
Kailang Yangbdd148a2007-05-08 15:19:08 +02006274 [ALC882_W2JC] = "w2jc",
Takashi Iwai0438a002007-09-06 14:54:11 +02006275 [ALC882_TARGA] = "targa",
6276 [ALC882_ASUS_A7J] = "asus-a7j",
6277 [ALC882_ASUS_A7M] = "asus-a7m",
Tobin Davis9102cd12006-12-15 10:02:12 +01006278 [ALC885_MACPRO] = "macpro",
Takashi Iwai87350ad2007-08-16 18:19:38 +02006279 [ALC885_MBP3] = "mbp3",
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006280 [ALC885_IMAC24] = "imac24",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006281 [ALC882_AUTO] = "auto",
6282};
6283
6284static struct snd_pci_quirk alc882_cfg_tbl[] = {
6285 SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG),
Kailang Yang272a5272007-05-14 11:00:38 +02006286 SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J),
Kailang Yangac8842a2007-09-20 12:51:39 +02006287 SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J),
Takashi Iwai914759b2007-09-06 14:52:04 +02006288 SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01006289 SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC),
Claudio Matsuokac5d9f1c2007-07-19 23:18:32 +02006290 SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG),
Tobin Davis7b9470d2006-12-28 13:56:48 +01006291 SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01006292 SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG),
Jiang zhe44447042008-01-28 12:28:24 +01006293 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01006294 SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */
6295 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG),
6296 SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA),
Kailang Yangdf694da2005-12-05 19:42:22 +01006297 {}
6298};
6299
6300static struct alc_config_preset alc882_presets[] = {
6301 [ALC882_3ST_DIG] = {
6302 .mixers = { alc882_base_mixer },
6303 .init_verbs = { alc882_init_verbs },
6304 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6305 .dac_nids = alc882_dac_nids,
6306 .dig_out_nid = ALC882_DIGOUT_NID,
Kailang Yangdf694da2005-12-05 19:42:22 +01006307 .dig_in_nid = ALC882_DIGIN_NID,
6308 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
6309 .channel_mode = alc882_ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02006310 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01006311 .input_mux = &alc882_capture_source,
6312 },
6313 [ALC882_6ST_DIG] = {
6314 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
6315 .init_verbs = { alc882_init_verbs },
6316 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6317 .dac_nids = alc882_dac_nids,
6318 .dig_out_nid = ALC882_DIGOUT_NID,
Kailang Yangdf694da2005-12-05 19:42:22 +01006319 .dig_in_nid = ALC882_DIGIN_NID,
6320 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
6321 .channel_mode = alc882_sixstack_modes,
6322 .input_mux = &alc882_capture_source,
6323 },
Takashi Iwai4b146cb2006-07-28 14:42:36 +02006324 [ALC882_ARIMA] = {
6325 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
6326 .init_verbs = { alc882_init_verbs, alc882_eapd_verbs },
6327 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6328 .dac_nids = alc882_dac_nids,
6329 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
6330 .channel_mode = alc882_sixstack_modes,
6331 .input_mux = &alc882_capture_source,
6332 },
Kailang Yangbdd148a2007-05-08 15:19:08 +02006333 [ALC882_W2JC] = {
6334 .mixers = { alc882_w2jc_mixer, alc882_chmode_mixer },
6335 .init_verbs = { alc882_init_verbs, alc882_eapd_verbs,
6336 alc880_gpio1_init_verbs },
6337 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6338 .dac_nids = alc882_dac_nids,
6339 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
6340 .channel_mode = alc880_threestack_modes,
6341 .need_dac_fix = 1,
6342 .input_mux = &alc882_capture_source,
6343 .dig_out_nid = ALC882_DIGOUT_NID,
6344 },
Takashi Iwai87350ad2007-08-16 18:19:38 +02006345 [ALC885_MBP3] = {
6346 .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer },
6347 .init_verbs = { alc885_mbp3_init_verbs,
6348 alc880_gpio1_init_verbs },
6349 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6350 .dac_nids = alc882_dac_nids,
6351 .channel_mode = alc885_mbp_6ch_modes,
6352 .num_channel_mode = ARRAY_SIZE(alc885_mbp_6ch_modes),
6353 .input_mux = &alc882_capture_source,
6354 .dig_out_nid = ALC882_DIGOUT_NID,
6355 .dig_in_nid = ALC882_DIGIN_NID,
6356 .unsol_event = alc885_mbp3_unsol_event,
6357 .init_hook = alc885_mbp3_automute,
6358 },
Tobin Davis9102cd12006-12-15 10:02:12 +01006359 [ALC885_MACPRO] = {
6360 .mixers = { alc882_macpro_mixer },
6361 .init_verbs = { alc882_macpro_init_verbs },
6362 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6363 .dac_nids = alc882_dac_nids,
6364 .dig_out_nid = ALC882_DIGOUT_NID,
6365 .dig_in_nid = ALC882_DIGIN_NID,
6366 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
6367 .channel_mode = alc882_ch_modes,
6368 .input_mux = &alc882_capture_source,
Takashi Iwai7debbe52007-08-16 15:01:03 +02006369 .init_hook = alc885_macpro_init_hook,
Tobin Davis9102cd12006-12-15 10:02:12 +01006370 },
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006371 [ALC885_IMAC24] = {
6372 .mixers = { alc885_imac24_mixer },
6373 .init_verbs = { alc885_imac24_init_verbs },
6374 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6375 .dac_nids = alc882_dac_nids,
6376 .dig_out_nid = ALC882_DIGOUT_NID,
6377 .dig_in_nid = ALC882_DIGIN_NID,
6378 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
6379 .channel_mode = alc882_ch_modes,
6380 .input_mux = &alc882_capture_source,
6381 .unsol_event = alc885_imac24_unsol_event,
Takashi Iwai7debbe52007-08-16 15:01:03 +02006382 .init_hook = alc885_imac24_init_hook,
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006383 },
Kailang Yang272a5272007-05-14 11:00:38 +02006384 [ALC882_TARGA] = {
6385 .mixers = { alc882_targa_mixer, alc882_chmode_mixer,
6386 alc882_capture_mixer },
6387 .init_verbs = { alc882_init_verbs, alc882_targa_verbs},
6388 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6389 .dac_nids = alc882_dac_nids,
6390 .dig_out_nid = ALC882_DIGOUT_NID,
6391 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
6392 .adc_nids = alc882_adc_nids,
Takashi Iwaie1406342008-02-11 18:32:32 +01006393 .capsrc_nids = alc882_capsrc_nids,
Kailang Yang272a5272007-05-14 11:00:38 +02006394 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
6395 .channel_mode = alc882_3ST_6ch_modes,
6396 .need_dac_fix = 1,
6397 .input_mux = &alc882_capture_source,
6398 .unsol_event = alc882_targa_unsol_event,
6399 .init_hook = alc882_targa_automute,
6400 },
6401 [ALC882_ASUS_A7J] = {
6402 .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer,
6403 alc882_capture_mixer },
6404 .init_verbs = { alc882_init_verbs, alc882_asus_a7j_verbs},
6405 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6406 .dac_nids = alc882_dac_nids,
6407 .dig_out_nid = ALC882_DIGOUT_NID,
6408 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
6409 .adc_nids = alc882_adc_nids,
Takashi Iwaie1406342008-02-11 18:32:32 +01006410 .capsrc_nids = alc882_capsrc_nids,
Kailang Yang272a5272007-05-14 11:00:38 +02006411 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
6412 .channel_mode = alc882_3ST_6ch_modes,
6413 .need_dac_fix = 1,
6414 .input_mux = &alc882_capture_source,
Kailang Yangea1fb292008-08-26 12:58:38 +02006415 },
Takashi Iwai914759b2007-09-06 14:52:04 +02006416 [ALC882_ASUS_A7M] = {
6417 .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer },
6418 .init_verbs = { alc882_init_verbs, alc882_eapd_verbs,
6419 alc880_gpio1_init_verbs,
6420 alc882_asus_a7m_verbs },
6421 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6422 .dac_nids = alc882_dac_nids,
6423 .dig_out_nid = ALC882_DIGOUT_NID,
6424 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
6425 .channel_mode = alc880_threestack_modes,
6426 .need_dac_fix = 1,
6427 .input_mux = &alc882_capture_source,
Kailang Yangea1fb292008-08-26 12:58:38 +02006428 },
Kailang Yangdf694da2005-12-05 19:42:22 +01006429};
6430
6431
6432/*
Takashi Iwaif95474e2007-07-10 00:47:43 +02006433 * Pin config fixes
6434 */
Kailang Yangea1fb292008-08-26 12:58:38 +02006435enum {
Takashi Iwaif95474e2007-07-10 00:47:43 +02006436 PINFIX_ABIT_AW9D_MAX
6437};
6438
6439static struct alc_pincfg alc882_abit_aw9d_pinfix[] = {
6440 { 0x15, 0x01080104 }, /* side */
6441 { 0x16, 0x01011012 }, /* rear */
6442 { 0x17, 0x01016011 }, /* clfe */
6443 { }
6444};
6445
6446static const struct alc_pincfg *alc882_pin_fixes[] = {
6447 [PINFIX_ABIT_AW9D_MAX] = alc882_abit_aw9d_pinfix,
6448};
6449
6450static struct snd_pci_quirk alc882_pinfix_tbl[] = {
6451 SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
6452 {}
6453};
6454
6455/*
Kailang Yangdf694da2005-12-05 19:42:22 +01006456 * BIOS auto configuration
6457 */
6458static void alc882_auto_set_output_and_unmute(struct hda_codec *codec,
6459 hda_nid_t nid, int pin_type,
6460 int dac_idx)
6461{
6462 /* set as output */
6463 struct alc_spec *spec = codec->spec;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006464 int idx;
6465
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006466 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01006467 if (spec->multiout.dac_nids[dac_idx] == 0x25)
6468 idx = 4;
6469 else
6470 idx = spec->multiout.dac_nids[dac_idx] - 2;
Kailang Yangdf694da2005-12-05 19:42:22 +01006471 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
6472
6473}
6474
6475static void alc882_auto_init_multi_out(struct hda_codec *codec)
6476{
6477 struct alc_spec *spec = codec->spec;
6478 int i;
6479
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006480 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Kailang Yangdf694da2005-12-05 19:42:22 +01006481 for (i = 0; i <= HDA_SIDE; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006482 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02006483 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01006484 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02006485 alc882_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006486 i);
Kailang Yangdf694da2005-12-05 19:42:22 +01006487 }
6488}
6489
6490static void alc882_auto_init_hp_out(struct hda_codec *codec)
6491{
6492 struct alc_spec *spec = codec->spec;
6493 hda_nid_t pin;
6494
Takashi Iwaieb06ed82006-09-20 17:10:27 +02006495 pin = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006496 if (pin) /* connect to front */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006497 /* use dac 0 */
6498 alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006499 pin = spec->autocfg.speaker_pins[0];
6500 if (pin)
6501 alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Kailang Yangdf694da2005-12-05 19:42:22 +01006502}
6503
6504#define alc882_is_input_pin(nid) alc880_is_input_pin(nid)
6505#define ALC882_PIN_CD_NID ALC880_PIN_CD_NID
6506
6507static void alc882_auto_init_analog_input(struct hda_codec *codec)
6508{
6509 struct alc_spec *spec = codec->spec;
6510 int i;
6511
6512 for (i = 0; i < AUTO_PIN_LAST; i++) {
6513 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwai7194cae2008-03-06 16:58:17 +01006514 unsigned int vref;
6515 if (!nid)
6516 continue;
6517 vref = PIN_IN;
6518 if (1 /*i <= AUTO_PIN_FRONT_MIC*/) {
Kailang Yang531240f2008-05-27 12:10:25 +02006519 unsigned int pincap;
6520 pincap = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
6521 if ((pincap >> AC_PINCAP_VREF_SHIFT) &
Takashi Iwai7194cae2008-03-06 16:58:17 +01006522 AC_PINCAP_VREF_80)
6523 vref = PIN_VREF80;
Kailang Yangdf694da2005-12-05 19:42:22 +01006524 }
Takashi Iwai7194cae2008-03-06 16:58:17 +01006525 snd_hda_codec_write(codec, nid, 0,
6526 AC_VERB_SET_PIN_WIDGET_CONTROL, vref);
6527 if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
6528 snd_hda_codec_write(codec, nid, 0,
6529 AC_VERB_SET_AMP_GAIN_MUTE,
6530 AMP_OUT_MUTE);
Kailang Yangdf694da2005-12-05 19:42:22 +01006531 }
6532}
6533
Takashi Iwaif511b012008-08-15 16:46:42 +02006534static void alc882_auto_init_input_src(struct hda_codec *codec)
6535{
6536 struct alc_spec *spec = codec->spec;
6537 const struct hda_input_mux *imux = spec->input_mux;
6538 int c;
6539
6540 for (c = 0; c < spec->num_adc_nids; c++) {
6541 hda_nid_t conn_list[HDA_MAX_NUM_INPUTS];
6542 hda_nid_t nid = spec->capsrc_nids[c];
6543 int conns, mute, idx, item;
6544
6545 conns = snd_hda_get_connections(codec, nid, conn_list,
6546 ARRAY_SIZE(conn_list));
6547 if (conns < 0)
6548 continue;
6549 for (idx = 0; idx < conns; idx++) {
6550 /* if the current connection is the selected one,
6551 * unmute it as default - otherwise mute it
6552 */
6553 mute = AMP_IN_MUTE(idx);
6554 for (item = 0; item < imux->num_items; item++) {
6555 if (imux->items[item].index == idx) {
6556 if (spec->cur_mux[c] == item)
6557 mute = AMP_IN_UNMUTE(idx);
6558 break;
6559 }
6560 }
6561 snd_hda_codec_write(codec, nid, 0,
6562 AC_VERB_SET_AMP_GAIN_MUTE, mute);
6563 }
6564 }
6565}
6566
Takashi Iwai776e1842007-08-29 15:07:11 +02006567/* add mic boosts if needed */
6568static int alc_auto_add_mic_boost(struct hda_codec *codec)
6569{
6570 struct alc_spec *spec = codec->spec;
6571 int err;
6572 hda_nid_t nid;
6573
6574 nid = spec->autocfg.input_pins[AUTO_PIN_MIC];
Takashi Iwaice22e032008-01-11 17:38:35 +01006575 if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
Takashi Iwai776e1842007-08-29 15:07:11 +02006576 err = add_control(spec, ALC_CTL_WIDGET_VOL,
6577 "Mic Boost",
6578 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
6579 if (err < 0)
6580 return err;
6581 }
6582 nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC];
Takashi Iwaice22e032008-01-11 17:38:35 +01006583 if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
Takashi Iwai776e1842007-08-29 15:07:11 +02006584 err = add_control(spec, ALC_CTL_WIDGET_VOL,
6585 "Front Mic Boost",
6586 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
6587 if (err < 0)
6588 return err;
6589 }
6590 return 0;
6591}
6592
Kailang Yangdf694da2005-12-05 19:42:22 +01006593/* almost identical with ALC880 parser... */
6594static int alc882_parse_auto_config(struct hda_codec *codec)
6595{
6596 struct alc_spec *spec = codec->spec;
6597 int err = alc880_parse_auto_config(codec);
6598
6599 if (err < 0)
6600 return err;
Takashi Iwai776e1842007-08-29 15:07:11 +02006601 else if (!err)
6602 return 0; /* no config found */
6603
6604 err = alc_auto_add_mic_boost(codec);
6605 if (err < 0)
6606 return err;
6607
6608 /* hack - override the init verbs */
6609 spec->init_verbs[0] = alc882_auto_init_verbs;
6610
6611 return 1; /* config found */
Kailang Yangdf694da2005-12-05 19:42:22 +01006612}
6613
Takashi Iwaiae6b8132006-03-03 16:47:17 +01006614/* additional initialization for auto-configuration model */
6615static void alc882_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01006616{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006617 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01006618 alc882_auto_init_multi_out(codec);
6619 alc882_auto_init_hp_out(codec);
6620 alc882_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +02006621 alc882_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006622 if (spec->unsol_event)
6623 alc_sku_automute(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01006624}
6625
Takashi Iwai7943a8a2008-04-16 17:29:09 +02006626static int patch_alc883(struct hda_codec *codec); /* called in patch_alc882() */
6627
Linus Torvalds1da177e2005-04-16 15:20:36 -07006628static int patch_alc882(struct hda_codec *codec)
6629{
6630 struct alc_spec *spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01006631 int err, board_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006632
Takashi Iwaie560d8d2005-09-09 14:21:46 +02006633 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006634 if (spec == NULL)
6635 return -ENOMEM;
6636
Linus Torvalds1da177e2005-04-16 15:20:36 -07006637 codec->spec = spec;
6638
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006639 board_config = snd_hda_check_board_config(codec, ALC882_MODEL_LAST,
6640 alc882_models,
6641 alc882_cfg_tbl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006642
Kailang Yangdf694da2005-12-05 19:42:22 +01006643 if (board_config < 0 || board_config >= ALC882_MODEL_LAST) {
Tobin Davis081d17c2007-02-15 17:46:18 +01006644 /* Pick up systems that don't supply PCI SSID */
6645 switch (codec->subsystem_id) {
6646 case 0x106b0c00: /* Mac Pro */
6647 board_config = ALC885_MACPRO;
6648 break;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006649 case 0x106b1000: /* iMac 24 */
6650 board_config = ALC885_IMAC24;
6651 break;
Takashi Iwaic7e07572008-06-26 14:42:51 +02006652 case 0x106b00a1: /* Macbook (might be wrong - PCI SSID?) */
Takashi Iwai87350ad2007-08-16 18:19:38 +02006653 case 0x106b2c00: /* Macbook Pro rev3 */
Takashi Iwaic7e07572008-06-26 14:42:51 +02006654 case 0x106b3600: /* Macbook 3.1 */
Takashi Iwai87350ad2007-08-16 18:19:38 +02006655 board_config = ALC885_MBP3;
6656 break;
Tobin Davis081d17c2007-02-15 17:46:18 +01006657 default:
Takashi Iwai7943a8a2008-04-16 17:29:09 +02006658 /* ALC889A is handled better as ALC888-compatible */
6659 if (codec->revision_id == 0x100103) {
6660 alc_free(codec);
6661 return patch_alc883(codec);
6662 }
Tobin Davis081d17c2007-02-15 17:46:18 +01006663 printk(KERN_INFO "hda_codec: Unknown model for ALC882, "
6664 "trying auto-probe from BIOS...\n");
6665 board_config = ALC882_AUTO;
6666 }
Kailang Yangdf694da2005-12-05 19:42:22 +01006667 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006668
Takashi Iwaif95474e2007-07-10 00:47:43 +02006669 alc_fix_pincfg(codec, alc882_pinfix_tbl, alc882_pin_fixes);
6670
Kailang Yangdf694da2005-12-05 19:42:22 +01006671 if (board_config == ALC882_AUTO) {
6672 /* automatic parse from the BIOS config */
6673 err = alc882_parse_auto_config(codec);
6674 if (err < 0) {
6675 alc_free(codec);
6676 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006677 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006678 printk(KERN_INFO
6679 "hda_codec: Cannot set up configuration "
6680 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01006681 board_config = ALC882_3ST_DIG;
6682 }
6683 }
6684
6685 if (board_config != ALC882_AUTO)
6686 setup_preset(spec, &alc882_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006687
Kailang Yang2f893282008-05-27 12:14:47 +02006688 if (codec->vendor_id == 0x10ec0885) {
6689 spec->stream_name_analog = "ALC885 Analog";
6690 spec->stream_name_digital = "ALC885 Digital";
6691 } else {
6692 spec->stream_name_analog = "ALC882 Analog";
6693 spec->stream_name_digital = "ALC882 Digital";
6694 }
6695
Kailang Yangdf694da2005-12-05 19:42:22 +01006696 spec->stream_analog_playback = &alc882_pcm_analog_playback;
6697 spec->stream_analog_capture = &alc882_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01006698 /* FIXME: setup DAC5 */
6699 /*spec->stream_analog_alt_playback = &alc880_pcm_analog_alt_playback;*/
6700 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006701
Kailang Yangdf694da2005-12-05 19:42:22 +01006702 spec->stream_digital_playback = &alc882_pcm_digital_playback;
6703 spec->stream_digital_capture = &alc882_pcm_digital_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006704
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006705 if (!spec->adc_nids && spec->input_mux) {
Kailang Yangdf694da2005-12-05 19:42:22 +01006706 /* check whether NID 0x07 is valid */
Takashi Iwai4a471b72005-12-07 13:56:29 +01006707 unsigned int wcap = get_wcaps(codec, 0x07);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006708 /* get type */
6709 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Kailang Yangdf694da2005-12-05 19:42:22 +01006710 if (wcap != AC_WID_AUD_IN) {
6711 spec->adc_nids = alc882_adc_nids_alt;
6712 spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids_alt);
Takashi Iwaie1406342008-02-11 18:32:32 +01006713 spec->capsrc_nids = alc882_capsrc_nids_alt;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006714 spec->mixers[spec->num_mixers] =
6715 alc882_capture_alt_mixer;
Kailang Yangdf694da2005-12-05 19:42:22 +01006716 spec->num_mixers++;
6717 } else {
6718 spec->adc_nids = alc882_adc_nids;
6719 spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids);
Takashi Iwaie1406342008-02-11 18:32:32 +01006720 spec->capsrc_nids = alc882_capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +01006721 spec->mixers[spec->num_mixers] = alc882_capture_mixer;
6722 spec->num_mixers++;
6723 }
6724 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006725
Takashi Iwai2134ea42008-01-10 16:53:55 +01006726 spec->vmaster_nid = 0x0c;
6727
Linus Torvalds1da177e2005-04-16 15:20:36 -07006728 codec->patch_ops = alc_patch_ops;
Kailang Yangdf694da2005-12-05 19:42:22 +01006729 if (board_config == ALC882_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01006730 spec->init_hook = alc882_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02006731#ifdef CONFIG_SND_HDA_POWER_SAVE
6732 if (!spec->loopback.amplist)
6733 spec->loopback.amplist = alc882_loopbacks;
6734#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006735
6736 return 0;
6737}
6738
6739/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006740 * ALC883 support
6741 *
6742 * ALC883 is almost identical with ALC880 but has cleaner and more flexible
6743 * configuration. Each pin widget can choose any input DACs and a mixer.
6744 * Each ADC is connected from a mixer of all inputs. This makes possible
6745 * 6-channel independent captures.
6746 *
6747 * In addition, an independent DAC for the multi-playback (not used in this
6748 * driver yet).
6749 */
6750#define ALC883_DIGOUT_NID 0x06
6751#define ALC883_DIGIN_NID 0x0a
6752
6753static hda_nid_t alc883_dac_nids[4] = {
6754 /* front, rear, clfe, rear_surr */
Herton Ronaldo Krzesinskif32a19e2008-03-18 09:27:08 +01006755 0x02, 0x03, 0x04, 0x05
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006756};
6757
6758static hda_nid_t alc883_adc_nids[2] = {
6759 /* ADC1-2 */
6760 0x08, 0x09,
6761};
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006762
Takashi Iwaie1406342008-02-11 18:32:32 +01006763static hda_nid_t alc883_capsrc_nids[2] = { 0x23, 0x22 };
6764
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006765/* input MUX */
6766/* FIXME: should be a matrix-type input source selection */
6767
6768static struct hda_input_mux alc883_capture_source = {
6769 .num_items = 4,
6770 .items = {
6771 { "Mic", 0x0 },
6772 { "Front Mic", 0x1 },
6773 { "Line", 0x2 },
6774 { "CD", 0x4 },
6775 },
6776};
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006777
Jiang zhe17bba1b2008-06-04 12:11:07 +02006778static struct hda_input_mux alc883_3stack_6ch_intel = {
6779 .num_items = 4,
6780 .items = {
6781 { "Mic", 0x1 },
6782 { "Front Mic", 0x0 },
6783 { "Line", 0x2 },
6784 { "CD", 0x4 },
6785 },
6786};
6787
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006788static struct hda_input_mux alc883_lenovo_101e_capture_source = {
6789 .num_items = 2,
6790 .items = {
6791 { "Mic", 0x1 },
6792 { "Line", 0x2 },
6793 },
6794};
6795
Kailang Yang272a5272007-05-14 11:00:38 +02006796static struct hda_input_mux alc883_lenovo_nb0763_capture_source = {
6797 .num_items = 4,
6798 .items = {
6799 { "Mic", 0x0 },
6800 { "iMic", 0x1 },
6801 { "Line", 0x2 },
6802 { "CD", 0x4 },
6803 },
6804};
6805
Jiang zhefb97dc62008-03-06 11:07:11 +01006806static struct hda_input_mux alc883_fujitsu_pi2515_capture_source = {
6807 .num_items = 2,
6808 .items = {
6809 { "Mic", 0x0 },
6810 { "Int Mic", 0x1 },
6811 },
6812};
6813
Kailang Yange2757d52008-08-26 13:17:46 +02006814static struct hda_input_mux alc883_lenovo_sky_capture_source = {
6815 .num_items = 3,
6816 .items = {
6817 { "Mic", 0x0 },
6818 { "Front Mic", 0x1 },
6819 { "Line", 0x4 },
6820 },
6821};
6822
6823static struct hda_input_mux alc883_asus_eee1601_capture_source = {
6824 .num_items = 2,
6825 .items = {
6826 { "Mic", 0x0 },
6827 { "Line", 0x2 },
6828 },
6829};
6830
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006831#define alc883_mux_enum_info alc_mux_enum_info
6832#define alc883_mux_enum_get alc_mux_enum_get
Takashi Iwaie1406342008-02-11 18:32:32 +01006833/* ALC883 has the ALC882-type input selection */
6834#define alc883_mux_enum_put alc882_mux_enum_put
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006835
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006836/*
6837 * 2ch mode
6838 */
6839static struct hda_channel_mode alc883_3ST_2ch_modes[1] = {
6840 { 2, NULL }
6841};
6842
6843/*
6844 * 2ch mode
6845 */
6846static struct hda_verb alc883_3ST_ch2_init[] = {
6847 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
6848 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6849 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
6850 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6851 { } /* end */
6852};
6853
6854/*
Tobin Davisb2011312007-09-17 12:45:11 +02006855 * 4ch mode
6856 */
6857static struct hda_verb alc883_3ST_ch4_init[] = {
6858 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
6859 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6860 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6861 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6862 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6863 { } /* end */
6864};
6865
6866/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006867 * 6ch mode
6868 */
6869static struct hda_verb alc883_3ST_ch6_init[] = {
6870 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6871 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6872 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
6873 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6874 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6875 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6876 { } /* end */
6877};
6878
Tobin Davisb2011312007-09-17 12:45:11 +02006879static struct hda_channel_mode alc883_3ST_6ch_modes[3] = {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006880 { 2, alc883_3ST_ch2_init },
Tobin Davisb2011312007-09-17 12:45:11 +02006881 { 4, alc883_3ST_ch4_init },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006882 { 6, alc883_3ST_ch6_init },
6883};
6884
6885/*
Jiang zhe17bba1b2008-06-04 12:11:07 +02006886 * 2ch mode
6887 */
6888static struct hda_verb alc883_3ST_ch2_intel_init[] = {
6889 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
6890 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6891 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
6892 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6893 { } /* end */
6894};
6895
6896/*
6897 * 4ch mode
6898 */
6899static struct hda_verb alc883_3ST_ch4_intel_init[] = {
6900 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
6901 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6902 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6903 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6904 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6905 { } /* end */
6906};
6907
6908/*
6909 * 6ch mode
6910 */
6911static struct hda_verb alc883_3ST_ch6_intel_init[] = {
6912 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6913 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6914 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x02 },
6915 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6916 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6917 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6918 { } /* end */
6919};
6920
6921static struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = {
6922 { 2, alc883_3ST_ch2_intel_init },
6923 { 4, alc883_3ST_ch4_intel_init },
6924 { 6, alc883_3ST_ch6_intel_init },
6925};
6926
6927/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006928 * 6ch mode
6929 */
6930static struct hda_verb alc883_sixstack_ch6_init[] = {
6931 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
6932 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6933 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6934 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6935 { } /* end */
6936};
6937
6938/*
6939 * 8ch mode
6940 */
6941static struct hda_verb alc883_sixstack_ch8_init[] = {
6942 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6943 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6944 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6945 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6946 { } /* end */
6947};
6948
6949static struct hda_channel_mode alc883_sixstack_modes[2] = {
6950 { 6, alc883_sixstack_ch6_init },
6951 { 8, alc883_sixstack_ch8_init },
6952};
6953
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01006954static struct hda_verb alc883_medion_eapd_verbs[] = {
6955 /* eanable EAPD on medion laptop */
6956 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
6957 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
6958 { }
6959};
6960
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006961/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
6962 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
6963 */
6964
6965static struct snd_kcontrol_new alc883_base_mixer[] = {
6966 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
6967 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
6968 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
6969 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
6970 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
6971 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
6972 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
6973 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
6974 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
6975 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
6976 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
6977 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
6978 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
6979 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
6980 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
6981 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006982 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006983 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
6984 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01006985 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006986 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
6987 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
6988 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
6989 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6990 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6991 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6992 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6993 {
6994 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6995 /* .name = "Capture Source", */
6996 .name = "Input Source",
6997 .count = 2,
6998 .info = alc883_mux_enum_info,
6999 .get = alc883_mux_enum_get,
7000 .put = alc883_mux_enum_put,
7001 },
7002 { } /* end */
7003};
7004
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01007005static struct snd_kcontrol_new alc883_mitac_mixer[] = {
7006 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7007 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7008 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7009 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
7010 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7011 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
7012 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
7013 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7014 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7015 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7016 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7017 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
7018 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
7019 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7020 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
7021 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
7022 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
7023 {
7024 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7025 /* .name = "Capture Source", */
7026 .name = "Input Source",
7027 .count = 2,
7028 .info = alc883_mux_enum_info,
7029 .get = alc883_mux_enum_get,
7030 .put = alc883_mux_enum_put,
7031 },
7032 { } /* end */
7033};
7034
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007035static struct snd_kcontrol_new alc883_clevo_m720_mixer[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01007036 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7037 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
7038 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7039 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
7040 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7041 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7042 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7043 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7044 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
7045 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
7046 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7047 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
7048 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
7049 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
7050 {
7051 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7052 /* .name = "Capture Source", */
7053 .name = "Input Source",
7054 .count = 2,
7055 .info = alc883_mux_enum_info,
7056 .get = alc883_mux_enum_get,
7057 .put = alc883_mux_enum_put,
7058 },
7059 { } /* end */
7060};
7061
Jiang zhefb97dc62008-03-06 11:07:11 +01007062static struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = {
7063 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7064 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
7065 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7066 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
7067 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7068 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7069 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7070 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7071 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
7072 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
7073 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7074 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
7075 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
7076 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
7077 {
7078 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7079 /* .name = "Capture Source", */
7080 .name = "Input Source",
7081 .count = 2,
7082 .info = alc883_mux_enum_info,
7083 .get = alc883_mux_enum_get,
7084 .put = alc883_mux_enum_put,
7085 },
7086 { } /* end */
7087};
7088
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007089static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = {
7090 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7091 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7092 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7093 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7094 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7095 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7096 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7097 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007098 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007099 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7100 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007101 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007102 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
7103 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
7104 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
7105 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7106 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
7107 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
7108 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
7109 {
7110 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7111 /* .name = "Capture Source", */
7112 .name = "Input Source",
7113 .count = 2,
7114 .info = alc883_mux_enum_info,
7115 .get = alc883_mux_enum_get,
7116 .put = alc883_mux_enum_put,
7117 },
7118 { } /* end */
7119};
7120
7121static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
7122 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7123 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7124 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7125 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
7126 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7127 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
7128 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7129 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
7130 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7131 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7132 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7133 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7134 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7135 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007136 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007137 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7138 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007139 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007140 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
7141 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
7142 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
7143 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7144 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007145 {
7146 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7147 /* .name = "Capture Source", */
7148 .name = "Input Source",
Kailang Yange2757d52008-08-26 13:17:46 +02007149 .count = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007150 .info = alc883_mux_enum_info,
7151 .get = alc883_mux_enum_get,
7152 .put = alc883_mux_enum_put,
7153 },
7154 { } /* end */
7155};
7156
Jiang zhe17bba1b2008-06-04 12:11:07 +02007157static struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = {
7158 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7159 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7160 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7161 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
7162 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
7163 HDA_OUTPUT),
7164 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
7165 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7166 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
7167 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
7168 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7169 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7170 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7171 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7172 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7173 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
7174 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
7175 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7176 HDA_CODEC_VOLUME("Front Mic Boost", 0x18, 0, HDA_INPUT),
7177 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7178 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
7179 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
7180 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7181 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
7182 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
7183 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
7184 {
7185 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7186 /* .name = "Capture Source", */
7187 .name = "Input Source",
7188 .count = 2,
7189 .info = alc883_mux_enum_info,
7190 .get = alc883_mux_enum_get,
7191 .put = alc883_mux_enum_put,
7192 },
7193 { } /* end */
7194};
7195
Takashi Iwaid1d985f2006-11-23 19:27:12 +01007196static struct snd_kcontrol_new alc883_fivestack_mixer[] = {
Tobin Davisc07584c2006-10-13 12:32:16 +02007197 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02007198 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007199 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02007200 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007201 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7202 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02007203 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7204 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007205 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7206 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7207 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7208 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7209 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7210 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007211 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007212 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7213 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007214 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007215 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
7216 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
7217 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
7218 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7219 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
7220
7221 {
7222 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7223 /* .name = "Capture Source", */
7224 .name = "Input Source",
7225 .count = 1,
7226 .info = alc883_mux_enum_info,
7227 .get = alc883_mux_enum_get,
7228 .put = alc883_mux_enum_put,
7229 },
7230 { } /* end */
7231};
7232
Kailang Yangccc656c2006-10-17 12:32:26 +02007233static struct snd_kcontrol_new alc883_tagra_mixer[] = {
7234 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7235 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7236 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7237 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7238 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
7239 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7240 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
7241 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7242 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
7243 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7244 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7245 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7246 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7247 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007248 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02007249 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7250 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7251 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
7252 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
7253 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
7254 {
7255 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7256 /* .name = "Capture Source", */
7257 .name = "Input Source",
7258 .count = 2,
7259 .info = alc883_mux_enum_info,
7260 .get = alc883_mux_enum_get,
7261 .put = alc883_mux_enum_put,
7262 },
7263 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007264};
Kailang Yangccc656c2006-10-17 12:32:26 +02007265
7266static struct snd_kcontrol_new alc883_tagra_2ch_mixer[] = {
7267 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7268 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7269 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7270 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7271 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7272 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007273 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02007274 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Jiang zhe4383fae2008-04-14 12:58:57 +02007275 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7276 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
7277 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02007278 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7279 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
7280 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
7281 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
7282 {
7283 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7284 /* .name = "Capture Source", */
7285 .name = "Input Source",
7286 .count = 2,
7287 .info = alc883_mux_enum_info,
7288 .get = alc883_mux_enum_get,
7289 .put = alc883_mux_enum_put,
7290 },
7291 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007292};
Kailang Yangccc656c2006-10-17 12:32:26 +02007293
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007294static struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = {
7295 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7296 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01007297 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7298 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007299 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7300 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7301 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7302 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
7303 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7304 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
7305 {
7306 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7307 /* .name = "Capture Source", */
7308 .name = "Input Source",
7309 .count = 1,
7310 .info = alc883_mux_enum_info,
7311 .get = alc883_mux_enum_get,
7312 .put = alc883_mux_enum_put,
7313 },
7314 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007315};
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007316
Kailang Yang272a5272007-05-14 11:00:38 +02007317static struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = {
7318 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7319 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
7320 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7321 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7322 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7323 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7324 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7325 HDA_CODEC_VOLUME("iMic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7326 HDA_CODEC_MUTE("iMic Playback Switch", 0x0b, 0x1, HDA_INPUT),
7327 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7328 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
7329 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
7330 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
7331 {
7332 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7333 /* .name = "Capture Source", */
7334 .name = "Input Source",
7335 .count = 2,
7336 .info = alc883_mux_enum_info,
7337 .get = alc883_mux_enum_get,
7338 .put = alc883_mux_enum_put,
7339 },
7340 { } /* end */
7341};
7342
7343static struct snd_kcontrol_new alc883_medion_md2_mixer[] = {
7344 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7345 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7346 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
7347 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7348 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7349 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7350 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7351 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7352 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7353 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7354 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
7355 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
7356 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
7357 {
7358 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7359 /* .name = "Capture Source", */
7360 .name = "Input Source",
7361 .count = 2,
7362 .info = alc883_mux_enum_info,
7363 .get = alc883_mux_enum_get,
7364 .put = alc883_mux_enum_put,
7365 },
7366 { } /* end */
Kailang Yangea1fb292008-08-26 12:58:38 +02007367};
Kailang Yang272a5272007-05-14 11:00:38 +02007368
Tobin Davis2880a862007-08-07 11:50:26 +02007369static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = {
Kailang Yangd1a991a2007-08-15 16:21:59 +02007370 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7371 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02007372 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02007373 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7374 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Kailang Yangd1a991a2007-08-15 16:21:59 +02007375 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7376 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7377 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02007378 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7379 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
7380 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
7381 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
7382 {
7383 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7384 /* .name = "Capture Source", */
7385 .name = "Input Source",
7386 .count = 2,
7387 .info = alc883_mux_enum_info,
7388 .get = alc883_mux_enum_get,
7389 .put = alc883_mux_enum_put,
7390 },
7391 { } /* end */
Kailang Yangd1a991a2007-08-15 16:21:59 +02007392};
Tobin Davis2880a862007-08-07 11:50:26 +02007393
Kailang Yange2757d52008-08-26 13:17:46 +02007394static struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = {
7395 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7396 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7397 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
7398 HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
7399 HDA_CODEC_VOLUME_MONO("Center Playback Volume",
7400 0x0d, 1, 0x0, HDA_OUTPUT),
7401 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
7402 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
7403 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
7404 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
7405 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
7406 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7407 HDA_CODEC_MUTE("iSpeaker Playback Switch", 0x1a, 0x0, HDA_OUTPUT),
7408 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7409 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7410 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7411 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7412 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7413 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7414 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7415 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7416 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
7417 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
7418 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7419 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
7420 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
7421 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
7422 {
7423 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7424 /* .name = "Capture Source", */
7425 .name = "Input Source",
7426 .count = 2,
7427 .info = alc883_mux_enum_info,
7428 .get = alc883_mux_enum_get,
7429 .put = alc883_mux_enum_put,
7430 },
7431 { } /* end */
7432};
7433
7434static struct hda_bind_ctls alc883_bind_cap_vol = {
7435 .ops = &snd_hda_bind_vol,
7436 .values = {
7437 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
7438 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
7439 0
7440 },
7441};
7442
7443static struct hda_bind_ctls alc883_bind_cap_switch = {
7444 .ops = &snd_hda_bind_sw,
7445 .values = {
7446 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
7447 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
7448 0
7449 },
7450};
7451
7452static struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = {
7453 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7454 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7455 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7456 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7457 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7458 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7459 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7460 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7461 HDA_BIND_VOL("Capture Volume", &alc883_bind_cap_vol),
7462 HDA_BIND_SW("Capture Switch", &alc883_bind_cap_switch),
7463 {
7464 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7465 /* .name = "Capture Source", */
7466 .name = "Input Source",
7467 .count = 1,
7468 .info = alc883_mux_enum_info,
7469 .get = alc883_mux_enum_get,
7470 .put = alc883_mux_enum_put,
7471 },
7472 { } /* end */
7473};
7474
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007475static struct snd_kcontrol_new alc883_chmode_mixer[] = {
7476 {
7477 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7478 .name = "Channel Mode",
7479 .info = alc_ch_mode_info,
7480 .get = alc_ch_mode_get,
7481 .put = alc_ch_mode_put,
7482 },
7483 { } /* end */
7484};
7485
7486static struct hda_verb alc883_init_verbs[] = {
7487 /* ADC1: mute amp left and right */
Kailang Yange2757d52008-08-26 13:17:46 +02007488 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007489 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
7490 /* ADC2: mute amp left and right */
7491 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7492 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
7493 /* Front mixer: unmute input/output amp left and right (volume = 0) */
7494 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7495 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7496 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7497 /* Rear mixer */
7498 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7499 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7500 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7501 /* CLFE mixer */
7502 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7503 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7504 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7505 /* Side mixer */
7506 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7507 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7508 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7509
Takashi Iwaicb53c622007-08-10 17:21:45 +02007510 /* mute analog input loopbacks */
7511 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7512 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7513 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7514 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7515 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007516
7517 /* Front Pin: output 0 (0x0c) */
7518 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7519 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7520 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
7521 /* Rear Pin: output 1 (0x0d) */
7522 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7523 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7524 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
7525 /* CLFE Pin: output 2 (0x0e) */
7526 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7527 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7528 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
7529 /* Side Pin: output 3 (0x0f) */
7530 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7531 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7532 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
7533 /* Mic (rear) pin: input vref at 80% */
7534 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7535 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7536 /* Front Mic pin: input vref at 80% */
7537 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7538 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7539 /* Line In pin: input */
7540 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
7541 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7542 /* Line-2 In: Headphone output (output 0 - 0x0c) */
7543 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7544 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7545 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
7546 /* CD pin widget for input */
7547 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
7548
7549 /* FIXME: use matrix-type input source selection */
7550 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
7551 /* Input mixer2 */
7552 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yange2757d52008-08-26 13:17:46 +02007553 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7554 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7555 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007556 /* Input mixer3 */
7557 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yange2757d52008-08-26 13:17:46 +02007558 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7559 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7560 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007561 { }
7562};
7563
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01007564/* toggle speaker-output according to the hp-jack state */
7565static void alc883_mitac_hp_automute(struct hda_codec *codec)
7566{
7567 unsigned int present;
7568
7569 present = snd_hda_codec_read(codec, 0x15, 0,
7570 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7571 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7572 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7573 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
7574 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7575}
7576
7577/* auto-toggle front mic */
7578/*
7579static void alc883_mitac_mic_automute(struct hda_codec *codec)
7580{
7581 unsigned int present;
7582 unsigned char bits;
7583
7584 present = snd_hda_codec_read(codec, 0x18, 0,
7585 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7586 bits = present ? HDA_AMP_MUTE : 0;
7587 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
7588}
7589*/
7590
7591static void alc883_mitac_automute(struct hda_codec *codec)
7592{
7593 alc883_mitac_hp_automute(codec);
7594 /* alc883_mitac_mic_automute(codec); */
7595}
7596
7597static void alc883_mitac_unsol_event(struct hda_codec *codec,
7598 unsigned int res)
7599{
7600 switch (res >> 26) {
7601 case ALC880_HP_EVENT:
7602 alc883_mitac_hp_automute(codec);
7603 break;
7604 case ALC880_MIC_EVENT:
7605 /* alc883_mitac_mic_automute(codec); */
7606 break;
7607 }
7608}
7609
7610static struct hda_verb alc883_mitac_verbs[] = {
7611 /* HP */
7612 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7613 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7614 /* Subwoofer */
7615 {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
7616 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7617
7618 /* enable unsolicited event */
7619 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7620 /* {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, */
7621
7622 { } /* end */
7623};
7624
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007625static struct hda_verb alc883_clevo_m720_verbs[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01007626 /* HP */
7627 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7628 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7629 /* Int speaker */
7630 {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
7631 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7632
7633 /* enable unsolicited event */
7634 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007635 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Jiang zhe368c7a92008-03-04 11:20:33 +01007636
7637 { } /* end */
7638};
7639
Jiang zhefb97dc62008-03-06 11:07:11 +01007640static struct hda_verb alc883_2ch_fujitsu_pi2515_verbs[] = {
7641 /* HP */
7642 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
7643 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7644 /* Subwoofer */
7645 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
7646 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7647
7648 /* enable unsolicited event */
7649 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7650
7651 { } /* end */
7652};
7653
Kailang Yangccc656c2006-10-17 12:32:26 +02007654static struct hda_verb alc883_tagra_verbs[] = {
7655 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7656 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7657
7658 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7659 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02007660
Kailang Yangccc656c2006-10-17 12:32:26 +02007661 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
7662 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
7663 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
7664
7665 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007666 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
7667 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
7668 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
Kailang Yangccc656c2006-10-17 12:32:26 +02007669
7670 { } /* end */
7671};
7672
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007673static struct hda_verb alc883_lenovo_101e_verbs[] = {
7674 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7675 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT|AC_USRSP_EN},
7676 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT|AC_USRSP_EN},
7677 { } /* end */
7678};
7679
Kailang Yang272a5272007-05-14 11:00:38 +02007680static struct hda_verb alc883_lenovo_nb0763_verbs[] = {
7681 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7682 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7683 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7684 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7685 { } /* end */
7686};
7687
7688static struct hda_verb alc888_lenovo_ms7195_verbs[] = {
7689 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7690 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7691 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7692 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT | AC_USRSP_EN},
7693 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7694 { } /* end */
7695};
7696
Kailang Yang189609a2007-08-20 11:31:23 +02007697static struct hda_verb alc883_haier_w66_verbs[] = {
7698 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7699 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7700
7701 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7702
7703 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
7704 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7705 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7706 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7707 { } /* end */
7708};
7709
Kailang Yange2757d52008-08-26 13:17:46 +02007710static struct hda_verb alc888_lenovo_sky_verbs[] = {
7711 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7712 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7713 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7714 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7715 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7716 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7717 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
7718 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7719 { } /* end */
7720};
7721
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007722static struct hda_verb alc888_3st_hp_verbs[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007723 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */
Herton Ronaldo Krzesinskif32a19e2008-03-18 09:27:08 +01007724 {0x16, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Rear : output 1 (0x0d) */
7725 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* CLFE : output 2 (0x0e) */
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007726 { }
7727};
7728
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007729static struct hda_verb alc888_6st_dell_verbs[] = {
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007730 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7731 { }
7732};
7733
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007734static struct hda_verb alc888_3st_hp_2ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007735 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7736 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7737 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7738 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7739 { }
7740};
7741
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007742static struct hda_verb alc888_3st_hp_6ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007743 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7744 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7745 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7746 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7747 { }
7748};
7749
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007750static struct hda_channel_mode alc888_3st_hp_modes[2] = {
7751 { 2, alc888_3st_hp_2ch_init },
7752 { 6, alc888_3st_hp_6ch_init },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007753};
7754
Kailang Yang272a5272007-05-14 11:00:38 +02007755/* toggle front-jack and RCA according to the hp-jack state */
7756static void alc888_lenovo_ms7195_front_automute(struct hda_codec *codec)
7757{
7758 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02007759
Kailang Yang272a5272007-05-14 11:00:38 +02007760 present = snd_hda_codec_read(codec, 0x1b, 0,
7761 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007762 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7763 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7764 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7765 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02007766}
7767
7768/* toggle RCA according to the front-jack state */
7769static void alc888_lenovo_ms7195_rca_automute(struct hda_codec *codec)
7770{
7771 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02007772
Kailang Yang272a5272007-05-14 11:00:38 +02007773 present = snd_hda_codec_read(codec, 0x14, 0,
7774 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007775 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7776 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02007777}
Takashi Iwai47fd8302007-08-10 17:11:07 +02007778
Kailang Yang272a5272007-05-14 11:00:38 +02007779static void alc883_lenovo_ms7195_unsol_event(struct hda_codec *codec,
7780 unsigned int res)
7781{
7782 if ((res >> 26) == ALC880_HP_EVENT)
7783 alc888_lenovo_ms7195_front_automute(codec);
7784 if ((res >> 26) == ALC880_FRONT_EVENT)
7785 alc888_lenovo_ms7195_rca_automute(codec);
7786}
7787
7788static struct hda_verb alc883_medion_md2_verbs[] = {
7789 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7790 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7791
7792 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7793
7794 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7795 { } /* end */
7796};
7797
7798/* toggle speaker-output according to the hp-jack state */
7799static void alc883_medion_md2_automute(struct hda_codec *codec)
7800{
7801 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02007802
Kailang Yang272a5272007-05-14 11:00:38 +02007803 present = snd_hda_codec_read(codec, 0x14, 0,
7804 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007805 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7806 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02007807}
7808
7809static void alc883_medion_md2_unsol_event(struct hda_codec *codec,
7810 unsigned int res)
7811{
7812 if ((res >> 26) == ALC880_HP_EVENT)
7813 alc883_medion_md2_automute(codec);
7814}
7815
Kailang Yangccc656c2006-10-17 12:32:26 +02007816/* toggle speaker-output according to the hp-jack state */
7817static void alc883_tagra_automute(struct hda_codec *codec)
7818{
7819 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007820 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02007821
7822 present = snd_hda_codec_read(codec, 0x14, 0,
7823 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007824 bits = present ? HDA_AMP_MUTE : 0;
7825 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
7826 HDA_AMP_MUTE, bits);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02007827 snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
7828 present ? 1 : 3);
Kailang Yangccc656c2006-10-17 12:32:26 +02007829}
7830
7831static void alc883_tagra_unsol_event(struct hda_codec *codec, unsigned int res)
7832{
7833 if ((res >> 26) == ALC880_HP_EVENT)
7834 alc883_tagra_automute(codec);
7835}
7836
Jiang zhe368c7a92008-03-04 11:20:33 +01007837/* toggle speaker-output according to the hp-jack state */
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007838static void alc883_clevo_m720_hp_automute(struct hda_codec *codec)
Jiang zhe368c7a92008-03-04 11:20:33 +01007839{
7840 unsigned int present;
7841 unsigned char bits;
7842
7843 present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0)
7844 & AC_PINSENSE_PRESENCE;
7845 bits = present ? HDA_AMP_MUTE : 0;
7846 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7847 HDA_AMP_MUTE, bits);
7848}
7849
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007850static void alc883_clevo_m720_mic_automute(struct hda_codec *codec)
7851{
7852 unsigned int present;
7853
7854 present = snd_hda_codec_read(codec, 0x18, 0,
7855 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7856 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
7857 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7858}
7859
7860static void alc883_clevo_m720_automute(struct hda_codec *codec)
7861{
7862 alc883_clevo_m720_hp_automute(codec);
7863 alc883_clevo_m720_mic_automute(codec);
7864}
7865
7866static void alc883_clevo_m720_unsol_event(struct hda_codec *codec,
Jiang zhe368c7a92008-03-04 11:20:33 +01007867 unsigned int res)
7868{
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007869 switch (res >> 26) {
7870 case ALC880_HP_EVENT:
7871 alc883_clevo_m720_hp_automute(codec);
7872 break;
7873 case ALC880_MIC_EVENT:
7874 alc883_clevo_m720_mic_automute(codec);
7875 break;
7876 }
Jiang zhe368c7a92008-03-04 11:20:33 +01007877}
7878
Jiang zhefb97dc62008-03-06 11:07:11 +01007879/* toggle speaker-output according to the hp-jack state */
7880static void alc883_2ch_fujitsu_pi2515_automute(struct hda_codec *codec)
7881{
7882 unsigned int present;
7883 unsigned char bits;
7884
7885 present = snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0)
7886 & AC_PINSENSE_PRESENCE;
7887 bits = present ? HDA_AMP_MUTE : 0;
7888 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7889 HDA_AMP_MUTE, bits);
7890}
7891
7892static void alc883_2ch_fujitsu_pi2515_unsol_event(struct hda_codec *codec,
7893 unsigned int res)
7894{
7895 if ((res >> 26) == ALC880_HP_EVENT)
7896 alc883_2ch_fujitsu_pi2515_automute(codec);
7897}
7898
Kailang Yang189609a2007-08-20 11:31:23 +02007899static void alc883_haier_w66_automute(struct hda_codec *codec)
7900{
7901 unsigned int present;
7902 unsigned char bits;
7903
7904 present = snd_hda_codec_read(codec, 0x1b, 0,
7905 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7906 bits = present ? 0x80 : 0;
7907 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7908 0x80, bits);
7909}
7910
7911static void alc883_haier_w66_unsol_event(struct hda_codec *codec,
7912 unsigned int res)
7913{
7914 if ((res >> 26) == ALC880_HP_EVENT)
7915 alc883_haier_w66_automute(codec);
7916}
7917
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007918static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
7919{
7920 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007921 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007922
7923 present = snd_hda_codec_read(codec, 0x14, 0,
7924 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007925 bits = present ? HDA_AMP_MUTE : 0;
7926 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7927 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007928}
7929
7930static void alc883_lenovo_101e_all_automute(struct hda_codec *codec)
7931{
7932 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007933 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007934
7935 present = snd_hda_codec_read(codec, 0x1b, 0,
7936 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007937 bits = present ? HDA_AMP_MUTE : 0;
7938 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7939 HDA_AMP_MUTE, bits);
7940 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7941 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007942}
7943
7944static void alc883_lenovo_101e_unsol_event(struct hda_codec *codec,
7945 unsigned int res)
7946{
7947 if ((res >> 26) == ALC880_HP_EVENT)
7948 alc883_lenovo_101e_all_automute(codec);
7949 if ((res >> 26) == ALC880_FRONT_EVENT)
7950 alc883_lenovo_101e_ispeaker_automute(codec);
7951}
7952
Takashi Iwai676a9b52007-08-16 15:23:35 +02007953/* toggle speaker-output according to the hp-jack state */
7954static void alc883_acer_aspire_automute(struct hda_codec *codec)
7955{
7956 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02007957
Takashi Iwai676a9b52007-08-16 15:23:35 +02007958 present = snd_hda_codec_read(codec, 0x14, 0,
7959 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7960 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7961 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7962 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
7963 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7964}
7965
7966static void alc883_acer_aspire_unsol_event(struct hda_codec *codec,
7967 unsigned int res)
7968{
7969 if ((res >> 26) == ALC880_HP_EVENT)
7970 alc883_acer_aspire_automute(codec);
7971}
7972
Kailang Yangd1a991a2007-08-15 16:21:59 +02007973static struct hda_verb alc883_acer_eapd_verbs[] = {
7974 /* HP Pin: output 0 (0x0c) */
7975 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7976 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7977 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
7978 /* Front Pin: output 0 (0x0c) */
Takashi Iwai676a9b52007-08-16 15:23:35 +02007979 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7980 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangd1a991a2007-08-15 16:21:59 +02007981 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangd1a991a2007-08-15 16:21:59 +02007982 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
7983 /* eanable EAPD on medion laptop */
7984 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
7985 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
Takashi Iwai676a9b52007-08-16 15:23:35 +02007986 /* enable unsolicited event */
7987 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yangd1a991a2007-08-15 16:21:59 +02007988 { }
7989};
7990
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007991static void alc888_6st_dell_front_automute(struct hda_codec *codec)
7992{
7993 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02007994
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007995 present = snd_hda_codec_read(codec, 0x1b, 0,
7996 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7997 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7998 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7999 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8000 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
8001 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
8002 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
8003 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
8004 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
8005}
8006
8007static void alc888_6st_dell_unsol_event(struct hda_codec *codec,
8008 unsigned int res)
8009{
8010 switch (res >> 26) {
8011 case ALC880_HP_EVENT:
8012 printk("hp_event\n");
8013 alc888_6st_dell_front_automute(codec);
8014 break;
8015 }
8016}
8017
Kailang Yange2757d52008-08-26 13:17:46 +02008018static void alc888_lenovo_sky_front_automute(struct hda_codec *codec)
8019{
8020 unsigned int mute;
8021 unsigned int present;
8022
8023 snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
8024 present = snd_hda_codec_read(codec, 0x1b, 0,
8025 AC_VERB_GET_PIN_SENSE, 0);
8026 present = (present & 0x80000000) != 0;
8027 if (present) {
8028 /* mute internal speaker */
8029 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8030 HDA_AMP_MUTE, HDA_AMP_MUTE);
8031 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8032 HDA_AMP_MUTE, HDA_AMP_MUTE);
8033 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
8034 HDA_AMP_MUTE, HDA_AMP_MUTE);
8035 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
8036 HDA_AMP_MUTE, HDA_AMP_MUTE);
8037 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0,
8038 HDA_AMP_MUTE, HDA_AMP_MUTE);
8039 } else {
8040 /* unmute internal speaker if necessary */
8041 mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
8042 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8043 HDA_AMP_MUTE, mute);
8044 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8045 HDA_AMP_MUTE, mute);
8046 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
8047 HDA_AMP_MUTE, mute);
8048 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
8049 HDA_AMP_MUTE, mute);
8050 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0,
8051 HDA_AMP_MUTE, mute);
8052 }
8053}
8054
8055static void alc883_lenovo_sky_unsol_event(struct hda_codec *codec,
8056 unsigned int res)
8057{
8058 if ((res >> 26) == ALC880_HP_EVENT)
8059 alc888_lenovo_sky_front_automute(codec);
8060}
8061
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008062/*
8063 * generic initialization of ADC, input mixers and output mixers
8064 */
8065static struct hda_verb alc883_auto_init_verbs[] = {
8066 /*
8067 * Unmute ADC0-2 and set the default input to mic-in
8068 */
8069 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8070 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8071 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8072 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8073
Takashi Iwaicb53c622007-08-10 17:21:45 +02008074 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008075 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008076 * Note: PASD motherboards uses the Line In 2 as the input for
8077 * front panel mic (mic 2)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008078 */
8079 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02008080 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8081 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8082 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8083 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8084 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008085
8086 /*
8087 * Set up output mixers (0x0c - 0x0f)
8088 */
8089 /* set vol=0 to output mixers */
8090 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8091 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8092 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8093 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8094 /* set up input amps for analog loopback */
8095 /* Amp Indices: DAC = 0, mixer = 1 */
8096 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8097 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8098 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8099 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8100 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8101 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8102 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8103 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8104 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8105 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8106
8107 /* FIXME: use matrix-type input source selection */
8108 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
8109 /* Input mixer1 */
8110 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8111 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8112 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008113 /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, */
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008114 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
8115 /* Input mixer2 */
8116 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8117 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8118 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008119 /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, */
Andy Shevchenkoe3cde642007-12-03 16:50:58 +01008120 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008121
8122 { }
8123};
8124
8125/* capture mixer elements */
8126static struct snd_kcontrol_new alc883_capture_mixer[] = {
8127 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
8128 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
8129 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
8130 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
8131 {
8132 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8133 /* The multiple "Capture Source" controls confuse alsamixer
8134 * So call somewhat different..
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008135 */
8136 /* .name = "Capture Source", */
8137 .name = "Input Source",
8138 .count = 2,
8139 .info = alc882_mux_enum_info,
8140 .get = alc882_mux_enum_get,
8141 .put = alc882_mux_enum_put,
8142 },
8143 { } /* end */
8144};
8145
Kailang Yange2757d52008-08-26 13:17:46 +02008146static struct hda_verb alc888_asus_m90v_verbs[] = {
8147 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8148 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8149 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8150 /* enable unsolicited event */
8151 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8152 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
8153 { } /* end */
8154};
8155
8156static void alc883_nb_mic_automute(struct hda_codec *codec)
8157{
8158 unsigned int present;
8159
8160 present = snd_hda_codec_read(codec, 0x18, 0,
8161 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
8162 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
8163 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
8164 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
8165 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
8166}
8167
8168static void alc883_M90V_speaker_automute(struct hda_codec *codec)
8169{
8170 unsigned int present;
8171 unsigned char bits;
8172
8173 present = snd_hda_codec_read(codec, 0x1b, 0,
8174 AC_VERB_GET_PIN_SENSE, 0)
8175 & AC_PINSENSE_PRESENCE;
8176 bits = present ? 0 : PIN_OUT;
8177 snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
8178 bits);
8179 snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
8180 bits);
8181 snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
8182 bits);
8183}
8184
8185static void alc883_mode2_unsol_event(struct hda_codec *codec,
8186 unsigned int res)
8187{
8188 switch (res >> 26) {
8189 case ALC880_HP_EVENT:
8190 alc883_M90V_speaker_automute(codec);
8191 break;
8192 case ALC880_MIC_EVENT:
8193 alc883_nb_mic_automute(codec);
8194 break;
8195 }
8196}
8197
8198static void alc883_mode2_inithook(struct hda_codec *codec)
8199{
8200 alc883_M90V_speaker_automute(codec);
8201 alc883_nb_mic_automute(codec);
8202}
8203
8204static struct hda_verb alc888_asus_eee1601_verbs[] = {
8205 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8206 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8207 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8208 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8209 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8210 {0x20, AC_VERB_SET_COEF_INDEX, 0x0b},
8211 {0x20, AC_VERB_SET_PROC_COEF, 0x0838},
8212 /* enable unsolicited event */
8213 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8214 { } /* end */
8215};
8216
8217static void alc883_eee1601_speaker_automute(struct hda_codec *codec)
8218{
8219 unsigned int present;
8220 unsigned char bits;
8221
8222 present = snd_hda_codec_read(codec, 0x14, 0,
8223 AC_VERB_GET_PIN_SENSE, 0)
8224 & AC_PINSENSE_PRESENCE;
8225 bits = present ? 0 : PIN_OUT;
8226 snd_hda_codec_write(codec, 0x1b, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
8227 bits);
8228}
8229
8230static void alc883_eee1601_unsol_event(struct hda_codec *codec,
8231 unsigned int res)
8232{
8233 switch (res >> 26) {
8234 case ALC880_HP_EVENT:
8235 alc883_eee1601_speaker_automute(codec);
8236 break;
8237 }
8238}
8239
8240static void alc883_eee1601_inithook(struct hda_codec *codec)
8241{
8242 alc883_eee1601_speaker_automute(codec);
8243}
8244
Takashi Iwaicb53c622007-08-10 17:21:45 +02008245#ifdef CONFIG_SND_HDA_POWER_SAVE
8246#define alc883_loopbacks alc880_loopbacks
8247#endif
8248
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008249/* pcm configuration: identiacal with ALC880 */
8250#define alc883_pcm_analog_playback alc880_pcm_analog_playback
8251#define alc883_pcm_analog_capture alc880_pcm_analog_capture
Takashi Iwai63300792008-01-24 15:31:36 +01008252#define alc883_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008253#define alc883_pcm_digital_playback alc880_pcm_digital_playback
8254#define alc883_pcm_digital_capture alc880_pcm_digital_capture
8255
8256/*
8257 * configuration and preset
8258 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008259static const char *alc883_models[ALC883_MODEL_LAST] = {
8260 [ALC883_3ST_2ch_DIG] = "3stack-dig",
8261 [ALC883_3ST_6ch_DIG] = "3stack-6ch-dig",
8262 [ALC883_3ST_6ch] = "3stack-6ch",
8263 [ALC883_6ST_DIG] = "6stack-dig",
8264 [ALC883_TARGA_DIG] = "targa-dig",
8265 [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008266 [ALC883_ACER] = "acer",
Tobin Davis2880a862007-08-07 11:50:26 +02008267 [ALC883_ACER_ASPIRE] = "acer-aspire",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008268 [ALC883_MEDION] = "medion",
Kailang Yang272a5272007-05-14 11:00:38 +02008269 [ALC883_MEDION_MD2] = "medion-md2",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008270 [ALC883_LAPTOP_EAPD] = "laptop-eapd",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008271 [ALC883_LENOVO_101E_2ch] = "lenovo-101e",
Kailang Yang272a5272007-05-14 11:00:38 +02008272 [ALC883_LENOVO_NB0763] = "lenovo-nb0763",
8273 [ALC888_LENOVO_MS7195_DIG] = "lenovo-ms7195-dig",
Kailang Yange2757d52008-08-26 13:17:46 +02008274 [ALC888_LENOVO_SKY] = "lenovo-sky",
Kailang Yang189609a2007-08-20 11:31:23 +02008275 [ALC883_HAIER_W66] = "haier-w66",
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008276 [ALC888_3ST_HP] = "3stack-hp",
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008277 [ALC888_6ST_DELL] = "6stack-dell",
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008278 [ALC883_MITAC] = "mitac",
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008279 [ALC883_CLEVO_M720] = "clevo-m720",
Jiang zhefb97dc62008-03-06 11:07:11 +01008280 [ALC883_FUJITSU_PI2515] = "fujitsu-pi2515",
Jiang zhe17bba1b2008-06-04 12:11:07 +02008281 [ALC883_3ST_6ch_INTEL] = "3stack-6ch-intel",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008282 [ALC883_AUTO] = "auto",
8283};
8284
8285static struct snd_pci_quirk alc883_cfg_tbl[] = {
8286 SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC883_3ST_6ch_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008287 SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE),
8288 SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE),
8289 SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE),
Jaroslav Kysela0b18cb12008-07-28 17:07:07 +02008290 SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_ACER_ASPIRE),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008291 SND_PCI_QUIRK(0x1025, 0, "Acer laptop", ALC883_ACER), /* default Acer */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008292 SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL),
Tobin Davisfebe3372007-06-12 11:27:46 +02008293 SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008294 SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP),
8295 SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP),
Herton Ronaldo Krzesinski5d85f8d2008-03-20 12:13:46 +01008296 SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008297 SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG),
Kailang Yange2757d52008-08-26 13:17:46 +02008298 SND_PCI_QUIRK(0x1043, 0x8317, "Asus M90V", ALC888_ASUS_M90V),
8299 SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_ASUS_EEE1601),
Travis Place97ec7102008-05-23 18:31:46 +02008300 SND_PCI_QUIRK(0x105b, 0x0ce8, "Foxconn P35AX-S", ALC883_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008301 SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008302 SND_PCI_QUIRK(0x1071, 0x8253, "Mitac 8252d", ALC883_MITAC),
8303 SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD),
Kailang Yange2757d52008-08-26 13:17:46 +02008304 SND_PCI_QUIRK(0x10f1, 0x2350, "TYAN-S2350", ALC888_6ST_DELL),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008305 SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch),
Tobin Davis57b14f22007-04-18 23:05:36 +02008306 SND_PCI_QUIRK(0x1458, 0xa002, "MSI", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008307 SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG),
8308 SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG),
8309 SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG),
Jiang zhe4383fae2008-04-14 12:58:57 +02008310 SND_PCI_QUIRK(0x1462, 0x2fb3, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008311 SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG),
Pascal Terjan82808232008-03-04 11:33:28 +01008312 SND_PCI_QUIRK(0x1462, 0x3783, "NEC S970", ALC883_TARGA_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008313 SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG),
8314 SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG),
8315 SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG),
8316 SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG),
8317 SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG),
8318 SND_PCI_QUIRK(0x1462, 0x3fdf, "MSI", ALC883_TARGA_DIG),
8319 SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG),
8320 SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG),
8321 SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008322 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG),
8323 SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG),
Tobin Davis799f88a2007-05-29 14:29:08 +02008324 SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG),
Herton Ronaldo Krzesinski86d34b72008-03-18 09:27:59 +01008325 SND_PCI_QUIRK(0x1462, 0x7267, "MSI", ALC883_3ST_6ch_DIG),
Leonard Norrgard2a296cb2007-01-08 11:28:22 +01008326 SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG),
Tobin Davis2dcd5222007-07-10 17:04:57 +02008327 SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008328 SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008329 SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG),
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008330 SND_PCI_QUIRK(0x1558, 0x0721, "Clevo laptop M720R", ALC883_CLEVO_M720),
8331 SND_PCI_QUIRK(0x1558, 0x0722, "Clevo laptop M720SR", ALC883_CLEVO_M720),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008332 SND_PCI_QUIRK(0x1558, 0, "Clevo laptop", ALC883_LAPTOP_EAPD),
Daniel T Chene60623b2007-05-29 03:41:55 -04008333 SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008334 SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION),
Jiang zhefb97dc62008-03-06 11:07:11 +01008335 SND_PCI_QUIRK(0x1734, 0x1108, "Fujitsu AMILO Pi2515", ALC883_FUJITSU_PI2515),
Kailang Yang272a5272007-05-14 11:00:38 +02008336 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch),
Kailang Yang272a5272007-05-14 11:00:38 +02008337 SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008338 SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763),
8339 SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Kailang Yange2757d52008-08-26 13:17:46 +02008340 SND_PCI_QUIRK(0x17aa, 0x101d, "Lenovo Sky", ALC888_LENOVO_SKY),
Kailang Yang272a5272007-05-14 11:00:38 +02008341 SND_PCI_QUIRK(0x17c0, 0x4071, "MEDION MD2", ALC883_MEDION_MD2),
Andrew Paprocki0b167bf2008-02-03 10:15:44 +01008342 SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG),
Kailang Yang189609a2007-08-20 11:31:23 +02008343 SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66),
Jiang zhe17bba1b2008-06-04 12:11:07 +02008344 SND_PCI_QUIRK(0x8086, 0x0001, "DG33BUC", ALC883_3ST_6ch_INTEL),
8345 SND_PCI_QUIRK(0x8086, 0x0002, "DG33FBC", ALC883_3ST_6ch_INTEL),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008346 SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008347 {}
8348};
8349
8350static struct alc_config_preset alc883_presets[] = {
8351 [ALC883_3ST_2ch_DIG] = {
8352 .mixers = { alc883_3ST_2ch_mixer },
8353 .init_verbs = { alc883_init_verbs },
8354 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8355 .dac_nids = alc883_dac_nids,
8356 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008357 .dig_in_nid = ALC883_DIGIN_NID,
8358 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8359 .channel_mode = alc883_3ST_2ch_modes,
8360 .input_mux = &alc883_capture_source,
8361 },
8362 [ALC883_3ST_6ch_DIG] = {
8363 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
8364 .init_verbs = { alc883_init_verbs },
8365 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8366 .dac_nids = alc883_dac_nids,
8367 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008368 .dig_in_nid = ALC883_DIGIN_NID,
8369 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
8370 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02008371 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008372 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008373 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008374 [ALC883_3ST_6ch] = {
8375 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
8376 .init_verbs = { alc883_init_verbs },
8377 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8378 .dac_nids = alc883_dac_nids,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008379 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
8380 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02008381 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008382 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008383 },
Jiang zhe17bba1b2008-06-04 12:11:07 +02008384 [ALC883_3ST_6ch_INTEL] = {
8385 .mixers = { alc883_3ST_6ch_intel_mixer, alc883_chmode_mixer },
8386 .init_verbs = { alc883_init_verbs },
8387 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8388 .dac_nids = alc883_dac_nids,
8389 .dig_out_nid = ALC883_DIGOUT_NID,
8390 .dig_in_nid = ALC883_DIGIN_NID,
8391 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_intel_modes),
8392 .channel_mode = alc883_3ST_6ch_intel_modes,
8393 .need_dac_fix = 1,
8394 .input_mux = &alc883_3stack_6ch_intel,
8395 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008396 [ALC883_6ST_DIG] = {
8397 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
8398 .init_verbs = { alc883_init_verbs },
8399 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8400 .dac_nids = alc883_dac_nids,
8401 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008402 .dig_in_nid = ALC883_DIGIN_NID,
8403 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
8404 .channel_mode = alc883_sixstack_modes,
8405 .input_mux = &alc883_capture_source,
8406 },
Kailang Yangccc656c2006-10-17 12:32:26 +02008407 [ALC883_TARGA_DIG] = {
8408 .mixers = { alc883_tagra_mixer, alc883_chmode_mixer },
8409 .init_verbs = { alc883_init_verbs, alc883_tagra_verbs},
8410 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8411 .dac_nids = alc883_dac_nids,
8412 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +02008413 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
8414 .channel_mode = alc883_3ST_6ch_modes,
8415 .need_dac_fix = 1,
8416 .input_mux = &alc883_capture_source,
8417 .unsol_event = alc883_tagra_unsol_event,
8418 .init_hook = alc883_tagra_automute,
8419 },
8420 [ALC883_TARGA_2ch_DIG] = {
8421 .mixers = { alc883_tagra_2ch_mixer},
8422 .init_verbs = { alc883_init_verbs, alc883_tagra_verbs},
8423 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8424 .dac_nids = alc883_dac_nids,
8425 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +02008426 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8427 .channel_mode = alc883_3ST_2ch_modes,
8428 .input_mux = &alc883_capture_source,
8429 .unsol_event = alc883_tagra_unsol_event,
8430 .init_hook = alc883_tagra_automute,
8431 },
Vladimir Avdoninbab282b92006-08-22 13:31:58 +02008432 [ALC883_ACER] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02008433 .mixers = { alc883_base_mixer },
Vladimir Avdoninbab282b92006-08-22 13:31:58 +02008434 /* On TravelMate laptops, GPIO 0 enables the internal speaker
8435 * and the headphone jack. Turn this on and rely on the
8436 * standard mute methods whenever the user wants to turn
8437 * these outputs off.
8438 */
8439 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs },
8440 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8441 .dac_nids = alc883_dac_nids,
Vladimir Avdoninbab282b92006-08-22 13:31:58 +02008442 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8443 .channel_mode = alc883_3ST_2ch_modes,
8444 .input_mux = &alc883_capture_source,
8445 },
Tobin Davis2880a862007-08-07 11:50:26 +02008446 [ALC883_ACER_ASPIRE] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02008447 .mixers = { alc883_acer_aspire_mixer },
Kailang Yangd1a991a2007-08-15 16:21:59 +02008448 .init_verbs = { alc883_init_verbs, alc883_acer_eapd_verbs },
Tobin Davis2880a862007-08-07 11:50:26 +02008449 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8450 .dac_nids = alc883_dac_nids,
8451 .dig_out_nid = ALC883_DIGOUT_NID,
Tobin Davis2880a862007-08-07 11:50:26 +02008452 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8453 .channel_mode = alc883_3ST_2ch_modes,
8454 .input_mux = &alc883_capture_source,
Takashi Iwai676a9b52007-08-16 15:23:35 +02008455 .unsol_event = alc883_acer_aspire_unsol_event,
8456 .init_hook = alc883_acer_aspire_automute,
Kailang Yangd1a991a2007-08-15 16:21:59 +02008457 },
Tobin Davisc07584c2006-10-13 12:32:16 +02008458 [ALC883_MEDION] = {
8459 .mixers = { alc883_fivestack_mixer,
8460 alc883_chmode_mixer },
8461 .init_verbs = { alc883_init_verbs,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008462 alc883_medion_eapd_verbs },
Tobin Davisc07584c2006-10-13 12:32:16 +02008463 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8464 .dac_nids = alc883_dac_nids,
Tobin Davisc07584c2006-10-13 12:32:16 +02008465 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
8466 .channel_mode = alc883_sixstack_modes,
8467 .input_mux = &alc883_capture_source,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008468 },
Kailang Yang272a5272007-05-14 11:00:38 +02008469 [ALC883_MEDION_MD2] = {
8470 .mixers = { alc883_medion_md2_mixer},
8471 .init_verbs = { alc883_init_verbs, alc883_medion_md2_verbs},
8472 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8473 .dac_nids = alc883_dac_nids,
8474 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang272a5272007-05-14 11:00:38 +02008475 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8476 .channel_mode = alc883_3ST_2ch_modes,
8477 .input_mux = &alc883_capture_source,
8478 .unsol_event = alc883_medion_md2_unsol_event,
8479 .init_hook = alc883_medion_md2_automute,
Kailang Yangea1fb292008-08-26 12:58:38 +02008480 },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008481 [ALC883_LAPTOP_EAPD] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02008482 .mixers = { alc883_base_mixer },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008483 .init_verbs = { alc883_init_verbs, alc882_eapd_verbs },
8484 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8485 .dac_nids = alc883_dac_nids,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008486 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8487 .channel_mode = alc883_3ST_2ch_modes,
8488 .input_mux = &alc883_capture_source,
8489 },
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008490 [ALC883_CLEVO_M720] = {
8491 .mixers = { alc883_clevo_m720_mixer },
8492 .init_verbs = { alc883_init_verbs, alc883_clevo_m720_verbs },
Jiang zhe368c7a92008-03-04 11:20:33 +01008493 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8494 .dac_nids = alc883_dac_nids,
8495 .dig_out_nid = ALC883_DIGOUT_NID,
8496 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8497 .channel_mode = alc883_3ST_2ch_modes,
8498 .input_mux = &alc883_capture_source,
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008499 .unsol_event = alc883_clevo_m720_unsol_event,
8500 .init_hook = alc883_clevo_m720_automute,
Jiang zhe368c7a92008-03-04 11:20:33 +01008501 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008502 [ALC883_LENOVO_101E_2ch] = {
8503 .mixers = { alc883_lenovo_101e_2ch_mixer},
8504 .init_verbs = { alc883_init_verbs, alc883_lenovo_101e_verbs},
8505 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8506 .dac_nids = alc883_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008507 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8508 .channel_mode = alc883_3ST_2ch_modes,
8509 .input_mux = &alc883_lenovo_101e_capture_source,
8510 .unsol_event = alc883_lenovo_101e_unsol_event,
8511 .init_hook = alc883_lenovo_101e_all_automute,
8512 },
Kailang Yang272a5272007-05-14 11:00:38 +02008513 [ALC883_LENOVO_NB0763] = {
8514 .mixers = { alc883_lenovo_nb0763_mixer },
8515 .init_verbs = { alc883_init_verbs, alc883_lenovo_nb0763_verbs},
8516 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8517 .dac_nids = alc883_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +02008518 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8519 .channel_mode = alc883_3ST_2ch_modes,
8520 .need_dac_fix = 1,
8521 .input_mux = &alc883_lenovo_nb0763_capture_source,
8522 .unsol_event = alc883_medion_md2_unsol_event,
8523 .init_hook = alc883_medion_md2_automute,
8524 },
8525 [ALC888_LENOVO_MS7195_DIG] = {
8526 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
8527 .init_verbs = { alc883_init_verbs, alc888_lenovo_ms7195_verbs},
8528 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8529 .dac_nids = alc883_dac_nids,
8530 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang272a5272007-05-14 11:00:38 +02008531 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
8532 .channel_mode = alc883_3ST_6ch_modes,
8533 .need_dac_fix = 1,
8534 .input_mux = &alc883_capture_source,
8535 .unsol_event = alc883_lenovo_ms7195_unsol_event,
8536 .init_hook = alc888_lenovo_ms7195_front_automute,
Kailang Yang189609a2007-08-20 11:31:23 +02008537 },
8538 [ALC883_HAIER_W66] = {
8539 .mixers = { alc883_tagra_2ch_mixer},
8540 .init_verbs = { alc883_init_verbs, alc883_haier_w66_verbs},
8541 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8542 .dac_nids = alc883_dac_nids,
8543 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang189609a2007-08-20 11:31:23 +02008544 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8545 .channel_mode = alc883_3ST_2ch_modes,
8546 .input_mux = &alc883_capture_source,
8547 .unsol_event = alc883_haier_w66_unsol_event,
8548 .init_hook = alc883_haier_w66_automute,
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +01008549 },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008550 [ALC888_3ST_HP] = {
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +01008551 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008552 .init_verbs = { alc883_init_verbs, alc888_3st_hp_verbs },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008553 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8554 .dac_nids = alc883_dac_nids,
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008555 .num_channel_mode = ARRAY_SIZE(alc888_3st_hp_modes),
8556 .channel_mode = alc888_3st_hp_modes,
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008557 .need_dac_fix = 1,
8558 .input_mux = &alc883_capture_source,
8559 },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008560 [ALC888_6ST_DELL] = {
Herton Ronaldo Krzesinskif24dbdc2008-03-20 12:14:28 +01008561 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008562 .init_verbs = { alc883_init_verbs, alc888_6st_dell_verbs },
8563 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8564 .dac_nids = alc883_dac_nids,
8565 .dig_out_nid = ALC883_DIGOUT_NID,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008566 .dig_in_nid = ALC883_DIGIN_NID,
8567 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
8568 .channel_mode = alc883_sixstack_modes,
8569 .input_mux = &alc883_capture_source,
8570 .unsol_event = alc888_6st_dell_unsol_event,
8571 .init_hook = alc888_6st_dell_front_automute,
8572 },
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008573 [ALC883_MITAC] = {
8574 .mixers = { alc883_mitac_mixer },
8575 .init_verbs = { alc883_init_verbs, alc883_mitac_verbs },
8576 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8577 .dac_nids = alc883_dac_nids,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008578 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8579 .channel_mode = alc883_3ST_2ch_modes,
8580 .input_mux = &alc883_capture_source,
8581 .unsol_event = alc883_mitac_unsol_event,
8582 .init_hook = alc883_mitac_automute,
8583 },
Jiang zhefb97dc62008-03-06 11:07:11 +01008584 [ALC883_FUJITSU_PI2515] = {
8585 .mixers = { alc883_2ch_fujitsu_pi2515_mixer },
8586 .init_verbs = { alc883_init_verbs,
8587 alc883_2ch_fujitsu_pi2515_verbs},
8588 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8589 .dac_nids = alc883_dac_nids,
8590 .dig_out_nid = ALC883_DIGOUT_NID,
8591 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8592 .channel_mode = alc883_3ST_2ch_modes,
8593 .input_mux = &alc883_fujitsu_pi2515_capture_source,
8594 .unsol_event = alc883_2ch_fujitsu_pi2515_unsol_event,
8595 .init_hook = alc883_2ch_fujitsu_pi2515_automute,
8596 },
Kailang Yange2757d52008-08-26 13:17:46 +02008597 [ALC888_LENOVO_SKY] = {
8598 .mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer },
8599 .init_verbs = { alc883_init_verbs, alc888_lenovo_sky_verbs},
8600 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8601 .dac_nids = alc883_dac_nids,
8602 .dig_out_nid = ALC883_DIGOUT_NID,
8603 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
8604 .adc_nids = alc883_adc_nids,
8605 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
8606 .channel_mode = alc883_sixstack_modes,
8607 .need_dac_fix = 1,
8608 .input_mux = &alc883_lenovo_sky_capture_source,
8609 .unsol_event = alc883_lenovo_sky_unsol_event,
8610 .init_hook = alc888_lenovo_sky_front_automute,
8611 },
8612 [ALC888_ASUS_M90V] = {
8613 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
8614 .init_verbs = { alc883_init_verbs, alc888_asus_m90v_verbs },
8615 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8616 .dac_nids = alc883_dac_nids,
8617 .dig_out_nid = ALC883_DIGOUT_NID,
8618 .dig_in_nid = ALC883_DIGIN_NID,
8619 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
8620 .channel_mode = alc883_3ST_6ch_modes,
8621 .need_dac_fix = 1,
8622 .input_mux = &alc883_fujitsu_pi2515_capture_source,
8623 .unsol_event = alc883_mode2_unsol_event,
8624 .init_hook = alc883_mode2_inithook,
8625 },
8626 [ALC888_ASUS_EEE1601] = {
8627 .mixers = { alc883_asus_eee1601_mixer },
8628 .init_verbs = { alc883_init_verbs, alc888_asus_eee1601_verbs },
8629 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8630 .dac_nids = alc883_dac_nids,
8631 .dig_out_nid = ALC883_DIGOUT_NID,
8632 .dig_in_nid = ALC883_DIGIN_NID,
8633 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8634 .channel_mode = alc883_3ST_2ch_modes,
8635 .need_dac_fix = 1,
8636 .input_mux = &alc883_asus_eee1601_capture_source,
8637 .unsol_event = alc883_eee1601_unsol_event,
8638 .init_hook = alc883_eee1601_inithook,
8639 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008640};
8641
8642
8643/*
8644 * BIOS auto configuration
8645 */
8646static void alc883_auto_set_output_and_unmute(struct hda_codec *codec,
8647 hda_nid_t nid, int pin_type,
8648 int dac_idx)
8649{
8650 /* set as output */
8651 struct alc_spec *spec = codec->spec;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008652 int idx;
8653
Takashi Iwaif6c7e542008-02-12 18:32:23 +01008654 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008655 if (spec->multiout.dac_nids[dac_idx] == 0x25)
8656 idx = 4;
8657 else
8658 idx = spec->multiout.dac_nids[dac_idx] - 2;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008659 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
8660
8661}
8662
8663static void alc883_auto_init_multi_out(struct hda_codec *codec)
8664{
8665 struct alc_spec *spec = codec->spec;
8666 int i;
8667
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008668 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008669 for (i = 0; i <= HDA_SIDE; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008670 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02008671 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008672 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02008673 alc883_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008674 i);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008675 }
8676}
8677
8678static void alc883_auto_init_hp_out(struct hda_codec *codec)
8679{
8680 struct alc_spec *spec = codec->spec;
8681 hda_nid_t pin;
8682
Takashi Iwaieb06ed82006-09-20 17:10:27 +02008683 pin = spec->autocfg.hp_pins[0];
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008684 if (pin) /* connect to front */
8685 /* use dac 0 */
8686 alc883_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01008687 pin = spec->autocfg.speaker_pins[0];
8688 if (pin)
8689 alc883_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008690}
8691
8692#define alc883_is_input_pin(nid) alc880_is_input_pin(nid)
8693#define ALC883_PIN_CD_NID ALC880_PIN_CD_NID
8694
8695static void alc883_auto_init_analog_input(struct hda_codec *codec)
8696{
8697 struct alc_spec *spec = codec->spec;
8698 int i;
8699
8700 for (i = 0; i < AUTO_PIN_LAST; i++) {
8701 hda_nid_t nid = spec->autocfg.input_pins[i];
8702 if (alc883_is_input_pin(nid)) {
8703 snd_hda_codec_write(codec, nid, 0,
8704 AC_VERB_SET_PIN_WIDGET_CONTROL,
8705 (i <= AUTO_PIN_FRONT_MIC ?
8706 PIN_VREF80 : PIN_IN));
8707 if (nid != ALC883_PIN_CD_NID)
8708 snd_hda_codec_write(codec, nid, 0,
8709 AC_VERB_SET_AMP_GAIN_MUTE,
8710 AMP_OUT_MUTE);
8711 }
8712 }
8713}
8714
Takashi Iwaif511b012008-08-15 16:46:42 +02008715#define alc883_auto_init_input_src alc882_auto_init_input_src
8716
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008717/* almost identical with ALC880 parser... */
8718static int alc883_parse_auto_config(struct hda_codec *codec)
8719{
8720 struct alc_spec *spec = codec->spec;
8721 int err = alc880_parse_auto_config(codec);
8722
8723 if (err < 0)
8724 return err;
Takashi Iwai776e1842007-08-29 15:07:11 +02008725 else if (!err)
8726 return 0; /* no config found */
8727
8728 err = alc_auto_add_mic_boost(codec);
8729 if (err < 0)
8730 return err;
8731
8732 /* hack - override the init verbs */
8733 spec->init_verbs[0] = alc883_auto_init_verbs;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008734 spec->mixers[spec->num_mixers] = alc883_capture_mixer;
8735 spec->num_mixers++;
Takashi Iwai776e1842007-08-29 15:07:11 +02008736
8737 return 1; /* config found */
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008738}
8739
8740/* additional initialization for auto-configuration model */
8741static void alc883_auto_init(struct hda_codec *codec)
8742{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01008743 struct alc_spec *spec = codec->spec;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008744 alc883_auto_init_multi_out(codec);
8745 alc883_auto_init_hp_out(codec);
8746 alc883_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +02008747 alc883_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01008748 if (spec->unsol_event)
8749 alc_sku_automute(codec);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008750}
8751
8752static int patch_alc883(struct hda_codec *codec)
8753{
8754 struct alc_spec *spec;
8755 int err, board_config;
8756
8757 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
8758 if (spec == NULL)
8759 return -ENOMEM;
8760
8761 codec->spec = spec;
8762
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02008763 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
8764
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008765 board_config = snd_hda_check_board_config(codec, ALC883_MODEL_LAST,
8766 alc883_models,
8767 alc883_cfg_tbl);
8768 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008769 printk(KERN_INFO "hda_codec: Unknown model for ALC883, "
8770 "trying auto-probe from BIOS...\n");
8771 board_config = ALC883_AUTO;
8772 }
8773
8774 if (board_config == ALC883_AUTO) {
8775 /* automatic parse from the BIOS config */
8776 err = alc883_parse_auto_config(codec);
8777 if (err < 0) {
8778 alc_free(codec);
8779 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008780 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008781 printk(KERN_INFO
8782 "hda_codec: Cannot set up configuration "
8783 "from BIOS. Using base mode...\n");
8784 board_config = ALC883_3ST_2ch_DIG;
8785 }
8786 }
8787
8788 if (board_config != ALC883_AUTO)
8789 setup_preset(spec, &alc883_presets[board_config]);
8790
Kailang Yang2f893282008-05-27 12:14:47 +02008791 switch (codec->vendor_id) {
8792 case 0x10ec0888:
8793 spec->stream_name_analog = "ALC888 Analog";
8794 spec->stream_name_digital = "ALC888 Digital";
8795 break;
8796 case 0x10ec0889:
8797 spec->stream_name_analog = "ALC889 Analog";
8798 spec->stream_name_digital = "ALC889 Digital";
8799 break;
8800 default:
8801 spec->stream_name_analog = "ALC883 Analog";
8802 spec->stream_name_digital = "ALC883 Digital";
8803 break;
8804 }
8805
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008806 spec->stream_analog_playback = &alc883_pcm_analog_playback;
8807 spec->stream_analog_capture = &alc883_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01008808 spec->stream_analog_alt_capture = &alc883_pcm_analog_alt_capture;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008809
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008810 spec->stream_digital_playback = &alc883_pcm_digital_playback;
8811 spec->stream_digital_capture = &alc883_pcm_digital_capture;
8812
Takashi Iwaie1406342008-02-11 18:32:32 +01008813 spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids);
8814 spec->adc_nids = alc883_adc_nids;
8815 spec->capsrc_nids = alc883_capsrc_nids;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008816
Takashi Iwai2134ea42008-01-10 16:53:55 +01008817 spec->vmaster_nid = 0x0c;
8818
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008819 codec->patch_ops = alc_patch_ops;
8820 if (board_config == ALC883_AUTO)
8821 spec->init_hook = alc883_auto_init;
Kailang Yangf9423e72008-05-27 12:32:25 +02008822
Takashi Iwaicb53c622007-08-10 17:21:45 +02008823#ifdef CONFIG_SND_HDA_POWER_SAVE
8824 if (!spec->loopback.amplist)
8825 spec->loopback.amplist = alc883_loopbacks;
8826#endif
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008827
8828 return 0;
8829}
8830
8831/*
Kailang Yangdf694da2005-12-05 19:42:22 +01008832 * ALC262 support
8833 */
8834
8835#define ALC262_DIGOUT_NID ALC880_DIGOUT_NID
8836#define ALC262_DIGIN_NID ALC880_DIGIN_NID
8837
8838#define alc262_dac_nids alc260_dac_nids
8839#define alc262_adc_nids alc882_adc_nids
8840#define alc262_adc_nids_alt alc882_adc_nids_alt
Takashi Iwai88c71a92008-02-14 17:27:17 +01008841#define alc262_capsrc_nids alc882_capsrc_nids
8842#define alc262_capsrc_nids_alt alc882_capsrc_nids_alt
Kailang Yangdf694da2005-12-05 19:42:22 +01008843
8844#define alc262_modes alc260_modes
Takashi Iwaic5f2ea02005-12-06 18:54:31 +01008845#define alc262_capture_source alc882_capture_source
Kailang Yangdf694da2005-12-05 19:42:22 +01008846
Kailang Yang4e555fe2008-08-26 13:05:55 +02008847static hda_nid_t alc262_dmic_adc_nids[1] = {
8848 /* ADC0 */
8849 0x09
8850};
8851
8852static hda_nid_t alc262_dmic_capsrc_nids[1] = { 0x22 };
8853
Kailang Yangdf694da2005-12-05 19:42:22 +01008854static struct snd_kcontrol_new alc262_base_mixer[] = {
8855 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8856 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8857 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8858 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8859 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8860 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8861 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8862 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008863 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01008864 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
8865 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008866 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01008867 /* HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01008868 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT), */
Kailang Yangdf694da2005-12-05 19:42:22 +01008869 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),
8870 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8871 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8872 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01008873 { } /* end */
Takashi Iwai834be882006-03-01 14:16:17 +01008874};
8875
Kailang Yangccc656c2006-10-17 12:32:26 +02008876static struct snd_kcontrol_new alc262_hippo1_mixer[] = {
8877 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8878 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8879 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8880 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8881 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8882 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8883 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8884 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008885 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008886 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
8887 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008888 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008889 /* HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01008890 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT), */
Kailang Yangccc656c2006-10-17 12:32:26 +02008891 /*HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),*/
8892 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8893 { } /* end */
8894};
8895
Takashi Iwaice875f02008-01-28 18:17:43 +01008896/* update HP, line and mono-out pins according to the master switch */
8897static void alc262_hp_master_update(struct hda_codec *codec)
8898{
8899 struct alc_spec *spec = codec->spec;
8900 int val = spec->master_sw;
8901
8902 /* HP & line-out */
8903 snd_hda_codec_write_cache(codec, 0x1b, 0,
8904 AC_VERB_SET_PIN_WIDGET_CONTROL,
8905 val ? PIN_HP : 0);
8906 snd_hda_codec_write_cache(codec, 0x15, 0,
8907 AC_VERB_SET_PIN_WIDGET_CONTROL,
8908 val ? PIN_HP : 0);
8909 /* mono (speaker) depending on the HP jack sense */
8910 val = val && !spec->jack_present;
8911 snd_hda_codec_write_cache(codec, 0x16, 0,
8912 AC_VERB_SET_PIN_WIDGET_CONTROL,
8913 val ? PIN_OUT : 0);
8914}
8915
8916static void alc262_hp_bpc_automute(struct hda_codec *codec)
8917{
8918 struct alc_spec *spec = codec->spec;
8919 unsigned int presence;
8920 presence = snd_hda_codec_read(codec, 0x1b, 0,
8921 AC_VERB_GET_PIN_SENSE, 0);
8922 spec->jack_present = !!(presence & AC_PINSENSE_PRESENCE);
8923 alc262_hp_master_update(codec);
8924}
8925
8926static void alc262_hp_bpc_unsol_event(struct hda_codec *codec, unsigned int res)
8927{
8928 if ((res >> 26) != ALC880_HP_EVENT)
8929 return;
8930 alc262_hp_bpc_automute(codec);
8931}
8932
8933static void alc262_hp_wildwest_automute(struct hda_codec *codec)
8934{
8935 struct alc_spec *spec = codec->spec;
8936 unsigned int presence;
8937 presence = snd_hda_codec_read(codec, 0x15, 0,
8938 AC_VERB_GET_PIN_SENSE, 0);
8939 spec->jack_present = !!(presence & AC_PINSENSE_PRESENCE);
8940 alc262_hp_master_update(codec);
8941}
8942
8943static void alc262_hp_wildwest_unsol_event(struct hda_codec *codec,
8944 unsigned int res)
8945{
8946 if ((res >> 26) != ALC880_HP_EVENT)
8947 return;
8948 alc262_hp_wildwest_automute(codec);
8949}
8950
8951static int alc262_hp_master_sw_get(struct snd_kcontrol *kcontrol,
8952 struct snd_ctl_elem_value *ucontrol)
8953{
8954 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
8955 struct alc_spec *spec = codec->spec;
8956 *ucontrol->value.integer.value = spec->master_sw;
8957 return 0;
8958}
8959
8960static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol,
8961 struct snd_ctl_elem_value *ucontrol)
8962{
8963 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
8964 struct alc_spec *spec = codec->spec;
8965 int val = !!*ucontrol->value.integer.value;
8966
8967 if (val == spec->master_sw)
8968 return 0;
8969 spec->master_sw = val;
8970 alc262_hp_master_update(codec);
8971 return 1;
8972}
8973
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008974static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
Takashi Iwaice875f02008-01-28 18:17:43 +01008975 {
8976 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8977 .name = "Master Playback Switch",
8978 .info = snd_ctl_boolean_mono_info,
8979 .get = alc262_hp_master_sw_get,
8980 .put = alc262_hp_master_sw_put,
8981 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008982 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8983 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8984 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +01008985 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
8986 HDA_OUTPUT),
8987 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
8988 HDA_OUTPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008989 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8990 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008991 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008992 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
8993 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008994 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008995 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8996 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8997 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8998 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8999 HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
9000 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT),
9001 HDA_CODEC_VOLUME("AUX IN Playback Volume", 0x0b, 0x06, HDA_INPUT),
9002 HDA_CODEC_MUTE("AUX IN Playback Switch", 0x0b, 0x06, HDA_INPUT),
9003 { } /* end */
9004};
9005
Kailang Yangcd7509a2007-01-26 18:33:17 +01009006static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = {
Takashi Iwaice875f02008-01-28 18:17:43 +01009007 {
9008 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9009 .name = "Master Playback Switch",
9010 .info = snd_ctl_boolean_mono_info,
9011 .get = alc262_hp_master_sw_get,
9012 .put = alc262_hp_master_sw_put,
9013 },
Kailang Yangcd7509a2007-01-26 18:33:17 +01009014 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9015 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
9016 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
9017 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +01009018 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
9019 HDA_OUTPUT),
9020 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
9021 HDA_OUTPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +01009022 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT),
9023 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01009024 HDA_CODEC_VOLUME("Front Mic Boost", 0x1a, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +01009025 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
9026 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
9027 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9028 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9029 HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
9030 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT),
9031 { } /* end */
9032};
9033
9034static struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = {
9035 HDA_CODEC_VOLUME("Rear Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9036 HDA_CODEC_MUTE("Rear Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01009037 HDA_CODEC_VOLUME("Rear Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +01009038 { } /* end */
9039};
9040
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009041/* mute/unmute internal speaker according to the hp jack and mute state */
9042static void alc262_hp_t5735_automute(struct hda_codec *codec, int force)
9043{
9044 struct alc_spec *spec = codec->spec;
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009045
9046 if (force || !spec->sense_updated) {
9047 unsigned int present;
9048 present = snd_hda_codec_read(codec, 0x15, 0,
9049 AC_VERB_GET_PIN_SENSE, 0);
Takashi Iwai4bb26132008-01-28 18:12:42 +01009050 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009051 spec->sense_updated = 1;
9052 }
Takashi Iwai4bb26132008-01-28 18:12:42 +01009053 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0, HDA_AMP_MUTE,
9054 spec->jack_present ? HDA_AMP_MUTE : 0);
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009055}
9056
9057static void alc262_hp_t5735_unsol_event(struct hda_codec *codec,
9058 unsigned int res)
9059{
9060 if ((res >> 26) != ALC880_HP_EVENT)
9061 return;
9062 alc262_hp_t5735_automute(codec, 1);
9063}
9064
9065static void alc262_hp_t5735_init_hook(struct hda_codec *codec)
9066{
9067 alc262_hp_t5735_automute(codec, 1);
9068}
9069
9070static struct snd_kcontrol_new alc262_hp_t5735_mixer[] = {
Takashi Iwai86cd9292008-01-28 18:09:56 +01009071 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9072 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009073 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
9074 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9075 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9076 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9077 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9078 { } /* end */
9079};
9080
9081static struct hda_verb alc262_hp_t5735_verbs[] = {
9082 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9083 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9084
9085 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9086 { }
9087};
9088
Kailang Yang8c427222008-01-10 13:03:59 +01009089static struct snd_kcontrol_new alc262_hp_rp5700_mixer[] = {
Takashi Iwaif2f48e12008-01-28 18:14:43 +01009090 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9091 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01009092 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
9093 HDA_CODEC_MUTE("Speaker Playback Switch", 0x16, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +01009094 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
9095 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
9096 { } /* end */
9097};
9098
9099static struct hda_verb alc262_hp_rp5700_verbs[] = {
9100 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9101 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9102 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9103 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9104 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
9105 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
9106 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
9107 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
9108 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
9109 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
9110 {}
9111};
9112
9113static struct hda_input_mux alc262_hp_rp5700_capture_source = {
9114 .num_items = 1,
9115 .items = {
9116 { "Line", 0x1 },
9117 },
9118};
9119
Takashi Iwai0724ea22007-08-23 00:31:43 +02009120/* bind hp and internal speaker mute (with plug check) */
9121static int alc262_sony_master_sw_put(struct snd_kcontrol *kcontrol,
9122 struct snd_ctl_elem_value *ucontrol)
9123{
9124 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
9125 long *valp = ucontrol->value.integer.value;
9126 int change;
9127
9128 /* change hp mute */
9129 change = snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0,
9130 HDA_AMP_MUTE,
9131 valp[0] ? 0 : HDA_AMP_MUTE);
9132 change |= snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0,
9133 HDA_AMP_MUTE,
9134 valp[1] ? 0 : HDA_AMP_MUTE);
9135 if (change) {
9136 /* change speaker according to HP jack state */
9137 struct alc_spec *spec = codec->spec;
9138 unsigned int mute;
9139 if (spec->jack_present)
9140 mute = HDA_AMP_MUTE;
9141 else
9142 mute = snd_hda_codec_amp_read(codec, 0x15, 0,
9143 HDA_OUTPUT, 0);
9144 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9145 HDA_AMP_MUTE, mute);
9146 }
9147 return change;
9148}
Takashi Iwai5b319542007-07-26 11:49:22 +02009149
Kailang Yang272a5272007-05-14 11:00:38 +02009150static struct snd_kcontrol_new alc262_sony_mixer[] = {
Takashi Iwai0724ea22007-08-23 00:31:43 +02009151 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9152 {
9153 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9154 .name = "Master Playback Switch",
9155 .info = snd_hda_mixer_amp_switch_info,
9156 .get = snd_hda_mixer_amp_switch_get,
9157 .put = alc262_sony_master_sw_put,
9158 .private_value = HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
9159 },
Kailang Yang272a5272007-05-14 11:00:38 +02009160 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9161 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9162 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
9163 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
9164 { } /* end */
9165};
9166
Kailang Yang83c34212007-07-05 11:43:05 +02009167static struct snd_kcontrol_new alc262_benq_t31_mixer[] = {
9168 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9169 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9170 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9171 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9172 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9173 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
9174 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
9175 { } /* end */
9176};
Kailang Yang272a5272007-05-14 11:00:38 +02009177
Kailang Yangdf694da2005-12-05 19:42:22 +01009178#define alc262_capture_mixer alc882_capture_mixer
9179#define alc262_capture_alt_mixer alc882_capture_alt_mixer
9180
9181/*
9182 * generic initialization of ADC, input mixers and output mixers
9183 */
9184static struct hda_verb alc262_init_verbs[] = {
9185 /*
9186 * Unmute ADC0-2 and set the default input to mic-in
9187 */
9188 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
9189 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9190 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
9191 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9192 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
9193 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9194
Takashi Iwaicb53c622007-08-10 17:21:45 +02009195 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +01009196 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009197 * Note: PASD motherboards uses the Line In 2 as the input for
9198 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01009199 */
9200 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02009201 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9202 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
9203 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
9204 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
9205 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01009206
9207 /*
9208 * Set up output mixers (0x0c - 0x0e)
9209 */
9210 /* set vol=0 to output mixers */
9211 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9212 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9213 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9214 /* set up input amps for analog loopback */
9215 /* Amp Indices: DAC = 0, mixer = 1 */
9216 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9217 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9218 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9219 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9220 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9221 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9222
9223 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
9224 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
9225 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
9226 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9227 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9228 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9229
9230 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
9231 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
9232 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
9233 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
9234 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Kailang Yangea1fb292008-08-26 12:58:38 +02009235
Kailang Yangdf694da2005-12-05 19:42:22 +01009236 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
9237 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Kailang Yangea1fb292008-08-26 12:58:38 +02009238
Kailang Yangdf694da2005-12-05 19:42:22 +01009239 /* FIXME: use matrix-type input source selection */
9240 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
9241 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
9242 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9243 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
9244 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
9245 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
9246 /* Input mixer2 */
9247 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9248 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
9249 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
9250 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
9251 /* Input mixer3 */
9252 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9253 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
9254 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009255 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
Kailang Yangdf694da2005-12-05 19:42:22 +01009256
9257 { }
9258};
9259
Kailang Yang4e555fe2008-08-26 13:05:55 +02009260static struct hda_verb alc262_eapd_verbs[] = {
9261 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
9262 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
9263 { }
9264};
9265
Kailang Yangccc656c2006-10-17 12:32:26 +02009266static struct hda_verb alc262_hippo_unsol_verbs[] = {
9267 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
9268 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9269 {}
9270};
9271
9272static struct hda_verb alc262_hippo1_unsol_verbs[] = {
9273 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
9274 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
9275 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
9276
9277 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
9278 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9279 {}
9280};
9281
Kailang Yang272a5272007-05-14 11:00:38 +02009282static struct hda_verb alc262_sony_unsol_verbs[] = {
9283 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
9284 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9285 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, // Front Mic
9286
9287 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
9288 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Akio Idehara7b1e8792008-06-09 22:46:07 +09009289 {}
Kailang Yang272a5272007-05-14 11:00:38 +02009290};
9291
Kailang Yang4e555fe2008-08-26 13:05:55 +02009292static struct hda_input_mux alc262_dmic_capture_source = {
9293 .num_items = 2,
9294 .items = {
9295 { "Int DMic", 0x9 },
9296 { "Mic", 0x0 },
9297 },
9298};
9299
9300static struct snd_kcontrol_new alc262_toshiba_s06_mixer[] = {
9301 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9302 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9303 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9304 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9305 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9306 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
9307 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
9308 {
9309 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9310 /* The multiple "Capture Source" controls confuse alsamixer
9311 * So call somewhat different..
9312 */
9313 /* .name = "Capture Source", */
9314 .name = "Input Source",
9315 .count = 1,
9316 .info = alc_mux_enum_info,
9317 .get = alc_mux_enum_get,
9318 .put = alc_mux_enum_put,
9319 },
9320 { } /* end */
9321};
9322
9323static struct hda_verb alc262_toshiba_s06_verbs[] = {
9324 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
9325 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9326 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9327 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9328 {0x22, AC_VERB_SET_CONNECT_SEL, 0x09},
9329 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9330 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
9331 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
9332 {}
9333};
9334
9335static void alc262_dmic_automute(struct hda_codec *codec)
9336{
9337 unsigned int present;
9338
9339 present = snd_hda_codec_read(codec, 0x18, 0,
9340 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
9341 snd_hda_codec_write(codec, 0x22, 0,
9342 AC_VERB_SET_CONNECT_SEL, present ? 0x0 : 0x09);
9343}
9344
9345/* toggle speaker-output according to the hp-jack state */
9346static void alc262_toshiba_s06_speaker_automute(struct hda_codec *codec)
9347{
9348 unsigned int present;
9349 unsigned char bits;
9350
9351 present = snd_hda_codec_read(codec, 0x15, 0,
9352 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
9353 bits = present ? 0 : PIN_OUT;
9354 snd_hda_codec_write(codec, 0x14, 0,
9355 AC_VERB_SET_PIN_WIDGET_CONTROL, bits);
9356}
9357
9358
9359
9360/* unsolicited event for HP jack sensing */
9361static void alc262_toshiba_s06_unsol_event(struct hda_codec *codec,
9362 unsigned int res)
9363{
9364 if ((res >> 26) == ALC880_HP_EVENT)
9365 alc262_toshiba_s06_speaker_automute(codec);
9366 if ((res >> 26) == ALC880_MIC_EVENT)
9367 alc262_dmic_automute(codec);
9368
9369}
9370
9371static void alc262_toshiba_s06_init_hook(struct hda_codec *codec)
9372{
9373 alc262_toshiba_s06_speaker_automute(codec);
9374 alc262_dmic_automute(codec);
9375}
9376
Kailang Yangccc656c2006-10-17 12:32:26 +02009377/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwai5b319542007-07-26 11:49:22 +02009378static void alc262_hippo_automute(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02009379{
9380 struct alc_spec *spec = codec->spec;
9381 unsigned int mute;
Takashi Iwai5b319542007-07-26 11:49:22 +02009382 unsigned int present;
Kailang Yangccc656c2006-10-17 12:32:26 +02009383
Takashi Iwai5b319542007-07-26 11:49:22 +02009384 /* need to execute and sync at first */
9385 snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0);
9386 present = snd_hda_codec_read(codec, 0x15, 0,
9387 AC_VERB_GET_PIN_SENSE, 0);
9388 spec->jack_present = (present & 0x80000000) != 0;
Kailang Yangccc656c2006-10-17 12:32:26 +02009389 if (spec->jack_present) {
9390 /* mute internal speaker */
Takashi Iwai47fd8302007-08-10 17:11:07 +02009391 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9392 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yangccc656c2006-10-17 12:32:26 +02009393 } else {
9394 /* unmute internal speaker if necessary */
9395 mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0);
Takashi Iwai47fd8302007-08-10 17:11:07 +02009396 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9397 HDA_AMP_MUTE, mute);
Kailang Yangccc656c2006-10-17 12:32:26 +02009398 }
9399}
9400
9401/* unsolicited event for HP jack sensing */
9402static void alc262_hippo_unsol_event(struct hda_codec *codec,
9403 unsigned int res)
9404{
9405 if ((res >> 26) != ALC880_HP_EVENT)
9406 return;
Takashi Iwai5b319542007-07-26 11:49:22 +02009407 alc262_hippo_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02009408}
9409
Takashi Iwai5b319542007-07-26 11:49:22 +02009410static void alc262_hippo1_automute(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02009411{
Kailang Yangccc656c2006-10-17 12:32:26 +02009412 unsigned int mute;
Takashi Iwai5b319542007-07-26 11:49:22 +02009413 unsigned int present;
Kailang Yangccc656c2006-10-17 12:32:26 +02009414
Takashi Iwai5b319542007-07-26 11:49:22 +02009415 snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
9416 present = snd_hda_codec_read(codec, 0x1b, 0,
9417 AC_VERB_GET_PIN_SENSE, 0);
9418 present = (present & 0x80000000) != 0;
9419 if (present) {
Kailang Yangccc656c2006-10-17 12:32:26 +02009420 /* mute internal speaker */
Takashi Iwai47fd8302007-08-10 17:11:07 +02009421 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9422 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yangccc656c2006-10-17 12:32:26 +02009423 } else {
9424 /* unmute internal speaker if necessary */
9425 mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
Takashi Iwai47fd8302007-08-10 17:11:07 +02009426 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9427 HDA_AMP_MUTE, mute);
Kailang Yangccc656c2006-10-17 12:32:26 +02009428 }
9429}
9430
9431/* unsolicited event for HP jack sensing */
9432static void alc262_hippo1_unsol_event(struct hda_codec *codec,
9433 unsigned int res)
9434{
9435 if ((res >> 26) != ALC880_HP_EVENT)
9436 return;
Takashi Iwai5b319542007-07-26 11:49:22 +02009437 alc262_hippo1_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02009438}
9439
Takashi Iwai834be882006-03-01 14:16:17 +01009440/*
Pascal Terjane8f9ae22008-08-04 14:36:05 +02009441 * nec model
9442 * 0x15 = headphone
9443 * 0x16 = internal speaker
9444 * 0x18 = external mic
9445 */
9446
9447static struct snd_kcontrol_new alc262_nec_mixer[] = {
9448 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
9449 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 0, 0x0, HDA_OUTPUT),
9450
9451 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9452 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9453 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9454
9455 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
9456 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9457 { } /* end */
9458};
9459
9460static struct hda_verb alc262_nec_verbs[] = {
9461 /* Unmute Speaker */
9462 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9463
9464 /* Headphone */
9465 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
9466 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9467
9468 /* External mic to headphone */
9469 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9470 /* External mic to speaker */
9471 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9472 {}
9473};
9474
9475/*
Takashi Iwai834be882006-03-01 14:16:17 +01009476 * fujitsu model
Tony Vroon5d9fab22008-03-14 17:09:18 +01009477 * 0x14 = headphone/spdif-out, 0x15 = internal speaker,
9478 * 0x1b = port replicator headphone out
Takashi Iwai834be882006-03-01 14:16:17 +01009479 */
9480
9481#define ALC_HP_EVENT 0x37
9482
9483static struct hda_verb alc262_fujitsu_unsol_verbs[] = {
9484 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
9485 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Tony Vroon5d9fab22008-03-14 17:09:18 +01009486 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
9487 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai834be882006-03-01 14:16:17 +01009488 {}
9489};
9490
Jiang zhe0e31daf2008-03-20 12:12:39 +01009491static struct hda_verb alc262_lenovo_3000_unsol_verbs[] = {
9492 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
9493 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9494 {}
9495};
9496
Takashi Iwai834be882006-03-01 14:16:17 +01009497static struct hda_input_mux alc262_fujitsu_capture_source = {
Takashi Iwai39d3ed32007-10-12 15:03:48 +02009498 .num_items = 3,
Takashi Iwai834be882006-03-01 14:16:17 +01009499 .items = {
9500 { "Mic", 0x0 },
Takashi Iwai39d3ed32007-10-12 15:03:48 +02009501 { "Int Mic", 0x1 },
Takashi Iwai834be882006-03-01 14:16:17 +01009502 { "CD", 0x4 },
9503 },
9504};
9505
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009506static struct hda_input_mux alc262_HP_capture_source = {
9507 .num_items = 5,
9508 .items = {
9509 { "Mic", 0x0 },
zhejiangaccbe492007-08-31 12:36:05 +02009510 { "Front Mic", 0x1 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009511 { "Line", 0x2 },
9512 { "CD", 0x4 },
9513 { "AUX IN", 0x6 },
9514 },
9515};
9516
zhejiangaccbe492007-08-31 12:36:05 +02009517static struct hda_input_mux alc262_HP_D7000_capture_source = {
9518 .num_items = 4,
9519 .items = {
9520 { "Mic", 0x0 },
9521 { "Front Mic", 0x2 },
9522 { "Line", 0x1 },
9523 { "CD", 0x4 },
9524 },
9525};
9526
Takashi Iwaiebc7a402008-05-20 09:23:05 +02009527/* mute/unmute internal speaker according to the hp jacks and mute state */
Takashi Iwai834be882006-03-01 14:16:17 +01009528static void alc262_fujitsu_automute(struct hda_codec *codec, int force)
9529{
9530 struct alc_spec *spec = codec->spec;
9531 unsigned int mute;
9532
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009533 if (force || !spec->sense_updated) {
Takashi Iwaiebc7a402008-05-20 09:23:05 +02009534 unsigned int present;
Takashi Iwai834be882006-03-01 14:16:17 +01009535 /* need to execute and sync at first */
9536 snd_hda_codec_read(codec, 0x14, 0, AC_VERB_SET_PIN_SENSE, 0);
Takashi Iwaiebc7a402008-05-20 09:23:05 +02009537 /* check laptop HP jack */
9538 present = snd_hda_codec_read(codec, 0x14, 0,
9539 AC_VERB_GET_PIN_SENSE, 0);
9540 /* need to execute and sync at first */
9541 snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
9542 /* check docking HP jack */
9543 present |= snd_hda_codec_read(codec, 0x1b, 0,
9544 AC_VERB_GET_PIN_SENSE, 0);
9545 if (present & AC_PINSENSE_PRESENCE)
9546 spec->jack_present = 1;
9547 else
9548 spec->jack_present = 0;
Takashi Iwai834be882006-03-01 14:16:17 +01009549 spec->sense_updated = 1;
9550 }
Takashi Iwaiebc7a402008-05-20 09:23:05 +02009551 /* unmute internal speaker only if both HPs are unplugged and
9552 * master switch is on
9553 */
9554 if (spec->jack_present)
9555 mute = HDA_AMP_MUTE;
9556 else
Takashi Iwai834be882006-03-01 14:16:17 +01009557 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
Takashi Iwaiebc7a402008-05-20 09:23:05 +02009558 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9559 HDA_AMP_MUTE, mute);
Takashi Iwai834be882006-03-01 14:16:17 +01009560}
9561
9562/* unsolicited event for HP jack sensing */
9563static void alc262_fujitsu_unsol_event(struct hda_codec *codec,
9564 unsigned int res)
9565{
9566 if ((res >> 26) != ALC_HP_EVENT)
9567 return;
9568 alc262_fujitsu_automute(codec, 1);
9569}
9570
Takashi Iwaiebc7a402008-05-20 09:23:05 +02009571static void alc262_fujitsu_init_hook(struct hda_codec *codec)
9572{
9573 alc262_fujitsu_automute(codec, 1);
9574}
9575
Takashi Iwai834be882006-03-01 14:16:17 +01009576/* bind volumes of both NID 0x0c and 0x0d */
Takashi Iwaicca3b372007-08-10 17:12:15 +02009577static struct hda_bind_ctls alc262_fujitsu_bind_master_vol = {
9578 .ops = &snd_hda_bind_vol,
9579 .values = {
9580 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT),
9581 HDA_COMPOSE_AMP_VAL(0x0d, 3, 0, HDA_OUTPUT),
9582 0
9583 },
9584};
Takashi Iwai834be882006-03-01 14:16:17 +01009585
Jiang zhe0e31daf2008-03-20 12:12:39 +01009586/* mute/unmute internal speaker according to the hp jack and mute state */
9587static void alc262_lenovo_3000_automute(struct hda_codec *codec, int force)
9588{
9589 struct alc_spec *spec = codec->spec;
9590 unsigned int mute;
9591
9592 if (force || !spec->sense_updated) {
9593 unsigned int present_int_hp;
9594 /* need to execute and sync at first */
9595 snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
9596 present_int_hp = snd_hda_codec_read(codec, 0x1b, 0,
9597 AC_VERB_GET_PIN_SENSE, 0);
9598 spec->jack_present = (present_int_hp & 0x80000000) != 0;
9599 spec->sense_updated = 1;
9600 }
9601 if (spec->jack_present) {
9602 /* mute internal speaker */
9603 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9604 HDA_AMP_MUTE, HDA_AMP_MUTE);
9605 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
9606 HDA_AMP_MUTE, HDA_AMP_MUTE);
9607 } else {
9608 /* unmute internal speaker if necessary */
9609 mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
9610 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9611 HDA_AMP_MUTE, mute);
9612 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
9613 HDA_AMP_MUTE, mute);
9614 }
9615}
9616
9617/* unsolicited event for HP jack sensing */
9618static void alc262_lenovo_3000_unsol_event(struct hda_codec *codec,
9619 unsigned int res)
9620{
9621 if ((res >> 26) != ALC_HP_EVENT)
9622 return;
9623 alc262_lenovo_3000_automute(codec, 1);
9624}
9625
Takashi Iwai834be882006-03-01 14:16:17 +01009626/* bind hp and internal speaker mute (with plug check) */
9627static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol,
9628 struct snd_ctl_elem_value *ucontrol)
9629{
9630 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
9631 long *valp = ucontrol->value.integer.value;
9632 int change;
9633
Tony Vroon5d9fab22008-03-14 17:09:18 +01009634 change = snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9635 HDA_AMP_MUTE,
9636 valp ? 0 : HDA_AMP_MUTE);
9637 change |= snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
9638 HDA_AMP_MUTE,
9639 valp ? 0 : HDA_AMP_MUTE);
9640
Takashi Iwai82beb8f2007-08-10 17:09:26 +02009641 if (change)
9642 alc262_fujitsu_automute(codec, 0);
Takashi Iwai834be882006-03-01 14:16:17 +01009643 return change;
9644}
9645
9646static struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02009647 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
Takashi Iwai834be882006-03-01 14:16:17 +01009648 {
9649 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9650 .name = "Master Playback Switch",
9651 .info = snd_hda_mixer_amp_switch_info,
9652 .get = snd_hda_mixer_amp_switch_get,
9653 .put = alc262_fujitsu_master_sw_put,
9654 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
9655 },
9656 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9657 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Tony Vroon06a9c302008-04-14 13:31:45 +02009658 HDA_CODEC_VOLUME("PC Speaker Volume", 0x0b, 0x05, HDA_INPUT),
9659 HDA_CODEC_MUTE("PC Speaker Switch", 0x0b, 0x05, HDA_INPUT),
Takashi Iwai834be882006-03-01 14:16:17 +01009660 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9661 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9662 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai39d3ed32007-10-12 15:03:48 +02009663 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
9664 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
9665 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai834be882006-03-01 14:16:17 +01009666 { } /* end */
9667};
9668
Jiang zhe0e31daf2008-03-20 12:12:39 +01009669/* bind hp and internal speaker mute (with plug check) */
9670static int alc262_lenovo_3000_master_sw_put(struct snd_kcontrol *kcontrol,
9671 struct snd_ctl_elem_value *ucontrol)
9672{
9673 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
9674 long *valp = ucontrol->value.integer.value;
9675 int change;
9676
9677 change = snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
9678 HDA_AMP_MUTE,
9679 valp ? 0 : HDA_AMP_MUTE);
9680
9681 if (change)
9682 alc262_lenovo_3000_automute(codec, 0);
9683 return change;
9684}
9685
9686static struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = {
9687 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
9688 {
9689 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9690 .name = "Master Playback Switch",
9691 .info = snd_hda_mixer_amp_switch_info,
9692 .get = snd_hda_mixer_amp_switch_get,
9693 .put = alc262_lenovo_3000_master_sw_put,
9694 .private_value = HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
9695 },
9696 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9697 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9698 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9699 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9700 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9701 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
9702 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
9703 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
9704 { } /* end */
9705};
9706
Takashi Iwai304dcaa2006-07-25 14:51:16 +02009707/* additional init verbs for Benq laptops */
9708static struct hda_verb alc262_EAPD_verbs[] = {
9709 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
9710 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
9711 {}
9712};
9713
Kailang Yang83c34212007-07-05 11:43:05 +02009714static struct hda_verb alc262_benq_t31_EAPD_verbs[] = {
9715 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9716 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9717
9718 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
9719 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
9720 {}
9721};
9722
Tobin Davisf651b502007-10-26 12:40:47 +02009723/* Samsung Q1 Ultra Vista model setup */
9724static struct snd_kcontrol_new alc262_ultra_mixer[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01009725 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9726 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +02009727 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
9728 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
9729 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01009730 HDA_CODEC_VOLUME("Headphone Mic Boost", 0x15, 0, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +02009731 { } /* end */
9732};
9733
9734static struct hda_verb alc262_ultra_verbs[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01009735 /* output mixer */
9736 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9737 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
9738 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9739 /* speaker */
9740 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9741 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9742 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9743 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
9744 /* HP */
Tobin Davisf651b502007-10-26 12:40:47 +02009745 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01009746 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9747 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9748 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9749 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
9750 /* internal mic */
9751 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
9752 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
9753 /* ADC, choose mic */
9754 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9755 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9756 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9757 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
9758 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
9759 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
9760 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
9761 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
9762 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
9763 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(8)},
Tobin Davisf651b502007-10-26 12:40:47 +02009764 {}
9765};
9766
Tobin Davisf651b502007-10-26 12:40:47 +02009767/* mute/unmute internal speaker according to the hp jack and mute state */
9768static void alc262_ultra_automute(struct hda_codec *codec)
9769{
9770 struct alc_spec *spec = codec->spec;
9771 unsigned int mute;
Tobin Davisf651b502007-10-26 12:40:47 +02009772
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01009773 mute = 0;
9774 /* auto-mute only when HP is used as HP */
9775 if (!spec->cur_mux[0]) {
9776 unsigned int present;
9777 /* need to execute and sync at first */
9778 snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0);
9779 present = snd_hda_codec_read(codec, 0x15, 0,
9780 AC_VERB_GET_PIN_SENSE, 0);
9781 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
9782 if (spec->jack_present)
9783 mute = HDA_AMP_MUTE;
Tobin Davisf651b502007-10-26 12:40:47 +02009784 }
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01009785 /* mute/unmute internal speaker */
9786 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9787 HDA_AMP_MUTE, mute);
9788 /* mute/unmute HP */
9789 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9790 HDA_AMP_MUTE, mute ? 0 : HDA_AMP_MUTE);
Tobin Davisf651b502007-10-26 12:40:47 +02009791}
9792
9793/* unsolicited event for HP jack sensing */
9794static void alc262_ultra_unsol_event(struct hda_codec *codec,
9795 unsigned int res)
9796{
9797 if ((res >> 26) != ALC880_HP_EVENT)
9798 return;
9799 alc262_ultra_automute(codec);
9800}
9801
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01009802static struct hda_input_mux alc262_ultra_capture_source = {
9803 .num_items = 2,
9804 .items = {
9805 { "Mic", 0x1 },
9806 { "Headphone", 0x7 },
9807 },
9808};
9809
9810static int alc262_ultra_mux_enum_put(struct snd_kcontrol *kcontrol,
9811 struct snd_ctl_elem_value *ucontrol)
9812{
9813 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
9814 struct alc_spec *spec = codec->spec;
9815 int ret;
9816
9817 ret = alc882_mux_enum_put(kcontrol, ucontrol);
9818 if (!ret)
9819 return 0;
9820 /* reprogram the HP pin as mic or HP according to the input source */
9821 snd_hda_codec_write_cache(codec, 0x15, 0,
9822 AC_VERB_SET_PIN_WIDGET_CONTROL,
9823 spec->cur_mux[0] ? PIN_VREF80 : PIN_HP);
9824 alc262_ultra_automute(codec); /* mute/unmute HP */
9825 return ret;
9826}
9827
9828static struct snd_kcontrol_new alc262_ultra_capture_mixer[] = {
9829 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
9830 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
9831 {
9832 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9833 .name = "Capture Source",
9834 .info = alc882_mux_enum_info,
9835 .get = alc882_mux_enum_get,
9836 .put = alc262_ultra_mux_enum_put,
9837 },
9838 { } /* end */
9839};
9840
Kailang Yangdf694da2005-12-05 19:42:22 +01009841/* add playback controls from the parsed DAC table */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009842static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
9843 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +01009844{
9845 hda_nid_t nid;
9846 int err;
9847
9848 spec->multiout.num_dacs = 1; /* only use one dac */
9849 spec->multiout.dac_nids = spec->private_dac_nids;
9850 spec->multiout.dac_nids[0] = 2;
9851
9852 nid = cfg->line_out_pins[0];
9853 if (nid) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009854 err = add_control(spec, ALC_CTL_WIDGET_VOL,
9855 "Front Playback Volume",
9856 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT));
9857 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009858 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009859 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
9860 "Front Playback Switch",
9861 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
9862 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009863 return err;
9864 }
9865
Takashi Iwai82bc9552006-03-21 11:24:42 +01009866 nid = cfg->speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01009867 if (nid) {
9868 if (nid == 0x16) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009869 err = add_control(spec, ALC_CTL_WIDGET_VOL,
9870 "Speaker Playback Volume",
9871 HDA_COMPOSE_AMP_VAL(0x0e, 2, 0,
9872 HDA_OUTPUT));
9873 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009874 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009875 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
9876 "Speaker Playback Switch",
9877 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
9878 HDA_OUTPUT));
9879 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009880 return err;
9881 } else {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009882 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
9883 "Speaker Playback Switch",
9884 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
9885 HDA_OUTPUT));
9886 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009887 return err;
9888 }
9889 }
Takashi Iwaieb06ed82006-09-20 17:10:27 +02009890 nid = cfg->hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01009891 if (nid) {
9892 /* spec->multiout.hp_nid = 2; */
9893 if (nid == 0x16) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009894 err = add_control(spec, ALC_CTL_WIDGET_VOL,
9895 "Headphone Playback Volume",
9896 HDA_COMPOSE_AMP_VAL(0x0e, 2, 0,
9897 HDA_OUTPUT));
9898 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009899 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009900 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
9901 "Headphone Playback Switch",
9902 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
9903 HDA_OUTPUT));
9904 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009905 return err;
9906 } else {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009907 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
9908 "Headphone Playback Switch",
9909 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
9910 HDA_OUTPUT));
9911 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009912 return err;
9913 }
9914 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009915 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01009916}
9917
9918/* identical with ALC880 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009919#define alc262_auto_create_analog_input_ctls \
9920 alc880_auto_create_analog_input_ctls
Kailang Yangdf694da2005-12-05 19:42:22 +01009921
9922/*
9923 * generic initialization of ADC, input mixers and output mixers
9924 */
9925static struct hda_verb alc262_volume_init_verbs[] = {
9926 /*
9927 * Unmute ADC0-2 and set the default input to mic-in
9928 */
9929 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
9930 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9931 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
9932 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9933 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
9934 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9935
Takashi Iwaicb53c622007-08-10 17:21:45 +02009936 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +01009937 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009938 * Note: PASD motherboards uses the Line In 2 as the input for
9939 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01009940 */
9941 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02009942 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9943 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
9944 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
9945 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
9946 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01009947
9948 /*
9949 * Set up output mixers (0x0c - 0x0f)
9950 */
9951 /* set vol=0 to output mixers */
9952 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9953 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9954 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yangea1fb292008-08-26 12:58:38 +02009955
Kailang Yangdf694da2005-12-05 19:42:22 +01009956 /* set up input amps for analog loopback */
9957 /* Amp Indices: DAC = 0, mixer = 1 */
9958 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9959 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9960 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9961 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9962 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9963 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9964
9965 /* FIXME: use matrix-type input source selection */
9966 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
9967 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
9968 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9969 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
9970 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
9971 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
9972 /* Input mixer2 */
9973 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9974 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
9975 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
9976 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
9977 /* Input mixer3 */
9978 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9979 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
9980 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
9981 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
9982
9983 { }
9984};
9985
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009986static struct hda_verb alc262_HP_BPC_init_verbs[] = {
9987 /*
9988 * Unmute ADC0-2 and set the default input to mic-in
9989 */
9990 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
9991 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9992 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
9993 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9994 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
9995 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9996
Takashi Iwaicb53c622007-08-10 17:21:45 +02009997 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009998 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009999 * Note: PASD motherboards uses the Line In 2 as the input for
10000 * front panel mic (mic 2)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010001 */
10002 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020010003 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
10004 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10005 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
10006 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
10007 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
10008 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
10009 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
Kailang Yangea1fb292008-08-26 12:58:38 +020010010
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010011 /*
10012 * Set up output mixers (0x0c - 0x0e)
10013 */
10014 /* set vol=0 to output mixers */
10015 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10016 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10017 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10018
10019 /* set up input amps for analog loopback */
10020 /* Amp Indices: DAC = 0, mixer = 1 */
10021 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10022 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10023 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10024 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10025 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10026 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10027
Takashi Iwaice875f02008-01-28 18:17:43 +010010028 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010029 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
10030 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
10031
10032 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
10033 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
10034
10035 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
10036 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
10037
10038 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10039 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
10040 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
10041 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10042 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10043
10044 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
10045 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10046 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10047 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
10048 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10049 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10050
10051
10052 /* FIXME: use matrix-type input source selection */
10053 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
10054 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
10055 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10056 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
10057 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
10058 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
10059 /* Input mixer2 */
10060 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10061 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
10062 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
10063 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
10064 /* Input mixer3 */
10065 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10066 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
10067 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
10068 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
10069
Takashi Iwaice875f02008-01-28 18:17:43 +010010070 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
10071
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010072 { }
10073};
10074
Kailang Yangcd7509a2007-01-26 18:33:17 +010010075static struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = {
10076 /*
10077 * Unmute ADC0-2 and set the default input to mic-in
10078 */
10079 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
10080 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10081 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
10082 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10083 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
10084 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10085
Takashi Iwaicb53c622007-08-10 17:21:45 +020010086 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangcd7509a2007-01-26 18:33:17 +010010087 * mixer widget
10088 * Note: PASD motherboards uses the Line In 2 as the input for front
10089 * panel mic (mic 2)
10090 */
10091 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020010092 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
10093 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10094 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
10095 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
10096 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
10097 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
10098 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
10099 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Kailang Yangcd7509a2007-01-26 18:33:17 +010010100 /*
10101 * Set up output mixers (0x0c - 0x0e)
10102 */
10103 /* set vol=0 to output mixers */
10104 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10105 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10106 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10107
10108 /* set up input amps for analog loopback */
10109 /* Amp Indices: DAC = 0, mixer = 1 */
10110 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10111 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10112 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10113 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10114 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10115 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10116
10117
10118 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP */
10119 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Mono */
10120 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* rear MIC */
10121 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* Line in */
10122 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
10123 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Line out */
10124 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD in */
10125
10126 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
10127 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
10128
10129 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
10130 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
10131
10132 /* {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, */
10133 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10134 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10135 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
10136 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10137 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10138
10139 /* FIXME: use matrix-type input source selection */
10140 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
10141 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
10142 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, /*rear MIC*/
10143 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, /*Line in*/
10144 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, /*F MIC*/
10145 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, /*Front*/
10146 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, /*CD*/
10147 /* {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
10148 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, /*HP*/
10149 /* Input mixer2 */
10150 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10151 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
10152 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
10153 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
10154 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
10155 /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
10156 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
10157 /* Input mixer3 */
10158 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10159 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
10160 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
10161 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
10162 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
10163 /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
10164 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
10165
Takashi Iwaice875f02008-01-28 18:17:43 +010010166 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
10167
Kailang Yangcd7509a2007-01-26 18:33:17 +010010168 { }
10169};
10170
Takashi Iwaicb53c622007-08-10 17:21:45 +020010171#ifdef CONFIG_SND_HDA_POWER_SAVE
10172#define alc262_loopbacks alc880_loopbacks
10173#endif
10174
Kailang Yangdf694da2005-12-05 19:42:22 +010010175/* pcm configuration: identiacal with ALC880 */
10176#define alc262_pcm_analog_playback alc880_pcm_analog_playback
10177#define alc262_pcm_analog_capture alc880_pcm_analog_capture
10178#define alc262_pcm_digital_playback alc880_pcm_digital_playback
10179#define alc262_pcm_digital_capture alc880_pcm_digital_capture
10180
10181/*
10182 * BIOS auto configuration
10183 */
10184static int alc262_parse_auto_config(struct hda_codec *codec)
10185{
10186 struct alc_spec *spec = codec->spec;
10187 int err;
10188 static hda_nid_t alc262_ignore[] = { 0x1d, 0 };
10189
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010190 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
10191 alc262_ignore);
10192 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010193 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010194 if (!spec->autocfg.line_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +010010195 return 0; /* can't find valid BIOS pin config */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010196 err = alc262_auto_create_multi_out_ctls(spec, &spec->autocfg);
10197 if (err < 0)
10198 return err;
10199 err = alc262_auto_create_analog_input_ctls(spec, &spec->autocfg);
10200 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010201 return err;
10202
10203 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
10204
10205 if (spec->autocfg.dig_out_pin)
10206 spec->multiout.dig_out_nid = ALC262_DIGOUT_NID;
10207 if (spec->autocfg.dig_in_pin)
10208 spec->dig_in_nid = ALC262_DIGIN_NID;
10209
10210 if (spec->kctl_alloc)
10211 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
10212
10213 spec->init_verbs[spec->num_init_verbs++] = alc262_volume_init_verbs;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020010214 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +010010215 spec->input_mux = &spec->private_imux;
10216
Takashi Iwai776e1842007-08-29 15:07:11 +020010217 err = alc_auto_add_mic_boost(codec);
10218 if (err < 0)
10219 return err;
10220
Kailang Yangdf694da2005-12-05 19:42:22 +010010221 return 1;
10222}
10223
10224#define alc262_auto_init_multi_out alc882_auto_init_multi_out
10225#define alc262_auto_init_hp_out alc882_auto_init_hp_out
10226#define alc262_auto_init_analog_input alc882_auto_init_analog_input
Takashi Iwaif511b012008-08-15 16:46:42 +020010227#define alc262_auto_init_input_src alc882_auto_init_input_src
Kailang Yangdf694da2005-12-05 19:42:22 +010010228
10229
10230/* init callback for auto-configuration model -- overriding the default init */
Takashi Iwaiae6b8132006-03-03 16:47:17 +010010231static void alc262_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010010232{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010233 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010010234 alc262_auto_init_multi_out(codec);
10235 alc262_auto_init_hp_out(codec);
10236 alc262_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020010237 alc262_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010238 if (spec->unsol_event)
10239 alc_sku_automute(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010010240}
10241
10242/*
10243 * configuration and preset
10244 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010245static const char *alc262_models[ALC262_MODEL_LAST] = {
10246 [ALC262_BASIC] = "basic",
10247 [ALC262_HIPPO] = "hippo",
10248 [ALC262_HIPPO_1] = "hippo_1",
10249 [ALC262_FUJITSU] = "fujitsu",
10250 [ALC262_HP_BPC] = "hp-bpc",
Kailang Yangcd7509a2007-01-26 18:33:17 +010010251 [ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000",
Takashi Iwai61dc35d2007-11-14 12:26:44 +010010252 [ALC262_HP_TC_T5735] = "hp-tc-t5735",
Kailang Yang8c427222008-01-10 13:03:59 +010010253 [ALC262_HP_RP5700] = "hp-rp5700",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010254 [ALC262_BENQ_ED8] = "benq",
Takashi Iwai0f405022007-07-06 12:24:11 +020010255 [ALC262_BENQ_T31] = "benq-t31",
10256 [ALC262_SONY_ASSAMD] = "sony-assamd",
Tobin Davisf651b502007-10-26 12:40:47 +020010257 [ALC262_ULTRA] = "ultra",
Jiang zhe0e31daf2008-03-20 12:12:39 +010010258 [ALC262_LENOVO_3000] = "lenovo-3000",
Pascal Terjane8f9ae22008-08-04 14:36:05 +020010259 [ALC262_NEC] = "nec",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010260 [ALC262_AUTO] = "auto",
10261};
10262
10263static struct snd_pci_quirk alc262_cfg_tbl[] = {
10264 SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO),
Pascal Terjane8f9ae22008-08-04 14:36:05 +020010265 SND_PCI_QUIRK(0x1033, 0x8895, "NEC Versa S9100", ALC262_NEC),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010266 SND_PCI_QUIRK(0x103c, 0x12fe, "HP xw9400", ALC262_HP_BPC),
Kailang Yang7d87de22007-06-05 12:17:21 +020010267 SND_PCI_QUIRK(0x103c, 0x12ff, "HP xw4550", ALC262_HP_BPC),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010268 SND_PCI_QUIRK(0x103c, 0x1306, "HP xw8600", ALC262_HP_BPC),
10269 SND_PCI_QUIRK(0x103c, 0x1307, "HP xw6600", ALC262_HP_BPC),
Kailang Yang7d87de22007-06-05 12:17:21 +020010270 SND_PCI_QUIRK(0x103c, 0x1308, "HP xw4600", ALC262_HP_BPC),
Takashi Iwaib98f9332007-11-07 14:18:01 +010010271 SND_PCI_QUIRK(0x103c, 0x1309, "HP xw4*00", ALC262_HP_BPC),
Takashi Iwaib98f9332007-11-07 14:18:01 +010010272 SND_PCI_QUIRK(0x103c, 0x130a, "HP xw6*00", ALC262_HP_BPC),
Takashi Iwaib98f9332007-11-07 14:18:01 +010010273 SND_PCI_QUIRK(0x103c, 0x130b, "HP xw8*00", ALC262_HP_BPC),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010274 SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010275 SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010276 SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010277 SND_PCI_QUIRK(0x103c, 0x2803, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010278 SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010279 SND_PCI_QUIRK(0x103c, 0x2805, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010280 SND_PCI_QUIRK(0x103c, 0x2806, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010281 SND_PCI_QUIRK(0x103c, 0x2807, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010282 SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC),
10283 SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC),
10284 SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC),
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010285 SND_PCI_QUIRK(0x103c, 0x302f, "HP Thin Client T5735",
10286 ALC262_HP_TC_T5735),
Kailang Yang8c427222008-01-10 13:03:59 +010010287 SND_PCI_QUIRK(0x103c, 0x2817, "HP RP5700", ALC262_HP_RP5700),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010288 SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010289 SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010290 SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD),
10291 SND_PCI_QUIRK(0x104d, 0x900e, "Sony ASSAMD", ALC262_SONY_ASSAMD),
10292 SND_PCI_QUIRK(0x104d, 0x9015, "Sony 0x9015", ALC262_SONY_ASSAMD),
Akio Idehara36ca6e12008-06-09 22:57:40 +090010293 SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1",
10294 ALC262_SONY_ASSAMD),
Kailang Yang4e555fe2008-08-26 13:05:55 +020010295 SND_PCI_QUIRK(0x1179, 0x0268, "Toshiba S06", ALC262_TOSHIBA_S06),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010296 SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU),
Tony Vroon3f1eeae2008-02-25 16:44:13 +010010297 SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010298 SND_PCI_QUIRK(0x144d, 0xc032, "Samsung Q1 Ultra", ALC262_ULTRA),
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010299 SND_PCI_QUIRK(0x144d, 0xc039, "Samsung Q1U EL", ALC262_ULTRA),
Jiang zhe0e31daf2008-03-20 12:12:39 +010010300 SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 y410", ALC262_LENOVO_3000),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010301 SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8),
Kailang Yang83c34212007-07-05 11:43:05 +020010302 SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010303 SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1),
Kailang Yangdf694da2005-12-05 19:42:22 +010010304 {}
10305};
10306
10307static struct alc_config_preset alc262_presets[] = {
10308 [ALC262_BASIC] = {
10309 .mixers = { alc262_base_mixer },
10310 .init_verbs = { alc262_init_verbs },
10311 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10312 .dac_nids = alc262_dac_nids,
10313 .hp_nid = 0x03,
10314 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10315 .channel_mode = alc262_modes,
Takashi Iwaia3bcba32005-12-06 19:05:29 +010010316 .input_mux = &alc262_capture_source,
Kailang Yangdf694da2005-12-05 19:42:22 +010010317 },
Kailang Yangccc656c2006-10-17 12:32:26 +020010318 [ALC262_HIPPO] = {
10319 .mixers = { alc262_base_mixer },
10320 .init_verbs = { alc262_init_verbs, alc262_hippo_unsol_verbs},
10321 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10322 .dac_nids = alc262_dac_nids,
10323 .hp_nid = 0x03,
10324 .dig_out_nid = ALC262_DIGOUT_NID,
10325 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10326 .channel_mode = alc262_modes,
10327 .input_mux = &alc262_capture_source,
10328 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +020010329 .init_hook = alc262_hippo_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020010330 },
10331 [ALC262_HIPPO_1] = {
10332 .mixers = { alc262_hippo1_mixer },
10333 .init_verbs = { alc262_init_verbs, alc262_hippo1_unsol_verbs},
10334 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10335 .dac_nids = alc262_dac_nids,
10336 .hp_nid = 0x02,
10337 .dig_out_nid = ALC262_DIGOUT_NID,
10338 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10339 .channel_mode = alc262_modes,
10340 .input_mux = &alc262_capture_source,
10341 .unsol_event = alc262_hippo1_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +020010342 .init_hook = alc262_hippo1_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020010343 },
Takashi Iwai834be882006-03-01 14:16:17 +010010344 [ALC262_FUJITSU] = {
10345 .mixers = { alc262_fujitsu_mixer },
Takashi Iwai39d3ed32007-10-12 15:03:48 +020010346 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
10347 alc262_fujitsu_unsol_verbs },
Takashi Iwai834be882006-03-01 14:16:17 +010010348 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10349 .dac_nids = alc262_dac_nids,
10350 .hp_nid = 0x03,
10351 .dig_out_nid = ALC262_DIGOUT_NID,
10352 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10353 .channel_mode = alc262_modes,
10354 .input_mux = &alc262_fujitsu_capture_source,
Takashi Iwaiae6b8132006-03-03 16:47:17 +010010355 .unsol_event = alc262_fujitsu_unsol_event,
Takashi Iwaiebc7a402008-05-20 09:23:05 +020010356 .init_hook = alc262_fujitsu_init_hook,
Takashi Iwai834be882006-03-01 14:16:17 +010010357 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010358 [ALC262_HP_BPC] = {
10359 .mixers = { alc262_HP_BPC_mixer },
10360 .init_verbs = { alc262_HP_BPC_init_verbs },
10361 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10362 .dac_nids = alc262_dac_nids,
10363 .hp_nid = 0x03,
10364 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10365 .channel_mode = alc262_modes,
10366 .input_mux = &alc262_HP_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010010367 .unsol_event = alc262_hp_bpc_unsol_event,
10368 .init_hook = alc262_hp_bpc_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010369 },
Kailang Yangcd7509a2007-01-26 18:33:17 +010010370 [ALC262_HP_BPC_D7000_WF] = {
10371 .mixers = { alc262_HP_BPC_WildWest_mixer },
10372 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
10373 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10374 .dac_nids = alc262_dac_nids,
10375 .hp_nid = 0x03,
10376 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10377 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +020010378 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010010379 .unsol_event = alc262_hp_wildwest_unsol_event,
10380 .init_hook = alc262_hp_wildwest_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010381 },
Kailang Yangcd7509a2007-01-26 18:33:17 +010010382 [ALC262_HP_BPC_D7000_WL] = {
10383 .mixers = { alc262_HP_BPC_WildWest_mixer,
10384 alc262_HP_BPC_WildWest_option_mixer },
10385 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
10386 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10387 .dac_nids = alc262_dac_nids,
10388 .hp_nid = 0x03,
10389 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10390 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +020010391 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010010392 .unsol_event = alc262_hp_wildwest_unsol_event,
10393 .init_hook = alc262_hp_wildwest_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010394 },
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010395 [ALC262_HP_TC_T5735] = {
10396 .mixers = { alc262_hp_t5735_mixer },
10397 .init_verbs = { alc262_init_verbs, alc262_hp_t5735_verbs },
10398 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10399 .dac_nids = alc262_dac_nids,
10400 .hp_nid = 0x03,
10401 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10402 .channel_mode = alc262_modes,
10403 .input_mux = &alc262_capture_source,
10404 .unsol_event = alc262_hp_t5735_unsol_event,
10405 .init_hook = alc262_hp_t5735_init_hook,
Kailang Yang8c427222008-01-10 13:03:59 +010010406 },
10407 [ALC262_HP_RP5700] = {
10408 .mixers = { alc262_hp_rp5700_mixer },
10409 .init_verbs = { alc262_init_verbs, alc262_hp_rp5700_verbs },
10410 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10411 .dac_nids = alc262_dac_nids,
10412 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10413 .channel_mode = alc262_modes,
10414 .input_mux = &alc262_hp_rp5700_capture_source,
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010415 },
Takashi Iwai304dcaa2006-07-25 14:51:16 +020010416 [ALC262_BENQ_ED8] = {
10417 .mixers = { alc262_base_mixer },
10418 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs },
10419 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10420 .dac_nids = alc262_dac_nids,
10421 .hp_nid = 0x03,
10422 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10423 .channel_mode = alc262_modes,
10424 .input_mux = &alc262_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010425 },
Kailang Yang272a5272007-05-14 11:00:38 +020010426 [ALC262_SONY_ASSAMD] = {
10427 .mixers = { alc262_sony_mixer },
10428 .init_verbs = { alc262_init_verbs, alc262_sony_unsol_verbs},
10429 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10430 .dac_nids = alc262_dac_nids,
10431 .hp_nid = 0x02,
10432 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10433 .channel_mode = alc262_modes,
10434 .input_mux = &alc262_capture_source,
10435 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +020010436 .init_hook = alc262_hippo_automute,
Kailang Yang83c34212007-07-05 11:43:05 +020010437 },
10438 [ALC262_BENQ_T31] = {
10439 .mixers = { alc262_benq_t31_mixer },
10440 .init_verbs = { alc262_init_verbs, alc262_benq_t31_EAPD_verbs, alc262_hippo_unsol_verbs },
10441 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10442 .dac_nids = alc262_dac_nids,
10443 .hp_nid = 0x03,
10444 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10445 .channel_mode = alc262_modes,
10446 .input_mux = &alc262_capture_source,
10447 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +020010448 .init_hook = alc262_hippo_automute,
Kailang Yangea1fb292008-08-26 12:58:38 +020010449 },
Tobin Davisf651b502007-10-26 12:40:47 +020010450 [ALC262_ULTRA] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010451 .mixers = { alc262_ultra_mixer, alc262_ultra_capture_mixer },
10452 .init_verbs = { alc262_ultra_verbs },
Tobin Davisf651b502007-10-26 12:40:47 +020010453 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10454 .dac_nids = alc262_dac_nids,
Tobin Davisf651b502007-10-26 12:40:47 +020010455 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10456 .channel_mode = alc262_modes,
10457 .input_mux = &alc262_ultra_capture_source,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010458 .adc_nids = alc262_adc_nids, /* ADC0 */
10459 .capsrc_nids = alc262_capsrc_nids,
10460 .num_adc_nids = 1, /* single ADC */
Tobin Davisf651b502007-10-26 12:40:47 +020010461 .unsol_event = alc262_ultra_unsol_event,
10462 .init_hook = alc262_ultra_automute,
10463 },
Jiang zhe0e31daf2008-03-20 12:12:39 +010010464 [ALC262_LENOVO_3000] = {
10465 .mixers = { alc262_lenovo_3000_mixer },
10466 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
10467 alc262_lenovo_3000_unsol_verbs },
10468 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10469 .dac_nids = alc262_dac_nids,
10470 .hp_nid = 0x03,
10471 .dig_out_nid = ALC262_DIGOUT_NID,
10472 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10473 .channel_mode = alc262_modes,
10474 .input_mux = &alc262_fujitsu_capture_source,
10475 .unsol_event = alc262_lenovo_3000_unsol_event,
10476 },
Pascal Terjane8f9ae22008-08-04 14:36:05 +020010477 [ALC262_NEC] = {
10478 .mixers = { alc262_nec_mixer },
10479 .init_verbs = { alc262_nec_verbs },
10480 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10481 .dac_nids = alc262_dac_nids,
10482 .hp_nid = 0x03,
10483 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10484 .channel_mode = alc262_modes,
10485 .input_mux = &alc262_capture_source,
10486 },
Kailang Yang4e555fe2008-08-26 13:05:55 +020010487 [ALC262_TOSHIBA_S06] = {
10488 .mixers = { alc262_toshiba_s06_mixer },
10489 .init_verbs = { alc262_init_verbs, alc262_toshiba_s06_verbs,
10490 alc262_eapd_verbs },
10491 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10492 .capsrc_nids = alc262_dmic_capsrc_nids,
10493 .dac_nids = alc262_dac_nids,
10494 .adc_nids = alc262_dmic_adc_nids, /* ADC0 */
10495 .dig_out_nid = ALC262_DIGOUT_NID,
10496 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10497 .channel_mode = alc262_modes,
10498 .input_mux = &alc262_dmic_capture_source,
10499 .unsol_event = alc262_toshiba_s06_unsol_event,
10500 .init_hook = alc262_toshiba_s06_init_hook,
10501 },
Kailang Yangdf694da2005-12-05 19:42:22 +010010502};
10503
10504static int patch_alc262(struct hda_codec *codec)
10505{
10506 struct alc_spec *spec;
10507 int board_config;
10508 int err;
10509
Robert P. J. Daydc041e02006-12-19 14:44:15 +010010510 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010010511 if (spec == NULL)
10512 return -ENOMEM;
10513
10514 codec->spec = spec;
10515#if 0
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010516 /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is
10517 * under-run
10518 */
Kailang Yangdf694da2005-12-05 19:42:22 +010010519 {
10520 int tmp;
10521 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
10522 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
10523 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
10524 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80);
10525 }
10526#endif
10527
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020010528 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
10529
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010530 board_config = snd_hda_check_board_config(codec, ALC262_MODEL_LAST,
10531 alc262_models,
10532 alc262_cfg_tbl);
Kailang Yangcd7509a2007-01-26 18:33:17 +010010533
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010534 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010535 printk(KERN_INFO "hda_codec: Unknown model for ALC262, "
10536 "trying auto-probe from BIOS...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010010537 board_config = ALC262_AUTO;
10538 }
10539
10540 if (board_config == ALC262_AUTO) {
10541 /* automatic parse from the BIOS config */
10542 err = alc262_parse_auto_config(codec);
10543 if (err < 0) {
10544 alc_free(codec);
10545 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010546 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010547 printk(KERN_INFO
10548 "hda_codec: Cannot set up configuration "
10549 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010010550 board_config = ALC262_BASIC;
10551 }
10552 }
10553
10554 if (board_config != ALC262_AUTO)
10555 setup_preset(spec, &alc262_presets[board_config]);
10556
10557 spec->stream_name_analog = "ALC262 Analog";
10558 spec->stream_analog_playback = &alc262_pcm_analog_playback;
10559 spec->stream_analog_capture = &alc262_pcm_analog_capture;
Kailang Yangea1fb292008-08-26 12:58:38 +020010560
Kailang Yangdf694da2005-12-05 19:42:22 +010010561 spec->stream_name_digital = "ALC262 Digital";
10562 spec->stream_digital_playback = &alc262_pcm_digital_playback;
10563 spec->stream_digital_capture = &alc262_pcm_digital_capture;
10564
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010565 if (!spec->adc_nids && spec->input_mux) {
Kailang Yangdf694da2005-12-05 19:42:22 +010010566 /* check whether NID 0x07 is valid */
Takashi Iwai4a471b72005-12-07 13:56:29 +010010567 unsigned int wcap = get_wcaps(codec, 0x07);
10568
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010569 /* get type */
10570 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Kailang Yangdf694da2005-12-05 19:42:22 +010010571 if (wcap != AC_WID_AUD_IN) {
10572 spec->adc_nids = alc262_adc_nids_alt;
10573 spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids_alt);
Takashi Iwai88c71a92008-02-14 17:27:17 +010010574 spec->capsrc_nids = alc262_capsrc_nids_alt;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010575 spec->mixers[spec->num_mixers] =
10576 alc262_capture_alt_mixer;
Kailang Yangdf694da2005-12-05 19:42:22 +010010577 spec->num_mixers++;
10578 } else {
10579 spec->adc_nids = alc262_adc_nids;
10580 spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids);
Takashi Iwai88c71a92008-02-14 17:27:17 +010010581 spec->capsrc_nids = alc262_capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +010010582 spec->mixers[spec->num_mixers] = alc262_capture_mixer;
10583 spec->num_mixers++;
10584 }
10585 }
10586
Takashi Iwai2134ea42008-01-10 16:53:55 +010010587 spec->vmaster_nid = 0x0c;
10588
Kailang Yangdf694da2005-12-05 19:42:22 +010010589 codec->patch_ops = alc_patch_ops;
10590 if (board_config == ALC262_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +010010591 spec->init_hook = alc262_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020010592#ifdef CONFIG_SND_HDA_POWER_SAVE
10593 if (!spec->loopback.amplist)
10594 spec->loopback.amplist = alc262_loopbacks;
10595#endif
Kailang Yangea1fb292008-08-26 12:58:38 +020010596
Kailang Yangdf694da2005-12-05 19:42:22 +010010597 return 0;
10598}
10599
Kailang Yangdf694da2005-12-05 19:42:22 +010010600/*
Kailang Yanga361d842007-06-05 12:30:55 +020010601 * ALC268 channel source setting (2 channel)
10602 */
10603#define ALC268_DIGOUT_NID ALC880_DIGOUT_NID
10604#define alc268_modes alc260_modes
Kailang Yangea1fb292008-08-26 12:58:38 +020010605
Kailang Yanga361d842007-06-05 12:30:55 +020010606static hda_nid_t alc268_dac_nids[2] = {
10607 /* front, hp */
10608 0x02, 0x03
10609};
10610
10611static hda_nid_t alc268_adc_nids[2] = {
10612 /* ADC0-1 */
10613 0x08, 0x07
10614};
10615
10616static hda_nid_t alc268_adc_nids_alt[1] = {
10617 /* ADC0 */
10618 0x08
10619};
10620
Takashi Iwaie1406342008-02-11 18:32:32 +010010621static hda_nid_t alc268_capsrc_nids[2] = { 0x23, 0x24 };
10622
Kailang Yanga361d842007-06-05 12:30:55 +020010623static struct snd_kcontrol_new alc268_base_mixer[] = {
10624 /* output mixer control */
10625 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
10626 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
10627 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
10628 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai33bf17a2007-08-21 11:51:42 +020010629 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10630 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
10631 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
Kailang Yanga361d842007-06-05 12:30:55 +020010632 { }
10633};
10634
Takashi Iwaiaef9d312008-02-19 13:16:41 +010010635/* bind Beep switches of both NID 0x0f and 0x10 */
10636static struct hda_bind_ctls alc268_bind_beep_sw = {
10637 .ops = &snd_hda_bind_sw,
10638 .values = {
10639 HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT),
10640 HDA_COMPOSE_AMP_VAL(0x10, 3, 1, HDA_INPUT),
10641 0
10642 },
10643};
10644
10645static struct snd_kcontrol_new alc268_beep_mixer[] = {
10646 HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT),
10647 HDA_BIND_SW("Beep Playback Switch", &alc268_bind_beep_sw),
10648 { }
10649};
10650
Kailang Yangd1a991a2007-08-15 16:21:59 +020010651static struct hda_verb alc268_eapd_verbs[] = {
10652 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
10653 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
10654 { }
10655};
10656
Takashi Iwaid2738092007-08-16 14:59:45 +020010657/* Toshiba specific */
10658#define alc268_toshiba_automute alc262_hippo_automute
10659
10660static struct hda_verb alc268_toshiba_verbs[] = {
10661 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
10662 { } /* end */
10663};
10664
Kailang Yang8ef355d2008-08-26 13:10:22 +020010665static struct hda_input_mux alc268_acer_lc_capture_source = {
10666 .num_items = 2,
10667 .items = {
10668 { "i-Mic", 0x6 },
10669 { "E-Mic", 0x0 },
10670 },
10671};
10672
Takashi Iwaid2738092007-08-16 14:59:45 +020010673/* Acer specific */
Takashi Iwai889c4392007-08-23 18:56:52 +020010674/* bind volumes of both NID 0x02 and 0x03 */
Takashi Iwai6bc96852007-08-17 09:02:12 +020010675static struct hda_bind_ctls alc268_acer_bind_master_vol = {
10676 .ops = &snd_hda_bind_vol,
10677 .values = {
10678 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
10679 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
10680 0
10681 },
10682};
10683
Takashi Iwai889c4392007-08-23 18:56:52 +020010684/* mute/unmute internal speaker according to the hp jack and mute state */
10685static void alc268_acer_automute(struct hda_codec *codec, int force)
10686{
10687 struct alc_spec *spec = codec->spec;
10688 unsigned int mute;
10689
10690 if (force || !spec->sense_updated) {
10691 unsigned int present;
10692 present = snd_hda_codec_read(codec, 0x14, 0,
10693 AC_VERB_GET_PIN_SENSE, 0);
10694 spec->jack_present = (present & 0x80000000) != 0;
10695 spec->sense_updated = 1;
10696 }
10697 if (spec->jack_present)
10698 mute = HDA_AMP_MUTE; /* mute internal speaker */
10699 else /* unmute internal speaker if necessary */
10700 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
10701 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
10702 HDA_AMP_MUTE, mute);
10703}
10704
10705
10706/* bind hp and internal speaker mute (with plug check) */
10707static int alc268_acer_master_sw_put(struct snd_kcontrol *kcontrol,
10708 struct snd_ctl_elem_value *ucontrol)
10709{
10710 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
10711 long *valp = ucontrol->value.integer.value;
10712 int change;
10713
10714 change = snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0,
10715 HDA_AMP_MUTE,
10716 valp[0] ? 0 : HDA_AMP_MUTE);
10717 change |= snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0,
10718 HDA_AMP_MUTE,
10719 valp[1] ? 0 : HDA_AMP_MUTE);
10720 if (change)
10721 alc268_acer_automute(codec, 0);
10722 return change;
10723}
Takashi Iwaid2738092007-08-16 14:59:45 +020010724
Kailang Yang8ef355d2008-08-26 13:10:22 +020010725static struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = {
10726 /* output mixer control */
10727 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
10728 {
10729 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10730 .name = "Master Playback Switch",
10731 .info = snd_hda_mixer_amp_switch_info,
10732 .get = snd_hda_mixer_amp_switch_get,
10733 .put = alc268_acer_master_sw_put,
10734 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
10735 },
10736 HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x18, 0, HDA_INPUT),
10737 { }
10738};
10739
Takashi Iwaid2738092007-08-16 14:59:45 +020010740static struct snd_kcontrol_new alc268_acer_mixer[] = {
10741 /* output mixer control */
10742 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
10743 {
10744 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10745 .name = "Master Playback Switch",
10746 .info = snd_hda_mixer_amp_switch_info,
10747 .get = snd_hda_mixer_amp_switch_get,
10748 .put = alc268_acer_master_sw_put,
10749 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
10750 },
Takashi Iwai33bf17a2007-08-21 11:51:42 +020010751 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10752 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
10753 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
Takashi Iwaid2738092007-08-16 14:59:45 +020010754 { }
10755};
10756
Kailang Yang8ef355d2008-08-26 13:10:22 +020010757static struct hda_verb alc268_acer_aspire_one_verbs[] = {
10758 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
10759 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
10760 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
10761 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
10762 {0x23, AC_VERB_SET_CONNECT_SEL, 0x06},
10763 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, 0xa017},
10764 { }
10765};
10766
Takashi Iwaid2738092007-08-16 14:59:45 +020010767static struct hda_verb alc268_acer_verbs[] = {
Takashi Iwai0ccb5412008-03-06 16:58:35 +010010768 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* internal dmic? */
10769 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaid2738092007-08-16 14:59:45 +020010770 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
10771 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai0ccb5412008-03-06 16:58:35 +010010772 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
10773 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaid2738092007-08-16 14:59:45 +020010774 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
10775 { }
10776};
10777
10778/* unsolicited event for HP jack sensing */
10779static void alc268_toshiba_unsol_event(struct hda_codec *codec,
10780 unsigned int res)
10781{
Takashi Iwai889c4392007-08-23 18:56:52 +020010782 if ((res >> 26) != ALC880_HP_EVENT)
Takashi Iwaid2738092007-08-16 14:59:45 +020010783 return;
10784 alc268_toshiba_automute(codec);
10785}
10786
10787static void alc268_acer_unsol_event(struct hda_codec *codec,
10788 unsigned int res)
10789{
Takashi Iwai889c4392007-08-23 18:56:52 +020010790 if ((res >> 26) != ALC880_HP_EVENT)
Takashi Iwaid2738092007-08-16 14:59:45 +020010791 return;
10792 alc268_acer_automute(codec, 1);
10793}
10794
Takashi Iwai889c4392007-08-23 18:56:52 +020010795static void alc268_acer_init_hook(struct hda_codec *codec)
10796{
10797 alc268_acer_automute(codec, 1);
10798}
10799
Kailang Yang8ef355d2008-08-26 13:10:22 +020010800/* toggle speaker-output according to the hp-jack state */
10801static void alc268_aspire_one_speaker_automute(struct hda_codec *codec)
10802{
10803 unsigned int present;
10804 unsigned char bits;
10805
10806 present = snd_hda_codec_read(codec, 0x15, 0,
10807 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
10808 bits = present ? AMP_IN_MUTE(0) : 0;
10809 snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 0,
10810 AMP_IN_MUTE(0), bits);
10811 snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 1,
10812 AMP_IN_MUTE(0), bits);
10813}
10814
10815
10816static void alc268_acer_mic_automute(struct hda_codec *codec)
10817{
10818 unsigned int present;
10819
10820 present = snd_hda_codec_read(codec, 0x18, 0,
10821 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
10822 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_CONNECT_SEL,
10823 present ? 0x0 : 0x6);
10824}
10825
10826static void alc268_acer_lc_unsol_event(struct hda_codec *codec,
10827 unsigned int res)
10828{
10829 if ((res >> 26) == ALC880_HP_EVENT)
10830 alc268_aspire_one_speaker_automute(codec);
10831 if ((res >> 26) == ALC880_MIC_EVENT)
10832 alc268_acer_mic_automute(codec);
10833}
10834
10835static void alc268_acer_lc_init_hook(struct hda_codec *codec)
10836{
10837 alc268_aspire_one_speaker_automute(codec);
10838 alc268_acer_mic_automute(codec);
10839}
10840
Takashi Iwai3866f0b2008-01-15 12:37:42 +010010841static struct snd_kcontrol_new alc268_dell_mixer[] = {
10842 /* output mixer control */
10843 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
10844 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
10845 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
10846 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
10847 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10848 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
10849 { }
10850};
10851
10852static struct hda_verb alc268_dell_verbs[] = {
10853 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
10854 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
10855 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
10856 { }
10857};
10858
10859/* mute/unmute internal speaker according to the hp jack and mute state */
10860static void alc268_dell_automute(struct hda_codec *codec)
10861{
10862 unsigned int present;
10863 unsigned int mute;
10864
10865 present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0);
10866 if (present & 0x80000000)
10867 mute = HDA_AMP_MUTE;
10868 else
10869 mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0);
10870 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
10871 HDA_AMP_MUTE, mute);
10872}
10873
10874static void alc268_dell_unsol_event(struct hda_codec *codec,
10875 unsigned int res)
10876{
10877 if ((res >> 26) != ALC880_HP_EVENT)
10878 return;
10879 alc268_dell_automute(codec);
10880}
10881
10882#define alc268_dell_init_hook alc268_dell_automute
10883
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020010884static struct snd_kcontrol_new alc267_quanta_il1_mixer[] = {
10885 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x2, 0x0, HDA_OUTPUT),
10886 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
10887 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
10888 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
10889 HDA_CODEC_VOLUME("Mic Capture Volume", 0x23, 0x0, HDA_OUTPUT),
10890 HDA_BIND_MUTE("Mic Capture Switch", 0x23, 2, HDA_OUTPUT),
10891 HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
10892 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
10893 { }
10894};
10895
10896static struct hda_verb alc267_quanta_il1_verbs[] = {
10897 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
10898 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
10899 { }
10900};
10901
10902static void alc267_quanta_il1_hp_automute(struct hda_codec *codec)
10903{
10904 unsigned int present;
10905
10906 present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0)
10907 & AC_PINSENSE_PRESENCE;
10908 snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
10909 present ? 0 : PIN_OUT);
10910}
10911
10912static void alc267_quanta_il1_mic_automute(struct hda_codec *codec)
10913{
10914 unsigned int present;
10915
10916 present = snd_hda_codec_read(codec, 0x18, 0,
10917 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
10918 snd_hda_codec_write(codec, 0x23, 0,
10919 AC_VERB_SET_CONNECT_SEL,
10920 present ? 0x00 : 0x01);
10921}
10922
10923static void alc267_quanta_il1_automute(struct hda_codec *codec)
10924{
10925 alc267_quanta_il1_hp_automute(codec);
10926 alc267_quanta_il1_mic_automute(codec);
10927}
10928
10929static void alc267_quanta_il1_unsol_event(struct hda_codec *codec,
10930 unsigned int res)
10931{
10932 switch (res >> 26) {
10933 case ALC880_HP_EVENT:
10934 alc267_quanta_il1_hp_automute(codec);
10935 break;
10936 case ALC880_MIC_EVENT:
10937 alc267_quanta_il1_mic_automute(codec);
10938 break;
10939 }
10940}
10941
Kailang Yanga361d842007-06-05 12:30:55 +020010942/*
10943 * generic initialization of ADC, input mixers and output mixers
10944 */
10945static struct hda_verb alc268_base_init_verbs[] = {
10946 /* Unmute DAC0-1 and set vol = 0 */
10947 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10948 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10949 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10950 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10951 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10952 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10953
10954 /*
10955 * Set up output mixers (0x0c - 0x0e)
10956 */
10957 /* set vol=0 to output mixers */
10958 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10959 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10960 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10961 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
10962
10963 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10964 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10965
10966 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
10967 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
10968 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
10969 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
10970 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
10971 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10972 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10973 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10974
10975 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10976 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10977 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10978 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10979 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10980 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10981 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwaiaef9d312008-02-19 13:16:41 +010010982
10983 /* set PCBEEP vol = 0, mute connections */
10984 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10985 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10986 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020010987
Jiang Zhea9b3aa82007-12-20 13:13:13 +010010988 /* Unmute Selector 23h,24h and set the default input to mic-in */
Kailang Yangea1fb292008-08-26 12:58:38 +020010989
Jiang Zhea9b3aa82007-12-20 13:13:13 +010010990 {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
10991 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10992 {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
10993 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020010994
Kailang Yanga361d842007-06-05 12:30:55 +020010995 { }
10996};
10997
10998/*
10999 * generic initialization of ADC, input mixers and output mixers
11000 */
11001static struct hda_verb alc268_volume_init_verbs[] = {
11002 /* set output DAC */
11003 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11004 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11005 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11006 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11007
11008 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11009 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11010 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11011 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11012 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11013
11014 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11015 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11016 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11017 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11018 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11019
11020 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11021 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11022 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11023 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11024
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011025 /* set PCBEEP vol = 0, mute connections */
11026 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11027 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11028 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020011029
11030 { }
11031};
11032
11033#define alc268_mux_enum_info alc_mux_enum_info
11034#define alc268_mux_enum_get alc_mux_enum_get
Takashi Iwaie1406342008-02-11 18:32:32 +010011035#define alc268_mux_enum_put alc_mux_enum_put
Kailang Yanga361d842007-06-05 12:30:55 +020011036
11037static struct snd_kcontrol_new alc268_capture_alt_mixer[] = {
11038 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
11039 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
11040 {
11041 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11042 /* The multiple "Capture Source" controls confuse alsamixer
11043 * So call somewhat different..
Kailang Yanga361d842007-06-05 12:30:55 +020011044 */
11045 /* .name = "Capture Source", */
11046 .name = "Input Source",
11047 .count = 1,
11048 .info = alc268_mux_enum_info,
11049 .get = alc268_mux_enum_get,
11050 .put = alc268_mux_enum_put,
11051 },
11052 { } /* end */
11053};
11054
11055static struct snd_kcontrol_new alc268_capture_mixer[] = {
11056 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
11057 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
11058 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x24, 0x0, HDA_OUTPUT),
11059 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x24, 0x0, HDA_OUTPUT),
11060 {
11061 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11062 /* The multiple "Capture Source" controls confuse alsamixer
11063 * So call somewhat different..
Kailang Yanga361d842007-06-05 12:30:55 +020011064 */
11065 /* .name = "Capture Source", */
11066 .name = "Input Source",
11067 .count = 2,
11068 .info = alc268_mux_enum_info,
11069 .get = alc268_mux_enum_get,
11070 .put = alc268_mux_enum_put,
11071 },
11072 { } /* end */
11073};
11074
11075static struct hda_input_mux alc268_capture_source = {
11076 .num_items = 4,
11077 .items = {
11078 { "Mic", 0x0 },
11079 { "Front Mic", 0x1 },
11080 { "Line", 0x2 },
11081 { "CD", 0x3 },
11082 },
11083};
11084
Takashi Iwai0ccb5412008-03-06 16:58:35 +010011085static struct hda_input_mux alc268_acer_capture_source = {
11086 .num_items = 3,
11087 .items = {
11088 { "Mic", 0x0 },
11089 { "Internal Mic", 0x6 },
11090 { "Line", 0x2 },
11091 },
11092};
11093
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010011094#ifdef CONFIG_SND_DEBUG
11095static struct snd_kcontrol_new alc268_test_mixer[] = {
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010011096 /* Volume widgets */
11097 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x02, 0x0, HDA_OUTPUT),
11098 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x03, 0x0, HDA_OUTPUT),
11099 HDA_BIND_MUTE_MONO("Mono sum Playback Switch", 0x0e, 1, 2, HDA_INPUT),
11100 HDA_BIND_MUTE("LINE-OUT sum Playback Switch", 0x0f, 2, HDA_INPUT),
11101 HDA_BIND_MUTE("HP-OUT sum Playback Switch", 0x10, 2, HDA_INPUT),
11102 HDA_BIND_MUTE("LINE-OUT Playback Switch", 0x14, 2, HDA_OUTPUT),
11103 HDA_BIND_MUTE("HP-OUT Playback Switch", 0x15, 2, HDA_OUTPUT),
11104 HDA_BIND_MUTE("Mono Playback Switch", 0x16, 2, HDA_OUTPUT),
11105 HDA_CODEC_VOLUME("MIC1 Capture Volume", 0x18, 0x0, HDA_INPUT),
11106 HDA_BIND_MUTE("MIC1 Capture Switch", 0x18, 2, HDA_OUTPUT),
11107 HDA_CODEC_VOLUME("MIC2 Capture Volume", 0x19, 0x0, HDA_INPUT),
11108 HDA_CODEC_VOLUME("LINE1 Capture Volume", 0x1a, 0x0, HDA_INPUT),
11109 HDA_BIND_MUTE("LINE1 Capture Switch", 0x1a, 2, HDA_OUTPUT),
Takashi Iwaif0747ee2008-01-15 11:41:41 +010011110 /* The below appears problematic on some hardwares */
11111 /*HDA_CODEC_VOLUME("PCBEEP Playback Volume", 0x1d, 0x0, HDA_INPUT),*/
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010011112 HDA_CODEC_VOLUME("PCM-IN1 Capture Volume", 0x23, 0x0, HDA_OUTPUT),
11113 HDA_BIND_MUTE("PCM-IN1 Capture Switch", 0x23, 2, HDA_OUTPUT),
11114 HDA_CODEC_VOLUME("PCM-IN2 Capture Volume", 0x24, 0x0, HDA_OUTPUT),
11115 HDA_BIND_MUTE("PCM-IN2 Capture Switch", 0x24, 2, HDA_OUTPUT),
11116
11117 /* Modes for retasking pin widgets */
11118 ALC_PIN_MODE("LINE-OUT pin mode", 0x14, ALC_PIN_DIR_INOUT),
11119 ALC_PIN_MODE("HP-OUT pin mode", 0x15, ALC_PIN_DIR_INOUT),
11120 ALC_PIN_MODE("MIC1 pin mode", 0x18, ALC_PIN_DIR_INOUT),
11121 ALC_PIN_MODE("LINE1 pin mode", 0x1a, ALC_PIN_DIR_INOUT),
11122
11123 /* Controls for GPIO pins, assuming they are configured as outputs */
11124 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
11125 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
11126 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
11127 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
11128
11129 /* Switches to allow the digital SPDIF output pin to be enabled.
11130 * The ALC268 does not have an SPDIF input.
11131 */
11132 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x06, 0x01),
11133
11134 /* A switch allowing EAPD to be enabled. Some laptops seem to use
11135 * this output to turn on an external amplifier.
11136 */
11137 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
11138 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
11139
11140 { } /* end */
11141};
11142#endif
11143
Kailang Yanga361d842007-06-05 12:30:55 +020011144/* create input playback/capture controls for the given pin */
11145static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
11146 const char *ctlname, int idx)
11147{
11148 char name[32];
11149 int err;
11150
11151 sprintf(name, "%s Playback Volume", ctlname);
11152 if (nid == 0x14) {
11153 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
11154 HDA_COMPOSE_AMP_VAL(0x02, 3, idx,
11155 HDA_OUTPUT));
11156 if (err < 0)
11157 return err;
11158 } else if (nid == 0x15) {
11159 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
11160 HDA_COMPOSE_AMP_VAL(0x03, 3, idx,
11161 HDA_OUTPUT));
11162 if (err < 0)
11163 return err;
11164 } else
11165 return -1;
11166 sprintf(name, "%s Playback Switch", ctlname);
11167 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
11168 HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
11169 if (err < 0)
11170 return err;
11171 return 0;
11172}
11173
11174/* add playback controls from the parsed DAC table */
11175static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
11176 const struct auto_pin_cfg *cfg)
11177{
11178 hda_nid_t nid;
11179 int err;
11180
11181 spec->multiout.num_dacs = 2; /* only use one dac */
11182 spec->multiout.dac_nids = spec->private_dac_nids;
11183 spec->multiout.dac_nids[0] = 2;
11184 spec->multiout.dac_nids[1] = 3;
11185
11186 nid = cfg->line_out_pins[0];
11187 if (nid)
Kailang Yangea1fb292008-08-26 12:58:38 +020011188 alc268_new_analog_output(spec, nid, "Front", 0);
Kailang Yanga361d842007-06-05 12:30:55 +020011189
11190 nid = cfg->speaker_pins[0];
11191 if (nid == 0x1d) {
11192 err = add_control(spec, ALC_CTL_WIDGET_VOL,
11193 "Speaker Playback Volume",
11194 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
11195 if (err < 0)
11196 return err;
11197 }
11198 nid = cfg->hp_pins[0];
11199 if (nid)
11200 alc268_new_analog_output(spec, nid, "Headphone", 0);
11201
11202 nid = cfg->line_out_pins[1] | cfg->line_out_pins[2];
11203 if (nid == 0x16) {
11204 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
11205 "Mono Playback Switch",
11206 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_INPUT));
11207 if (err < 0)
11208 return err;
11209 }
Kailang Yangea1fb292008-08-26 12:58:38 +020011210 return 0;
Kailang Yanga361d842007-06-05 12:30:55 +020011211}
11212
11213/* create playback/capture controls for input pins */
11214static int alc268_auto_create_analog_input_ctls(struct alc_spec *spec,
11215 const struct auto_pin_cfg *cfg)
11216{
11217 struct hda_input_mux *imux = &spec->private_imux;
11218 int i, idx1;
11219
11220 for (i = 0; i < AUTO_PIN_LAST; i++) {
11221 switch(cfg->input_pins[i]) {
11222 case 0x18:
11223 idx1 = 0; /* Mic 1 */
11224 break;
11225 case 0x19:
11226 idx1 = 1; /* Mic 2 */
11227 break;
11228 case 0x1a:
11229 idx1 = 2; /* Line In */
11230 break;
Kailang Yangea1fb292008-08-26 12:58:38 +020011231 case 0x1c:
Kailang Yanga361d842007-06-05 12:30:55 +020011232 idx1 = 3; /* CD */
11233 break;
Takashi Iwai7194cae2008-03-06 16:58:17 +010011234 case 0x12:
11235 case 0x13:
11236 idx1 = 6; /* digital mics */
11237 break;
Kailang Yanga361d842007-06-05 12:30:55 +020011238 default:
11239 continue;
11240 }
11241 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
11242 imux->items[imux->num_items].index = idx1;
Kailang Yangea1fb292008-08-26 12:58:38 +020011243 imux->num_items++;
Kailang Yanga361d842007-06-05 12:30:55 +020011244 }
11245 return 0;
11246}
11247
11248static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec)
11249{
11250 struct alc_spec *spec = codec->spec;
11251 hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
11252 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
11253 hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
11254 unsigned int dac_vol1, dac_vol2;
11255
11256 if (speaker_nid) {
11257 snd_hda_codec_write(codec, speaker_nid, 0,
11258 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
11259 snd_hda_codec_write(codec, 0x0f, 0,
11260 AC_VERB_SET_AMP_GAIN_MUTE,
11261 AMP_IN_UNMUTE(1));
11262 snd_hda_codec_write(codec, 0x10, 0,
11263 AC_VERB_SET_AMP_GAIN_MUTE,
11264 AMP_IN_UNMUTE(1));
11265 } else {
11266 snd_hda_codec_write(codec, 0x0f, 0,
11267 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
11268 snd_hda_codec_write(codec, 0x10, 0,
11269 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
11270 }
11271
11272 dac_vol1 = dac_vol2 = 0xb000 | 0x40; /* set max volume */
Kailang Yangea1fb292008-08-26 12:58:38 +020011273 if (line_nid == 0x14)
Kailang Yanga361d842007-06-05 12:30:55 +020011274 dac_vol2 = AMP_OUT_ZERO;
11275 else if (line_nid == 0x15)
11276 dac_vol1 = AMP_OUT_ZERO;
Kailang Yangea1fb292008-08-26 12:58:38 +020011277 if (hp_nid == 0x14)
Kailang Yanga361d842007-06-05 12:30:55 +020011278 dac_vol2 = AMP_OUT_ZERO;
11279 else if (hp_nid == 0x15)
11280 dac_vol1 = AMP_OUT_ZERO;
11281 if (line_nid != 0x16 || hp_nid != 0x16 ||
11282 spec->autocfg.line_out_pins[1] != 0x16 ||
11283 spec->autocfg.line_out_pins[2] != 0x16)
11284 dac_vol1 = dac_vol2 = AMP_OUT_ZERO;
11285
11286 snd_hda_codec_write(codec, 0x02, 0,
11287 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol1);
11288 snd_hda_codec_write(codec, 0x03, 0,
11289 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol2);
11290}
11291
11292/* pcm configuration: identiacal with ALC880 */
11293#define alc268_pcm_analog_playback alc880_pcm_analog_playback
11294#define alc268_pcm_analog_capture alc880_pcm_analog_capture
Takashi Iwai63300792008-01-24 15:31:36 +010011295#define alc268_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
Kailang Yanga361d842007-06-05 12:30:55 +020011296#define alc268_pcm_digital_playback alc880_pcm_digital_playback
11297
11298/*
11299 * BIOS auto configuration
11300 */
11301static int alc268_parse_auto_config(struct hda_codec *codec)
11302{
11303 struct alc_spec *spec = codec->spec;
11304 int err;
11305 static hda_nid_t alc268_ignore[] = { 0 };
11306
11307 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
11308 alc268_ignore);
11309 if (err < 0)
11310 return err;
11311 if (!spec->autocfg.line_outs)
11312 return 0; /* can't find valid BIOS pin config */
11313
11314 err = alc268_auto_create_multi_out_ctls(spec, &spec->autocfg);
11315 if (err < 0)
11316 return err;
11317 err = alc268_auto_create_analog_input_ctls(spec, &spec->autocfg);
11318 if (err < 0)
11319 return err;
11320
11321 spec->multiout.max_channels = 2;
11322
11323 /* digital only support output */
11324 if (spec->autocfg.dig_out_pin)
11325 spec->multiout.dig_out_nid = ALC268_DIGOUT_NID;
11326
11327 if (spec->kctl_alloc)
11328 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
11329
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011330 if (spec->autocfg.speaker_pins[0] != 0x1d)
11331 spec->mixers[spec->num_mixers++] = alc268_beep_mixer;
11332
Kailang Yanga361d842007-06-05 12:30:55 +020011333 spec->init_verbs[spec->num_init_verbs++] = alc268_volume_init_verbs;
11334 spec->num_mux_defs = 1;
11335 spec->input_mux = &spec->private_imux;
11336
Takashi Iwai776e1842007-08-29 15:07:11 +020011337 err = alc_auto_add_mic_boost(codec);
11338 if (err < 0)
11339 return err;
11340
Kailang Yanga361d842007-06-05 12:30:55 +020011341 return 1;
11342}
11343
11344#define alc268_auto_init_multi_out alc882_auto_init_multi_out
11345#define alc268_auto_init_hp_out alc882_auto_init_hp_out
11346#define alc268_auto_init_analog_input alc882_auto_init_analog_input
11347
11348/* init callback for auto-configuration model -- overriding the default init */
11349static void alc268_auto_init(struct hda_codec *codec)
11350{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010011351 struct alc_spec *spec = codec->spec;
Kailang Yanga361d842007-06-05 12:30:55 +020011352 alc268_auto_init_multi_out(codec);
11353 alc268_auto_init_hp_out(codec);
11354 alc268_auto_init_mono_speaker_out(codec);
11355 alc268_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010011356 if (spec->unsol_event)
11357 alc_sku_automute(codec);
Kailang Yanga361d842007-06-05 12:30:55 +020011358}
11359
11360/*
11361 * configuration and preset
11362 */
11363static const char *alc268_models[ALC268_MODEL_LAST] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020011364 [ALC267_QUANTA_IL1] = "quanta-il1",
Kailang Yanga361d842007-06-05 12:30:55 +020011365 [ALC268_3ST] = "3stack",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020011366 [ALC268_TOSHIBA] = "toshiba",
Takashi Iwaid2738092007-08-16 14:59:45 +020011367 [ALC268_ACER] = "acer",
Kailang Yang8ef355d2008-08-26 13:10:22 +020011368 [ALC268_ACER_ASPIRE_ONE] = "acer-aspire",
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011369 [ALC268_DELL] = "dell",
Mirco Tischlerf12462c2008-02-04 12:33:59 +010011370 [ALC268_ZEPTO] = "zepto",
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010011371#ifdef CONFIG_SND_DEBUG
11372 [ALC268_TEST] = "test",
11373#endif
Kailang Yanga361d842007-06-05 12:30:55 +020011374 [ALC268_AUTO] = "auto",
11375};
11376
11377static struct snd_pci_quirk alc268_cfg_tbl[] = {
Takashi Iwaia0b8f7d2008-04-22 19:39:49 +020011378 SND_PCI_QUIRK(0x1025, 0x011e, "Acer Aspire 5720z", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011379 SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER),
Andy Shevchenkodafc8352008-01-25 11:53:50 +010011380 SND_PCI_QUIRK(0x1025, 0x012e, "Acer Aspire 5310", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011381 SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER),
Andy Shevchenko29a52c22008-01-24 17:29:00 +010011382 SND_PCI_QUIRK(0x1025, 0x0136, "Acer Aspire 5315", ALC268_ACER),
Kailang Yang8ef355d2008-08-26 13:10:22 +020011383 SND_PCI_QUIRK(0x1025, 0x015b, "Acer Aspire One",
11384 ALC268_ACER_ASPIRE_ONE),
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011385 SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011386 SND_PCI_QUIRK(0x103c, 0x30cc, "TOSHIBA", ALC268_TOSHIBA),
Kailang Yanga361d842007-06-05 12:30:55 +020011387 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST),
Kailang Yangd1a991a2007-08-15 16:21:59 +020011388 SND_PCI_QUIRK(0x1179, 0xff10, "TOSHIBA A205", ALC268_TOSHIBA),
Takashi Iwai8e7f00f2007-09-07 10:58:58 +020011389 SND_PCI_QUIRK(0x1179, 0xff50, "TOSHIBA A305", ALC268_TOSHIBA),
Tony Vroon378bd6a2008-06-04 12:08:30 +020011390 SND_PCI_QUIRK(0x14c0, 0x0025, "COMPAL IFL90/JFL-92", ALC268_TOSHIBA),
Takashi Iwaib875bf32007-09-06 15:00:27 +020011391 SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER),
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020011392 SND_PCI_QUIRK(0x152d, 0x0771, "Quanta IL1", ALC267_QUANTA_IL1),
Mirco Tischlerf12462c2008-02-04 12:33:59 +010011393 SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO),
Kailang Yanga361d842007-06-05 12:30:55 +020011394 {}
11395};
11396
11397static struct alc_config_preset alc268_presets[] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020011398 [ALC267_QUANTA_IL1] = {
11399 .mixers = { alc267_quanta_il1_mixer },
11400 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
11401 alc267_quanta_il1_verbs },
11402 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11403 .dac_nids = alc268_dac_nids,
11404 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
11405 .adc_nids = alc268_adc_nids_alt,
11406 .hp_nid = 0x03,
11407 .num_channel_mode = ARRAY_SIZE(alc268_modes),
11408 .channel_mode = alc268_modes,
11409 .input_mux = &alc268_capture_source,
11410 .unsol_event = alc267_quanta_il1_unsol_event,
11411 .init_hook = alc267_quanta_il1_automute,
11412 },
Kailang Yanga361d842007-06-05 12:30:55 +020011413 [ALC268_3ST] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011414 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
11415 alc268_beep_mixer },
Kailang Yanga361d842007-06-05 12:30:55 +020011416 .init_verbs = { alc268_base_init_verbs },
11417 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11418 .dac_nids = alc268_dac_nids,
11419 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
11420 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010011421 .capsrc_nids = alc268_capsrc_nids,
Kailang Yanga361d842007-06-05 12:30:55 +020011422 .hp_nid = 0x03,
11423 .dig_out_nid = ALC268_DIGOUT_NID,
11424 .num_channel_mode = ARRAY_SIZE(alc268_modes),
11425 .channel_mode = alc268_modes,
11426 .input_mux = &alc268_capture_source,
11427 },
Kailang Yangd1a991a2007-08-15 16:21:59 +020011428 [ALC268_TOSHIBA] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011429 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
11430 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020011431 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
11432 alc268_toshiba_verbs },
Kailang Yangd1a991a2007-08-15 16:21:59 +020011433 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11434 .dac_nids = alc268_dac_nids,
11435 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
11436 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010011437 .capsrc_nids = alc268_capsrc_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020011438 .hp_nid = 0x03,
11439 .num_channel_mode = ARRAY_SIZE(alc268_modes),
11440 .channel_mode = alc268_modes,
11441 .input_mux = &alc268_capture_source,
Takashi Iwaid2738092007-08-16 14:59:45 +020011442 .unsol_event = alc268_toshiba_unsol_event,
11443 .init_hook = alc268_toshiba_automute,
11444 },
11445 [ALC268_ACER] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011446 .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer,
11447 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020011448 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
11449 alc268_acer_verbs },
11450 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11451 .dac_nids = alc268_dac_nids,
11452 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
11453 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010011454 .capsrc_nids = alc268_capsrc_nids,
Takashi Iwaid2738092007-08-16 14:59:45 +020011455 .hp_nid = 0x02,
11456 .num_channel_mode = ARRAY_SIZE(alc268_modes),
11457 .channel_mode = alc268_modes,
Takashi Iwai0ccb5412008-03-06 16:58:35 +010011458 .input_mux = &alc268_acer_capture_source,
Takashi Iwaid2738092007-08-16 14:59:45 +020011459 .unsol_event = alc268_acer_unsol_event,
Takashi Iwai889c4392007-08-23 18:56:52 +020011460 .init_hook = alc268_acer_init_hook,
Kailang Yangd1a991a2007-08-15 16:21:59 +020011461 },
Kailang Yang8ef355d2008-08-26 13:10:22 +020011462 [ALC268_ACER_ASPIRE_ONE] = {
11463 .mixers = { alc268_acer_aspire_one_mixer,
11464 alc268_capture_alt_mixer },
11465 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
11466 alc268_acer_aspire_one_verbs },
11467 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11468 .dac_nids = alc268_dac_nids,
11469 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
11470 .adc_nids = alc268_adc_nids_alt,
11471 .capsrc_nids = alc268_capsrc_nids,
11472 .hp_nid = 0x03,
11473 .num_channel_mode = ARRAY_SIZE(alc268_modes),
11474 .channel_mode = alc268_modes,
11475 .input_mux = &alc268_acer_lc_capture_source,
11476 .unsol_event = alc268_acer_lc_unsol_event,
11477 .init_hook = alc268_acer_lc_init_hook,
11478 },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011479 [ALC268_DELL] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011480 .mixers = { alc268_dell_mixer, alc268_beep_mixer },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011481 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
11482 alc268_dell_verbs },
11483 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11484 .dac_nids = alc268_dac_nids,
11485 .hp_nid = 0x02,
11486 .num_channel_mode = ARRAY_SIZE(alc268_modes),
11487 .channel_mode = alc268_modes,
11488 .unsol_event = alc268_dell_unsol_event,
11489 .init_hook = alc268_dell_init_hook,
11490 .input_mux = &alc268_capture_source,
11491 },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010011492 [ALC268_ZEPTO] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011493 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
11494 alc268_beep_mixer },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010011495 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
11496 alc268_toshiba_verbs },
11497 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11498 .dac_nids = alc268_dac_nids,
11499 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
11500 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010011501 .capsrc_nids = alc268_capsrc_nids,
Mirco Tischlerf12462c2008-02-04 12:33:59 +010011502 .hp_nid = 0x03,
11503 .dig_out_nid = ALC268_DIGOUT_NID,
11504 .num_channel_mode = ARRAY_SIZE(alc268_modes),
11505 .channel_mode = alc268_modes,
11506 .input_mux = &alc268_capture_source,
11507 .unsol_event = alc268_toshiba_unsol_event,
11508 .init_hook = alc268_toshiba_automute
11509 },
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010011510#ifdef CONFIG_SND_DEBUG
11511 [ALC268_TEST] = {
11512 .mixers = { alc268_test_mixer, alc268_capture_mixer },
11513 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
11514 alc268_volume_init_verbs },
11515 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11516 .dac_nids = alc268_dac_nids,
11517 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
11518 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010011519 .capsrc_nids = alc268_capsrc_nids,
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010011520 .hp_nid = 0x03,
11521 .dig_out_nid = ALC268_DIGOUT_NID,
11522 .num_channel_mode = ARRAY_SIZE(alc268_modes),
11523 .channel_mode = alc268_modes,
11524 .input_mux = &alc268_capture_source,
11525 },
11526#endif
Kailang Yanga361d842007-06-05 12:30:55 +020011527};
11528
11529static int patch_alc268(struct hda_codec *codec)
11530{
11531 struct alc_spec *spec;
11532 int board_config;
11533 int err;
11534
11535 spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
11536 if (spec == NULL)
11537 return -ENOMEM;
11538
11539 codec->spec = spec;
11540
11541 board_config = snd_hda_check_board_config(codec, ALC268_MODEL_LAST,
11542 alc268_models,
11543 alc268_cfg_tbl);
11544
11545 if (board_config < 0 || board_config >= ALC268_MODEL_LAST) {
11546 printk(KERN_INFO "hda_codec: Unknown model for ALC268, "
11547 "trying auto-probe from BIOS...\n");
11548 board_config = ALC268_AUTO;
11549 }
11550
11551 if (board_config == ALC268_AUTO) {
11552 /* automatic parse from the BIOS config */
11553 err = alc268_parse_auto_config(codec);
11554 if (err < 0) {
11555 alc_free(codec);
11556 return err;
11557 } else if (!err) {
11558 printk(KERN_INFO
11559 "hda_codec: Cannot set up configuration "
11560 "from BIOS. Using base mode...\n");
11561 board_config = ALC268_3ST;
11562 }
11563 }
11564
11565 if (board_config != ALC268_AUTO)
11566 setup_preset(spec, &alc268_presets[board_config]);
11567
Kailang Yang2f893282008-05-27 12:14:47 +020011568 if (codec->vendor_id == 0x10ec0267) {
11569 spec->stream_name_analog = "ALC267 Analog";
11570 spec->stream_name_digital = "ALC267 Digital";
11571 } else {
11572 spec->stream_name_analog = "ALC268 Analog";
11573 spec->stream_name_digital = "ALC268 Digital";
11574 }
11575
Kailang Yanga361d842007-06-05 12:30:55 +020011576 spec->stream_analog_playback = &alc268_pcm_analog_playback;
11577 spec->stream_analog_capture = &alc268_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +010011578 spec->stream_analog_alt_capture = &alc268_pcm_analog_alt_capture;
Kailang Yanga361d842007-06-05 12:30:55 +020011579
Kailang Yanga361d842007-06-05 12:30:55 +020011580 spec->stream_digital_playback = &alc268_pcm_digital_playback;
11581
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011582 if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
11583 /* override the amp caps for beep generator */
11584 snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT,
11585 (0x0c << AC_AMPCAP_OFFSET_SHIFT) |
11586 (0x0c << AC_AMPCAP_NUM_STEPS_SHIFT) |
11587 (0x07 << AC_AMPCAP_STEP_SIZE_SHIFT) |
11588 (0 << AC_AMPCAP_MUTE_SHIFT));
11589
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011590 if (!spec->adc_nids && spec->input_mux) {
11591 /* check whether NID 0x07 is valid */
11592 unsigned int wcap = get_wcaps(codec, 0x07);
Takashi Iwai85860c02008-02-19 15:00:15 +010011593 int i;
Kailang Yanga361d842007-06-05 12:30:55 +020011594
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011595 /* get type */
11596 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Takashi Iwai67ebcb02008-02-19 15:03:57 +010011597 if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011598 spec->adc_nids = alc268_adc_nids_alt;
11599 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt);
11600 spec->mixers[spec->num_mixers] =
Kailang Yanga361d842007-06-05 12:30:55 +020011601 alc268_capture_alt_mixer;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011602 spec->num_mixers++;
11603 } else {
11604 spec->adc_nids = alc268_adc_nids;
11605 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids);
11606 spec->mixers[spec->num_mixers] =
11607 alc268_capture_mixer;
11608 spec->num_mixers++;
Kailang Yanga361d842007-06-05 12:30:55 +020011609 }
Takashi Iwaie1406342008-02-11 18:32:32 +010011610 spec->capsrc_nids = alc268_capsrc_nids;
Takashi Iwai85860c02008-02-19 15:00:15 +010011611 /* set default input source */
11612 for (i = 0; i < spec->num_adc_nids; i++)
11613 snd_hda_codec_write_cache(codec, alc268_capsrc_nids[i],
11614 0, AC_VERB_SET_CONNECT_SEL,
11615 spec->input_mux->items[0].index);
Kailang Yanga361d842007-06-05 12:30:55 +020011616 }
Takashi Iwai2134ea42008-01-10 16:53:55 +010011617
11618 spec->vmaster_nid = 0x02;
11619
Kailang Yanga361d842007-06-05 12:30:55 +020011620 codec->patch_ops = alc_patch_ops;
11621 if (board_config == ALC268_AUTO)
11622 spec->init_hook = alc268_auto_init;
Kailang Yangea1fb292008-08-26 12:58:38 +020011623
Kailang Yanga361d842007-06-05 12:30:55 +020011624 return 0;
11625}
11626
11627/*
Kailang Yangf6a92242007-12-13 16:52:54 +010011628 * ALC269 channel source setting (2 channel)
11629 */
11630#define ALC269_DIGOUT_NID ALC880_DIGOUT_NID
11631
11632#define alc269_dac_nids alc260_dac_nids
11633
11634static hda_nid_t alc269_adc_nids[1] = {
11635 /* ADC1 */
Kailang Yangf53281e2008-07-18 12:36:43 +020011636 0x08,
11637};
11638
Takashi Iwaie01bf502008-08-21 16:25:07 +020011639static hda_nid_t alc269_capsrc_nids[1] = {
11640 0x23,
11641};
11642
11643/* NOTE: ADC2 (0x07) is connected from a recording *MIXER* (0x24),
11644 * not a mux!
11645 */
11646
Kailang Yangf53281e2008-07-18 12:36:43 +020011647static struct hda_input_mux alc269_eeepc_dmic_capture_source = {
11648 .num_items = 2,
11649 .items = {
11650 { "i-Mic", 0x5 },
11651 { "e-Mic", 0x0 },
11652 },
11653};
11654
11655static struct hda_input_mux alc269_eeepc_amic_capture_source = {
11656 .num_items = 2,
11657 .items = {
11658 { "i-Mic", 0x1 },
11659 { "e-Mic", 0x0 },
11660 },
Kailang Yangf6a92242007-12-13 16:52:54 +010011661};
11662
11663#define alc269_modes alc260_modes
11664#define alc269_capture_source alc880_lg_lw_capture_source
11665
11666static struct snd_kcontrol_new alc269_base_mixer[] = {
11667 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
11668 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11669 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11670 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11671 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11672 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai2005af22008-08-20 18:38:26 +020011673 HDA_CODEC_VOLUME("Beep Playback Volume", 0x0b, 0x4, HDA_INPUT),
11674 HDA_CODEC_MUTE("Beep Playback Switch", 0x0b, 0x4, HDA_INPUT),
Kailang Yangf6a92242007-12-13 16:52:54 +010011675 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11676 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11677 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11678 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
11679 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11680 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
11681 { } /* end */
11682};
11683
Kailang Yang60db6b52008-08-26 13:13:00 +020011684static struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = {
11685 /* output mixer control */
11686 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
11687 {
11688 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11689 .name = "Master Playback Switch",
11690 .info = snd_hda_mixer_amp_switch_info,
11691 .get = snd_hda_mixer_amp_switch_get,
11692 .put = alc268_acer_master_sw_put,
11693 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
11694 },
11695 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11696 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11697 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11698 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11699 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11700 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
11701 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x04, HDA_INPUT),
11702 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x04, HDA_INPUT),
11703 { }
11704};
11705
Kailang Yangf53281e2008-07-18 12:36:43 +020011706/* bind volumes of both NID 0x0c and 0x0d */
11707static struct hda_bind_ctls alc269_epc_bind_vol = {
11708 .ops = &snd_hda_bind_vol,
11709 .values = {
11710 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
11711 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
11712 0
11713 },
11714};
11715
11716static struct snd_kcontrol_new alc269_eeepc_mixer[] = {
11717 HDA_CODEC_MUTE("iSpeaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11718 HDA_BIND_VOL("LineOut Playback Volume", &alc269_epc_bind_vol),
11719 HDA_CODEC_MUTE("LineOut Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11720 { } /* end */
11721};
11722
Kailang Yangf6a92242007-12-13 16:52:54 +010011723/* capture mixer elements */
11724static struct snd_kcontrol_new alc269_capture_mixer[] = {
Kailang Yangf53281e2008-07-18 12:36:43 +020011725 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
11726 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
Kailang Yangf6a92242007-12-13 16:52:54 +010011727 {
11728 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11729 /* The multiple "Capture Source" controls confuse alsamixer
11730 * So call somewhat different..
Kailang Yangf6a92242007-12-13 16:52:54 +010011731 */
11732 /* .name = "Capture Source", */
11733 .name = "Input Source",
11734 .count = 1,
11735 .info = alc_mux_enum_info,
11736 .get = alc_mux_enum_get,
11737 .put = alc_mux_enum_put,
11738 },
11739 { } /* end */
11740};
11741
Kailang Yangf53281e2008-07-18 12:36:43 +020011742/* capture mixer elements */
11743static struct snd_kcontrol_new alc269_epc_capture_mixer[] = {
11744 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
11745 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
11746 { } /* end */
11747};
11748
Takashi Iwai2005af22008-08-20 18:38:26 +020011749/* beep control */
11750static struct snd_kcontrol_new alc269_beep_mixer[] = {
11751 HDA_CODEC_VOLUME("Beep Playback Volume", 0x0b, 0x4, HDA_INPUT),
11752 HDA_CODEC_MUTE("Beep Playback Switch", 0x0b, 0x4, HDA_INPUT),
11753 { } /* end */
11754};
11755
Kailang Yang60db6b52008-08-26 13:13:00 +020011756static struct hda_verb alc269_quanta_fl1_verbs[] = {
11757 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
11758 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11759 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11760 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
11761 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
11762 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11763 { }
11764};
11765
11766/* toggle speaker-output according to the hp-jack state */
11767static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec)
11768{
11769 unsigned int present;
11770 unsigned char bits;
11771
11772 present = snd_hda_codec_read(codec, 0x15, 0,
11773 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
11774 bits = present ? AMP_IN_MUTE(0) : 0;
11775 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
11776 AMP_IN_MUTE(0), bits);
11777 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
11778 AMP_IN_MUTE(0), bits);
11779
11780 snd_hda_codec_write(codec, 0x20, 0,
11781 AC_VERB_SET_COEF_INDEX, 0x0c);
11782 snd_hda_codec_write(codec, 0x20, 0,
11783 AC_VERB_SET_PROC_COEF, 0x680);
11784
11785 snd_hda_codec_write(codec, 0x20, 0,
11786 AC_VERB_SET_COEF_INDEX, 0x0c);
11787 snd_hda_codec_write(codec, 0x20, 0,
11788 AC_VERB_SET_PROC_COEF, 0x480);
11789}
11790
11791static void alc269_quanta_fl1_mic_automute(struct hda_codec *codec)
11792{
11793 unsigned int present;
11794
11795 present = snd_hda_codec_read(codec, 0x18, 0,
11796 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
11797 snd_hda_codec_write(codec, 0x23, 0,
11798 AC_VERB_SET_CONNECT_SEL, present ? 0x0 : 0x1);
11799}
11800
11801static void alc269_quanta_fl1_unsol_event(struct hda_codec *codec,
11802 unsigned int res)
11803{
11804 if ((res >> 26) == ALC880_HP_EVENT)
11805 alc269_quanta_fl1_speaker_automute(codec);
11806 if ((res >> 26) == ALC880_MIC_EVENT)
11807 alc269_quanta_fl1_mic_automute(codec);
11808}
11809
11810static void alc269_quanta_fl1_init_hook(struct hda_codec *codec)
11811{
11812 alc269_quanta_fl1_speaker_automute(codec);
11813 alc269_quanta_fl1_mic_automute(codec);
11814}
11815
11816static struct hda_verb alc269_eeepc_dmic_init_verbs[] = {
11817 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
11818 {0x23, AC_VERB_SET_CONNECT_SEL, 0x05},
11819 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
11820 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
11821 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11822 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
11823 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11824 {}
11825};
11826
11827static struct hda_verb alc269_eeepc_amic_init_verbs[] = {
11828 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
11829 {0x23, AC_VERB_SET_CONNECT_SEL, 0x01},
11830 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
11831 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x701b | (0x00 << 8))},
11832 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
11833 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11834 {}
11835};
11836
11837/* toggle speaker-output according to the hp-jack state */
11838static void alc269_speaker_automute(struct hda_codec *codec)
11839{
11840 unsigned int present;
11841 unsigned char bits;
11842
11843 present = snd_hda_codec_read(codec, 0x15, 0,
11844 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
11845 bits = present ? AMP_IN_MUTE(0) : 0;
11846 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
11847 AMP_IN_MUTE(0), bits);
11848 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
11849 AMP_IN_MUTE(0), bits);
11850}
11851
11852static void alc269_eeepc_dmic_automute(struct hda_codec *codec)
11853{
11854 unsigned int present;
11855
11856 present = snd_hda_codec_read(codec, 0x18, 0,
11857 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
11858 snd_hda_codec_write(codec, 0x23, 0,
11859 AC_VERB_SET_CONNECT_SEL, (present ? 0 : 5));
11860}
11861
11862static void alc269_eeepc_amic_automute(struct hda_codec *codec)
11863{
11864 unsigned int present;
11865
11866 present = snd_hda_codec_read(codec, 0x18, 0,
11867 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
11868 snd_hda_codec_write(codec, 0x24, 0, AC_VERB_SET_AMP_GAIN_MUTE,
11869 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
11870 snd_hda_codec_write(codec, 0x24, 0, AC_VERB_SET_AMP_GAIN_MUTE,
11871 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
11872}
11873
11874/* unsolicited event for HP jack sensing */
11875static void alc269_eeepc_dmic_unsol_event(struct hda_codec *codec,
11876 unsigned int res)
11877{
11878 if ((res >> 26) == ALC880_HP_EVENT)
11879 alc269_speaker_automute(codec);
11880
11881 if ((res >> 26) == ALC880_MIC_EVENT)
11882 alc269_eeepc_dmic_automute(codec);
11883}
11884
11885static void alc269_eeepc_dmic_inithook(struct hda_codec *codec)
11886{
11887 alc269_speaker_automute(codec);
11888 alc269_eeepc_dmic_automute(codec);
11889}
11890
11891/* unsolicited event for HP jack sensing */
11892static void alc269_eeepc_amic_unsol_event(struct hda_codec *codec,
11893 unsigned int res)
11894{
11895 if ((res >> 26) == ALC880_HP_EVENT)
11896 alc269_speaker_automute(codec);
11897
11898 if ((res >> 26) == ALC880_MIC_EVENT)
11899 alc269_eeepc_amic_automute(codec);
11900}
11901
11902static void alc269_eeepc_amic_inithook(struct hda_codec *codec)
11903{
11904 alc269_speaker_automute(codec);
11905 alc269_eeepc_amic_automute(codec);
11906}
11907
Kailang Yangf6a92242007-12-13 16:52:54 +010011908/*
11909 * generic initialization of ADC, input mixers and output mixers
11910 */
11911static struct hda_verb alc269_init_verbs[] = {
11912 /*
11913 * Unmute ADC0 and set the default input to mic-in
11914 */
Kailang Yang60db6b52008-08-26 13:13:00 +020011915 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangf6a92242007-12-13 16:52:54 +010011916
11917 /* Mute input amps (PCBeep, Line In, Mic 1 & Mic 2) of the
11918 * analog-loopback mixer widget
11919 * Note: PASD motherboards uses the Line In 2 as the input for
11920 * front panel mic (mic 2)
11921 */
11922 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
11923 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11924 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11925 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
11926 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
11927 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
11928
11929 /*
11930 * Set up output mixers (0x0c - 0x0e)
11931 */
11932 /* set vol=0 to output mixers */
11933 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11934 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11935
11936 /* set up input amps for analog loopback */
11937 /* Amp Indices: DAC = 0, mixer = 1 */
11938 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11939 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11940 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11941 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11942 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11943 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11944
11945 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11946 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11947 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11948 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
11949 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
11950 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11951 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11952
11953 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11954 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11955 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11956 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11957 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11958 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11959 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11960
11961 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
11962 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11963
11964 /* FIXME: use matrix-type input source selection */
11965 /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
11966 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yang60db6b52008-08-26 13:13:00 +020011967 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11968 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangf6a92242007-12-13 16:52:54 +010011969 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
11970 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
11971
11972 /* set EAPD */
11973 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
11974 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
11975 { }
11976};
11977
11978/* add playback controls from the parsed DAC table */
11979static int alc269_auto_create_multi_out_ctls(struct alc_spec *spec,
11980 const struct auto_pin_cfg *cfg)
11981{
11982 hda_nid_t nid;
11983 int err;
11984
11985 spec->multiout.num_dacs = 1; /* only use one dac */
11986 spec->multiout.dac_nids = spec->private_dac_nids;
11987 spec->multiout.dac_nids[0] = 2;
11988
11989 nid = cfg->line_out_pins[0];
11990 if (nid) {
11991 err = add_control(spec, ALC_CTL_WIDGET_VOL,
11992 "Front Playback Volume",
11993 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT));
11994 if (err < 0)
11995 return err;
11996 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
11997 "Front Playback Switch",
11998 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
11999 if (err < 0)
12000 return err;
12001 }
12002
12003 nid = cfg->speaker_pins[0];
12004 if (nid) {
12005 if (!cfg->line_out_pins[0]) {
12006 err = add_control(spec, ALC_CTL_WIDGET_VOL,
12007 "Speaker Playback Volume",
12008 HDA_COMPOSE_AMP_VAL(0x02, 3, 0,
12009 HDA_OUTPUT));
12010 if (err < 0)
12011 return err;
12012 }
12013 if (nid == 0x16) {
12014 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
12015 "Speaker Playback Switch",
12016 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
12017 HDA_OUTPUT));
12018 if (err < 0)
12019 return err;
12020 } else {
12021 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
12022 "Speaker Playback Switch",
12023 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
12024 HDA_OUTPUT));
12025 if (err < 0)
12026 return err;
12027 }
12028 }
12029 nid = cfg->hp_pins[0];
12030 if (nid) {
12031 /* spec->multiout.hp_nid = 2; */
12032 if (!cfg->line_out_pins[0] && !cfg->speaker_pins[0]) {
12033 err = add_control(spec, ALC_CTL_WIDGET_VOL,
12034 "Headphone Playback Volume",
12035 HDA_COMPOSE_AMP_VAL(0x02, 3, 0,
12036 HDA_OUTPUT));
12037 if (err < 0)
12038 return err;
12039 }
12040 if (nid == 0x16) {
12041 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
12042 "Headphone Playback Switch",
12043 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
12044 HDA_OUTPUT));
12045 if (err < 0)
12046 return err;
12047 } else {
12048 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
12049 "Headphone Playback Switch",
12050 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
12051 HDA_OUTPUT));
12052 if (err < 0)
12053 return err;
12054 }
12055 }
12056 return 0;
12057}
12058
12059#define alc269_auto_create_analog_input_ctls \
12060 alc880_auto_create_analog_input_ctls
12061
12062#ifdef CONFIG_SND_HDA_POWER_SAVE
12063#define alc269_loopbacks alc880_loopbacks
12064#endif
12065
12066/* pcm configuration: identiacal with ALC880 */
12067#define alc269_pcm_analog_playback alc880_pcm_analog_playback
12068#define alc269_pcm_analog_capture alc880_pcm_analog_capture
12069#define alc269_pcm_digital_playback alc880_pcm_digital_playback
12070#define alc269_pcm_digital_capture alc880_pcm_digital_capture
12071
12072/*
12073 * BIOS auto configuration
12074 */
12075static int alc269_parse_auto_config(struct hda_codec *codec)
12076{
12077 struct alc_spec *spec = codec->spec;
Takashi Iwai2005af22008-08-20 18:38:26 +020012078 int i, err;
Kailang Yangf6a92242007-12-13 16:52:54 +010012079 static hda_nid_t alc269_ignore[] = { 0x1d, 0 };
12080
12081 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
12082 alc269_ignore);
12083 if (err < 0)
12084 return err;
12085
12086 err = alc269_auto_create_multi_out_ctls(spec, &spec->autocfg);
12087 if (err < 0)
12088 return err;
12089 err = alc269_auto_create_analog_input_ctls(spec, &spec->autocfg);
12090 if (err < 0)
12091 return err;
12092
12093 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
12094
12095 if (spec->autocfg.dig_out_pin)
12096 spec->multiout.dig_out_nid = ALC269_DIGOUT_NID;
12097
12098 if (spec->kctl_alloc)
12099 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
12100
Takashi Iwai2005af22008-08-20 18:38:26 +020012101 /* create a beep mixer control if the pin 0x1d isn't assigned */
12102 for (i = 0; i < ARRAY_SIZE(spec->autocfg.input_pins); i++)
12103 if (spec->autocfg.input_pins[i] == 0x1d)
12104 break;
12105 if (i >= ARRAY_SIZE(spec->autocfg.input_pins))
12106 spec->mixers[spec->num_mixers++] = alc269_beep_mixer;
12107
Kailang Yangf6a92242007-12-13 16:52:54 +010012108 spec->init_verbs[spec->num_init_verbs++] = alc269_init_verbs;
12109 spec->num_mux_defs = 1;
12110 spec->input_mux = &spec->private_imux;
Takashi Iwaie01bf502008-08-21 16:25:07 +020012111 /* set default input source */
12112 snd_hda_codec_write_cache(codec, alc269_capsrc_nids[0],
12113 0, AC_VERB_SET_CONNECT_SEL,
12114 spec->input_mux->items[0].index);
Kailang Yangf6a92242007-12-13 16:52:54 +010012115
12116 err = alc_auto_add_mic_boost(codec);
12117 if (err < 0)
12118 return err;
12119
Kailang Yangf53281e2008-07-18 12:36:43 +020012120 spec->mixers[spec->num_mixers] = alc269_capture_mixer;
12121 spec->num_mixers++;
12122
Kailang Yangf6a92242007-12-13 16:52:54 +010012123 return 1;
12124}
12125
12126#define alc269_auto_init_multi_out alc882_auto_init_multi_out
12127#define alc269_auto_init_hp_out alc882_auto_init_hp_out
12128#define alc269_auto_init_analog_input alc882_auto_init_analog_input
12129
12130
12131/* init callback for auto-configuration model -- overriding the default init */
12132static void alc269_auto_init(struct hda_codec *codec)
12133{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012134 struct alc_spec *spec = codec->spec;
Kailang Yangf6a92242007-12-13 16:52:54 +010012135 alc269_auto_init_multi_out(codec);
12136 alc269_auto_init_hp_out(codec);
12137 alc269_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012138 if (spec->unsol_event)
12139 alc_sku_automute(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010012140}
12141
12142/*
12143 * configuration and preset
12144 */
12145static const char *alc269_models[ALC269_MODEL_LAST] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020012146 [ALC269_BASIC] = "basic",
12147 [ALC269_QUANTA_FL1] = "Quanta",
12148 [ALC269_ASUS_EEEPC_P901] = "Asus_Epc_Dmic"
Kailang Yangf6a92242007-12-13 16:52:54 +010012149};
12150
12151static struct snd_pci_quirk alc269_cfg_tbl[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020012152 SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_QUANTA_FL1),
Kailang Yangf53281e2008-07-18 12:36:43 +020012153 SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A",
12154 ALC269_ASUS_EEEPC_P703),
12155 SND_PCI_QUIRK(0x1043, 0x831a, "ASUS Eeepc P901",
12156 ALC269_ASUS_EEEPC_P901),
Kailang Yang60db6b52008-08-26 13:13:00 +020012157 SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101",
12158 ALC269_ASUS_EEEPC_P901),
Kailang Yangf6a92242007-12-13 16:52:54 +010012159 {}
12160};
12161
12162static struct alc_config_preset alc269_presets[] = {
12163 [ALC269_BASIC] = {
Kailang Yangf53281e2008-07-18 12:36:43 +020012164 .mixers = { alc269_base_mixer, alc269_capture_mixer },
Kailang Yangf6a92242007-12-13 16:52:54 +010012165 .init_verbs = { alc269_init_verbs },
12166 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
12167 .dac_nids = alc269_dac_nids,
12168 .hp_nid = 0x03,
12169 .num_channel_mode = ARRAY_SIZE(alc269_modes),
12170 .channel_mode = alc269_modes,
12171 .input_mux = &alc269_capture_source,
12172 },
Kailang Yang60db6b52008-08-26 13:13:00 +020012173 [ALC269_QUANTA_FL1] = {
12174 .mixers = { alc269_quanta_fl1_mixer },
12175 .init_verbs = { alc269_init_verbs, alc269_quanta_fl1_verbs },
12176 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
12177 .dac_nids = alc269_dac_nids,
12178 .hp_nid = 0x03,
12179 .num_channel_mode = ARRAY_SIZE(alc269_modes),
12180 .channel_mode = alc269_modes,
12181 .input_mux = &alc269_capture_source,
12182 .unsol_event = alc269_quanta_fl1_unsol_event,
12183 .init_hook = alc269_quanta_fl1_init_hook,
12184 },
Kailang Yangf53281e2008-07-18 12:36:43 +020012185 [ALC269_ASUS_EEEPC_P703] = {
12186 .mixers = { alc269_eeepc_mixer, alc269_epc_capture_mixer },
12187 .init_verbs = { alc269_init_verbs,
12188 alc269_eeepc_amic_init_verbs },
12189 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
12190 .dac_nids = alc269_dac_nids,
12191 .hp_nid = 0x03,
12192 .num_channel_mode = ARRAY_SIZE(alc269_modes),
12193 .channel_mode = alc269_modes,
12194 .input_mux = &alc269_eeepc_amic_capture_source,
12195 .unsol_event = alc269_eeepc_amic_unsol_event,
12196 .init_hook = alc269_eeepc_amic_inithook,
12197 },
12198 [ALC269_ASUS_EEEPC_P901] = {
12199 .mixers = { alc269_eeepc_mixer, alc269_epc_capture_mixer},
12200 .init_verbs = { alc269_init_verbs,
12201 alc269_eeepc_dmic_init_verbs },
12202 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
12203 .dac_nids = alc269_dac_nids,
12204 .hp_nid = 0x03,
12205 .num_channel_mode = ARRAY_SIZE(alc269_modes),
12206 .channel_mode = alc269_modes,
12207 .input_mux = &alc269_eeepc_dmic_capture_source,
12208 .unsol_event = alc269_eeepc_dmic_unsol_event,
12209 .init_hook = alc269_eeepc_dmic_inithook,
12210 },
Kailang Yangf6a92242007-12-13 16:52:54 +010012211};
12212
12213static int patch_alc269(struct hda_codec *codec)
12214{
12215 struct alc_spec *spec;
12216 int board_config;
12217 int err;
12218
12219 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
12220 if (spec == NULL)
12221 return -ENOMEM;
12222
12223 codec->spec = spec;
12224
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020012225 alc_fix_pll_init(codec, 0x20, 0x04, 15);
12226
Kailang Yangf6a92242007-12-13 16:52:54 +010012227 board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST,
12228 alc269_models,
12229 alc269_cfg_tbl);
12230
12231 if (board_config < 0) {
12232 printk(KERN_INFO "hda_codec: Unknown model for ALC269, "
12233 "trying auto-probe from BIOS...\n");
12234 board_config = ALC269_AUTO;
12235 }
12236
12237 if (board_config == ALC269_AUTO) {
12238 /* automatic parse from the BIOS config */
12239 err = alc269_parse_auto_config(codec);
12240 if (err < 0) {
12241 alc_free(codec);
12242 return err;
12243 } else if (!err) {
12244 printk(KERN_INFO
12245 "hda_codec: Cannot set up configuration "
12246 "from BIOS. Using base mode...\n");
12247 board_config = ALC269_BASIC;
12248 }
12249 }
12250
12251 if (board_config != ALC269_AUTO)
12252 setup_preset(spec, &alc269_presets[board_config]);
12253
12254 spec->stream_name_analog = "ALC269 Analog";
12255 spec->stream_analog_playback = &alc269_pcm_analog_playback;
12256 spec->stream_analog_capture = &alc269_pcm_analog_capture;
12257
12258 spec->stream_name_digital = "ALC269 Digital";
12259 spec->stream_digital_playback = &alc269_pcm_digital_playback;
12260 spec->stream_digital_capture = &alc269_pcm_digital_capture;
12261
12262 spec->adc_nids = alc269_adc_nids;
12263 spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids);
Takashi Iwaie01bf502008-08-21 16:25:07 +020012264 spec->capsrc_nids = alc269_capsrc_nids;
Kailang Yangf6a92242007-12-13 16:52:54 +010012265
12266 codec->patch_ops = alc_patch_ops;
12267 if (board_config == ALC269_AUTO)
12268 spec->init_hook = alc269_auto_init;
12269#ifdef CONFIG_SND_HDA_POWER_SAVE
12270 if (!spec->loopback.amplist)
12271 spec->loopback.amplist = alc269_loopbacks;
12272#endif
12273
12274 return 0;
12275}
12276
12277/*
Kailang Yangdf694da2005-12-05 19:42:22 +010012278 * ALC861 channel source setting (2/6 channel selection for 3-stack)
12279 */
12280
12281/*
12282 * set the path ways for 2 channel output
12283 * need to set the codec line out and mic 1 pin widgets to inputs
12284 */
12285static struct hda_verb alc861_threestack_ch2_init[] = {
12286 /* set pin widget 1Ah (line in) for input */
12287 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012288 /* set pin widget 18h (mic1/2) for input, for mic also enable
12289 * the vref
12290 */
Kailang Yangdf694da2005-12-05 19:42:22 +010012291 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12292
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012293 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
12294#if 0
12295 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
12296 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
12297#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010012298 { } /* end */
12299};
12300/*
12301 * 6ch mode
12302 * need to set the codec line out and mic 1 pin widgets to outputs
12303 */
12304static struct hda_verb alc861_threestack_ch6_init[] = {
12305 /* set pin widget 1Ah (line in) for output (Back Surround)*/
12306 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12307 /* set pin widget 18h (mic1) for output (CLFE)*/
12308 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12309
12310 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012311 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010012312
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012313 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
12314#if 0
12315 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
12316 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
12317#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010012318 { } /* end */
12319};
12320
12321static struct hda_channel_mode alc861_threestack_modes[2] = {
12322 { 2, alc861_threestack_ch2_init },
12323 { 6, alc861_threestack_ch6_init },
12324};
Takashi Iwai22309c32006-08-09 16:57:28 +020012325/* Set mic1 as input and unmute the mixer */
12326static struct hda_verb alc861_uniwill_m31_ch2_init[] = {
12327 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12328 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
12329 { } /* end */
12330};
12331/* Set mic1 as output and mute mixer */
12332static struct hda_verb alc861_uniwill_m31_ch4_init[] = {
12333 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12334 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
12335 { } /* end */
12336};
12337
12338static struct hda_channel_mode alc861_uniwill_m31_modes[2] = {
12339 { 2, alc861_uniwill_m31_ch2_init },
12340 { 4, alc861_uniwill_m31_ch4_init },
12341};
Kailang Yangdf694da2005-12-05 19:42:22 +010012342
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012343/* Set mic1 and line-in as input and unmute the mixer */
12344static struct hda_verb alc861_asus_ch2_init[] = {
12345 /* set pin widget 1Ah (line in) for input */
12346 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012347 /* set pin widget 18h (mic1/2) for input, for mic also enable
12348 * the vref
12349 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012350 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12351
12352 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
12353#if 0
12354 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
12355 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
12356#endif
12357 { } /* end */
12358};
12359/* Set mic1 nad line-in as output and mute mixer */
12360static struct hda_verb alc861_asus_ch6_init[] = {
12361 /* set pin widget 1Ah (line in) for output (Back Surround)*/
12362 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12363 /* { 0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
12364 /* set pin widget 18h (mic1) for output (CLFE)*/
12365 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12366 /* { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
12367 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
12368 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
12369
12370 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
12371#if 0
12372 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
12373 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
12374#endif
12375 { } /* end */
12376};
12377
12378static struct hda_channel_mode alc861_asus_modes[2] = {
12379 { 2, alc861_asus_ch2_init },
12380 { 6, alc861_asus_ch6_init },
12381};
12382
Kailang Yangdf694da2005-12-05 19:42:22 +010012383/* patch-ALC861 */
12384
12385static struct snd_kcontrol_new alc861_base_mixer[] = {
12386 /* output mixer control */
12387 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
12388 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
12389 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
12390 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
12391 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
12392
12393 /*Input mixer control */
12394 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
12395 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
12396 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
12397 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
12398 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
12399 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
12400 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
12401 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
12402 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
12403 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012404
Kailang Yangdf694da2005-12-05 19:42:22 +010012405 /* Capture mixer control */
12406 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
12407 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
12408 {
12409 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12410 .name = "Capture Source",
12411 .count = 1,
12412 .info = alc_mux_enum_info,
12413 .get = alc_mux_enum_get,
12414 .put = alc_mux_enum_put,
12415 },
12416 { } /* end */
12417};
12418
12419static struct snd_kcontrol_new alc861_3ST_mixer[] = {
12420 /* output mixer control */
12421 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
12422 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
12423 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
12424 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
12425 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
12426
12427 /* Input mixer control */
12428 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
12429 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
12430 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
12431 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
12432 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
12433 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
12434 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
12435 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
12436 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
12437 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012438
Kailang Yangdf694da2005-12-05 19:42:22 +010012439 /* Capture mixer control */
12440 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
12441 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
12442 {
12443 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12444 .name = "Capture Source",
12445 .count = 1,
12446 .info = alc_mux_enum_info,
12447 .get = alc_mux_enum_get,
12448 .put = alc_mux_enum_put,
12449 },
12450 {
12451 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12452 .name = "Channel Mode",
12453 .info = alc_ch_mode_info,
12454 .get = alc_ch_mode_get,
12455 .put = alc_ch_mode_put,
12456 .private_value = ARRAY_SIZE(alc861_threestack_modes),
12457 },
12458 { } /* end */
Tobin Davisa53d1ae2006-10-17 12:00:28 +020012459};
12460
Takashi Iwaid1d985f2006-11-23 19:27:12 +010012461static struct snd_kcontrol_new alc861_toshiba_mixer[] = {
Tobin Davisa53d1ae2006-10-17 12:00:28 +020012462 /* output mixer control */
12463 HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT),
12464 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
12465 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
Kailang Yangea1fb292008-08-26 12:58:38 +020012466
Tobin Davisa53d1ae2006-10-17 12:00:28 +020012467 /*Capture mixer control */
12468 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
12469 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
12470 {
12471 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12472 .name = "Capture Source",
12473 .count = 1,
12474 .info = alc_mux_enum_info,
12475 .get = alc_mux_enum_get,
12476 .put = alc_mux_enum_put,
12477 },
12478
12479 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012480};
Tobin Davisa53d1ae2006-10-17 12:00:28 +020012481
Takashi Iwai22309c32006-08-09 16:57:28 +020012482static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = {
12483 /* output mixer control */
12484 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
12485 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
12486 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
12487 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
12488 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
12489
12490 /* Input mixer control */
12491 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
12492 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
12493 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
12494 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
12495 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
12496 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
12497 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
12498 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
12499 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
12500 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012501
Takashi Iwai22309c32006-08-09 16:57:28 +020012502 /* Capture mixer control */
12503 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
12504 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
12505 {
12506 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12507 .name = "Capture Source",
12508 .count = 1,
12509 .info = alc_mux_enum_info,
12510 .get = alc_mux_enum_get,
12511 .put = alc_mux_enum_put,
12512 },
12513 {
12514 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12515 .name = "Channel Mode",
12516 .info = alc_ch_mode_info,
12517 .get = alc_ch_mode_get,
12518 .put = alc_ch_mode_put,
12519 .private_value = ARRAY_SIZE(alc861_uniwill_m31_modes),
12520 },
12521 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012522};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012523
12524static struct snd_kcontrol_new alc861_asus_mixer[] = {
12525 /* output mixer control */
12526 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
12527 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
12528 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
12529 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
12530 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
12531
12532 /* Input mixer control */
12533 HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
12534 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT),
12535 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
12536 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
12537 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
12538 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
12539 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
12540 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
12541 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012542 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_OUTPUT),
12543
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012544 /* Capture mixer control */
12545 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
12546 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
12547 {
12548 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12549 .name = "Capture Source",
12550 .count = 1,
12551 .info = alc_mux_enum_info,
12552 .get = alc_mux_enum_get,
12553 .put = alc_mux_enum_put,
12554 },
12555 {
12556 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12557 .name = "Channel Mode",
12558 .info = alc_ch_mode_info,
12559 .get = alc_ch_mode_get,
12560 .put = alc_ch_mode_put,
12561 .private_value = ARRAY_SIZE(alc861_asus_modes),
12562 },
12563 { }
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010012564};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012565
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010012566/* additional mixer */
Takashi Iwaid1d985f2006-11-23 19:27:12 +010012567static struct snd_kcontrol_new alc861_asus_laptop_mixer[] = {
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010012568 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
12569 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
12570 HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x23, 0x0, HDA_OUTPUT),
12571 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x23, 0x0, HDA_OUTPUT),
12572 { }
12573};
12574
Kailang Yangdf694da2005-12-05 19:42:22 +010012575/*
12576 * generic initialization of ADC, input mixers and output mixers
12577 */
12578static struct hda_verb alc861_base_init_verbs[] = {
12579 /*
12580 * Unmute ADC0 and set the default input to mic-in
12581 */
12582 /* port-A for surround (rear panel) */
12583 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12584 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x00 },
12585 /* port-B for mic-in (rear panel) with vref */
12586 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12587 /* port-C for line-in (rear panel) */
12588 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
12589 /* port-D for Front */
12590 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12591 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
12592 /* port-E for HP out (front panel) */
12593 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
12594 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010012595 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010012596 /* port-F for mic-in (front panel) with vref */
12597 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12598 /* port-G for CLFE (rear panel) */
12599 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12600 { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x00 },
12601 /* port-H for side (rear panel) */
12602 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12603 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x00 },
12604 /* CD-in */
12605 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
12606 /* route front mic to ADC1*/
12607 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
12608 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020012609
Kailang Yangdf694da2005-12-05 19:42:22 +010012610 /* Unmute DAC0~3 & spdif out*/
12611 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12612 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12613 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12614 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12615 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020012616
Kailang Yangdf694da2005-12-05 19:42:22 +010012617 /* Unmute Mixer 14 (mic) 1c (Line in)*/
12618 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12619 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12620 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12621 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020012622
Kailang Yangdf694da2005-12-05 19:42:22 +010012623 /* Unmute Stereo Mixer 15 */
12624 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12625 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12626 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012627 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010012628
12629 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12630 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12631 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12632 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12633 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12634 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12635 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12636 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012637 /* hp used DAC 3 (Front) */
12638 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010012639 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
12640
12641 { }
12642};
12643
12644static struct hda_verb alc861_threestack_init_verbs[] = {
12645 /*
12646 * Unmute ADC0 and set the default input to mic-in
12647 */
12648 /* port-A for surround (rear panel) */
12649 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
12650 /* port-B for mic-in (rear panel) with vref */
12651 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12652 /* port-C for line-in (rear panel) */
12653 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
12654 /* port-D for Front */
12655 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12656 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
12657 /* port-E for HP out (front panel) */
12658 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
12659 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010012660 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010012661 /* port-F for mic-in (front panel) with vref */
12662 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12663 /* port-G for CLFE (rear panel) */
12664 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
12665 /* port-H for side (rear panel) */
12666 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
12667 /* CD-in */
12668 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
12669 /* route front mic to ADC1*/
12670 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
12671 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12672 /* Unmute DAC0~3 & spdif out*/
12673 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12674 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12675 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12676 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12677 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020012678
Kailang Yangdf694da2005-12-05 19:42:22 +010012679 /* Unmute Mixer 14 (mic) 1c (Line in)*/
12680 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12681 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12682 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12683 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020012684
Kailang Yangdf694da2005-12-05 19:42:22 +010012685 /* Unmute Stereo Mixer 15 */
12686 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12687 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12688 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012689 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010012690
12691 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12692 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12693 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12694 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12695 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12696 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12697 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12698 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012699 /* hp used DAC 3 (Front) */
12700 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010012701 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
12702 { }
12703};
Takashi Iwai22309c32006-08-09 16:57:28 +020012704
12705static struct hda_verb alc861_uniwill_m31_init_verbs[] = {
12706 /*
12707 * Unmute ADC0 and set the default input to mic-in
12708 */
12709 /* port-A for surround (rear panel) */
12710 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
12711 /* port-B for mic-in (rear panel) with vref */
12712 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12713 /* port-C for line-in (rear panel) */
12714 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
12715 /* port-D for Front */
12716 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12717 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
12718 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012719 /* this has to be set to VREF80 */
12720 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Takashi Iwai22309c32006-08-09 16:57:28 +020012721 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010012722 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai22309c32006-08-09 16:57:28 +020012723 /* port-F for mic-in (front panel) with vref */
12724 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12725 /* port-G for CLFE (rear panel) */
12726 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
12727 /* port-H for side (rear panel) */
12728 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
12729 /* CD-in */
12730 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
12731 /* route front mic to ADC1*/
12732 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
12733 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12734 /* Unmute DAC0~3 & spdif out*/
12735 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12736 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12737 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12738 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12739 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020012740
Takashi Iwai22309c32006-08-09 16:57:28 +020012741 /* Unmute Mixer 14 (mic) 1c (Line in)*/
12742 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12743 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12744 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12745 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020012746
Takashi Iwai22309c32006-08-09 16:57:28 +020012747 /* Unmute Stereo Mixer 15 */
12748 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12749 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12750 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012751 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Takashi Iwai22309c32006-08-09 16:57:28 +020012752
12753 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12754 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12755 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12756 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12757 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12758 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12759 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12760 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012761 /* hp used DAC 3 (Front) */
12762 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Takashi Iwai22309c32006-08-09 16:57:28 +020012763 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
12764 { }
12765};
12766
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012767static struct hda_verb alc861_asus_init_verbs[] = {
12768 /*
12769 * Unmute ADC0 and set the default input to mic-in
12770 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012771 /* port-A for surround (rear panel)
12772 * according to codec#0 this is the HP jack
12773 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012774 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* was 0x00 */
12775 /* route front PCM to HP */
12776 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x01 },
12777 /* port-B for mic-in (rear panel) with vref */
12778 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12779 /* port-C for line-in (rear panel) */
12780 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
12781 /* port-D for Front */
12782 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12783 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
12784 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012785 /* this has to be set to VREF80 */
12786 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012787 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010012788 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012789 /* port-F for mic-in (front panel) with vref */
12790 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12791 /* port-G for CLFE (rear panel) */
12792 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12793 /* port-H for side (rear panel) */
12794 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12795 /* CD-in */
12796 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
12797 /* route front mic to ADC1*/
12798 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
12799 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12800 /* Unmute DAC0~3 & spdif out*/
12801 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12802 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12803 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12804 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12805 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12806 /* Unmute Mixer 14 (mic) 1c (Line in)*/
12807 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12808 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12809 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12810 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020012811
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012812 /* Unmute Stereo Mixer 15 */
12813 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12814 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12815 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012816 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012817
12818 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12819 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12820 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12821 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12822 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12823 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12824 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12825 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012826 /* hp used DAC 3 (Front) */
12827 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012828 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
12829 { }
12830};
12831
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010012832/* additional init verbs for ASUS laptops */
12833static struct hda_verb alc861_asus_laptop_init_verbs[] = {
12834 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x45 }, /* HP-out */
12835 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2) }, /* mute line-in */
12836 { }
12837};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012838
Kailang Yangdf694da2005-12-05 19:42:22 +010012839/*
12840 * generic initialization of ADC, input mixers and output mixers
12841 */
12842static struct hda_verb alc861_auto_init_verbs[] = {
12843 /*
12844 * Unmute ADC0 and set the default input to mic-in
12845 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012846 /* {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, */
Kailang Yangdf694da2005-12-05 19:42:22 +010012847 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020012848
Kailang Yangdf694da2005-12-05 19:42:22 +010012849 /* Unmute DAC0~3 & spdif out*/
12850 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12851 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12852 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12853 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12854 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020012855
Kailang Yangdf694da2005-12-05 19:42:22 +010012856 /* Unmute Mixer 14 (mic) 1c (Line in)*/
12857 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12858 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12859 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12860 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020012861
Kailang Yangdf694da2005-12-05 19:42:22 +010012862 /* Unmute Stereo Mixer 15 */
12863 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12864 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12865 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
12866 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c},
12867
12868 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12869 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12870 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12871 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12872 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12873 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12874 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12875 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12876
12877 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12878 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012879 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
12880 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010012881 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12882 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012883 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
12884 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010012885
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012886 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, /* set Mic 1 */
Kailang Yangdf694da2005-12-05 19:42:22 +010012887
12888 { }
12889};
12890
Tobin Davisa53d1ae2006-10-17 12:00:28 +020012891static struct hda_verb alc861_toshiba_init_verbs[] = {
12892 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012893
Tobin Davisa53d1ae2006-10-17 12:00:28 +020012894 { }
12895};
12896
12897/* toggle speaker-output according to the hp-jack state */
12898static void alc861_toshiba_automute(struct hda_codec *codec)
12899{
12900 unsigned int present;
12901
12902 present = snd_hda_codec_read(codec, 0x0f, 0,
12903 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020012904 snd_hda_codec_amp_stereo(codec, 0x16, HDA_INPUT, 0,
12905 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
12906 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_INPUT, 3,
12907 HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE);
Tobin Davisa53d1ae2006-10-17 12:00:28 +020012908}
12909
12910static void alc861_toshiba_unsol_event(struct hda_codec *codec,
12911 unsigned int res)
12912{
Tobin Davisa53d1ae2006-10-17 12:00:28 +020012913 if ((res >> 26) == ALC880_HP_EVENT)
12914 alc861_toshiba_automute(codec);
12915}
12916
Kailang Yangdf694da2005-12-05 19:42:22 +010012917/* pcm configuration: identiacal with ALC880 */
12918#define alc861_pcm_analog_playback alc880_pcm_analog_playback
12919#define alc861_pcm_analog_capture alc880_pcm_analog_capture
12920#define alc861_pcm_digital_playback alc880_pcm_digital_playback
12921#define alc861_pcm_digital_capture alc880_pcm_digital_capture
12922
12923
12924#define ALC861_DIGOUT_NID 0x07
12925
12926static struct hda_channel_mode alc861_8ch_modes[1] = {
12927 { 8, NULL }
12928};
12929
12930static hda_nid_t alc861_dac_nids[4] = {
12931 /* front, surround, clfe, side */
12932 0x03, 0x06, 0x05, 0x04
12933};
12934
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012935static hda_nid_t alc660_dac_nids[3] = {
12936 /* front, clfe, surround */
12937 0x03, 0x05, 0x06
12938};
12939
Kailang Yangdf694da2005-12-05 19:42:22 +010012940static hda_nid_t alc861_adc_nids[1] = {
12941 /* ADC0-2 */
12942 0x08,
12943};
12944
12945static struct hda_input_mux alc861_capture_source = {
12946 .num_items = 5,
12947 .items = {
12948 { "Mic", 0x0 },
12949 { "Front Mic", 0x3 },
12950 { "Line", 0x1 },
12951 { "CD", 0x4 },
12952 { "Mixer", 0x5 },
12953 },
12954};
12955
12956/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012957static int alc861_auto_fill_dac_nids(struct alc_spec *spec,
12958 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010012959{
12960 int i;
12961 hda_nid_t nid;
12962
12963 spec->multiout.dac_nids = spec->private_dac_nids;
12964 for (i = 0; i < cfg->line_outs; i++) {
12965 nid = cfg->line_out_pins[i];
12966 if (nid) {
12967 if (i >= ARRAY_SIZE(alc861_dac_nids))
12968 continue;
12969 spec->multiout.dac_nids[i] = alc861_dac_nids[i];
12970 }
12971 }
12972 spec->multiout.num_dacs = cfg->line_outs;
12973 return 0;
12974}
12975
12976/* add playback controls from the parsed DAC table */
12977static int alc861_auto_create_multi_out_ctls(struct alc_spec *spec,
12978 const struct auto_pin_cfg *cfg)
12979{
12980 char name[32];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012981 static const char *chname[4] = {
12982 "Front", "Surround", NULL /*CLFE*/, "Side"
12983 };
Kailang Yangdf694da2005-12-05 19:42:22 +010012984 hda_nid_t nid;
12985 int i, idx, err;
12986
12987 for (i = 0; i < cfg->line_outs; i++) {
12988 nid = spec->multiout.dac_nids[i];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012989 if (!nid)
Kailang Yangdf694da2005-12-05 19:42:22 +010012990 continue;
12991 if (nid == 0x05) {
12992 /* Center/LFE */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012993 err = add_control(spec, ALC_CTL_BIND_MUTE,
12994 "Center Playback Switch",
12995 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
12996 HDA_OUTPUT));
12997 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010012998 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012999 err = add_control(spec, ALC_CTL_BIND_MUTE,
13000 "LFE Playback Switch",
13001 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
13002 HDA_OUTPUT));
13003 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010013004 return err;
13005 } else {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013006 for (idx = 0; idx < ARRAY_SIZE(alc861_dac_nids) - 1;
13007 idx++)
Kailang Yangdf694da2005-12-05 19:42:22 +010013008 if (nid == alc861_dac_nids[idx])
13009 break;
13010 sprintf(name, "%s Playback Switch", chname[idx]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013011 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
13012 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
13013 HDA_OUTPUT));
13014 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010013015 return err;
13016 }
13017 }
13018 return 0;
13019}
13020
13021static int alc861_auto_create_hp_ctls(struct alc_spec *spec, hda_nid_t pin)
13022{
13023 int err;
13024 hda_nid_t nid;
13025
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013026 if (!pin)
Kailang Yangdf694da2005-12-05 19:42:22 +010013027 return 0;
13028
13029 if ((pin >= 0x0b && pin <= 0x10) || pin == 0x1f || pin == 0x20) {
13030 nid = 0x03;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013031 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
13032 "Headphone Playback Switch",
13033 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
13034 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010013035 return err;
13036 spec->multiout.hp_nid = nid;
13037 }
13038 return 0;
13039}
13040
13041/* create playback/capture controls for input pins */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013042static int alc861_auto_create_analog_input_ctls(struct alc_spec *spec,
13043 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010013044{
Kailang Yangdf694da2005-12-05 19:42:22 +010013045 struct hda_input_mux *imux = &spec->private_imux;
13046 int i, err, idx, idx1;
13047
13048 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013049 switch (cfg->input_pins[i]) {
Kailang Yangdf694da2005-12-05 19:42:22 +010013050 case 0x0c:
13051 idx1 = 1;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013052 idx = 2; /* Line In */
Kailang Yangdf694da2005-12-05 19:42:22 +010013053 break;
13054 case 0x0f:
13055 idx1 = 2;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013056 idx = 2; /* Line In */
Kailang Yangdf694da2005-12-05 19:42:22 +010013057 break;
13058 case 0x0d:
13059 idx1 = 0;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013060 idx = 1; /* Mic In */
Kailang Yangdf694da2005-12-05 19:42:22 +010013061 break;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013062 case 0x10:
Kailang Yangdf694da2005-12-05 19:42:22 +010013063 idx1 = 3;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013064 idx = 1; /* Mic In */
Kailang Yangdf694da2005-12-05 19:42:22 +010013065 break;
13066 case 0x11:
13067 idx1 = 4;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013068 idx = 0; /* CD */
Kailang Yangdf694da2005-12-05 19:42:22 +010013069 break;
13070 default:
13071 continue;
13072 }
13073
Takashi Iwai4a471b72005-12-07 13:56:29 +010013074 err = new_analog_input(spec, cfg->input_pins[i],
13075 auto_pin_cfg_labels[i], idx, 0x15);
Kailang Yangdf694da2005-12-05 19:42:22 +010013076 if (err < 0)
13077 return err;
13078
Takashi Iwai4a471b72005-12-07 13:56:29 +010013079 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
Kailang Yangdf694da2005-12-05 19:42:22 +010013080 imux->items[imux->num_items].index = idx1;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013081 imux->num_items++;
Kailang Yangdf694da2005-12-05 19:42:22 +010013082 }
13083 return 0;
13084}
13085
13086static struct snd_kcontrol_new alc861_capture_mixer[] = {
13087 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
13088 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
13089
13090 {
13091 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13092 /* The multiple "Capture Source" controls confuse alsamixer
13093 * So call somewhat different..
Kailang Yangdf694da2005-12-05 19:42:22 +010013094 */
13095 /* .name = "Capture Source", */
13096 .name = "Input Source",
13097 .count = 1,
13098 .info = alc_mux_enum_info,
13099 .get = alc_mux_enum_get,
13100 .put = alc_mux_enum_put,
13101 },
13102 { } /* end */
13103};
13104
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013105static void alc861_auto_set_output_and_unmute(struct hda_codec *codec,
13106 hda_nid_t nid,
Kailang Yangdf694da2005-12-05 19:42:22 +010013107 int pin_type, int dac_idx)
13108{
Jacek Luczak564c5be2008-05-03 18:41:23 +020013109 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
13110 pin_type);
13111 snd_hda_codec_write(codec, dac_idx, 0, AC_VERB_SET_AMP_GAIN_MUTE,
13112 AMP_OUT_UNMUTE);
Kailang Yangdf694da2005-12-05 19:42:22 +010013113}
13114
13115static void alc861_auto_init_multi_out(struct hda_codec *codec)
13116{
13117 struct alc_spec *spec = codec->spec;
13118 int i;
13119
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013120 alc_subsystem_id(codec, 0x0e, 0x0f, 0x0b);
Kailang Yangdf694da2005-12-05 19:42:22 +010013121 for (i = 0; i < spec->autocfg.line_outs; i++) {
13122 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020013123 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangdf694da2005-12-05 19:42:22 +010013124 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020013125 alc861_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013126 spec->multiout.dac_nids[i]);
Kailang Yangdf694da2005-12-05 19:42:22 +010013127 }
13128}
13129
13130static void alc861_auto_init_hp_out(struct hda_codec *codec)
13131{
13132 struct alc_spec *spec = codec->spec;
13133 hda_nid_t pin;
13134
Takashi Iwaieb06ed82006-09-20 17:10:27 +020013135 pin = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010013136 if (pin) /* connect to front */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013137 alc861_auto_set_output_and_unmute(codec, pin, PIN_HP,
13138 spec->multiout.dac_nids[0]);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013139 pin = spec->autocfg.speaker_pins[0];
13140 if (pin)
13141 alc861_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Kailang Yangdf694da2005-12-05 19:42:22 +010013142}
13143
13144static void alc861_auto_init_analog_input(struct hda_codec *codec)
13145{
13146 struct alc_spec *spec = codec->spec;
13147 int i;
13148
13149 for (i = 0; i < AUTO_PIN_LAST; i++) {
13150 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013151 if (nid >= 0x0c && nid <= 0x11) {
13152 snd_hda_codec_write(codec, nid, 0,
13153 AC_VERB_SET_PIN_WIDGET_CONTROL,
13154 i <= AUTO_PIN_FRONT_MIC ?
13155 PIN_VREF80 : PIN_IN);
Kailang Yangdf694da2005-12-05 19:42:22 +010013156 }
13157 }
13158}
13159
13160/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013161/* return 1 if successful, 0 if the proper config is not found,
13162 * or a negative error code
13163 */
Kailang Yangdf694da2005-12-05 19:42:22 +010013164static int alc861_parse_auto_config(struct hda_codec *codec)
13165{
13166 struct alc_spec *spec = codec->spec;
13167 int err;
13168 static hda_nid_t alc861_ignore[] = { 0x1d, 0 };
13169
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013170 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
13171 alc861_ignore);
13172 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010013173 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013174 if (!spec->autocfg.line_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +010013175 return 0; /* can't find valid BIOS pin config */
13176
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013177 err = alc861_auto_fill_dac_nids(spec, &spec->autocfg);
13178 if (err < 0)
13179 return err;
13180 err = alc861_auto_create_multi_out_ctls(spec, &spec->autocfg);
13181 if (err < 0)
13182 return err;
13183 err = alc861_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
13184 if (err < 0)
13185 return err;
13186 err = alc861_auto_create_analog_input_ctls(spec, &spec->autocfg);
13187 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010013188 return err;
13189
13190 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
13191
13192 if (spec->autocfg.dig_out_pin)
13193 spec->multiout.dig_out_nid = ALC861_DIGOUT_NID;
13194
13195 if (spec->kctl_alloc)
13196 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
13197
13198 spec->init_verbs[spec->num_init_verbs++] = alc861_auto_init_verbs;
13199
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020013200 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +010013201 spec->input_mux = &spec->private_imux;
13202
13203 spec->adc_nids = alc861_adc_nids;
13204 spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids);
13205 spec->mixers[spec->num_mixers] = alc861_capture_mixer;
13206 spec->num_mixers++;
13207
13208 return 1;
13209}
13210
Takashi Iwaiae6b8132006-03-03 16:47:17 +010013211/* additional initialization for auto-configuration model */
13212static void alc861_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010013213{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013214 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010013215 alc861_auto_init_multi_out(codec);
13216 alc861_auto_init_hp_out(codec);
13217 alc861_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013218 if (spec->unsol_event)
13219 alc_sku_automute(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010013220}
13221
Takashi Iwaicb53c622007-08-10 17:21:45 +020013222#ifdef CONFIG_SND_HDA_POWER_SAVE
13223static struct hda_amp_list alc861_loopbacks[] = {
13224 { 0x15, HDA_INPUT, 0 },
13225 { 0x15, HDA_INPUT, 1 },
13226 { 0x15, HDA_INPUT, 2 },
13227 { 0x15, HDA_INPUT, 3 },
13228 { } /* end */
13229};
13230#endif
13231
Kailang Yangdf694da2005-12-05 19:42:22 +010013232
13233/*
13234 * configuration and preset
13235 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010013236static const char *alc861_models[ALC861_MODEL_LAST] = {
13237 [ALC861_3ST] = "3stack",
13238 [ALC660_3ST] = "3stack-660",
13239 [ALC861_3ST_DIG] = "3stack-dig",
13240 [ALC861_6ST_DIG] = "6stack-dig",
13241 [ALC861_UNIWILL_M31] = "uniwill-m31",
13242 [ALC861_TOSHIBA] = "toshiba",
13243 [ALC861_ASUS] = "asus",
13244 [ALC861_ASUS_LAPTOP] = "asus-laptop",
13245 [ALC861_AUTO] = "auto",
13246};
13247
13248static struct snd_pci_quirk alc861_cfg_tbl[] = {
Takashi Iwai687a47b2007-01-10 11:25:58 +010013249 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010013250 SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP),
13251 SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP),
13252 SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013253 SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP),
Kailang Yang83c34212007-07-05 11:43:05 +020013254 SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS P1-AH2", ALC861_3ST_DIG),
Tobin Davisad5e7732007-01-08 10:57:32 +010013255 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA),
Takashi Iwai341d4eb2007-07-09 17:53:18 +020013256 /* FIXME: the entry below breaks Toshiba A100 (model=auto works!)
13257 * Any other models that need this preset?
13258 */
13259 /* SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), */
Claudio Matsuokaef64adb2007-07-14 00:26:16 +020013260 SND_PCI_QUIRK(0x1462, 0x7254, "HP dx2200 (MSI MS-7254)", ALC861_3ST),
13261 SND_PCI_QUIRK(0x1462, 0x7297, "HP dx2250 (MSI MS-7297)", ALC861_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013262 SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31),
13263 SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31),
13264 SND_PCI_QUIRK(0x1584, 0x9075, "Airis Praxis N1212", ALC861_ASUS_LAPTOP),
13265 /* FIXME: the below seems conflict */
13266 /* SND_PCI_QUIRK(0x1584, 0x9075, "Uniwill", ALC861_UNIWILL_M31), */
13267 SND_PCI_QUIRK(0x1849, 0x0660, "Asrock 939SLI32", ALC660_3ST),
13268 SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST),
Kailang Yangdf694da2005-12-05 19:42:22 +010013269 {}
13270};
13271
13272static struct alc_config_preset alc861_presets[] = {
13273 [ALC861_3ST] = {
13274 .mixers = { alc861_3ST_mixer },
13275 .init_verbs = { alc861_threestack_init_verbs },
13276 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
13277 .dac_nids = alc861_dac_nids,
13278 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
13279 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020013280 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010013281 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13282 .adc_nids = alc861_adc_nids,
13283 .input_mux = &alc861_capture_source,
13284 },
13285 [ALC861_3ST_DIG] = {
13286 .mixers = { alc861_base_mixer },
13287 .init_verbs = { alc861_threestack_init_verbs },
13288 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
13289 .dac_nids = alc861_dac_nids,
13290 .dig_out_nid = ALC861_DIGOUT_NID,
13291 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
13292 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020013293 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010013294 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13295 .adc_nids = alc861_adc_nids,
13296 .input_mux = &alc861_capture_source,
13297 },
13298 [ALC861_6ST_DIG] = {
13299 .mixers = { alc861_base_mixer },
13300 .init_verbs = { alc861_base_init_verbs },
13301 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
13302 .dac_nids = alc861_dac_nids,
13303 .dig_out_nid = ALC861_DIGOUT_NID,
13304 .num_channel_mode = ARRAY_SIZE(alc861_8ch_modes),
13305 .channel_mode = alc861_8ch_modes,
13306 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13307 .adc_nids = alc861_adc_nids,
13308 .input_mux = &alc861_capture_source,
13309 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013310 [ALC660_3ST] = {
13311 .mixers = { alc861_3ST_mixer },
13312 .init_verbs = { alc861_threestack_init_verbs },
13313 .num_dacs = ARRAY_SIZE(alc660_dac_nids),
13314 .dac_nids = alc660_dac_nids,
13315 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
13316 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020013317 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013318 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13319 .adc_nids = alc861_adc_nids,
13320 .input_mux = &alc861_capture_source,
13321 },
Takashi Iwai22309c32006-08-09 16:57:28 +020013322 [ALC861_UNIWILL_M31] = {
13323 .mixers = { alc861_uniwill_m31_mixer },
13324 .init_verbs = { alc861_uniwill_m31_init_verbs },
13325 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
13326 .dac_nids = alc861_dac_nids,
13327 .dig_out_nid = ALC861_DIGOUT_NID,
13328 .num_channel_mode = ARRAY_SIZE(alc861_uniwill_m31_modes),
13329 .channel_mode = alc861_uniwill_m31_modes,
13330 .need_dac_fix = 1,
13331 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13332 .adc_nids = alc861_adc_nids,
13333 .input_mux = &alc861_capture_source,
13334 },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013335 [ALC861_TOSHIBA] = {
13336 .mixers = { alc861_toshiba_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013337 .init_verbs = { alc861_base_init_verbs,
13338 alc861_toshiba_init_verbs },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013339 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
13340 .dac_nids = alc861_dac_nids,
13341 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
13342 .channel_mode = alc883_3ST_2ch_modes,
13343 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13344 .adc_nids = alc861_adc_nids,
13345 .input_mux = &alc861_capture_source,
13346 .unsol_event = alc861_toshiba_unsol_event,
13347 .init_hook = alc861_toshiba_automute,
13348 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013349 [ALC861_ASUS] = {
13350 .mixers = { alc861_asus_mixer },
13351 .init_verbs = { alc861_asus_init_verbs },
13352 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
13353 .dac_nids = alc861_dac_nids,
13354 .dig_out_nid = ALC861_DIGOUT_NID,
13355 .num_channel_mode = ARRAY_SIZE(alc861_asus_modes),
13356 .channel_mode = alc861_asus_modes,
13357 .need_dac_fix = 1,
13358 .hp_nid = 0x06,
13359 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13360 .adc_nids = alc861_adc_nids,
13361 .input_mux = &alc861_capture_source,
13362 },
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010013363 [ALC861_ASUS_LAPTOP] = {
13364 .mixers = { alc861_toshiba_mixer, alc861_asus_laptop_mixer },
13365 .init_verbs = { alc861_asus_init_verbs,
13366 alc861_asus_laptop_init_verbs },
13367 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
13368 .dac_nids = alc861_dac_nids,
13369 .dig_out_nid = ALC861_DIGOUT_NID,
13370 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
13371 .channel_mode = alc883_3ST_2ch_modes,
13372 .need_dac_fix = 1,
13373 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13374 .adc_nids = alc861_adc_nids,
13375 .input_mux = &alc861_capture_source,
13376 },
13377};
Kailang Yangdf694da2005-12-05 19:42:22 +010013378
13379
13380static int patch_alc861(struct hda_codec *codec)
13381{
13382 struct alc_spec *spec;
13383 int board_config;
13384 int err;
13385
Robert P. J. Daydc041e02006-12-19 14:44:15 +010013386 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010013387 if (spec == NULL)
13388 return -ENOMEM;
13389
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013390 codec->spec = spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010013391
Takashi Iwaif5fcc132006-11-24 17:07:44 +010013392 board_config = snd_hda_check_board_config(codec, ALC861_MODEL_LAST,
13393 alc861_models,
13394 alc861_cfg_tbl);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013395
Takashi Iwaif5fcc132006-11-24 17:07:44 +010013396 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013397 printk(KERN_INFO "hda_codec: Unknown model for ALC861, "
13398 "trying auto-probe from BIOS...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010013399 board_config = ALC861_AUTO;
13400 }
13401
13402 if (board_config == ALC861_AUTO) {
13403 /* automatic parse from the BIOS config */
13404 err = alc861_parse_auto_config(codec);
13405 if (err < 0) {
13406 alc_free(codec);
13407 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013408 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013409 printk(KERN_INFO
13410 "hda_codec: Cannot set up configuration "
13411 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010013412 board_config = ALC861_3ST_DIG;
13413 }
13414 }
13415
13416 if (board_config != ALC861_AUTO)
13417 setup_preset(spec, &alc861_presets[board_config]);
13418
13419 spec->stream_name_analog = "ALC861 Analog";
13420 spec->stream_analog_playback = &alc861_pcm_analog_playback;
13421 spec->stream_analog_capture = &alc861_pcm_analog_capture;
13422
13423 spec->stream_name_digital = "ALC861 Digital";
13424 spec->stream_digital_playback = &alc861_pcm_digital_playback;
13425 spec->stream_digital_capture = &alc861_pcm_digital_capture;
13426
Takashi Iwai2134ea42008-01-10 16:53:55 +010013427 spec->vmaster_nid = 0x03;
13428
Kailang Yangdf694da2005-12-05 19:42:22 +010013429 codec->patch_ops = alc_patch_ops;
13430 if (board_config == ALC861_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +010013431 spec->init_hook = alc861_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020013432#ifdef CONFIG_SND_HDA_POWER_SAVE
13433 if (!spec->loopback.amplist)
13434 spec->loopback.amplist = alc861_loopbacks;
13435#endif
Kailang Yangea1fb292008-08-26 12:58:38 +020013436
Kailang Yangdf694da2005-12-05 19:42:22 +010013437 return 0;
13438}
13439
13440/*
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013441 * ALC861-VD support
13442 *
13443 * Based on ALC882
13444 *
13445 * In addition, an independent DAC
13446 */
13447#define ALC861VD_DIGOUT_NID 0x06
13448
13449static hda_nid_t alc861vd_dac_nids[4] = {
13450 /* front, surr, clfe, side surr */
13451 0x02, 0x03, 0x04, 0x05
13452};
13453
13454/* dac_nids for ALC660vd are in a different order - according to
13455 * Realtek's driver.
13456 * This should probably tesult in a different mixer for 6stack models
13457 * of ALC660vd codecs, but for now there is only 3stack mixer
13458 * - and it is the same as in 861vd.
13459 * adc_nids in ALC660vd are (is) the same as in 861vd
13460 */
13461static hda_nid_t alc660vd_dac_nids[3] = {
13462 /* front, rear, clfe, rear_surr */
13463 0x02, 0x04, 0x03
13464};
13465
13466static hda_nid_t alc861vd_adc_nids[1] = {
13467 /* ADC0 */
13468 0x09,
13469};
13470
Takashi Iwaie1406342008-02-11 18:32:32 +010013471static hda_nid_t alc861vd_capsrc_nids[1] = { 0x22 };
13472
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013473/* input MUX */
13474/* FIXME: should be a matrix-type input source selection */
13475static struct hda_input_mux alc861vd_capture_source = {
13476 .num_items = 4,
13477 .items = {
13478 { "Mic", 0x0 },
13479 { "Front Mic", 0x1 },
13480 { "Line", 0x2 },
13481 { "CD", 0x4 },
13482 },
13483};
13484
Kailang Yang272a5272007-05-14 11:00:38 +020013485static struct hda_input_mux alc861vd_dallas_capture_source = {
Tobin Davisb419f342008-03-07 11:57:51 +010013486 .num_items = 2,
Kailang Yang272a5272007-05-14 11:00:38 +020013487 .items = {
Tobin Davisb419f342008-03-07 11:57:51 +010013488 { "Ext Mic", 0x0 },
13489 { "Int Mic", 0x1 },
Kailang Yang272a5272007-05-14 11:00:38 +020013490 },
13491};
13492
Kailang Yangd1a991a2007-08-15 16:21:59 +020013493static struct hda_input_mux alc861vd_hp_capture_source = {
13494 .num_items = 2,
13495 .items = {
13496 { "Front Mic", 0x0 },
13497 { "ATAPI Mic", 0x1 },
13498 },
13499};
13500
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013501#define alc861vd_mux_enum_info alc_mux_enum_info
13502#define alc861vd_mux_enum_get alc_mux_enum_get
Takashi Iwaie1406342008-02-11 18:32:32 +010013503/* ALC861VD has the ALC882-type input selection (but has only one ADC) */
13504#define alc861vd_mux_enum_put alc882_mux_enum_put
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013505
13506/*
13507 * 2ch mode
13508 */
13509static struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = {
13510 { 2, NULL }
13511};
13512
13513/*
13514 * 6ch mode
13515 */
13516static struct hda_verb alc861vd_6stack_ch6_init[] = {
13517 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
13518 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
13519 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
13520 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
13521 { } /* end */
13522};
13523
13524/*
13525 * 8ch mode
13526 */
13527static struct hda_verb alc861vd_6stack_ch8_init[] = {
13528 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
13529 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
13530 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
13531 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
13532 { } /* end */
13533};
13534
13535static struct hda_channel_mode alc861vd_6stack_modes[2] = {
13536 { 6, alc861vd_6stack_ch6_init },
13537 { 8, alc861vd_6stack_ch8_init },
13538};
13539
13540static struct snd_kcontrol_new alc861vd_chmode_mixer[] = {
13541 {
13542 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13543 .name = "Channel Mode",
13544 .info = alc_ch_mode_info,
13545 .get = alc_ch_mode_get,
13546 .put = alc_ch_mode_put,
13547 },
13548 { } /* end */
13549};
13550
13551static struct snd_kcontrol_new alc861vd_capture_mixer[] = {
13552 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
13553 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
13554
13555 {
13556 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13557 /* The multiple "Capture Source" controls confuse alsamixer
13558 * So call somewhat different..
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013559 */
13560 /* .name = "Capture Source", */
13561 .name = "Input Source",
13562 .count = 1,
13563 .info = alc861vd_mux_enum_info,
13564 .get = alc861vd_mux_enum_get,
13565 .put = alc861vd_mux_enum_put,
13566 },
13567 { } /* end */
13568};
13569
13570/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
13571 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
13572 */
13573static struct snd_kcontrol_new alc861vd_6st_mixer[] = {
13574 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13575 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
13576
13577 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
13578 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
13579
13580 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0,
13581 HDA_OUTPUT),
13582 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0,
13583 HDA_OUTPUT),
13584 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
13585 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
13586
13587 HDA_CODEC_VOLUME("Side Playback Volume", 0x05, 0x0, HDA_OUTPUT),
13588 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
13589
13590 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
13591
13592 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13593 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13594 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13595
13596 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
13597 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
13598 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
13599
13600 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
13601 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
13602
13603 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
13604 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
13605
13606 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
13607 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
13608
13609 { } /* end */
13610};
13611
13612static struct snd_kcontrol_new alc861vd_3st_mixer[] = {
13613 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13614 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
13615
13616 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
13617
13618 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13619 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13620 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13621
13622 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
13623 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
13624 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
13625
13626 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
13627 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
13628
13629 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
13630 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
13631
13632 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
13633 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
13634
13635 { } /* end */
13636};
13637
Kailang Yangbdd148a2007-05-08 15:19:08 +020013638static struct snd_kcontrol_new alc861vd_lenovo_mixer[] = {
13639 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13640 /*HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),*/
13641 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
13642
13643 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
13644
13645 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13646 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13647 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13648
13649 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
13650 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
13651 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
13652
13653 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
13654 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
13655
13656 { } /* end */
13657};
13658
Tobin Davisb419f342008-03-07 11:57:51 +010013659/* Pin assignment: Speaker=0x14, HP = 0x15,
13660 * Ext Mic=0x18, Int Mic = 0x19, CD = 0x1c, PC Beep = 0x1d
Kailang Yang272a5272007-05-14 11:00:38 +020013661 */
13662static struct snd_kcontrol_new alc861vd_dallas_mixer[] = {
Tobin Davisb419f342008-03-07 11:57:51 +010013663 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13664 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020013665 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
13666 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
Tobin Davisb419f342008-03-07 11:57:51 +010013667 HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
13668 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13669 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13670 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
13671 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
13672 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
13673 HDA_CODEC_VOLUME("PC Beep Volume", 0x0b, 0x05, HDA_INPUT),
13674 HDA_CODEC_MUTE("PC Beep Switch", 0x0b, 0x05, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020013675 { } /* end */
13676};
13677
Kailang Yangd1a991a2007-08-15 16:21:59 +020013678/* Pin assignment: Speaker=0x14, Line-out = 0x15,
13679 * Front Mic=0x18, ATAPI Mic = 0x19,
13680 */
13681static struct snd_kcontrol_new alc861vd_hp_mixer[] = {
13682 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13683 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
13684 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
13685 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
13686 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13687 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13688 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
13689 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangea1fb292008-08-26 12:58:38 +020013690
Kailang Yangd1a991a2007-08-15 16:21:59 +020013691 { } /* end */
13692};
13693
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013694/*
13695 * generic initialization of ADC, input mixers and output mixers
13696 */
13697static struct hda_verb alc861vd_volume_init_verbs[] = {
13698 /*
13699 * Unmute ADC0 and set the default input to mic-in
13700 */
13701 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
13702 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13703
13704 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of
13705 * the analog-loopback mixer widget
13706 */
13707 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020013708 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13709 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13710 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
13711 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
13712 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013713
13714 /* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yangbdd148a2007-05-08 15:19:08 +020013715 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13716 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13717 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013718 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013719
13720 /*
13721 * Set up output mixers (0x02 - 0x05)
13722 */
13723 /* set vol=0 to output mixers */
13724 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13725 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13726 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13727 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13728
13729 /* set up input amps for analog loopback */
13730 /* Amp Indices: DAC = 0, mixer = 1 */
13731 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13732 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13733 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13734 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13735 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13736 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13737 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13738 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13739
13740 { }
13741};
13742
13743/*
13744 * 3-stack pin configuration:
13745 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
13746 */
13747static struct hda_verb alc861vd_3stack_init_verbs[] = {
13748 /*
13749 * Set pin mode and muting
13750 */
13751 /* set front pin widgets 0x14 for output */
13752 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13753 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13754 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
13755
13756 /* Mic (rear) pin: input vref at 80% */
13757 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
13758 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13759 /* Front Mic pin: input vref at 80% */
13760 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
13761 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13762 /* Line In pin: input */
13763 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13764 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13765 /* Line-2 In: Headphone output (output 0 - 0x0c) */
13766 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13767 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13768 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
13769 /* CD pin widget for input */
13770 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13771
13772 { }
13773};
13774
13775/*
13776 * 6-stack pin configuration:
13777 */
13778static struct hda_verb alc861vd_6stack_init_verbs[] = {
13779 /*
13780 * Set pin mode and muting
13781 */
13782 /* set front pin widgets 0x14 for output */
13783 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13784 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13785 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
13786
13787 /* Rear Pin: output 1 (0x0d) */
13788 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13789 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13790 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
13791 /* CLFE Pin: output 2 (0x0e) */
13792 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13793 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13794 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
13795 /* Side Pin: output 3 (0x0f) */
13796 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13797 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13798 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
13799
13800 /* Mic (rear) pin: input vref at 80% */
13801 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
13802 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13803 /* Front Mic pin: input vref at 80% */
13804 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
13805 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13806 /* Line In pin: input */
13807 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13808 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13809 /* Line-2 In: Headphone output (output 0 - 0x0c) */
13810 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13811 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13812 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
13813 /* CD pin widget for input */
13814 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13815
13816 { }
13817};
13818
Kailang Yangbdd148a2007-05-08 15:19:08 +020013819static struct hda_verb alc861vd_eapd_verbs[] = {
13820 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
13821 { }
13822};
13823
Kailang Yangf9423e72008-05-27 12:32:25 +020013824static struct hda_verb alc660vd_eapd_verbs[] = {
13825 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
13826 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
13827 { }
13828};
13829
Kailang Yangbdd148a2007-05-08 15:19:08 +020013830static struct hda_verb alc861vd_lenovo_unsol_verbs[] = {
13831 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13832 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13833 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
13834 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Kailang Yangea1fb292008-08-26 12:58:38 +020013835 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
Kailang Yangbdd148a2007-05-08 15:19:08 +020013836 {}
13837};
13838
13839/* toggle speaker-output according to the hp-jack state */
13840static void alc861vd_lenovo_hp_automute(struct hda_codec *codec)
13841{
13842 unsigned int present;
13843 unsigned char bits;
13844
13845 present = snd_hda_codec_read(codec, 0x1b, 0,
13846 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020013847 bits = present ? HDA_AMP_MUTE : 0;
13848 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
13849 HDA_AMP_MUTE, bits);
Kailang Yangbdd148a2007-05-08 15:19:08 +020013850}
13851
13852static void alc861vd_lenovo_mic_automute(struct hda_codec *codec)
13853{
13854 unsigned int present;
13855 unsigned char bits;
13856
13857 present = snd_hda_codec_read(codec, 0x18, 0,
13858 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020013859 bits = present ? HDA_AMP_MUTE : 0;
13860 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
13861 HDA_AMP_MUTE, bits);
Kailang Yangbdd148a2007-05-08 15:19:08 +020013862}
13863
13864static void alc861vd_lenovo_automute(struct hda_codec *codec)
13865{
13866 alc861vd_lenovo_hp_automute(codec);
13867 alc861vd_lenovo_mic_automute(codec);
13868}
13869
13870static void alc861vd_lenovo_unsol_event(struct hda_codec *codec,
13871 unsigned int res)
13872{
13873 switch (res >> 26) {
13874 case ALC880_HP_EVENT:
13875 alc861vd_lenovo_hp_automute(codec);
13876 break;
13877 case ALC880_MIC_EVENT:
13878 alc861vd_lenovo_mic_automute(codec);
13879 break;
13880 }
13881}
13882
Kailang Yang272a5272007-05-14 11:00:38 +020013883static struct hda_verb alc861vd_dallas_verbs[] = {
13884 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13885 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13886 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13887 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13888
13889 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13890 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13891 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13892 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13893 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13894 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13895 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13896 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020013897
Kailang Yang272a5272007-05-14 11:00:38 +020013898 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13899 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13900 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13901 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13902 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13903 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13904 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13905 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13906
13907 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
13908 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13909 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
13910 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13911 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13912 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13913 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13914 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13915
13916 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13917 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
13918 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
13919 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
13920
13921 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020013922 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yang272a5272007-05-14 11:00:38 +020013923 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
13924
13925 { } /* end */
13926};
13927
13928/* toggle speaker-output according to the hp-jack state */
13929static void alc861vd_dallas_automute(struct hda_codec *codec)
13930{
13931 unsigned int present;
13932
13933 present = snd_hda_codec_read(codec, 0x15, 0,
13934 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020013935 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
13936 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +020013937}
13938
13939static void alc861vd_dallas_unsol_event(struct hda_codec *codec, unsigned int res)
13940{
13941 if ((res >> 26) == ALC880_HP_EVENT)
13942 alc861vd_dallas_automute(codec);
13943}
13944
Takashi Iwaicb53c622007-08-10 17:21:45 +020013945#ifdef CONFIG_SND_HDA_POWER_SAVE
13946#define alc861vd_loopbacks alc880_loopbacks
13947#endif
13948
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013949/* pcm configuration: identiacal with ALC880 */
13950#define alc861vd_pcm_analog_playback alc880_pcm_analog_playback
13951#define alc861vd_pcm_analog_capture alc880_pcm_analog_capture
13952#define alc861vd_pcm_digital_playback alc880_pcm_digital_playback
13953#define alc861vd_pcm_digital_capture alc880_pcm_digital_capture
13954
13955/*
13956 * configuration and preset
13957 */
13958static const char *alc861vd_models[ALC861VD_MODEL_LAST] = {
13959 [ALC660VD_3ST] = "3stack-660",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020013960 [ALC660VD_3ST_DIG] = "3stack-660-digout",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013961 [ALC861VD_3ST] = "3stack",
13962 [ALC861VD_3ST_DIG] = "3stack-digout",
13963 [ALC861VD_6ST_DIG] = "6stack-digout",
Kailang Yangbdd148a2007-05-08 15:19:08 +020013964 [ALC861VD_LENOVO] = "lenovo",
Kailang Yang272a5272007-05-14 11:00:38 +020013965 [ALC861VD_DALLAS] = "dallas",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020013966 [ALC861VD_HP] = "hp",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013967 [ALC861VD_AUTO] = "auto",
13968};
13969
13970static struct snd_pci_quirk alc861vd_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013971 SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST),
13972 SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP),
Takashi Iwai07e038b2007-02-15 18:23:41 +010013973 SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013974 SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),
Alexander Holler2522d732008-07-17 23:36:15 +020013975 SND_PCI_QUIRK(0x1043, 0x1633, "Asus V1Sn", ALC861VD_LENOVO),
Mike Crash6963f842007-06-25 12:12:51 +020013976 SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013977 SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013978 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO),
Takashi Iwai38baf5a2007-08-16 17:52:43 +020013979 /*SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS),*/ /*lenovo*/
Kailang Yang272a5272007-05-14 11:00:38 +020013980 SND_PCI_QUIRK(0x1179, 0xff01, "DALLAS", ALC861VD_DALLAS),
Takashi Iwai542d7c62007-08-16 18:57:30 +020013981 SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO),
Tobin Davisb419f342008-03-07 11:57:51 +010013982 SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_DALLAS),
Takashi Iwai39c5d412007-08-15 16:24:17 +020013983 SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013984 SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo", ALC861VD_LENOVO),
13985 SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo 3000 C200", ALC861VD_LENOVO),
Takashi Iwaibe321a892008-07-07 16:04:04 +020013986 SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 N200", ALC861VD_LENOVO),
Tobin Davis625dc0b2007-07-30 21:42:10 +020013987 SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013988 {}
13989};
13990
13991static struct alc_config_preset alc861vd_presets[] = {
13992 [ALC660VD_3ST] = {
13993 .mixers = { alc861vd_3st_mixer },
13994 .init_verbs = { alc861vd_volume_init_verbs,
13995 alc861vd_3stack_init_verbs },
13996 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
13997 .dac_nids = alc660vd_dac_nids,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013998 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
13999 .channel_mode = alc861vd_3stack_2ch_modes,
14000 .input_mux = &alc861vd_capture_source,
14001 },
Mike Crash6963f842007-06-25 12:12:51 +020014002 [ALC660VD_3ST_DIG] = {
14003 .mixers = { alc861vd_3st_mixer },
14004 .init_verbs = { alc861vd_volume_init_verbs,
14005 alc861vd_3stack_init_verbs },
14006 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
14007 .dac_nids = alc660vd_dac_nids,
14008 .dig_out_nid = ALC861VD_DIGOUT_NID,
Mike Crash6963f842007-06-25 12:12:51 +020014009 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14010 .channel_mode = alc861vd_3stack_2ch_modes,
14011 .input_mux = &alc861vd_capture_source,
14012 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014013 [ALC861VD_3ST] = {
14014 .mixers = { alc861vd_3st_mixer },
14015 .init_verbs = { alc861vd_volume_init_verbs,
14016 alc861vd_3stack_init_verbs },
14017 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
14018 .dac_nids = alc861vd_dac_nids,
14019 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14020 .channel_mode = alc861vd_3stack_2ch_modes,
14021 .input_mux = &alc861vd_capture_source,
14022 },
14023 [ALC861VD_3ST_DIG] = {
14024 .mixers = { alc861vd_3st_mixer },
14025 .init_verbs = { alc861vd_volume_init_verbs,
14026 alc861vd_3stack_init_verbs },
14027 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
14028 .dac_nids = alc861vd_dac_nids,
14029 .dig_out_nid = ALC861VD_DIGOUT_NID,
14030 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14031 .channel_mode = alc861vd_3stack_2ch_modes,
14032 .input_mux = &alc861vd_capture_source,
14033 },
14034 [ALC861VD_6ST_DIG] = {
14035 .mixers = { alc861vd_6st_mixer, alc861vd_chmode_mixer },
14036 .init_verbs = { alc861vd_volume_init_verbs,
14037 alc861vd_6stack_init_verbs },
14038 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
14039 .dac_nids = alc861vd_dac_nids,
14040 .dig_out_nid = ALC861VD_DIGOUT_NID,
14041 .num_channel_mode = ARRAY_SIZE(alc861vd_6stack_modes),
14042 .channel_mode = alc861vd_6stack_modes,
14043 .input_mux = &alc861vd_capture_source,
14044 },
Kailang Yangbdd148a2007-05-08 15:19:08 +020014045 [ALC861VD_LENOVO] = {
14046 .mixers = { alc861vd_lenovo_mixer },
14047 .init_verbs = { alc861vd_volume_init_verbs,
14048 alc861vd_3stack_init_verbs,
14049 alc861vd_eapd_verbs,
14050 alc861vd_lenovo_unsol_verbs },
14051 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
14052 .dac_nids = alc660vd_dac_nids,
Kailang Yangbdd148a2007-05-08 15:19:08 +020014053 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14054 .channel_mode = alc861vd_3stack_2ch_modes,
14055 .input_mux = &alc861vd_capture_source,
14056 .unsol_event = alc861vd_lenovo_unsol_event,
14057 .init_hook = alc861vd_lenovo_automute,
14058 },
Kailang Yang272a5272007-05-14 11:00:38 +020014059 [ALC861VD_DALLAS] = {
14060 .mixers = { alc861vd_dallas_mixer },
14061 .init_verbs = { alc861vd_dallas_verbs },
14062 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
14063 .dac_nids = alc861vd_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +020014064 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14065 .channel_mode = alc861vd_3stack_2ch_modes,
14066 .input_mux = &alc861vd_dallas_capture_source,
14067 .unsol_event = alc861vd_dallas_unsol_event,
14068 .init_hook = alc861vd_dallas_automute,
Kailang Yangd1a991a2007-08-15 16:21:59 +020014069 },
14070 [ALC861VD_HP] = {
14071 .mixers = { alc861vd_hp_mixer },
14072 .init_verbs = { alc861vd_dallas_verbs, alc861vd_eapd_verbs },
14073 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
14074 .dac_nids = alc861vd_dac_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020014075 .dig_out_nid = ALC861VD_DIGOUT_NID,
Kailang Yangd1a991a2007-08-15 16:21:59 +020014076 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14077 .channel_mode = alc861vd_3stack_2ch_modes,
14078 .input_mux = &alc861vd_hp_capture_source,
14079 .unsol_event = alc861vd_dallas_unsol_event,
14080 .init_hook = alc861vd_dallas_automute,
Kailang Yangea1fb292008-08-26 12:58:38 +020014081 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014082};
14083
14084/*
14085 * BIOS auto configuration
14086 */
14087static void alc861vd_auto_set_output_and_unmute(struct hda_codec *codec,
14088 hda_nid_t nid, int pin_type, int dac_idx)
14089{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014090 alc_set_pin_output(codec, nid, pin_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014091}
14092
14093static void alc861vd_auto_init_multi_out(struct hda_codec *codec)
14094{
14095 struct alc_spec *spec = codec->spec;
14096 int i;
14097
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014098 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014099 for (i = 0; i <= HDA_SIDE; i++) {
14100 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020014101 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014102 if (nid)
14103 alc861vd_auto_set_output_and_unmute(codec, nid,
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020014104 pin_type, i);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014105 }
14106}
14107
14108
14109static void alc861vd_auto_init_hp_out(struct hda_codec *codec)
14110{
14111 struct alc_spec *spec = codec->spec;
14112 hda_nid_t pin;
14113
14114 pin = spec->autocfg.hp_pins[0];
14115 if (pin) /* connect to front and use dac 0 */
14116 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014117 pin = spec->autocfg.speaker_pins[0];
14118 if (pin)
14119 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014120}
14121
14122#define alc861vd_is_input_pin(nid) alc880_is_input_pin(nid)
14123#define ALC861VD_PIN_CD_NID ALC880_PIN_CD_NID
14124
14125static void alc861vd_auto_init_analog_input(struct hda_codec *codec)
14126{
14127 struct alc_spec *spec = codec->spec;
14128 int i;
14129
14130 for (i = 0; i < AUTO_PIN_LAST; i++) {
14131 hda_nid_t nid = spec->autocfg.input_pins[i];
14132 if (alc861vd_is_input_pin(nid)) {
14133 snd_hda_codec_write(codec, nid, 0,
14134 AC_VERB_SET_PIN_WIDGET_CONTROL,
14135 i <= AUTO_PIN_FRONT_MIC ?
14136 PIN_VREF80 : PIN_IN);
14137 if (nid != ALC861VD_PIN_CD_NID)
14138 snd_hda_codec_write(codec, nid, 0,
14139 AC_VERB_SET_AMP_GAIN_MUTE,
14140 AMP_OUT_MUTE);
14141 }
14142 }
14143}
14144
Takashi Iwaif511b012008-08-15 16:46:42 +020014145#define alc861vd_auto_init_input_src alc882_auto_init_input_src
14146
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014147#define alc861vd_idx_to_mixer_vol(nid) ((nid) + 0x02)
14148#define alc861vd_idx_to_mixer_switch(nid) ((nid) + 0x0c)
14149
14150/* add playback controls from the parsed DAC table */
14151/* Based on ALC880 version. But ALC861VD has separate,
14152 * different NIDs for mute/unmute switch and volume control */
14153static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
14154 const struct auto_pin_cfg *cfg)
14155{
14156 char name[32];
14157 static const char *chname[4] = {"Front", "Surround", "CLFE", "Side"};
14158 hda_nid_t nid_v, nid_s;
14159 int i, err;
14160
14161 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014162 if (!spec->multiout.dac_nids[i])
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014163 continue;
14164 nid_v = alc861vd_idx_to_mixer_vol(
14165 alc880_dac_to_idx(
14166 spec->multiout.dac_nids[i]));
14167 nid_s = alc861vd_idx_to_mixer_switch(
14168 alc880_dac_to_idx(
14169 spec->multiout.dac_nids[i]));
14170
14171 if (i == 2) {
14172 /* Center/LFE */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014173 err = add_control(spec, ALC_CTL_WIDGET_VOL,
14174 "Center Playback Volume",
14175 HDA_COMPOSE_AMP_VAL(nid_v, 1, 0,
14176 HDA_OUTPUT));
14177 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014178 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014179 err = add_control(spec, ALC_CTL_WIDGET_VOL,
14180 "LFE Playback Volume",
14181 HDA_COMPOSE_AMP_VAL(nid_v, 2, 0,
14182 HDA_OUTPUT));
14183 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014184 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014185 err = add_control(spec, ALC_CTL_BIND_MUTE,
14186 "Center Playback Switch",
14187 HDA_COMPOSE_AMP_VAL(nid_s, 1, 2,
14188 HDA_INPUT));
14189 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014190 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014191 err = add_control(spec, ALC_CTL_BIND_MUTE,
14192 "LFE Playback Switch",
14193 HDA_COMPOSE_AMP_VAL(nid_s, 2, 2,
14194 HDA_INPUT));
14195 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014196 return err;
14197 } else {
14198 sprintf(name, "%s Playback Volume", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014199 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
14200 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0,
14201 HDA_OUTPUT));
14202 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014203 return err;
14204 sprintf(name, "%s Playback Switch", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014205 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
Kailang Yangbdd148a2007-05-08 15:19:08 +020014206 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014207 HDA_INPUT));
14208 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014209 return err;
14210 }
14211 }
14212 return 0;
14213}
14214
14215/* add playback controls for speaker and HP outputs */
14216/* Based on ALC880 version. But ALC861VD has separate,
14217 * different NIDs for mute/unmute switch and volume control */
14218static int alc861vd_auto_create_extra_out(struct alc_spec *spec,
14219 hda_nid_t pin, const char *pfx)
14220{
14221 hda_nid_t nid_v, nid_s;
14222 int err;
14223 char name[32];
14224
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014225 if (!pin)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014226 return 0;
14227
14228 if (alc880_is_fixed_pin(pin)) {
14229 nid_v = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
14230 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014231 if (!spec->multiout.hp_nid)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014232 spec->multiout.hp_nid = nid_v;
14233 else
14234 spec->multiout.extra_out_nid[0] = nid_v;
14235 /* control HP volume/switch on the output mixer amp */
14236 nid_v = alc861vd_idx_to_mixer_vol(
14237 alc880_fixed_pin_idx(pin));
14238 nid_s = alc861vd_idx_to_mixer_switch(
14239 alc880_fixed_pin_idx(pin));
14240
14241 sprintf(name, "%s Playback Volume", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014242 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
14243 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0, HDA_OUTPUT));
14244 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014245 return err;
14246 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014247 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
14248 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2, HDA_INPUT));
14249 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014250 return err;
14251 } else if (alc880_is_multi_pin(pin)) {
14252 /* set manual connection */
14253 /* we have only a switch on HP-out PIN */
14254 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014255 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
14256 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
14257 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014258 return err;
14259 }
14260 return 0;
14261}
14262
14263/* parse the BIOS configuration and set up the alc_spec
14264 * return 1 if successful, 0 if the proper config is not found,
14265 * or a negative error code
14266 * Based on ALC880 version - had to change it to override
14267 * alc880_auto_create_extra_out and alc880_auto_create_multi_out_ctls */
14268static int alc861vd_parse_auto_config(struct hda_codec *codec)
14269{
14270 struct alc_spec *spec = codec->spec;
14271 int err;
14272 static hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
14273
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014274 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
14275 alc861vd_ignore);
14276 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014277 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014278 if (!spec->autocfg.line_outs)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014279 return 0; /* can't find valid BIOS pin config */
14280
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014281 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
14282 if (err < 0)
14283 return err;
14284 err = alc861vd_auto_create_multi_out_ctls(spec, &spec->autocfg);
14285 if (err < 0)
14286 return err;
14287 err = alc861vd_auto_create_extra_out(spec,
14288 spec->autocfg.speaker_pins[0],
14289 "Speaker");
14290 if (err < 0)
14291 return err;
14292 err = alc861vd_auto_create_extra_out(spec,
14293 spec->autocfg.hp_pins[0],
14294 "Headphone");
14295 if (err < 0)
14296 return err;
14297 err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg);
14298 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014299 return err;
14300
14301 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
14302
14303 if (spec->autocfg.dig_out_pin)
14304 spec->multiout.dig_out_nid = ALC861VD_DIGOUT_NID;
14305
14306 if (spec->kctl_alloc)
14307 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
14308
14309 spec->init_verbs[spec->num_init_verbs++]
14310 = alc861vd_volume_init_verbs;
14311
14312 spec->num_mux_defs = 1;
14313 spec->input_mux = &spec->private_imux;
14314
Takashi Iwai776e1842007-08-29 15:07:11 +020014315 err = alc_auto_add_mic_boost(codec);
14316 if (err < 0)
14317 return err;
14318
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014319 return 1;
14320}
14321
14322/* additional initialization for auto-configuration model */
14323static void alc861vd_auto_init(struct hda_codec *codec)
14324{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014325 struct alc_spec *spec = codec->spec;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014326 alc861vd_auto_init_multi_out(codec);
14327 alc861vd_auto_init_hp_out(codec);
14328 alc861vd_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020014329 alc861vd_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014330 if (spec->unsol_event)
14331 alc_sku_automute(codec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014332}
14333
14334static int patch_alc861vd(struct hda_codec *codec)
14335{
14336 struct alc_spec *spec;
14337 int err, board_config;
14338
14339 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
14340 if (spec == NULL)
14341 return -ENOMEM;
14342
14343 codec->spec = spec;
14344
14345 board_config = snd_hda_check_board_config(codec, ALC861VD_MODEL_LAST,
14346 alc861vd_models,
14347 alc861vd_cfg_tbl);
14348
14349 if (board_config < 0 || board_config >= ALC861VD_MODEL_LAST) {
14350 printk(KERN_INFO "hda_codec: Unknown model for ALC660VD/"
14351 "ALC861VD, trying auto-probe from BIOS...\n");
14352 board_config = ALC861VD_AUTO;
14353 }
14354
14355 if (board_config == ALC861VD_AUTO) {
14356 /* automatic parse from the BIOS config */
14357 err = alc861vd_parse_auto_config(codec);
14358 if (err < 0) {
14359 alc_free(codec);
14360 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014361 } else if (!err) {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014362 printk(KERN_INFO
14363 "hda_codec: Cannot set up configuration "
14364 "from BIOS. Using base mode...\n");
14365 board_config = ALC861VD_3ST;
14366 }
14367 }
14368
14369 if (board_config != ALC861VD_AUTO)
14370 setup_preset(spec, &alc861vd_presets[board_config]);
14371
Kailang Yang2f893282008-05-27 12:14:47 +020014372 if (codec->vendor_id == 0x10ec0660) {
14373 spec->stream_name_analog = "ALC660-VD Analog";
14374 spec->stream_name_digital = "ALC660-VD Digital";
Kailang Yangf9423e72008-05-27 12:32:25 +020014375 /* always turn on EAPD */
14376 spec->init_verbs[spec->num_init_verbs++] = alc660vd_eapd_verbs;
Kailang Yang2f893282008-05-27 12:14:47 +020014377 } else {
14378 spec->stream_name_analog = "ALC861VD Analog";
14379 spec->stream_name_digital = "ALC861VD Digital";
14380 }
14381
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014382 spec->stream_analog_playback = &alc861vd_pcm_analog_playback;
14383 spec->stream_analog_capture = &alc861vd_pcm_analog_capture;
14384
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014385 spec->stream_digital_playback = &alc861vd_pcm_digital_playback;
14386 spec->stream_digital_capture = &alc861vd_pcm_digital_capture;
14387
14388 spec->adc_nids = alc861vd_adc_nids;
14389 spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids);
Takashi Iwaie1406342008-02-11 18:32:32 +010014390 spec->capsrc_nids = alc861vd_capsrc_nids;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014391
14392 spec->mixers[spec->num_mixers] = alc861vd_capture_mixer;
14393 spec->num_mixers++;
14394
Takashi Iwai2134ea42008-01-10 16:53:55 +010014395 spec->vmaster_nid = 0x02;
14396
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014397 codec->patch_ops = alc_patch_ops;
14398
14399 if (board_config == ALC861VD_AUTO)
14400 spec->init_hook = alc861vd_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020014401#ifdef CONFIG_SND_HDA_POWER_SAVE
14402 if (!spec->loopback.amplist)
14403 spec->loopback.amplist = alc861vd_loopbacks;
14404#endif
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014405
14406 return 0;
14407}
14408
14409/*
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014410 * ALC662 support
14411 *
14412 * ALC662 is almost identical with ALC880 but has cleaner and more flexible
14413 * configuration. Each pin widget can choose any input DACs and a mixer.
14414 * Each ADC is connected from a mixer of all inputs. This makes possible
14415 * 6-channel independent captures.
14416 *
14417 * In addition, an independent DAC for the multi-playback (not used in this
14418 * driver yet).
14419 */
14420#define ALC662_DIGOUT_NID 0x06
14421#define ALC662_DIGIN_NID 0x0a
14422
14423static hda_nid_t alc662_dac_nids[4] = {
14424 /* front, rear, clfe, rear_surr */
14425 0x02, 0x03, 0x04
14426};
14427
14428static hda_nid_t alc662_adc_nids[1] = {
14429 /* ADC1-2 */
14430 0x09,
14431};
Takashi Iwaie1406342008-02-11 18:32:32 +010014432
Kailang Yang77a261b2008-02-19 11:38:05 +010014433static hda_nid_t alc662_capsrc_nids[1] = { 0x22 };
Takashi Iwaie1406342008-02-11 18:32:32 +010014434
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014435/* input MUX */
14436/* FIXME: should be a matrix-type input source selection */
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014437static struct hda_input_mux alc662_capture_source = {
14438 .num_items = 4,
14439 .items = {
14440 { "Mic", 0x0 },
14441 { "Front Mic", 0x1 },
14442 { "Line", 0x2 },
14443 { "CD", 0x4 },
14444 },
14445};
14446
14447static struct hda_input_mux alc662_lenovo_101e_capture_source = {
14448 .num_items = 2,
14449 .items = {
14450 { "Mic", 0x1 },
14451 { "Line", 0x2 },
14452 },
14453};
Kailang Yang291702f2007-10-16 14:28:03 +020014454
14455static struct hda_input_mux alc662_eeepc_capture_source = {
14456 .num_items = 2,
14457 .items = {
14458 { "i-Mic", 0x1 },
14459 { "e-Mic", 0x0 },
14460 },
14461};
14462
Kailang Yang6dda9f42008-05-27 12:05:31 +020014463static struct hda_input_mux alc663_capture_source = {
14464 .num_items = 3,
14465 .items = {
14466 { "Mic", 0x0 },
14467 { "Front Mic", 0x1 },
14468 { "Line", 0x2 },
14469 },
14470};
14471
14472static struct hda_input_mux alc663_m51va_capture_source = {
14473 .num_items = 2,
14474 .items = {
14475 { "Ext-Mic", 0x0 },
14476 { "D-Mic", 0x9 },
14477 },
14478};
14479
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014480#define alc662_mux_enum_info alc_mux_enum_info
14481#define alc662_mux_enum_get alc_mux_enum_get
Takashi Iwaie1406342008-02-11 18:32:32 +010014482#define alc662_mux_enum_put alc882_mux_enum_put
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014483
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014484/*
14485 * 2ch mode
14486 */
14487static struct hda_channel_mode alc662_3ST_2ch_modes[1] = {
14488 { 2, NULL }
14489};
14490
14491/*
14492 * 2ch mode
14493 */
14494static struct hda_verb alc662_3ST_ch2_init[] = {
14495 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
14496 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
14497 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
14498 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
14499 { } /* end */
14500};
14501
14502/*
14503 * 6ch mode
14504 */
14505static struct hda_verb alc662_3ST_ch6_init[] = {
14506 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14507 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
14508 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
14509 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14510 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
14511 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
14512 { } /* end */
14513};
14514
14515static struct hda_channel_mode alc662_3ST_6ch_modes[2] = {
14516 { 2, alc662_3ST_ch2_init },
14517 { 6, alc662_3ST_ch6_init },
14518};
14519
14520/*
14521 * 2ch mode
14522 */
14523static struct hda_verb alc662_sixstack_ch6_init[] = {
14524 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
14525 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
14526 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14527 { } /* end */
14528};
14529
14530/*
14531 * 6ch mode
14532 */
14533static struct hda_verb alc662_sixstack_ch8_init[] = {
14534 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14535 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14536 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14537 { } /* end */
14538};
14539
14540static struct hda_channel_mode alc662_5stack_modes[2] = {
14541 { 2, alc662_sixstack_ch6_init },
14542 { 6, alc662_sixstack_ch8_init },
14543};
14544
14545/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
14546 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
14547 */
14548
14549static struct snd_kcontrol_new alc662_base_mixer[] = {
14550 /* output mixer control */
14551 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010014552 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014553 HDA_CODEC_VOLUME("Surround Playback Volume", 0x3, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010014554 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014555 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
14556 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010014557 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
14558 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014559 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
14560
14561 /*Input mixer control */
14562 HDA_CODEC_VOLUME("CD Playback Volume", 0xb, 0x4, HDA_INPUT),
14563 HDA_CODEC_MUTE("CD Playback Switch", 0xb, 0x4, HDA_INPUT),
14564 HDA_CODEC_VOLUME("Line Playback Volume", 0xb, 0x02, HDA_INPUT),
14565 HDA_CODEC_MUTE("Line Playback Switch", 0xb, 0x02, HDA_INPUT),
14566 HDA_CODEC_VOLUME("Mic Playback Volume", 0xb, 0x0, HDA_INPUT),
14567 HDA_CODEC_MUTE("Mic Playback Switch", 0xb, 0x0, HDA_INPUT),
14568 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0xb, 0x01, HDA_INPUT),
14569 HDA_CODEC_MUTE("Front Mic Playback Switch", 0xb, 0x01, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014570 { } /* end */
14571};
14572
14573static struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = {
14574 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010014575 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014576 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
14577 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
14578 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
14579 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
14580 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
14581 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14582 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14583 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14584 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14585 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
14586 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014587 { } /* end */
14588};
14589
14590static struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = {
14591 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010014592 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014593 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010014594 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014595 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
14596 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010014597 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
14598 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014599 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
14600 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
14601 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
14602 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
14603 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
14604 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14605 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14606 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14607 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14608 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
14609 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014610 { } /* end */
14611};
14612
14613static struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = {
14614 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14615 HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010014616 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x03, 0x0, HDA_OUTPUT),
14617 HDA_BIND_MUTE("Speaker Playback Switch", 0x03, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014618 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
14619 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
14620 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
14621 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14622 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014623 { } /* end */
14624};
14625
Kailang Yang291702f2007-10-16 14:28:03 +020014626static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = {
Takashi Iwai86cd9292008-01-28 18:09:56 +010014627 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang291702f2007-10-16 14:28:03 +020014628
Herton Ronaldo Krzesinskib4818492008-02-23 11:34:12 +010014629 HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14630 HDA_CODEC_MUTE("Line-Out Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yang291702f2007-10-16 14:28:03 +020014631
14632 HDA_CODEC_VOLUME("e-Mic Boost", 0x18, 0, HDA_INPUT),
14633 HDA_CODEC_VOLUME("e-Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14634 HDA_CODEC_MUTE("e-Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14635
14636 HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT),
14637 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14638 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14639 { } /* end */
14640};
14641
Kailang Yang8c427222008-01-10 13:03:59 +010014642static struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = {
Takashi Iwai31bffaa2008-02-27 16:10:44 +010014643 HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14644 HDA_CODEC_MUTE("Line-Out Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010014645 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
14646 HDA_BIND_MUTE("Surround Playback Switch", 0x03, 2, HDA_INPUT),
14647 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
14648 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
14649 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x04, 1, 2, HDA_INPUT),
14650 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x04, 2, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010014651 HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010014652 HDA_BIND_MUTE("MuteCtrl Playback Switch", 0x0c, 2, HDA_INPUT),
14653 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
14654 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
14655 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14656 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14657 { } /* end */
14658};
14659
Kailang Yang6dda9f42008-05-27 12:05:31 +020014660static struct snd_kcontrol_new alc663_m51va_mixer[] = {
14661 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14662 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
14663 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
14664 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14665 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14666 HDA_CODEC_MUTE("DMic Playback Switch", 0x23, 0x9, HDA_INPUT),
14667 { } /* end */
14668};
14669
14670static struct snd_kcontrol_new alc663_g71v_mixer[] = {
14671 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14672 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
14673 HDA_CODEC_VOLUME("Front Playback Volume", 0x03, 0x0, HDA_OUTPUT),
14674 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
14675 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
14676
14677 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14678 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14679 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14680 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14681 { } /* end */
14682};
14683
14684static struct snd_kcontrol_new alc663_g50v_mixer[] = {
14685 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14686 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
14687 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
14688
14689 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14690 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14691 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14692 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14693 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
14694 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
14695 { } /* end */
14696};
14697
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014698static struct snd_kcontrol_new alc662_chmode_mixer[] = {
14699 {
14700 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
14701 .name = "Channel Mode",
14702 .info = alc_ch_mode_info,
14703 .get = alc_ch_mode_get,
14704 .put = alc_ch_mode_put,
14705 },
14706 { } /* end */
14707};
14708
14709static struct hda_verb alc662_init_verbs[] = {
14710 /* ADC: mute amp left and right */
14711 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14712 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
14713 /* Front mixer: unmute input/output amp left and right (volume = 0) */
14714
Takashi Iwaicb53c622007-08-10 17:21:45 +020014715 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14716 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
14717 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
14718 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
14719 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014720
Kailang Yangb60dd392007-09-20 12:50:29 +020014721 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14722 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14723 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14724 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14725 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14726 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014727
14728 /* Front Pin: output 0 (0x0c) */
14729 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14730 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14731
14732 /* Rear Pin: output 1 (0x0d) */
14733 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14734 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14735
14736 /* CLFE Pin: output 2 (0x0e) */
14737 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14738 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14739
14740 /* Mic (rear) pin: input vref at 80% */
14741 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14742 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14743 /* Front Mic pin: input vref at 80% */
14744 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14745 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14746 /* Line In pin: input */
14747 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14748 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14749 /* Line-2 In: Headphone output (output 0 - 0x0c) */
14750 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14751 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14752 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
14753 /* CD pin widget for input */
14754 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14755
14756 /* FIXME: use matrix-type input source selection */
14757 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
14758 /* Input mixer */
14759 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14760 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14761 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
14762 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Kailang Yang291702f2007-10-16 14:28:03 +020014763
14764 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14765 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14766 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
14767 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Kailang Yang6dda9f42008-05-27 12:05:31 +020014768
14769 /* always trun on EAPD */
14770 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
14771 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
14772
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014773 { }
14774};
14775
14776static struct hda_verb alc662_sue_init_verbs[] = {
14777 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
14778 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
Kailang Yang291702f2007-10-16 14:28:03 +020014779 {}
14780};
14781
14782static struct hda_verb alc662_eeepc_sue_init_verbs[] = {
14783 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14784 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14785 {}
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014786};
14787
Kailang Yang8c427222008-01-10 13:03:59 +010014788/* Set Unsolicited Event*/
14789static struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = {
14790 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14791 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14792 {}
14793};
14794
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014795/*
14796 * generic initialization of ADC, input mixers and output mixers
14797 */
14798static struct hda_verb alc662_auto_init_verbs[] = {
14799 /*
14800 * Unmute ADC and set the default input to mic-in
14801 */
14802 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
14803 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14804
14805 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
14806 * mixer widget
14807 * Note: PASD motherboards uses the Line In 2 as the input for front
14808 * panel mic (mic 2)
14809 */
14810 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020014811 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14812 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
14813 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
14814 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
14815 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014816
14817 /*
14818 * Set up output mixers (0x0c - 0x0f)
14819 */
14820 /* set vol=0 to output mixers */
14821 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14822 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14823 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14824
14825 /* set up input amps for analog loopback */
14826 /* Amp Indices: DAC = 0, mixer = 1 */
Kailang Yangb60dd392007-09-20 12:50:29 +020014827 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14828 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14829 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14830 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14831 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14832 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014833
14834
14835 /* FIXME: use matrix-type input source selection */
14836 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
14837 /* Input mixer */
14838 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangd1a991a2007-08-15 16:21:59 +020014839 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014840 { }
14841};
14842
Takashi Iwai24fb9172008-09-02 14:48:20 +020014843/* additional verbs for ALC663 */
14844static struct hda_verb alc663_auto_init_verbs[] = {
14845 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14846 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14847 { }
14848};
14849
Kailang Yang6dda9f42008-05-27 12:05:31 +020014850static struct hda_verb alc663_m51va_init_verbs[] = {
14851 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14852 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14853 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
14854
14855 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
14856
14857 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14858 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14859 {}
14860};
14861
14862static struct hda_verb alc663_g71v_init_verbs[] = {
14863 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14864 /* {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
14865 /* {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, */ /* Headphone */
14866
14867 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14868 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14869 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
14870
14871 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
14872 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_MIC_EVENT},
14873 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
14874 {}
14875};
14876
14877static struct hda_verb alc663_g50v_init_verbs[] = {
14878 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14879 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14880 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
14881
14882 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14883 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14884 {}
14885};
14886
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014887/* capture mixer elements */
14888static struct snd_kcontrol_new alc662_capture_mixer[] = {
14889 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
14890 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
14891 {
14892 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
14893 /* The multiple "Capture Source" controls confuse alsamixer
14894 * So call somewhat different..
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014895 */
14896 /* .name = "Capture Source", */
14897 .name = "Input Source",
14898 .count = 1,
Herton Ronaldo Krzesinski6e7939b2007-12-19 17:49:02 +010014899 .info = alc662_mux_enum_info,
14900 .get = alc662_mux_enum_get,
14901 .put = alc662_mux_enum_put,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014902 },
14903 { } /* end */
14904};
14905
14906static void alc662_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
14907{
14908 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014909 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014910
14911 present = snd_hda_codec_read(codec, 0x14, 0,
14912 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020014913 bits = present ? HDA_AMP_MUTE : 0;
14914 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
14915 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014916}
14917
14918static void alc662_lenovo_101e_all_automute(struct hda_codec *codec)
14919{
14920 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014921 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014922
14923 present = snd_hda_codec_read(codec, 0x1b, 0,
14924 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020014925 bits = present ? HDA_AMP_MUTE : 0;
14926 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
14927 HDA_AMP_MUTE, bits);
14928 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
14929 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014930}
14931
14932static void alc662_lenovo_101e_unsol_event(struct hda_codec *codec,
14933 unsigned int res)
14934{
14935 if ((res >> 26) == ALC880_HP_EVENT)
14936 alc662_lenovo_101e_all_automute(codec);
14937 if ((res >> 26) == ALC880_FRONT_EVENT)
14938 alc662_lenovo_101e_ispeaker_automute(codec);
14939}
14940
Kailang Yang291702f2007-10-16 14:28:03 +020014941static void alc662_eeepc_mic_automute(struct hda_codec *codec)
14942{
14943 unsigned int present;
14944
14945 present = snd_hda_codec_read(codec, 0x18, 0,
14946 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
14947 snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
14948 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
14949 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
14950 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
14951 snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
14952 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
14953 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
14954 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
14955}
14956
14957/* unsolicited event for HP jack sensing */
14958static void alc662_eeepc_unsol_event(struct hda_codec *codec,
14959 unsigned int res)
14960{
14961 if ((res >> 26) == ALC880_HP_EVENT)
14962 alc262_hippo1_automute( codec );
14963
14964 if ((res >> 26) == ALC880_MIC_EVENT)
14965 alc662_eeepc_mic_automute(codec);
14966}
14967
14968static void alc662_eeepc_inithook(struct hda_codec *codec)
14969{
14970 alc262_hippo1_automute( codec );
14971 alc662_eeepc_mic_automute(codec);
14972}
14973
Kailang Yang8c427222008-01-10 13:03:59 +010014974static void alc662_eeepc_ep20_automute(struct hda_codec *codec)
14975{
14976 unsigned int mute;
14977 unsigned int present;
14978
14979 snd_hda_codec_read(codec, 0x14, 0, AC_VERB_SET_PIN_SENSE, 0);
14980 present = snd_hda_codec_read(codec, 0x14, 0,
14981 AC_VERB_GET_PIN_SENSE, 0);
14982 present = (present & 0x80000000) != 0;
14983 if (present) {
14984 /* mute internal speaker */
14985 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +020014986 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yang8c427222008-01-10 13:03:59 +010014987 } else {
14988 /* unmute internal speaker if necessary */
14989 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
14990 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +020014991 HDA_AMP_MUTE, mute);
Kailang Yang8c427222008-01-10 13:03:59 +010014992 }
14993}
14994
14995/* unsolicited event for HP jack sensing */
14996static void alc662_eeepc_ep20_unsol_event(struct hda_codec *codec,
14997 unsigned int res)
14998{
14999 if ((res >> 26) == ALC880_HP_EVENT)
15000 alc662_eeepc_ep20_automute(codec);
15001}
15002
15003static void alc662_eeepc_ep20_inithook(struct hda_codec *codec)
15004{
15005 alc662_eeepc_ep20_automute(codec);
15006}
15007
Kailang Yang6dda9f42008-05-27 12:05:31 +020015008static void alc663_m51va_speaker_automute(struct hda_codec *codec)
15009{
15010 unsigned int present;
15011 unsigned char bits;
15012
15013 present = snd_hda_codec_read(codec, 0x21, 0,
15014 AC_VERB_GET_PIN_SENSE, 0)
15015 & AC_PINSENSE_PRESENCE;
15016 bits = present ? HDA_AMP_MUTE : 0;
15017 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
15018 HDA_AMP_MUTE, bits);
15019}
15020
15021static void alc663_m51va_mic_automute(struct hda_codec *codec)
15022{
15023 unsigned int present;
15024
15025 present = snd_hda_codec_read(codec, 0x18, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +020015026 AC_VERB_GET_PIN_SENSE, 0)
15027 & AC_PINSENSE_PRESENCE;
Kailang Yang6dda9f42008-05-27 12:05:31 +020015028 snd_hda_codec_write_cache(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangea1fb292008-08-26 12:58:38 +020015029 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
Kailang Yang6dda9f42008-05-27 12:05:31 +020015030 snd_hda_codec_write_cache(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangea1fb292008-08-26 12:58:38 +020015031 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
Kailang Yang6dda9f42008-05-27 12:05:31 +020015032 snd_hda_codec_write_cache(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangea1fb292008-08-26 12:58:38 +020015033 0x7000 | (0x09 << 8) | (present ? 0x80 : 0));
Kailang Yang6dda9f42008-05-27 12:05:31 +020015034 snd_hda_codec_write_cache(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangea1fb292008-08-26 12:58:38 +020015035 0x7000 | (0x09 << 8) | (present ? 0x80 : 0));
Kailang Yang6dda9f42008-05-27 12:05:31 +020015036}
15037
15038static void alc663_m51va_unsol_event(struct hda_codec *codec,
15039 unsigned int res)
15040{
15041 switch (res >> 26) {
15042 case ALC880_HP_EVENT:
15043 alc663_m51va_speaker_automute(codec);
15044 break;
15045 case ALC880_MIC_EVENT:
15046 alc663_m51va_mic_automute(codec);
15047 break;
15048 }
15049}
15050
15051static void alc663_m51va_inithook(struct hda_codec *codec)
15052{
15053 alc663_m51va_speaker_automute(codec);
15054 alc663_m51va_mic_automute(codec);
15055}
15056
15057static void alc663_g71v_hp_automute(struct hda_codec *codec)
15058{
15059 unsigned int present;
15060 unsigned char bits;
15061
15062 present = snd_hda_codec_read(codec, 0x21, 0,
15063 AC_VERB_GET_PIN_SENSE, 0)
15064 & AC_PINSENSE_PRESENCE;
15065 bits = present ? HDA_AMP_MUTE : 0;
15066 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
15067 HDA_AMP_MUTE, bits);
15068 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
15069 HDA_AMP_MUTE, bits);
15070}
15071
15072static void alc663_g71v_front_automute(struct hda_codec *codec)
15073{
15074 unsigned int present;
15075 unsigned char bits;
15076
15077 present = snd_hda_codec_read(codec, 0x15, 0,
15078 AC_VERB_GET_PIN_SENSE, 0)
15079 & AC_PINSENSE_PRESENCE;
15080 bits = present ? HDA_AMP_MUTE : 0;
15081 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
15082 HDA_AMP_MUTE, bits);
15083}
15084
15085static void alc663_g71v_unsol_event(struct hda_codec *codec,
15086 unsigned int res)
15087{
15088 switch (res >> 26) {
15089 case ALC880_HP_EVENT:
15090 alc663_g71v_hp_automute(codec);
15091 break;
15092 case ALC880_FRONT_EVENT:
15093 alc663_g71v_front_automute(codec);
15094 break;
15095 case ALC880_MIC_EVENT:
15096 alc662_eeepc_mic_automute(codec);
15097 break;
15098 }
15099}
15100
15101static void alc663_g71v_inithook(struct hda_codec *codec)
15102{
15103 alc663_g71v_front_automute(codec);
15104 alc663_g71v_hp_automute(codec);
15105 alc662_eeepc_mic_automute(codec);
15106}
15107
15108static void alc663_g50v_unsol_event(struct hda_codec *codec,
15109 unsigned int res)
15110{
15111 switch (res >> 26) {
15112 case ALC880_HP_EVENT:
15113 alc663_m51va_speaker_automute(codec);
15114 break;
15115 case ALC880_MIC_EVENT:
15116 alc662_eeepc_mic_automute(codec);
15117 break;
15118 }
15119}
15120
15121static void alc663_g50v_inithook(struct hda_codec *codec)
15122{
15123 alc663_m51va_speaker_automute(codec);
15124 alc662_eeepc_mic_automute(codec);
15125}
15126
Takashi Iwaicb53c622007-08-10 17:21:45 +020015127#ifdef CONFIG_SND_HDA_POWER_SAVE
15128#define alc662_loopbacks alc880_loopbacks
15129#endif
15130
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015131
15132/* pcm configuration: identiacal with ALC880 */
15133#define alc662_pcm_analog_playback alc880_pcm_analog_playback
15134#define alc662_pcm_analog_capture alc880_pcm_analog_capture
15135#define alc662_pcm_digital_playback alc880_pcm_digital_playback
15136#define alc662_pcm_digital_capture alc880_pcm_digital_capture
15137
15138/*
15139 * configuration and preset
15140 */
15141static const char *alc662_models[ALC662_MODEL_LAST] = {
15142 [ALC662_3ST_2ch_DIG] = "3stack-dig",
15143 [ALC662_3ST_6ch_DIG] = "3stack-6ch-dig",
15144 [ALC662_3ST_6ch] = "3stack-6ch",
15145 [ALC662_5ST_DIG] = "6stack-dig",
15146 [ALC662_LENOVO_101E] = "lenovo-101e",
Takashi Iwaib995d762007-10-17 10:41:06 +020015147 [ALC662_ASUS_EEEPC_P701] = "eeepc-p701",
Kailang Yang8c427222008-01-10 13:03:59 +010015148 [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20",
Kailang Yang6dda9f42008-05-27 12:05:31 +020015149 [ALC663_ASUS_M51VA] = "m51va",
15150 [ALC663_ASUS_G71V] = "g71v",
15151 [ALC663_ASUS_H13] = "h13",
15152 [ALC663_ASUS_G50V] = "g50v",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015153 [ALC662_AUTO] = "auto",
15154};
15155
15156static struct snd_pci_quirk alc662_cfg_tbl[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020015157 SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS G71V", ALC663_ASUS_G71V),
15158 SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M51VA", ALC663_ASUS_M51VA),
15159 SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS M51VA", ALC663_ASUS_G50V),
Herton Ronaldo Krzesinski3da23ca2008-03-14 12:52:59 +010015160 SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG),
Kailang Yang291702f2007-10-16 14:28:03 +020015161 SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701),
Kailang Yang8c427222008-01-10 13:03:59 +010015162 SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010015163 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E),
Kailang Yang6dda9f42008-05-27 12:05:31 +020015164 SND_PCI_QUIRK(0x1854, 0x2000, "ASUS H13-2000", ALC663_ASUS_H13),
15165 SND_PCI_QUIRK(0x1854, 0x2001, "ASUS H13-2001", ALC663_ASUS_H13),
15166 SND_PCI_QUIRK(0x1854, 0x2002, "ASUS H13-2002", ALC663_ASUS_H13),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015167 {}
15168};
15169
15170static struct alc_config_preset alc662_presets[] = {
15171 [ALC662_3ST_2ch_DIG] = {
Kailang Yang291702f2007-10-16 14:28:03 +020015172 .mixers = { alc662_3ST_2ch_mixer, alc662_capture_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015173 .init_verbs = { alc662_init_verbs },
15174 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15175 .dac_nids = alc662_dac_nids,
15176 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015177 .dig_in_nid = ALC662_DIGIN_NID,
15178 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15179 .channel_mode = alc662_3ST_2ch_modes,
15180 .input_mux = &alc662_capture_source,
15181 },
15182 [ALC662_3ST_6ch_DIG] = {
Kailang Yang291702f2007-10-16 14:28:03 +020015183 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer,
15184 alc662_capture_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015185 .init_verbs = { alc662_init_verbs },
15186 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15187 .dac_nids = alc662_dac_nids,
15188 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015189 .dig_in_nid = ALC662_DIGIN_NID,
15190 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
15191 .channel_mode = alc662_3ST_6ch_modes,
15192 .need_dac_fix = 1,
15193 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015194 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015195 [ALC662_3ST_6ch] = {
Kailang Yang291702f2007-10-16 14:28:03 +020015196 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer,
15197 alc662_capture_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015198 .init_verbs = { alc662_init_verbs },
15199 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15200 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015201 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
15202 .channel_mode = alc662_3ST_6ch_modes,
15203 .need_dac_fix = 1,
15204 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015205 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015206 [ALC662_5ST_DIG] = {
Kailang Yang291702f2007-10-16 14:28:03 +020015207 .mixers = { alc662_base_mixer, alc662_chmode_mixer,
15208 alc662_capture_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015209 .init_verbs = { alc662_init_verbs },
15210 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15211 .dac_nids = alc662_dac_nids,
15212 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015213 .dig_in_nid = ALC662_DIGIN_NID,
15214 .num_channel_mode = ARRAY_SIZE(alc662_5stack_modes),
15215 .channel_mode = alc662_5stack_modes,
15216 .input_mux = &alc662_capture_source,
15217 },
15218 [ALC662_LENOVO_101E] = {
Kailang Yang291702f2007-10-16 14:28:03 +020015219 .mixers = { alc662_lenovo_101e_mixer, alc662_capture_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015220 .init_verbs = { alc662_init_verbs, alc662_sue_init_verbs },
15221 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15222 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015223 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15224 .channel_mode = alc662_3ST_2ch_modes,
15225 .input_mux = &alc662_lenovo_101e_capture_source,
15226 .unsol_event = alc662_lenovo_101e_unsol_event,
15227 .init_hook = alc662_lenovo_101e_all_automute,
15228 },
Kailang Yang291702f2007-10-16 14:28:03 +020015229 [ALC662_ASUS_EEEPC_P701] = {
15230 .mixers = { alc662_eeepc_p701_mixer, alc662_capture_mixer },
15231 .init_verbs = { alc662_init_verbs,
15232 alc662_eeepc_sue_init_verbs },
15233 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15234 .dac_nids = alc662_dac_nids,
Kailang Yang291702f2007-10-16 14:28:03 +020015235 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15236 .channel_mode = alc662_3ST_2ch_modes,
15237 .input_mux = &alc662_eeepc_capture_source,
15238 .unsol_event = alc662_eeepc_unsol_event,
15239 .init_hook = alc662_eeepc_inithook,
15240 },
Kailang Yang8c427222008-01-10 13:03:59 +010015241 [ALC662_ASUS_EEEPC_EP20] = {
15242 .mixers = { alc662_eeepc_ep20_mixer, alc662_capture_mixer,
15243 alc662_chmode_mixer },
15244 .init_verbs = { alc662_init_verbs,
15245 alc662_eeepc_ep20_sue_init_verbs },
15246 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15247 .dac_nids = alc662_dac_nids,
Kailang Yang8c427222008-01-10 13:03:59 +010015248 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
15249 .channel_mode = alc662_3ST_6ch_modes,
15250 .input_mux = &alc662_lenovo_101e_capture_source,
15251 .unsol_event = alc662_eeepc_ep20_unsol_event,
15252 .init_hook = alc662_eeepc_ep20_inithook,
15253 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020015254 [ALC663_ASUS_M51VA] = {
15255 .mixers = { alc663_m51va_mixer, alc662_capture_mixer},
15256 .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
15257 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15258 .dac_nids = alc662_dac_nids,
15259 .dig_out_nid = ALC662_DIGOUT_NID,
15260 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15261 .channel_mode = alc662_3ST_2ch_modes,
15262 .input_mux = &alc663_m51va_capture_source,
15263 .unsol_event = alc663_m51va_unsol_event,
15264 .init_hook = alc663_m51va_inithook,
15265 },
15266 [ALC663_ASUS_G71V] = {
15267 .mixers = { alc663_g71v_mixer, alc662_capture_mixer},
15268 .init_verbs = { alc662_init_verbs, alc663_g71v_init_verbs },
15269 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15270 .dac_nids = alc662_dac_nids,
15271 .dig_out_nid = ALC662_DIGOUT_NID,
15272 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15273 .channel_mode = alc662_3ST_2ch_modes,
15274 .input_mux = &alc662_eeepc_capture_source,
15275 .unsol_event = alc663_g71v_unsol_event,
15276 .init_hook = alc663_g71v_inithook,
15277 },
15278 [ALC663_ASUS_H13] = {
15279 .mixers = { alc663_m51va_mixer, alc662_capture_mixer},
15280 .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
15281 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15282 .dac_nids = alc662_dac_nids,
15283 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15284 .channel_mode = alc662_3ST_2ch_modes,
15285 .input_mux = &alc663_m51va_capture_source,
15286 .unsol_event = alc663_m51va_unsol_event,
15287 .init_hook = alc663_m51va_inithook,
15288 },
15289 [ALC663_ASUS_G50V] = {
15290 .mixers = { alc663_g50v_mixer, alc662_capture_mixer},
15291 .init_verbs = { alc662_init_verbs, alc663_g50v_init_verbs },
15292 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15293 .dac_nids = alc662_dac_nids,
15294 .dig_out_nid = ALC662_DIGOUT_NID,
15295 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
15296 .channel_mode = alc662_3ST_6ch_modes,
15297 .input_mux = &alc663_capture_source,
15298 .unsol_event = alc663_g50v_unsol_event,
15299 .init_hook = alc663_g50v_inithook,
15300 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015301};
15302
15303
15304/*
15305 * BIOS auto configuration
15306 */
15307
15308/* add playback controls from the parsed DAC table */
15309static int alc662_auto_create_multi_out_ctls(struct alc_spec *spec,
15310 const struct auto_pin_cfg *cfg)
15311{
15312 char name[32];
15313 static const char *chname[4] = {
15314 "Front", "Surround", NULL /*CLFE*/, "Side"
15315 };
15316 hda_nid_t nid;
15317 int i, err;
15318
15319 for (i = 0; i < cfg->line_outs; i++) {
15320 if (!spec->multiout.dac_nids[i])
15321 continue;
Kailang Yangb60dd392007-09-20 12:50:29 +020015322 nid = alc880_idx_to_dac(i);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015323 if (i == 2) {
15324 /* Center/LFE */
15325 err = add_control(spec, ALC_CTL_WIDGET_VOL,
15326 "Center Playback Volume",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015327 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
15328 HDA_OUTPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015329 if (err < 0)
15330 return err;
15331 err = add_control(spec, ALC_CTL_WIDGET_VOL,
15332 "LFE Playback Volume",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015333 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
15334 HDA_OUTPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015335 if (err < 0)
15336 return err;
15337 err = add_control(spec, ALC_CTL_BIND_MUTE,
15338 "Center Playback Switch",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015339 HDA_COMPOSE_AMP_VAL(nid, 1, 2,
15340 HDA_INPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015341 if (err < 0)
15342 return err;
15343 err = add_control(spec, ALC_CTL_BIND_MUTE,
15344 "LFE Playback Switch",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015345 HDA_COMPOSE_AMP_VAL(nid, 2, 2,
15346 HDA_INPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015347 if (err < 0)
15348 return err;
15349 } else {
15350 sprintf(name, "%s Playback Volume", chname[i]);
15351 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015352 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
15353 HDA_OUTPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015354 if (err < 0)
15355 return err;
15356 sprintf(name, "%s Playback Switch", chname[i]);
15357 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015358 HDA_COMPOSE_AMP_VAL(nid, 3, 2,
15359 HDA_INPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015360 if (err < 0)
15361 return err;
15362 }
15363 }
15364 return 0;
15365}
15366
15367/* add playback controls for speaker and HP outputs */
15368static int alc662_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
15369 const char *pfx)
15370{
15371 hda_nid_t nid;
15372 int err;
15373 char name[32];
15374
15375 if (!pin)
15376 return 0;
15377
Takashi Iwai24fb9172008-09-02 14:48:20 +020015378 if (pin == 0x17) {
15379 /* ALC663 has a mono output pin on 0x17 */
15380 sprintf(name, "%s Playback Switch", pfx);
15381 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
15382 HDA_COMPOSE_AMP_VAL(pin, 2, 0, HDA_OUTPUT));
15383 return err;
15384 }
15385
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015386 if (alc880_is_fixed_pin(pin)) {
15387 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
15388 /* printk("DAC nid=%x\n",nid); */
15389 /* specify the DAC as the extra output */
15390 if (!spec->multiout.hp_nid)
15391 spec->multiout.hp_nid = nid;
15392 else
15393 spec->multiout.extra_out_nid[0] = nid;
15394 /* control HP volume/switch on the output mixer amp */
15395 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
15396 sprintf(name, "%s Playback Volume", pfx);
15397 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
15398 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
15399 if (err < 0)
15400 return err;
15401 sprintf(name, "%s Playback Switch", pfx);
15402 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
15403 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
15404 if (err < 0)
15405 return err;
15406 } else if (alc880_is_multi_pin(pin)) {
15407 /* set manual connection */
15408 /* we have only a switch on HP-out PIN */
15409 sprintf(name, "%s Playback Switch", pfx);
15410 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
15411 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
15412 if (err < 0)
15413 return err;
15414 }
15415 return 0;
15416}
15417
15418/* create playback/capture controls for input pins */
15419static int alc662_auto_create_analog_input_ctls(struct alc_spec *spec,
15420 const struct auto_pin_cfg *cfg)
15421{
15422 struct hda_input_mux *imux = &spec->private_imux;
15423 int i, err, idx;
15424
15425 for (i = 0; i < AUTO_PIN_LAST; i++) {
15426 if (alc880_is_input_pin(cfg->input_pins[i])) {
15427 idx = alc880_input_pin_idx(cfg->input_pins[i]);
15428 err = new_analog_input(spec, cfg->input_pins[i],
15429 auto_pin_cfg_labels[i],
15430 idx, 0x0b);
15431 if (err < 0)
15432 return err;
15433 imux->items[imux->num_items].label =
15434 auto_pin_cfg_labels[i];
15435 imux->items[imux->num_items].index =
15436 alc880_input_pin_idx(cfg->input_pins[i]);
15437 imux->num_items++;
15438 }
15439 }
15440 return 0;
15441}
15442
15443static void alc662_auto_set_output_and_unmute(struct hda_codec *codec,
15444 hda_nid_t nid, int pin_type,
15445 int dac_idx)
15446{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010015447 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015448 /* need the manual connection? */
15449 if (alc880_is_multi_pin(nid)) {
15450 struct alc_spec *spec = codec->spec;
15451 int idx = alc880_multi_pin_idx(nid);
15452 snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
15453 AC_VERB_SET_CONNECT_SEL,
15454 alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
15455 }
15456}
15457
15458static void alc662_auto_init_multi_out(struct hda_codec *codec)
15459{
15460 struct alc_spec *spec = codec->spec;
15461 int i;
15462
Kailang Yang8c427222008-01-10 13:03:59 +010015463 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015464 for (i = 0; i <= HDA_SIDE; i++) {
15465 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020015466 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015467 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020015468 alc662_auto_set_output_and_unmute(codec, nid, pin_type,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015469 i);
15470 }
15471}
15472
15473static void alc662_auto_init_hp_out(struct hda_codec *codec)
15474{
15475 struct alc_spec *spec = codec->spec;
15476 hda_nid_t pin;
15477
15478 pin = spec->autocfg.hp_pins[0];
15479 if (pin) /* connect to front */
15480 /* use dac 0 */
15481 alc662_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010015482 pin = spec->autocfg.speaker_pins[0];
15483 if (pin)
15484 alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015485}
15486
15487#define alc662_is_input_pin(nid) alc880_is_input_pin(nid)
15488#define ALC662_PIN_CD_NID ALC880_PIN_CD_NID
15489
15490static void alc662_auto_init_analog_input(struct hda_codec *codec)
15491{
15492 struct alc_spec *spec = codec->spec;
15493 int i;
15494
15495 for (i = 0; i < AUTO_PIN_LAST; i++) {
15496 hda_nid_t nid = spec->autocfg.input_pins[i];
15497 if (alc662_is_input_pin(nid)) {
15498 snd_hda_codec_write(codec, nid, 0,
15499 AC_VERB_SET_PIN_WIDGET_CONTROL,
15500 (i <= AUTO_PIN_FRONT_MIC ?
15501 PIN_VREF80 : PIN_IN));
15502 if (nid != ALC662_PIN_CD_NID)
15503 snd_hda_codec_write(codec, nid, 0,
15504 AC_VERB_SET_AMP_GAIN_MUTE,
15505 AMP_OUT_MUTE);
15506 }
15507 }
15508}
15509
Takashi Iwaif511b012008-08-15 16:46:42 +020015510#define alc662_auto_init_input_src alc882_auto_init_input_src
15511
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015512static int alc662_parse_auto_config(struct hda_codec *codec)
15513{
15514 struct alc_spec *spec = codec->spec;
15515 int err;
15516 static hda_nid_t alc662_ignore[] = { 0x1d, 0 };
15517
15518 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
15519 alc662_ignore);
15520 if (err < 0)
15521 return err;
15522 if (!spec->autocfg.line_outs)
15523 return 0; /* can't find valid BIOS pin config */
15524
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015525 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
15526 if (err < 0)
15527 return err;
15528 err = alc662_auto_create_multi_out_ctls(spec, &spec->autocfg);
15529 if (err < 0)
15530 return err;
15531 err = alc662_auto_create_extra_out(spec,
15532 spec->autocfg.speaker_pins[0],
15533 "Speaker");
15534 if (err < 0)
15535 return err;
15536 err = alc662_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
15537 "Headphone");
15538 if (err < 0)
15539 return err;
15540 err = alc662_auto_create_analog_input_ctls(spec, &spec->autocfg);
15541 if (err < 0)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015542 return err;
15543
15544 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
15545
15546 if (spec->autocfg.dig_out_pin)
15547 spec->multiout.dig_out_nid = ALC880_DIGOUT_NID;
15548
15549 if (spec->kctl_alloc)
15550 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
15551
15552 spec->num_mux_defs = 1;
15553 spec->input_mux = &spec->private_imux;
Kailang Yangea1fb292008-08-26 12:58:38 +020015554
Takashi Iwai8c87286f2007-06-19 12:11:16 +020015555 spec->init_verbs[spec->num_init_verbs++] = alc662_auto_init_verbs;
Takashi Iwai24fb9172008-09-02 14:48:20 +020015556 if (codec->vendor_id == 0x10ec0663)
15557 spec->init_verbs[spec->num_init_verbs++] =
15558 alc663_auto_init_verbs;
Takashi Iwaiee979a142008-09-02 15:42:20 +020015559
15560 err = alc_auto_add_mic_boost(codec);
15561 if (err < 0)
15562 return err;
15563
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015564 spec->mixers[spec->num_mixers] = alc662_capture_mixer;
15565 spec->num_mixers++;
Takashi Iwai8c87286f2007-06-19 12:11:16 +020015566 return 1;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015567}
15568
15569/* additional initialization for auto-configuration model */
15570static void alc662_auto_init(struct hda_codec *codec)
15571{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010015572 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015573 alc662_auto_init_multi_out(codec);
15574 alc662_auto_init_hp_out(codec);
15575 alc662_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020015576 alc662_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010015577 if (spec->unsol_event)
15578 alc_sku_automute(codec);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015579}
15580
15581static int patch_alc662(struct hda_codec *codec)
15582{
15583 struct alc_spec *spec;
15584 int err, board_config;
15585
15586 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
15587 if (!spec)
15588 return -ENOMEM;
15589
15590 codec->spec = spec;
15591
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020015592 alc_fix_pll_init(codec, 0x20, 0x04, 15);
15593
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015594 board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST,
15595 alc662_models,
15596 alc662_cfg_tbl);
15597 if (board_config < 0) {
15598 printk(KERN_INFO "hda_codec: Unknown model for ALC662, "
15599 "trying auto-probe from BIOS...\n");
15600 board_config = ALC662_AUTO;
15601 }
15602
15603 if (board_config == ALC662_AUTO) {
15604 /* automatic parse from the BIOS config */
15605 err = alc662_parse_auto_config(codec);
15606 if (err < 0) {
15607 alc_free(codec);
15608 return err;
Takashi Iwai8c87286f2007-06-19 12:11:16 +020015609 } else if (!err) {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015610 printk(KERN_INFO
15611 "hda_codec: Cannot set up configuration "
15612 "from BIOS. Using base mode...\n");
15613 board_config = ALC662_3ST_2ch_DIG;
15614 }
15615 }
15616
15617 if (board_config != ALC662_AUTO)
15618 setup_preset(spec, &alc662_presets[board_config]);
15619
Kailang Yang6dda9f42008-05-27 12:05:31 +020015620 if (codec->vendor_id == 0x10ec0663) {
15621 spec->stream_name_analog = "ALC663 Analog";
15622 spec->stream_name_digital = "ALC663 Digital";
15623 } else {
15624 spec->stream_name_analog = "ALC662 Analog";
15625 spec->stream_name_digital = "ALC662 Digital";
15626 }
15627
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015628 spec->stream_analog_playback = &alc662_pcm_analog_playback;
15629 spec->stream_analog_capture = &alc662_pcm_analog_capture;
15630
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015631 spec->stream_digital_playback = &alc662_pcm_digital_playback;
15632 spec->stream_digital_capture = &alc662_pcm_digital_capture;
15633
Takashi Iwaie1406342008-02-11 18:32:32 +010015634 spec->adc_nids = alc662_adc_nids;
15635 spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids);
15636 spec->capsrc_nids = alc662_capsrc_nids;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015637
Takashi Iwai2134ea42008-01-10 16:53:55 +010015638 spec->vmaster_nid = 0x02;
15639
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015640 codec->patch_ops = alc_patch_ops;
15641 if (board_config == ALC662_AUTO)
15642 spec->init_hook = alc662_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020015643#ifdef CONFIG_SND_HDA_POWER_SAVE
15644 if (!spec->loopback.amplist)
15645 spec->loopback.amplist = alc662_loopbacks;
15646#endif
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015647
15648 return 0;
15649}
15650
15651/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070015652 * patch entries
15653 */
15654struct hda_codec_preset snd_hda_preset_realtek[] = {
15655 { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
Kailang Yangdf694da2005-12-05 19:42:22 +010015656 { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
Kailang Yangf6a92242007-12-13 16:52:54 +010015657 { .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 },
Kailang Yanga361d842007-06-05 12:30:55 +020015658 { .id = 0x10ec0268, .name = "ALC268", .patch = patch_alc268 },
Kailang Yangf6a92242007-12-13 16:52:54 +010015659 { .id = 0x10ec0269, .name = "ALC269", .patch = patch_alc269 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015660 { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015661 .patch = patch_alc861 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015662 { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
15663 { .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 },
15664 { .id = 0x10ec0862, .name = "ALC861-VD", .patch = patch_alc861vd },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015665 { .id = 0x10ec0662, .rev = 0x100002, .name = "ALC662 rev2",
15666 .patch = patch_alc883 },
15667 { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1",
15668 .patch = patch_alc662 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020015669 { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015670 { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070015671 { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015672 { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc883 },
Takashi Iwaicb308f92008-04-16 14:13:29 +020015673 { .id = 0x10ec0885, .rev = 0x100103, .name = "ALC889A",
Takashi Iwai7943a8a2008-04-16 17:29:09 +020015674 .patch = patch_alc882 }, /* should be patch_alc883() in future */
Kailang Yangdf694da2005-12-05 19:42:22 +010015675 { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015676 { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc883 },
Kailang Yangf6a92242007-12-13 16:52:54 +010015677 { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc883 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070015678 {} /* terminator */
15679};