blob: 700fc8632c663931d11a5430d30c5dfe62e8c1cf [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Universal Interface for Intel High Definition Audio Codec
3 *
4 * HD audio interface patch for ALC 260/880/882 codecs
5 *
Kailang Yangdf694da2005-12-05 19:42:22 +01006 * Copyright (c) 2004 Kailang Yang <kailang@realtek.com.tw>
7 * PeiSen Hou <pshou@realtek.com.tw>
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 * Takashi Iwai <tiwai@suse.de>
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01009 * Jonathan Woithe <jwoithe@physics.adelaide.edu.au>
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 *
11 * This driver is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This driver is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <linux/init.h>
27#include <linux/delay.h>
28#include <linux/slab.h>
29#include <linux/pci.h>
30#include <sound/core.h>
31#include "hda_codec.h"
32#include "hda_local.h"
Harvey Harrison3c9a3202008-02-29 11:59:26 +010033#include "hda_patch.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070034
Kailang Yangccc656c2006-10-17 12:32:26 +020035#define ALC880_FRONT_EVENT 0x01
36#define ALC880_DCVOL_EVENT 0x02
37#define ALC880_HP_EVENT 0x04
38#define ALC880_MIC_EVENT 0x08
Linus Torvalds1da177e2005-04-16 15:20:36 -070039
40/* ALC880 board config type */
41enum {
Linus Torvalds1da177e2005-04-16 15:20:36 -070042 ALC880_3ST,
43 ALC880_3ST_DIG,
44 ALC880_5ST,
45 ALC880_5ST_DIG,
46 ALC880_W810,
Takashi Iwaidfc0ff62005-05-12 14:31:49 +020047 ALC880_Z71V,
Takashi Iwaib6482d42005-06-27 15:32:43 +020048 ALC880_6ST,
Takashi Iwai16ded522005-06-10 19:58:24 +020049 ALC880_6ST_DIG,
50 ALC880_F1734,
51 ALC880_ASUS,
52 ALC880_ASUS_DIG,
53 ALC880_ASUS_W1V,
Kailang Yangdf694da2005-12-05 19:42:22 +010054 ALC880_ASUS_DIG2,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +010055 ALC880_FUJITSU,
Takashi Iwai16ded522005-06-10 19:58:24 +020056 ALC880_UNIWILL_DIG,
Kailang Yangccc656c2006-10-17 12:32:26 +020057 ALC880_UNIWILL,
58 ALC880_UNIWILL_P53,
Kailang Yangdf694da2005-12-05 19:42:22 +010059 ALC880_CLEVO,
60 ALC880_TCL_S700,
Takashi Iwaiae6b8132006-03-03 16:47:17 +010061 ALC880_LG,
Takashi Iwaid6815182006-03-23 16:06:23 +010062 ALC880_LG_LW,
Takashi Iwaidf99cd32008-04-25 15:25:04 +020063 ALC880_MEDION_RIM,
Takashi Iwaie9edcee2005-06-13 14:16:38 +020064#ifdef CONFIG_SND_DEBUG
65 ALC880_TEST,
66#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010067 ALC880_AUTO,
Takashi Iwai16ded522005-06-10 19:58:24 +020068 ALC880_MODEL_LAST /* last tag */
69};
70
71/* ALC260 models */
72enum {
73 ALC260_BASIC,
74 ALC260_HP,
Kailang Yang3f878302008-08-26 13:02:23 +020075 ALC260_HP_DC7600,
Kailang Yangdf694da2005-12-05 19:42:22 +010076 ALC260_HP_3013,
77 ALC260_FUJITSU_S702X,
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +010078 ALC260_ACER,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020079 ALC260_WILL,
80 ALC260_REPLACER_672V,
Jonathan Woithe7cf51e482006-02-09 12:01:26 +010081#ifdef CONFIG_SND_DEBUG
82 ALC260_TEST,
83#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010084 ALC260_AUTO,
Takashi Iwai16ded522005-06-10 19:58:24 +020085 ALC260_MODEL_LAST /* last tag */
Linus Torvalds1da177e2005-04-16 15:20:36 -070086};
87
Kailang Yangdf694da2005-12-05 19:42:22 +010088/* ALC262 models */
89enum {
90 ALC262_BASIC,
Kailang Yangccc656c2006-10-17 12:32:26 +020091 ALC262_HIPPO,
92 ALC262_HIPPO_1,
Takashi Iwai834be882006-03-01 14:16:17 +010093 ALC262_FUJITSU,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020094 ALC262_HP_BPC,
Kailang Yangcd7509a2007-01-26 18:33:17 +010095 ALC262_HP_BPC_D7000_WL,
96 ALC262_HP_BPC_D7000_WF,
Kailang Yang66d2a9d2007-11-14 12:06:21 +010097 ALC262_HP_TC_T5735,
Kailang Yang8c427222008-01-10 13:03:59 +010098 ALC262_HP_RP5700,
Takashi Iwai304dcaa2006-07-25 14:51:16 +020099 ALC262_BENQ_ED8,
Kailang Yang272a5272007-05-14 11:00:38 +0200100 ALC262_SONY_ASSAMD,
Kailang Yang83c34212007-07-05 11:43:05 +0200101 ALC262_BENQ_T31,
Tobin Davisf651b502007-10-26 12:40:47 +0200102 ALC262_ULTRA,
Jiang zhe0e31daf2008-03-20 12:12:39 +0100103 ALC262_LENOVO_3000,
Pascal Terjane8f9ae22008-08-04 14:36:05 +0200104 ALC262_NEC,
Kailang Yang4e555fe2008-08-26 13:05:55 +0200105 ALC262_TOSHIBA_S06,
Hiroshi Miura9f99a632008-08-28 16:09:06 +0200106 ALC262_TOSHIBA_RX1,
Kailang Yangdf694da2005-12-05 19:42:22 +0100107 ALC262_AUTO,
108 ALC262_MODEL_LAST /* last tag */
109};
110
Kailang Yanga361d842007-06-05 12:30:55 +0200111/* ALC268 models */
112enum {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +0200113 ALC267_QUANTA_IL1,
Kailang Yanga361d842007-06-05 12:30:55 +0200114 ALC268_3ST,
Kailang Yangd1a991a2007-08-15 16:21:59 +0200115 ALC268_TOSHIBA,
Takashi Iwaid2738092007-08-16 14:59:45 +0200116 ALC268_ACER,
Kailang Yang8ef355d2008-08-26 13:10:22 +0200117 ALC268_ACER_ASPIRE_ONE,
Takashi Iwai3866f0b2008-01-15 12:37:42 +0100118 ALC268_DELL,
Mirco Tischlerf12462c2008-02-04 12:33:59 +0100119 ALC268_ZEPTO,
Jonathan Woithe86c53bd2008-01-08 12:33:19 +0100120#ifdef CONFIG_SND_DEBUG
121 ALC268_TEST,
122#endif
Kailang Yanga361d842007-06-05 12:30:55 +0200123 ALC268_AUTO,
124 ALC268_MODEL_LAST /* last tag */
125};
126
Kailang Yangf6a92242007-12-13 16:52:54 +0100127/* ALC269 models */
128enum {
129 ALC269_BASIC,
Kailang Yang60db6b52008-08-26 13:13:00 +0200130 ALC269_QUANTA_FL1,
Kailang Yangf53281e2008-07-18 12:36:43 +0200131 ALC269_ASUS_EEEPC_P703,
132 ALC269_ASUS_EEEPC_P901,
Takashi Iwai26f5df22008-11-03 17:39:46 +0100133 ALC269_FUJITSU,
Kailang Yangf6a92242007-12-13 16:52:54 +0100134 ALC269_AUTO,
135 ALC269_MODEL_LAST /* last tag */
136};
137
Kailang Yangdf694da2005-12-05 19:42:22 +0100138/* ALC861 models */
139enum {
140 ALC861_3ST,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200141 ALC660_3ST,
Kailang Yangdf694da2005-12-05 19:42:22 +0100142 ALC861_3ST_DIG,
143 ALC861_6ST_DIG,
Takashi Iwai22309c32006-08-09 16:57:28 +0200144 ALC861_UNIWILL_M31,
Tobin Davisa53d1ae2006-10-17 12:00:28 +0200145 ALC861_TOSHIBA,
Mariusz Domanski7cdbff92006-10-23 13:42:56 +0200146 ALC861_ASUS,
Takashi Iwai56bb0ca2006-11-22 11:52:52 +0100147 ALC861_ASUS_LAPTOP,
Kailang Yangdf694da2005-12-05 19:42:22 +0100148 ALC861_AUTO,
149 ALC861_MODEL_LAST,
150};
151
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100152/* ALC861-VD models */
153enum {
154 ALC660VD_3ST,
Mike Crash6963f842007-06-25 12:12:51 +0200155 ALC660VD_3ST_DIG,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100156 ALC861VD_3ST,
157 ALC861VD_3ST_DIG,
158 ALC861VD_6ST_DIG,
Kailang Yangbdd148a2007-05-08 15:19:08 +0200159 ALC861VD_LENOVO,
Kailang Yang272a5272007-05-14 11:00:38 +0200160 ALC861VD_DALLAS,
Kailang Yangd1a991a2007-08-15 16:21:59 +0200161 ALC861VD_HP,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100162 ALC861VD_AUTO,
163 ALC861VD_MODEL_LAST,
164};
165
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200166/* ALC662 models */
167enum {
168 ALC662_3ST_2ch_DIG,
169 ALC662_3ST_6ch_DIG,
170 ALC662_3ST_6ch,
171 ALC662_5ST_DIG,
172 ALC662_LENOVO_101E,
Kailang Yang291702f2007-10-16 14:28:03 +0200173 ALC662_ASUS_EEEPC_P701,
Kailang Yang8c427222008-01-10 13:03:59 +0100174 ALC662_ASUS_EEEPC_EP20,
Kailang Yang6dda9f42008-05-27 12:05:31 +0200175 ALC663_ASUS_M51VA,
176 ALC663_ASUS_G71V,
177 ALC663_ASUS_H13,
178 ALC663_ASUS_G50V,
Kailang Yangf1d4e282008-08-26 14:03:29 +0200179 ALC662_ECS,
180 ALC663_ASUS_MODE1,
181 ALC662_ASUS_MODE2,
182 ALC663_ASUS_MODE3,
183 ALC663_ASUS_MODE4,
184 ALC663_ASUS_MODE5,
185 ALC663_ASUS_MODE6,
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200186 ALC662_AUTO,
187 ALC662_MODEL_LAST,
188};
189
Kailang Yangdf694da2005-12-05 19:42:22 +0100190/* ALC882 models */
191enum {
192 ALC882_3ST_DIG,
193 ALC882_6ST_DIG,
Takashi Iwai4b146cb2006-07-28 14:42:36 +0200194 ALC882_ARIMA,
Kailang Yangbdd148a2007-05-08 15:19:08 +0200195 ALC882_W2JC,
Kailang Yang272a5272007-05-14 11:00:38 +0200196 ALC882_TARGA,
197 ALC882_ASUS_A7J,
Takashi Iwai914759b2007-09-06 14:52:04 +0200198 ALC882_ASUS_A7M,
Tobin Davis9102cd12006-12-15 10:02:12 +0100199 ALC885_MACPRO,
Takashi Iwai87350ad2007-08-16 18:19:38 +0200200 ALC885_MBP3,
Nicola Fagnanic54728d2007-07-19 23:28:52 +0200201 ALC885_IMAC24,
Kailang Yang272a5272007-05-14 11:00:38 +0200202 ALC882_AUTO,
Kailang Yangdf694da2005-12-05 19:42:22 +0100203 ALC882_MODEL_LAST,
204};
205
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200206/* ALC883 models */
207enum {
208 ALC883_3ST_2ch_DIG,
209 ALC883_3ST_6ch_DIG,
210 ALC883_3ST_6ch,
211 ALC883_6ST_DIG,
Kailang Yangccc656c2006-10-17 12:32:26 +0200212 ALC883_TARGA_DIG,
213 ALC883_TARGA_2ch_DIG,
Vladimir Avdoninbab282b92006-08-22 13:31:58 +0200214 ALC883_ACER,
Tobin Davis2880a862007-08-07 11:50:26 +0200215 ALC883_ACER_ASPIRE,
Tobin Davisc07584c2006-10-13 12:32:16 +0200216 ALC883_MEDION,
Kailang Yangea1fb292008-08-26 12:58:38 +0200217 ALC883_MEDION_MD2,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +0100218 ALC883_LAPTOP_EAPD,
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200219 ALC883_LENOVO_101E_2ch,
Kailang Yang272a5272007-05-14 11:00:38 +0200220 ALC883_LENOVO_NB0763,
Kailang Yang189609a2007-08-20 11:31:23 +0200221 ALC888_LENOVO_MS7195_DIG,
Kailang Yange2757d52008-08-26 13:17:46 +0200222 ALC888_LENOVO_SKY,
Kailang Yangea1fb292008-08-26 12:58:38 +0200223 ALC883_HAIER_W66,
Claudio Matsuoka4723c022007-07-13 14:36:19 +0200224 ALC888_3ST_HP,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +0100225 ALC888_6ST_DELL,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +0100226 ALC883_MITAC,
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +0100227 ALC883_CLEVO_M720,
Jiang zhefb97dc62008-03-06 11:07:11 +0100228 ALC883_FUJITSU_PI2515,
Jiang zhe17bba1b2008-06-04 12:11:07 +0200229 ALC883_3ST_6ch_INTEL,
Kailang Yange2757d52008-08-26 13:17:46 +0200230 ALC888_ASUS_M90V,
231 ALC888_ASUS_EEE1601,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200232 ALC883_AUTO,
233 ALC883_MODEL_LAST,
234};
235
Kailang Yangdf694da2005-12-05 19:42:22 +0100236/* for GPIO Poll */
237#define GPIO_MASK 0x03
238
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239struct alc_spec {
240 /* codec parameterization */
Kailang Yangdf694da2005-12-05 19:42:22 +0100241 struct snd_kcontrol_new *mixers[5]; /* mixer arrays */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 unsigned int num_mixers;
Takashi Iwaif9e336f2008-10-31 16:37:07 +0100243 struct snd_kcontrol_new *cap_mixer; /* capture mixer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244
Kailang Yangdf694da2005-12-05 19:42:22 +0100245 const struct hda_verb *init_verbs[5]; /* initialization verbs
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200246 * don't forget NULL
247 * termination!
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200248 */
249 unsigned int num_init_verbs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250
Takashi Iwai16ded522005-06-10 19:58:24 +0200251 char *stream_name_analog; /* analog PCM stream */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252 struct hda_pcm_stream *stream_analog_playback;
253 struct hda_pcm_stream *stream_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +0100254 struct hda_pcm_stream *stream_analog_alt_playback;
255 struct hda_pcm_stream *stream_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200257 char *stream_name_digital; /* digital PCM stream */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 struct hda_pcm_stream *stream_digital_playback;
259 struct hda_pcm_stream *stream_digital_capture;
260
261 /* playback */
Takashi Iwai16ded522005-06-10 19:58:24 +0200262 struct hda_multi_out multiout; /* playback set-up
263 * max_channels, dacs must be set
264 * dig_out_nid and hp_nid are optional
265 */
Takashi Iwai63300792008-01-24 15:31:36 +0100266 hda_nid_t alt_dac_nid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267
268 /* capture */
269 unsigned int num_adc_nids;
270 hda_nid_t *adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100271 hda_nid_t *capsrc_nids;
Takashi Iwai16ded522005-06-10 19:58:24 +0200272 hda_nid_t dig_in_nid; /* digital-in NID; optional */
Takashi Iwai54cbc9a2008-10-31 15:24:04 +0100273 unsigned char is_mix_capture; /* matrix-style capture (non-mux) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274
275 /* capture source */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200276 unsigned int num_mux_defs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 const struct hda_input_mux *input_mux;
278 unsigned int cur_mux[3];
279
280 /* channel model */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100281 const struct hda_channel_mode *channel_mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 int num_channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200283 int need_dac_fix;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284
285 /* PCM information */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100286 struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */
Takashi Iwai41e41f12005-06-08 14:48:49 +0200287
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200288 /* dynamic controls, init_verbs and input_mux */
289 struct auto_pin_cfg autocfg;
Takashi Iwai603c4012008-07-30 15:01:44 +0200290 struct snd_array kctls;
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200291 struct hda_input_mux private_imux;
Takashi Iwai41923e42007-10-22 17:20:10 +0200292 hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
Takashi Iwai834be882006-03-01 14:16:17 +0100293
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100294 /* hooks */
295 void (*init_hook)(struct hda_codec *codec);
296 void (*unsol_event)(struct hda_codec *codec, unsigned int res);
297
Takashi Iwai834be882006-03-01 14:16:17 +0100298 /* for pin sensing */
299 unsigned int sense_updated: 1;
300 unsigned int jack_present: 1;
Takashi Iwaibec15c32008-01-28 18:16:30 +0100301 unsigned int master_sw: 1;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200302
Takashi Iwai2134ea42008-01-10 16:53:55 +0100303 /* for virtual master */
304 hda_nid_t vmaster_nid;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200305#ifdef CONFIG_SND_HDA_POWER_SAVE
306 struct hda_loopback_check loopback;
307#endif
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +0200308
309 /* for PLL fix */
310 hda_nid_t pll_nid;
311 unsigned int pll_coef_idx, pll_coef_bit;
Takashi Iwaie044c392008-10-27 16:56:24 +0100312
313#ifdef SND_HDA_NEEDS_RESUME
314#define ALC_MAX_PINS 16
315 unsigned int num_pins;
316 hda_nid_t pin_nids[ALC_MAX_PINS];
317 unsigned int pin_cfgs[ALC_MAX_PINS];
318#endif
Kailang Yangdf694da2005-12-05 19:42:22 +0100319};
320
321/*
322 * configuration template - to be copied to the spec instance
323 */
324struct alc_config_preset {
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200325 struct snd_kcontrol_new *mixers[5]; /* should be identical size
326 * with spec
327 */
Takashi Iwaif9e336f2008-10-31 16:37:07 +0100328 struct snd_kcontrol_new *cap_mixer; /* capture mixer */
Kailang Yangdf694da2005-12-05 19:42:22 +0100329 const struct hda_verb *init_verbs[5];
330 unsigned int num_dacs;
331 hda_nid_t *dac_nids;
332 hda_nid_t dig_out_nid; /* optional */
333 hda_nid_t hp_nid; /* optional */
334 unsigned int num_adc_nids;
335 hda_nid_t *adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100336 hda_nid_t *capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +0100337 hda_nid_t dig_in_nid;
338 unsigned int num_channel_mode;
339 const struct hda_channel_mode *channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200340 int need_dac_fix;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200341 unsigned int num_mux_defs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100342 const struct hda_input_mux *input_mux;
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100343 void (*unsol_event)(struct hda_codec *, unsigned int);
344 void (*init_hook)(struct hda_codec *);
Takashi Iwaicb53c622007-08-10 17:21:45 +0200345#ifdef CONFIG_SND_HDA_POWER_SAVE
346 struct hda_amp_list *loopbacks;
347#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348};
349
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350
351/*
352 * input MUX handling
353 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200354static int alc_mux_enum_info(struct snd_kcontrol *kcontrol,
355 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356{
357 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
358 struct alc_spec *spec = codec->spec;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200359 unsigned int mux_idx = snd_ctl_get_ioffidx(kcontrol, &uinfo->id);
360 if (mux_idx >= spec->num_mux_defs)
361 mux_idx = 0;
362 return snd_hda_input_mux_info(&spec->input_mux[mux_idx], uinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363}
364
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200365static int alc_mux_enum_get(struct snd_kcontrol *kcontrol,
366 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367{
368 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
369 struct alc_spec *spec = codec->spec;
370 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
371
372 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
373 return 0;
374}
375
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200376static int alc_mux_enum_put(struct snd_kcontrol *kcontrol,
377 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378{
379 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
380 struct alc_spec *spec = codec->spec;
Takashi Iwai54cbc9a2008-10-31 15:24:04 +0100381 const struct hda_input_mux *imux = spec->input_mux;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Takashi Iwaie1406342008-02-11 18:32:32 +0100383 hda_nid_t nid = spec->capsrc_nids ?
384 spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385
Takashi Iwai54cbc9a2008-10-31 15:24:04 +0100386 if (spec->is_mix_capture) {
387 /* Matrix-mixer style (e.g. ALC882) */
388 unsigned int *cur_val = &spec->cur_mux[adc_idx];
389 unsigned int i, idx;
390
391 idx = ucontrol->value.enumerated.item[0];
392 if (idx >= imux->num_items)
393 idx = imux->num_items - 1;
394 if (*cur_val == idx)
395 return 0;
396 for (i = 0; i < imux->num_items; i++) {
397 unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE;
398 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT,
399 imux->items[i].index,
400 HDA_AMP_MUTE, v);
401 }
402 *cur_val = idx;
403 return 1;
404 } else {
405 /* MUX style (e.g. ALC880) */
406 unsigned int mux_idx;
407 mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx;
408 return snd_hda_input_mux_put(codec, &spec->input_mux[mux_idx],
409 ucontrol, nid,
410 &spec->cur_mux[adc_idx]);
411 }
412}
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200413
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414/*
415 * channel mode setting
416 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200417static int alc_ch_mode_info(struct snd_kcontrol *kcontrol,
418 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419{
420 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
421 struct alc_spec *spec = codec->spec;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100422 return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode,
423 spec->num_channel_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424}
425
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200426static int alc_ch_mode_get(struct snd_kcontrol *kcontrol,
427 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428{
429 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
430 struct alc_spec *spec = codec->spec;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100431 return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200432 spec->num_channel_mode,
433 spec->multiout.max_channels);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434}
435
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200436static int alc_ch_mode_put(struct snd_kcontrol *kcontrol,
437 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438{
439 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
440 struct alc_spec *spec = codec->spec;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200441 int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
442 spec->num_channel_mode,
443 &spec->multiout.max_channels);
Takashi Iwaibd2033f2006-10-10 19:49:31 +0200444 if (err >= 0 && spec->need_dac_fix)
Takashi Iwai4e195a72006-07-28 14:47:34 +0200445 spec->multiout.num_dacs = spec->multiout.max_channels / 2;
446 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447}
448
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449/*
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100450 * Control the mode of pin widget settings via the mixer. "pc" is used
Kailang Yangea1fb292008-08-26 12:58:38 +0200451 * instead of "%" to avoid consequences of accidently treating the % as
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100452 * being part of a format specifier. Maximum allowed length of a value is
453 * 63 characters plus NULL terminator.
Jonathan Woithe7cf51e482006-02-09 12:01:26 +0100454 *
455 * Note: some retasking pin complexes seem to ignore requests for input
456 * states other than HiZ (eg: PIN_VREFxx) and revert to HiZ if any of these
457 * are requested. Therefore order this list so that this behaviour will not
458 * cause problems when mixer clients move through the enum sequentially.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200459 * NIDs 0x0f and 0x10 have been observed to have this behaviour as of
460 * March 2006.
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200461 */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100462static char *alc_pin_mode_names[] = {
Jonathan Woithe7cf51e482006-02-09 12:01:26 +0100463 "Mic 50pc bias", "Mic 80pc bias",
464 "Line in", "Line out", "Headphone out",
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100465};
466static unsigned char alc_pin_mode_values[] = {
Jonathan Woithe7cf51e482006-02-09 12:01:26 +0100467 PIN_VREF50, PIN_VREF80, PIN_IN, PIN_OUT, PIN_HP,
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100468};
469/* The control can present all 5 options, or it can limit the options based
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200470 * in the pin being assumed to be exclusively an input or an output pin. In
471 * addition, "input" pins may or may not process the mic bias option
472 * depending on actual widget capability (NIDs 0x0f and 0x10 don't seem to
473 * accept requests for bias as of chip versions up to March 2006) and/or
474 * wiring in the computer.
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100475 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200476#define ALC_PIN_DIR_IN 0x00
477#define ALC_PIN_DIR_OUT 0x01
478#define ALC_PIN_DIR_INOUT 0x02
479#define ALC_PIN_DIR_IN_NOMICBIAS 0x03
480#define ALC_PIN_DIR_INOUT_NOMICBIAS 0x04
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100481
Kailang Yangea1fb292008-08-26 12:58:38 +0200482/* Info about the pin modes supported by the different pin direction modes.
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100483 * For each direction the minimum and maximum values are given.
484 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200485static signed char alc_pin_mode_dir_info[5][2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100486 { 0, 2 }, /* ALC_PIN_DIR_IN */
487 { 3, 4 }, /* ALC_PIN_DIR_OUT */
488 { 0, 4 }, /* ALC_PIN_DIR_INOUT */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200489 { 2, 2 }, /* ALC_PIN_DIR_IN_NOMICBIAS */
490 { 2, 4 }, /* ALC_PIN_DIR_INOUT_NOMICBIAS */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100491};
492#define alc_pin_mode_min(_dir) (alc_pin_mode_dir_info[_dir][0])
493#define alc_pin_mode_max(_dir) (alc_pin_mode_dir_info[_dir][1])
494#define alc_pin_mode_n_items(_dir) \
495 (alc_pin_mode_max(_dir)-alc_pin_mode_min(_dir)+1)
496
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200497static int alc_pin_mode_info(struct snd_kcontrol *kcontrol,
498 struct snd_ctl_elem_info *uinfo)
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200499{
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100500 unsigned int item_num = uinfo->value.enumerated.item;
501 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
502
503 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200504 uinfo->count = 1;
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100505 uinfo->value.enumerated.items = alc_pin_mode_n_items(dir);
506
507 if (item_num<alc_pin_mode_min(dir) || item_num>alc_pin_mode_max(dir))
508 item_num = alc_pin_mode_min(dir);
509 strcpy(uinfo->value.enumerated.name, alc_pin_mode_names[item_num]);
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200510 return 0;
511}
512
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200513static int alc_pin_mode_get(struct snd_kcontrol *kcontrol,
514 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200515{
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100516 unsigned int i;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200517 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
518 hda_nid_t nid = kcontrol->private_value & 0xffff;
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100519 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200520 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200521 unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
522 AC_VERB_GET_PIN_WIDGET_CONTROL,
523 0x00);
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200524
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100525 /* Find enumerated value for current pinctl setting */
526 i = alc_pin_mode_min(dir);
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200527 while (alc_pin_mode_values[i] != pinctl && i <= alc_pin_mode_max(dir))
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100528 i++;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200529 *valp = i <= alc_pin_mode_max(dir) ? i: alc_pin_mode_min(dir);
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100530 return 0;
531}
532
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200533static int alc_pin_mode_put(struct snd_kcontrol *kcontrol,
534 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100535{
536 signed int change;
537 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
538 hda_nid_t nid = kcontrol->private_value & 0xffff;
539 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
540 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200541 unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
542 AC_VERB_GET_PIN_WIDGET_CONTROL,
543 0x00);
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100544
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200545 if (val < alc_pin_mode_min(dir) || val > alc_pin_mode_max(dir))
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100546 val = alc_pin_mode_min(dir);
547
548 change = pinctl != alc_pin_mode_values[val];
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100549 if (change) {
550 /* Set pin mode to that requested */
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200551 snd_hda_codec_write_cache(codec, nid, 0,
552 AC_VERB_SET_PIN_WIDGET_CONTROL,
553 alc_pin_mode_values[val]);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100554
Kailang Yangea1fb292008-08-26 12:58:38 +0200555 /* Also enable the retasking pin's input/output as required
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100556 * for the requested pin mode. Enum values of 2 or less are
557 * input modes.
558 *
559 * Dynamically switching the input/output buffers probably
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200560 * reduces noise slightly (particularly on input) so we'll
561 * do it. However, having both input and output buffers
562 * enabled simultaneously doesn't seem to be problematic if
563 * this turns out to be necessary in the future.
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100564 */
565 if (val <= 2) {
Takashi Iwai47fd8302007-08-10 17:11:07 +0200566 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
567 HDA_AMP_MUTE, HDA_AMP_MUTE);
568 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
569 HDA_AMP_MUTE, 0);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100570 } else {
Takashi Iwai47fd8302007-08-10 17:11:07 +0200571 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
572 HDA_AMP_MUTE, HDA_AMP_MUTE);
573 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
574 HDA_AMP_MUTE, 0);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100575 }
576 }
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200577 return change;
578}
579
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100580#define ALC_PIN_MODE(xname, nid, dir) \
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200581 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100582 .info = alc_pin_mode_info, \
583 .get = alc_pin_mode_get, \
584 .put = alc_pin_mode_put, \
585 .private_value = nid | (dir<<16) }
Kailang Yangdf694da2005-12-05 19:42:22 +0100586
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100587/* A switch control for ALC260 GPIO pins. Multiple GPIOs can be ganged
588 * together using a mask with more than one bit set. This control is
589 * currently used only by the ALC260 test model. At this stage they are not
590 * needed for any "production" models.
591 */
592#ifdef CONFIG_SND_DEBUG
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200593#define alc_gpio_data_info snd_ctl_boolean_mono_info
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200594
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200595static int alc_gpio_data_get(struct snd_kcontrol *kcontrol,
596 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100597{
598 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
599 hda_nid_t nid = kcontrol->private_value & 0xffff;
600 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
601 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200602 unsigned int val = snd_hda_codec_read(codec, nid, 0,
603 AC_VERB_GET_GPIO_DATA, 0x00);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100604
605 *valp = (val & mask) != 0;
606 return 0;
607}
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200608static int alc_gpio_data_put(struct snd_kcontrol *kcontrol,
609 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100610{
611 signed int change;
612 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
613 hda_nid_t nid = kcontrol->private_value & 0xffff;
614 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
615 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200616 unsigned int gpio_data = snd_hda_codec_read(codec, nid, 0,
617 AC_VERB_GET_GPIO_DATA,
618 0x00);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100619
620 /* Set/unset the masked GPIO bit(s) as needed */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200621 change = (val == 0 ? 0 : mask) != (gpio_data & mask);
622 if (val == 0)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100623 gpio_data &= ~mask;
624 else
625 gpio_data |= mask;
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200626 snd_hda_codec_write_cache(codec, nid, 0,
627 AC_VERB_SET_GPIO_DATA, gpio_data);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100628
629 return change;
630}
631#define ALC_GPIO_DATA_SWITCH(xname, nid, mask) \
632 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
633 .info = alc_gpio_data_info, \
634 .get = alc_gpio_data_get, \
635 .put = alc_gpio_data_put, \
636 .private_value = nid | (mask<<16) }
637#endif /* CONFIG_SND_DEBUG */
638
Jonathan Woithe92621f12006-02-28 11:47:47 +0100639/* A switch control to allow the enabling of the digital IO pins on the
640 * ALC260. This is incredibly simplistic; the intention of this control is
641 * to provide something in the test model allowing digital outputs to be
642 * identified if present. If models are found which can utilise these
643 * outputs a more complete mixer control can be devised for those models if
644 * necessary.
645 */
646#ifdef CONFIG_SND_DEBUG
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200647#define alc_spdif_ctrl_info snd_ctl_boolean_mono_info
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200648
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200649static int alc_spdif_ctrl_get(struct snd_kcontrol *kcontrol,
650 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe92621f12006-02-28 11:47:47 +0100651{
652 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
653 hda_nid_t nid = kcontrol->private_value & 0xffff;
654 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
655 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200656 unsigned int val = snd_hda_codec_read(codec, nid, 0,
Andrew Paprocki3982d172007-12-19 12:13:44 +0100657 AC_VERB_GET_DIGI_CONVERT_1, 0x00);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100658
659 *valp = (val & mask) != 0;
660 return 0;
661}
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200662static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol,
663 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe92621f12006-02-28 11:47:47 +0100664{
665 signed int change;
666 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
667 hda_nid_t nid = kcontrol->private_value & 0xffff;
668 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
669 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200670 unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
Andrew Paprocki3982d172007-12-19 12:13:44 +0100671 AC_VERB_GET_DIGI_CONVERT_1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200672 0x00);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100673
674 /* Set/unset the masked control bit(s) as needed */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200675 change = (val == 0 ? 0 : mask) != (ctrl_data & mask);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100676 if (val==0)
677 ctrl_data &= ~mask;
678 else
679 ctrl_data |= mask;
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200680 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
681 ctrl_data);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100682
683 return change;
684}
685#define ALC_SPDIF_CTRL_SWITCH(xname, nid, mask) \
686 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
687 .info = alc_spdif_ctrl_info, \
688 .get = alc_spdif_ctrl_get, \
689 .put = alc_spdif_ctrl_put, \
690 .private_value = nid | (mask<<16) }
691#endif /* CONFIG_SND_DEBUG */
692
Jonathan Woithef8225f62008-01-08 12:16:54 +0100693/* A switch control to allow the enabling EAPD digital outputs on the ALC26x.
694 * Again, this is only used in the ALC26x test models to help identify when
695 * the EAPD line must be asserted for features to work.
696 */
697#ifdef CONFIG_SND_DEBUG
698#define alc_eapd_ctrl_info snd_ctl_boolean_mono_info
699
700static int alc_eapd_ctrl_get(struct snd_kcontrol *kcontrol,
701 struct snd_ctl_elem_value *ucontrol)
702{
703 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
704 hda_nid_t nid = kcontrol->private_value & 0xffff;
705 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
706 long *valp = ucontrol->value.integer.value;
707 unsigned int val = snd_hda_codec_read(codec, nid, 0,
708 AC_VERB_GET_EAPD_BTLENABLE, 0x00);
709
710 *valp = (val & mask) != 0;
711 return 0;
712}
713
714static int alc_eapd_ctrl_put(struct snd_kcontrol *kcontrol,
715 struct snd_ctl_elem_value *ucontrol)
716{
717 int change;
718 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
719 hda_nid_t nid = kcontrol->private_value & 0xffff;
720 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
721 long val = *ucontrol->value.integer.value;
722 unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
723 AC_VERB_GET_EAPD_BTLENABLE,
724 0x00);
725
726 /* Set/unset the masked control bit(s) as needed */
727 change = (!val ? 0 : mask) != (ctrl_data & mask);
728 if (!val)
729 ctrl_data &= ~mask;
730 else
731 ctrl_data |= mask;
732 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
733 ctrl_data);
734
735 return change;
736}
737
738#define ALC_EAPD_CTRL_SWITCH(xname, nid, mask) \
739 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
740 .info = alc_eapd_ctrl_info, \
741 .get = alc_eapd_ctrl_get, \
742 .put = alc_eapd_ctrl_put, \
743 .private_value = nid | (mask<<16) }
744#endif /* CONFIG_SND_DEBUG */
745
Kailang Yangdf694da2005-12-05 19:42:22 +0100746/*
Takashi Iwaid88897e2008-10-31 15:01:37 +0100747 */
748static void add_mixer(struct alc_spec *spec, struct snd_kcontrol_new *mix)
749{
750 if (snd_BUG_ON(spec->num_mixers >= ARRAY_SIZE(spec->mixers)))
751 return;
752 spec->mixers[spec->num_mixers++] = mix;
753}
754
755static void add_verb(struct alc_spec *spec, const struct hda_verb *verb)
756{
757 if (snd_BUG_ON(spec->num_init_verbs >= ARRAY_SIZE(spec->init_verbs)))
758 return;
759 spec->init_verbs[spec->num_init_verbs++] = verb;
760}
761
762/*
Kailang Yangdf694da2005-12-05 19:42:22 +0100763 * set up from the preset table
764 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200765static void setup_preset(struct alc_spec *spec,
766 const struct alc_config_preset *preset)
Kailang Yangdf694da2005-12-05 19:42:22 +0100767{
768 int i;
769
770 for (i = 0; i < ARRAY_SIZE(preset->mixers) && preset->mixers[i]; i++)
Takashi Iwaid88897e2008-10-31 15:01:37 +0100771 add_mixer(spec, preset->mixers[i]);
Takashi Iwaif9e336f2008-10-31 16:37:07 +0100772 spec->cap_mixer = preset->cap_mixer;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200773 for (i = 0; i < ARRAY_SIZE(preset->init_verbs) && preset->init_verbs[i];
774 i++)
Takashi Iwaid88897e2008-10-31 15:01:37 +0100775 add_verb(spec, preset->init_verbs[i]);
Kailang Yangea1fb292008-08-26 12:58:38 +0200776
Kailang Yangdf694da2005-12-05 19:42:22 +0100777 spec->channel_mode = preset->channel_mode;
778 spec->num_channel_mode = preset->num_channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200779 spec->need_dac_fix = preset->need_dac_fix;
Kailang Yangdf694da2005-12-05 19:42:22 +0100780
781 spec->multiout.max_channels = spec->channel_mode[0].channels;
782
783 spec->multiout.num_dacs = preset->num_dacs;
784 spec->multiout.dac_nids = preset->dac_nids;
785 spec->multiout.dig_out_nid = preset->dig_out_nid;
786 spec->multiout.hp_nid = preset->hp_nid;
Kailang Yangea1fb292008-08-26 12:58:38 +0200787
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200788 spec->num_mux_defs = preset->num_mux_defs;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200789 if (!spec->num_mux_defs)
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200790 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +0100791 spec->input_mux = preset->input_mux;
792
793 spec->num_adc_nids = preset->num_adc_nids;
794 spec->adc_nids = preset->adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100795 spec->capsrc_nids = preset->capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +0100796 spec->dig_in_nid = preset->dig_in_nid;
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100797
798 spec->unsol_event = preset->unsol_event;
799 spec->init_hook = preset->init_hook;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200800#ifdef CONFIG_SND_HDA_POWER_SAVE
801 spec->loopback.amplist = preset->loopbacks;
802#endif
Kailang Yangdf694da2005-12-05 19:42:22 +0100803}
804
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200805/* Enable GPIO mask and set output */
806static struct hda_verb alc_gpio1_init_verbs[] = {
807 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
808 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
809 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
810 { }
811};
812
813static struct hda_verb alc_gpio2_init_verbs[] = {
814 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
815 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
816 {0x01, AC_VERB_SET_GPIO_DATA, 0x02},
817 { }
818};
819
Kailang Yangbdd148a2007-05-08 15:19:08 +0200820static struct hda_verb alc_gpio3_init_verbs[] = {
821 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
822 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
823 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
824 { }
825};
826
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +0200827/*
828 * Fix hardware PLL issue
829 * On some codecs, the analog PLL gating control must be off while
830 * the default value is 1.
831 */
832static void alc_fix_pll(struct hda_codec *codec)
833{
834 struct alc_spec *spec = codec->spec;
835 unsigned int val;
836
837 if (!spec->pll_nid)
838 return;
839 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
840 spec->pll_coef_idx);
841 val = snd_hda_codec_read(codec, spec->pll_nid, 0,
842 AC_VERB_GET_PROC_COEF, 0);
843 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
844 spec->pll_coef_idx);
845 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_PROC_COEF,
846 val & ~(1 << spec->pll_coef_bit));
847}
848
849static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
850 unsigned int coef_idx, unsigned int coef_bit)
851{
852 struct alc_spec *spec = codec->spec;
853 spec->pll_nid = nid;
854 spec->pll_coef_idx = coef_idx;
855 spec->pll_coef_bit = coef_bit;
856 alc_fix_pll(codec);
857}
858
Kailang Yangc9b58002007-10-16 14:30:01 +0200859static void alc_sku_automute(struct hda_codec *codec)
860{
861 struct alc_spec *spec = codec->spec;
Kailang Yangc9b58002007-10-16 14:30:01 +0200862 unsigned int present;
863 unsigned int hp_nid = spec->autocfg.hp_pins[0];
864 unsigned int sp_nid = spec->autocfg.speaker_pins[0];
865
866 /* need to execute and sync at first */
867 snd_hda_codec_read(codec, hp_nid, 0, AC_VERB_SET_PIN_SENSE, 0);
868 present = snd_hda_codec_read(codec, hp_nid, 0,
869 AC_VERB_GET_PIN_SENSE, 0);
870 spec->jack_present = (present & 0x80000000) != 0;
Takashi Iwaif6c7e542008-02-12 18:32:23 +0100871 snd_hda_codec_write(codec, sp_nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
872 spec->jack_present ? 0 : PIN_OUT);
Kailang Yangc9b58002007-10-16 14:30:01 +0200873}
874
Takashi Iwai4605b712008-10-31 14:18:24 +0100875#if 0 /* it's broken in some acses -- temporarily disabled */
Kailang Yang7fb0d782008-10-15 11:12:35 +0200876static void alc_mic_automute(struct hda_codec *codec)
877{
878 struct alc_spec *spec = codec->spec;
879 unsigned int present;
880 unsigned int mic_nid = spec->autocfg.input_pins[AUTO_PIN_MIC];
881 unsigned int fmic_nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC];
882 unsigned int mix_nid = spec->capsrc_nids[0];
883 unsigned int capsrc_idx_mic, capsrc_idx_fmic;
884
885 capsrc_idx_mic = mic_nid - 0x18;
886 capsrc_idx_fmic = fmic_nid - 0x18;
887 present = snd_hda_codec_read(codec, mic_nid, 0,
888 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
889 snd_hda_codec_write(codec, mix_nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
890 0x7000 | (capsrc_idx_mic << 8) | (present ? 0 : 0x80));
891 snd_hda_codec_write(codec, mix_nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
892 0x7000 | (capsrc_idx_fmic << 8) | (present ? 0x80 : 0));
893 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, capsrc_idx_fmic,
894 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
895}
Takashi Iwai4605b712008-10-31 14:18:24 +0100896#else
897#define alc_mic_automute(codec) /* NOP */
898#endif /* disabled */
Kailang Yang7fb0d782008-10-15 11:12:35 +0200899
Kailang Yangc9b58002007-10-16 14:30:01 +0200900/* unsolicited event for HP jack sensing */
901static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res)
902{
903 if (codec->vendor_id == 0x10ec0880)
904 res >>= 28;
905 else
906 res >>= 26;
Kailang Yang7fb0d782008-10-15 11:12:35 +0200907 if (res == ALC880_HP_EVENT)
908 alc_sku_automute(codec);
Kailang Yangc9b58002007-10-16 14:30:01 +0200909
Kailang Yang7fb0d782008-10-15 11:12:35 +0200910 if (res == ALC880_MIC_EVENT)
911 alc_mic_automute(codec);
912}
913
914static void alc_inithook(struct hda_codec *codec)
915{
Kailang Yangc9b58002007-10-16 14:30:01 +0200916 alc_sku_automute(codec);
Kailang Yang7fb0d782008-10-15 11:12:35 +0200917 alc_mic_automute(codec);
Kailang Yangc9b58002007-10-16 14:30:01 +0200918}
919
Kailang Yangf9423e72008-05-27 12:32:25 +0200920/* additional initialization for ALC888 variants */
921static void alc888_coef_init(struct hda_codec *codec)
922{
923 unsigned int tmp;
924
925 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0);
926 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
927 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
928 if ((tmp & 0xf0) == 2)
929 /* alc888S-VC */
930 snd_hda_codec_read(codec, 0x20, 0,
931 AC_VERB_SET_PROC_COEF, 0x830);
932 else
933 /* alc888-VB */
934 snd_hda_codec_read(codec, 0x20, 0,
935 AC_VERB_SET_PROC_COEF, 0x3030);
936}
937
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200938/* 32-bit subsystem ID for BIOS loading in HD Audio codec.
939 * 31 ~ 16 : Manufacture ID
940 * 15 ~ 8 : SKU ID
941 * 7 ~ 0 : Assembly ID
942 * port-A --> pin 39/41, port-E --> pin 14/15, port-D --> pin 35/36
943 */
944static void alc_subsystem_id(struct hda_codec *codec,
945 unsigned int porta, unsigned int porte,
946 unsigned int portd)
947{
Kailang Yangc9b58002007-10-16 14:30:01 +0200948 unsigned int ass, tmp, i;
949 unsigned nid;
950 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200951
Kailang Yangc9b58002007-10-16 14:30:01 +0200952 ass = codec->subsystem_id & 0xffff;
953 if ((ass != codec->bus->pci->subsystem_device) && (ass & 1))
954 goto do_sku;
955
Kailang Yangea1fb292008-08-26 12:58:38 +0200956 /*
Kailang Yangc9b58002007-10-16 14:30:01 +0200957 * 31~30 : port conetcivity
958 * 29~21 : reserve
959 * 20 : PCBEEP input
960 * 19~16 : Check sum (15:1)
961 * 15~1 : Custom
962 * 0 : override
963 */
964 nid = 0x1d;
965 if (codec->vendor_id == 0x10ec0260)
966 nid = 0x17;
967 ass = snd_hda_codec_read(codec, nid, 0,
968 AC_VERB_GET_CONFIG_DEFAULT, 0);
969 if (!(ass & 1) && !(ass & 0x100000))
970 return;
971 if ((ass >> 30) != 1) /* no physical connection */
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200972 return;
973
Kailang Yangc9b58002007-10-16 14:30:01 +0200974 /* check sum */
975 tmp = 0;
976 for (i = 1; i < 16; i++) {
Kailang Yang8c427222008-01-10 13:03:59 +0100977 if ((ass >> i) & 1)
Kailang Yangc9b58002007-10-16 14:30:01 +0200978 tmp++;
979 }
980 if (((ass >> 16) & 0xf) != tmp)
981 return;
982do_sku:
983 /*
984 * 0 : override
985 * 1 : Swap Jack
986 * 2 : 0 --> Desktop, 1 --> Laptop
987 * 3~5 : External Amplifier control
988 * 7~6 : Reserved
989 */
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200990 tmp = (ass & 0x38) >> 3; /* external Amp control */
991 switch (tmp) {
992 case 1:
993 snd_hda_sequence_write(codec, alc_gpio1_init_verbs);
994 break;
995 case 3:
996 snd_hda_sequence_write(codec, alc_gpio2_init_verbs);
997 break;
Kailang Yangbdd148a2007-05-08 15:19:08 +0200998 case 7:
999 snd_hda_sequence_write(codec, alc_gpio3_init_verbs);
1000 break;
Kailang Yangc9b58002007-10-16 14:30:01 +02001001 case 5: /* set EAPD output high */
Kailang Yangbdd148a2007-05-08 15:19:08 +02001002 switch (codec->vendor_id) {
Kailang Yangc9b58002007-10-16 14:30:01 +02001003 case 0x10ec0260:
1004 snd_hda_codec_write(codec, 0x0f, 0,
1005 AC_VERB_SET_EAPD_BTLENABLE, 2);
1006 snd_hda_codec_write(codec, 0x10, 0,
1007 AC_VERB_SET_EAPD_BTLENABLE, 2);
1008 break;
1009 case 0x10ec0262:
Kailang Yangbdd148a2007-05-08 15:19:08 +02001010 case 0x10ec0267:
1011 case 0x10ec0268:
Kailang Yangc9b58002007-10-16 14:30:01 +02001012 case 0x10ec0269:
Kailang Yangf9423e72008-05-27 12:32:25 +02001013 case 0x10ec0660:
1014 case 0x10ec0662:
1015 case 0x10ec0663:
Kailang Yangc9b58002007-10-16 14:30:01 +02001016 case 0x10ec0862:
Takashi Iwai20a3a052008-05-23 17:52:53 +02001017 case 0x10ec0889:
Kailang Yangbdd148a2007-05-08 15:19:08 +02001018 snd_hda_codec_write(codec, 0x14, 0,
1019 AC_VERB_SET_EAPD_BTLENABLE, 2);
1020 snd_hda_codec_write(codec, 0x15, 0,
1021 AC_VERB_SET_EAPD_BTLENABLE, 2);
Kailang Yangc9b58002007-10-16 14:30:01 +02001022 break;
Kailang Yangbdd148a2007-05-08 15:19:08 +02001023 }
Kailang Yangc9b58002007-10-16 14:30:01 +02001024 switch (codec->vendor_id) {
1025 case 0x10ec0260:
1026 snd_hda_codec_write(codec, 0x1a, 0,
1027 AC_VERB_SET_COEF_INDEX, 7);
1028 tmp = snd_hda_codec_read(codec, 0x1a, 0,
1029 AC_VERB_GET_PROC_COEF, 0);
1030 snd_hda_codec_write(codec, 0x1a, 0,
1031 AC_VERB_SET_COEF_INDEX, 7);
1032 snd_hda_codec_write(codec, 0x1a, 0,
1033 AC_VERB_SET_PROC_COEF,
1034 tmp | 0x2010);
1035 break;
1036 case 0x10ec0262:
1037 case 0x10ec0880:
1038 case 0x10ec0882:
1039 case 0x10ec0883:
1040 case 0x10ec0885:
Takashi Iwai20a3a052008-05-23 17:52:53 +02001041 case 0x10ec0889:
Kailang Yangc9b58002007-10-16 14:30:01 +02001042 snd_hda_codec_write(codec, 0x20, 0,
1043 AC_VERB_SET_COEF_INDEX, 7);
1044 tmp = snd_hda_codec_read(codec, 0x20, 0,
1045 AC_VERB_GET_PROC_COEF, 0);
1046 snd_hda_codec_write(codec, 0x20, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +02001047 AC_VERB_SET_COEF_INDEX, 7);
Kailang Yangc9b58002007-10-16 14:30:01 +02001048 snd_hda_codec_write(codec, 0x20, 0,
1049 AC_VERB_SET_PROC_COEF,
1050 tmp | 0x2010);
1051 break;
Kailang Yangf9423e72008-05-27 12:32:25 +02001052 case 0x10ec0888:
Takashi Iwai1082c742008-08-22 15:24:22 +02001053 /*alc888_coef_init(codec);*/ /* called in alc_init() */
Kailang Yangf9423e72008-05-27 12:32:25 +02001054 break;
Kailang Yangc9b58002007-10-16 14:30:01 +02001055 case 0x10ec0267:
1056 case 0x10ec0268:
1057 snd_hda_codec_write(codec, 0x20, 0,
1058 AC_VERB_SET_COEF_INDEX, 7);
1059 tmp = snd_hda_codec_read(codec, 0x20, 0,
1060 AC_VERB_GET_PROC_COEF, 0);
1061 snd_hda_codec_write(codec, 0x20, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +02001062 AC_VERB_SET_COEF_INDEX, 7);
Kailang Yangc9b58002007-10-16 14:30:01 +02001063 snd_hda_codec_write(codec, 0x20, 0,
1064 AC_VERB_SET_PROC_COEF,
1065 tmp | 0x3000);
1066 break;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001067 }
Kailang Yangc9b58002007-10-16 14:30:01 +02001068 default:
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001069 break;
1070 }
Kailang Yangea1fb292008-08-26 12:58:38 +02001071
Kailang Yang8c427222008-01-10 13:03:59 +01001072 /* is laptop or Desktop and enable the function "Mute internal speaker
Kailang Yangc9b58002007-10-16 14:30:01 +02001073 * when the external headphone out jack is plugged"
1074 */
Kailang Yang8c427222008-01-10 13:03:59 +01001075 if (!(ass & 0x8000))
Kailang Yangc9b58002007-10-16 14:30:01 +02001076 return;
1077 /*
1078 * 10~8 : Jack location
1079 * 12~11: Headphone out -> 00: PortA, 01: PortE, 02: PortD, 03: Resvered
1080 * 14~13: Resvered
1081 * 15 : 1 --> enable the function "Mute internal speaker
1082 * when the external headphone out jack is plugged"
1083 */
1084 if (!spec->autocfg.speaker_pins[0]) {
Kailang Yang8c427222008-01-10 13:03:59 +01001085 if (spec->autocfg.line_out_pins[0])
Kailang Yangc9b58002007-10-16 14:30:01 +02001086 spec->autocfg.speaker_pins[0] =
Kailang Yang8c427222008-01-10 13:03:59 +01001087 spec->autocfg.line_out_pins[0];
Kailang Yangc9b58002007-10-16 14:30:01 +02001088 else
1089 return;
1090 }
1091
1092 if (!spec->autocfg.hp_pins[0]) {
1093 tmp = (ass >> 11) & 0x3; /* HP to chassis */
1094 if (tmp == 0)
1095 spec->autocfg.hp_pins[0] = porta;
1096 else if (tmp == 1)
1097 spec->autocfg.hp_pins[0] = porte;
1098 else if (tmp == 2)
1099 spec->autocfg.hp_pins[0] = portd;
1100 else
1101 return;
1102 }
Kailang Yang7fb0d782008-10-15 11:12:35 +02001103 if (spec->autocfg.hp_pins[0])
1104 snd_hda_codec_write(codec, spec->autocfg.hp_pins[0], 0,
1105 AC_VERB_SET_UNSOLICITED_ENABLE,
1106 AC_USRSP_EN | ALC880_HP_EVENT);
Kailang Yangc9b58002007-10-16 14:30:01 +02001107
Takashi Iwai4605b712008-10-31 14:18:24 +01001108#if 0 /* it's broken in some acses -- temporarily disabled */
Kailang Yang7fb0d782008-10-15 11:12:35 +02001109 if (spec->autocfg.input_pins[AUTO_PIN_MIC] &&
1110 spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC])
1111 snd_hda_codec_write(codec,
1112 spec->autocfg.input_pins[AUTO_PIN_MIC], 0,
1113 AC_VERB_SET_UNSOLICITED_ENABLE,
1114 AC_USRSP_EN | ALC880_MIC_EVENT);
Takashi Iwai4605b712008-10-31 14:18:24 +01001115#endif /* disabled */
Kailang Yangea1fb292008-08-26 12:58:38 +02001116
Kailang Yangc9b58002007-10-16 14:30:01 +02001117 spec->unsol_event = alc_sku_unsol_event;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001118}
1119
Takashi Iwai41e41f12005-06-08 14:48:49 +02001120/*
Takashi Iwaif95474e2007-07-10 00:47:43 +02001121 * Fix-up pin default configurations
1122 */
1123
1124struct alc_pincfg {
1125 hda_nid_t nid;
1126 u32 val;
1127};
1128
1129static void alc_fix_pincfg(struct hda_codec *codec,
1130 const struct snd_pci_quirk *quirk,
1131 const struct alc_pincfg **pinfix)
1132{
1133 const struct alc_pincfg *cfg;
1134
1135 quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk);
1136 if (!quirk)
1137 return;
1138
1139 cfg = pinfix[quirk->value];
1140 for (; cfg->nid; cfg++) {
1141 int i;
1142 u32 val = cfg->val;
1143 for (i = 0; i < 4; i++) {
1144 snd_hda_codec_write(codec, cfg->nid, 0,
1145 AC_VERB_SET_CONFIG_DEFAULT_BYTES_0 + i,
1146 val & 0xff);
1147 val >>= 8;
1148 }
1149 }
1150}
1151
1152/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001153 * ALC880 3-stack model
1154 *
1155 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0e)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001156 * Pin assignment: Front = 0x14, Line-In/Surr = 0x1a, Mic/CLFE = 0x18,
1157 * F-Mic = 0x1b, HP = 0x19
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 */
1159
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001160static hda_nid_t alc880_dac_nids[4] = {
1161 /* front, rear, clfe, rear_surr */
1162 0x02, 0x05, 0x04, 0x03
1163};
1164
1165static hda_nid_t alc880_adc_nids[3] = {
1166 /* ADC0-2 */
1167 0x07, 0x08, 0x09,
1168};
1169
1170/* The datasheet says the node 0x07 is connected from inputs,
1171 * but it shows zero connection in the real implementation on some devices.
Kailang Yangdf694da2005-12-05 19:42:22 +01001172 * Note: this is a 915GAV bug, fixed on 915GLV
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001174static hda_nid_t alc880_adc_nids_alt[2] = {
1175 /* ADC1-2 */
1176 0x08, 0x09,
1177};
1178
1179#define ALC880_DIGOUT_NID 0x06
1180#define ALC880_DIGIN_NID 0x0a
1181
1182static struct hda_input_mux alc880_capture_source = {
1183 .num_items = 4,
1184 .items = {
1185 { "Mic", 0x0 },
1186 { "Front Mic", 0x3 },
1187 { "Line", 0x2 },
1188 { "CD", 0x4 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189 },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001190};
1191
1192/* channel source setting (2/6 channel selection for 3-stack) */
1193/* 2ch mode */
1194static struct hda_verb alc880_threestack_ch2_init[] = {
1195 /* set line-in to input, mute it */
1196 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
1197 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1198 /* set mic-in to input vref 80%, mute it */
1199 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1200 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201 { } /* end */
1202};
1203
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001204/* 6ch mode */
1205static struct hda_verb alc880_threestack_ch6_init[] = {
1206 /* set line-in to output, unmute it */
1207 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1208 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1209 /* set mic-in to output, unmute it */
1210 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1211 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1212 { } /* end */
1213};
1214
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001215static struct hda_channel_mode alc880_threestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001216 { 2, alc880_threestack_ch2_init },
1217 { 6, alc880_threestack_ch6_init },
1218};
1219
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001220static struct snd_kcontrol_new alc880_three_stack_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02001221 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001222 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02001223 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001224 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02001225 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1226 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001227 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1228 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1230 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1231 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1232 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1233 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1234 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1235 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
1236 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
1237 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
1238 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001240 {
1241 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1242 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01001243 .info = alc_ch_mode_info,
1244 .get = alc_ch_mode_get,
1245 .put = alc_ch_mode_put,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001246 },
1247 { } /* end */
1248};
1249
1250/* capture mixer elements */
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001251static int alc_cap_vol_info(struct snd_kcontrol *kcontrol,
1252 struct snd_ctl_elem_info *uinfo)
1253{
1254 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1255 struct alc_spec *spec = codec->spec;
1256 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001257
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001258 mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */
1259 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0,
1260 HDA_INPUT);
1261 err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo);
1262 mutex_unlock(&codec->spdif_mutex); /* reuse spdif_mutex */
1263 return err;
1264}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001266static int alc_cap_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
1267 unsigned int size, unsigned int __user *tlv)
1268{
1269 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1270 struct alc_spec *spec = codec->spec;
1271 int err;
1272
1273 mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */
1274 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0,
1275 HDA_INPUT);
1276 err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv);
1277 mutex_unlock(&codec->spdif_mutex); /* reuse spdif_mutex */
1278 return err;
1279}
1280
1281typedef int (*getput_call_t)(struct snd_kcontrol *kcontrol,
1282 struct snd_ctl_elem_value *ucontrol);
1283
1284static int alc_cap_getput_caller(struct snd_kcontrol *kcontrol,
1285 struct snd_ctl_elem_value *ucontrol,
1286 getput_call_t func)
1287{
1288 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1289 struct alc_spec *spec = codec->spec;
1290 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1291 int err;
1292
1293 mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */
1294 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[adc_idx],
1295 3, 0, HDA_INPUT);
1296 err = func(kcontrol, ucontrol);
1297 mutex_unlock(&codec->spdif_mutex); /* reuse spdif_mutex */
1298 return err;
1299}
1300
1301static int alc_cap_vol_get(struct snd_kcontrol *kcontrol,
1302 struct snd_ctl_elem_value *ucontrol)
1303{
1304 return alc_cap_getput_caller(kcontrol, ucontrol,
1305 snd_hda_mixer_amp_volume_get);
1306}
1307
1308static int alc_cap_vol_put(struct snd_kcontrol *kcontrol,
1309 struct snd_ctl_elem_value *ucontrol)
1310{
1311 return alc_cap_getput_caller(kcontrol, ucontrol,
1312 snd_hda_mixer_amp_volume_put);
1313}
1314
1315/* capture mixer elements */
1316#define alc_cap_sw_info snd_ctl_boolean_stereo_info
1317
1318static int alc_cap_sw_get(struct snd_kcontrol *kcontrol,
1319 struct snd_ctl_elem_value *ucontrol)
1320{
1321 return alc_cap_getput_caller(kcontrol, ucontrol,
1322 snd_hda_mixer_amp_switch_get);
1323}
1324
1325static int alc_cap_sw_put(struct snd_kcontrol *kcontrol,
1326 struct snd_ctl_elem_value *ucontrol)
1327{
1328 return alc_cap_getput_caller(kcontrol, ucontrol,
1329 snd_hda_mixer_amp_switch_put);
1330}
1331
1332#define DEFINE_CAPMIX(num) \
1333static struct snd_kcontrol_new alc_capture_mixer ## num[] = { \
1334 { \
1335 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
1336 .name = "Capture Switch", \
1337 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
1338 .count = num, \
1339 .info = alc_cap_sw_info, \
1340 .get = alc_cap_sw_get, \
1341 .put = alc_cap_sw_put, \
1342 }, \
1343 { \
1344 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
1345 .name = "Capture Volume", \
1346 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | \
1347 SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
1348 SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK), \
1349 .count = num, \
1350 .info = alc_cap_vol_info, \
1351 .get = alc_cap_vol_get, \
1352 .put = alc_cap_vol_put, \
1353 .tlv = { .c = alc_cap_vol_tlv }, \
1354 }, \
Takashi Iwai3c3e9892008-10-31 17:48:56 +01001355 { \
1356 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
1357 /* .name = "Capture Source", */ \
1358 .name = "Input Source", \
1359 .count = num, \
1360 .info = alc_mux_enum_info, \
1361 .get = alc_mux_enum_get, \
1362 .put = alc_mux_enum_put, \
1363 }, \
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001364 { } /* end */ \
1365}
1366
1367/* up to three ADCs */
1368DEFINE_CAPMIX(1);
1369DEFINE_CAPMIX(2);
1370DEFINE_CAPMIX(3);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001371
1372
1373/*
1374 * ALC880 5-stack model
1375 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001376 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0d),
1377 * Side = 0x02 (0xd)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001378 * Pin assignment: Front = 0x14, Surr = 0x17, CLFE = 0x16
1379 * Line-In/Side = 0x1a, Mic = 0x18, F-Mic = 0x1b, HP = 0x19
1380 */
1381
1382/* additional mixers to alc880_three_stack_mixer */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001383static struct snd_kcontrol_new alc880_five_stack_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001384 HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001385 HDA_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386 { } /* end */
1387};
1388
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001389/* channel source setting (6/8 channel selection for 5-stack) */
1390/* 6ch mode */
1391static struct hda_verb alc880_fivestack_ch6_init[] = {
1392 /* set line-in to input, mute it */
1393 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
1394 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02001395 { } /* end */
1396};
1397
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001398/* 8ch mode */
1399static struct hda_verb alc880_fivestack_ch8_init[] = {
1400 /* set line-in to output, unmute it */
1401 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1402 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1403 { } /* end */
1404};
1405
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001406static struct hda_channel_mode alc880_fivestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001407 { 6, alc880_fivestack_ch6_init },
1408 { 8, alc880_fivestack_ch8_init },
1409};
1410
1411
1412/*
1413 * ALC880 6-stack model
1414 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001415 * DAC: Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e),
1416 * Side = 0x05 (0x0f)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001417 * Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, Side = 0x17,
1418 * Mic = 0x18, F-Mic = 0x19, Line = 0x1a, HP = 0x1b
1419 */
1420
1421static hda_nid_t alc880_6st_dac_nids[4] = {
1422 /* front, rear, clfe, rear_surr */
1423 0x02, 0x03, 0x04, 0x05
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02001424};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001425
1426static struct hda_input_mux alc880_6stack_capture_source = {
1427 .num_items = 4,
1428 .items = {
1429 { "Mic", 0x0 },
1430 { "Front Mic", 0x1 },
1431 { "Line", 0x2 },
1432 { "CD", 0x4 },
1433 },
1434};
1435
1436/* fixed 8-channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001437static struct hda_channel_mode alc880_sixstack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001438 { 8, NULL },
1439};
1440
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001441static struct snd_kcontrol_new alc880_six_stack_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001442 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001443 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001444 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001445 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001446 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1447 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001448 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1449 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001450 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001451 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001452 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1453 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1454 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1455 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1456 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1457 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1458 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1459 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
1460 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
1461 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001462 {
1463 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1464 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01001465 .info = alc_ch_mode_info,
1466 .get = alc_ch_mode_get,
1467 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02001468 },
1469 { } /* end */
1470};
1471
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001472
1473/*
1474 * ALC880 W810 model
1475 *
1476 * W810 has rear IO for:
1477 * Front (DAC 02)
1478 * Surround (DAC 03)
1479 * Center/LFE (DAC 04)
1480 * Digital out (06)
1481 *
1482 * The system also has a pair of internal speakers, and a headphone jack.
1483 * These are both connected to Line2 on the codec, hence to DAC 02.
Kailang Yangea1fb292008-08-26 12:58:38 +02001484 *
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001485 * There is a variable resistor to control the speaker or headphone
1486 * volume. This is a hardware-only device without a software API.
1487 *
1488 * Plugging headphones in will disable the internal speakers. This is
1489 * implemented in hardware, not via the driver using jack sense. In
1490 * a similar fashion, plugging into the rear socket marked "front" will
1491 * disable both the speakers and headphones.
1492 *
1493 * For input, there's a microphone jack, and an "audio in" jack.
1494 * These may not do anything useful with this driver yet, because I
1495 * haven't setup any initialization verbs for these yet...
1496 */
1497
1498static hda_nid_t alc880_w810_dac_nids[3] = {
1499 /* front, rear/surround, clfe */
1500 0x02, 0x03, 0x04
1501};
1502
1503/* fixed 6 channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001504static struct hda_channel_mode alc880_w810_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001505 { 6, NULL }
1506};
1507
1508/* Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, HP = 0x1b */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001509static struct snd_kcontrol_new alc880_w810_base_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001510 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001511 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001512 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001513 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001514 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1515 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001516 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1517 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001518 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
1519 { } /* end */
1520};
1521
1522
1523/*
1524 * Z710V model
1525 *
1526 * DAC: Front = 0x02 (0x0c), HP = 0x03 (0x0d)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001527 * Pin assignment: Front = 0x14, HP = 0x15, Mic = 0x18, Mic2 = 0x19(?),
1528 * Line = 0x1a
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001529 */
1530
1531static hda_nid_t alc880_z71v_dac_nids[1] = {
1532 0x02
1533};
1534#define ALC880_Z71V_HP_DAC 0x03
1535
1536/* fixed 2 channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001537static struct hda_channel_mode alc880_2_jack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001538 { 2, NULL }
1539};
1540
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001541static struct snd_kcontrol_new alc880_z71v_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001542 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001543 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001544 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001545 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001546 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1547 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1548 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1549 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1550 { } /* end */
1551};
1552
1553
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001554/*
1555 * ALC880 F1734 model
1556 *
1557 * DAC: HP = 0x02 (0x0c), Front = 0x03 (0x0d)
1558 * Pin assignment: HP = 0x14, Front = 0x15, Mic = 0x18
1559 */
1560
1561static hda_nid_t alc880_f1734_dac_nids[1] = {
1562 0x03
1563};
1564#define ALC880_F1734_HP_DAC 0x02
1565
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001566static struct snd_kcontrol_new alc880_f1734_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001567 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001568 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01001569 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1570 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001571 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1572 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Takashi Iwai937b4162008-02-11 14:52:36 +01001573 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1574 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001575 { } /* end */
1576};
1577
Takashi Iwai937b4162008-02-11 14:52:36 +01001578static struct hda_input_mux alc880_f1734_capture_source = {
1579 .num_items = 2,
1580 .items = {
1581 { "Mic", 0x1 },
1582 { "CD", 0x4 },
1583 },
1584};
1585
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001586
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001587/*
1588 * ALC880 ASUS model
1589 *
1590 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
1591 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
1592 * Mic = 0x18, Line = 0x1a
1593 */
1594
1595#define alc880_asus_dac_nids alc880_w810_dac_nids /* identical with w810 */
1596#define alc880_asus_modes alc880_threestack_modes /* 2/6 channel mode */
1597
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001598static struct snd_kcontrol_new alc880_asus_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001599 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001600 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001601 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001602 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001603 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1604 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001605 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1606 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001607 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1608 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1609 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1610 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1611 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1612 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001613 {
1614 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1615 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01001616 .info = alc_ch_mode_info,
1617 .get = alc_ch_mode_get,
1618 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02001619 },
1620 { } /* end */
1621};
1622
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001623/*
1624 * ALC880 ASUS W1V model
1625 *
1626 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
1627 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
1628 * Mic = 0x18, Line = 0x1a, Line2 = 0x1b
1629 */
1630
1631/* additional mixers to alc880_asus_mixer */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001632static struct snd_kcontrol_new alc880_asus_w1v_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001633 HDA_CODEC_VOLUME("Line2 Playback Volume", 0x0b, 0x03, HDA_INPUT),
1634 HDA_CODEC_MUTE("Line2 Playback Switch", 0x0b, 0x03, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001635 { } /* end */
1636};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001637
Takashi Iwai3c10a9d2005-08-23 20:02:27 +02001638/* additional mixers to alc880_asus_mixer */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001639static struct snd_kcontrol_new alc880_pcbeep_mixer[] = {
Takashi Iwai3c10a9d2005-08-23 20:02:27 +02001640 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
1641 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
1642 { } /* end */
1643};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001644
Kailang Yangdf694da2005-12-05 19:42:22 +01001645/* TCL S700 */
1646static struct snd_kcontrol_new alc880_tcl_s700_mixer[] = {
1647 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1648 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
1649 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
1650 HDA_CODEC_VOLUME("CD Playback Volume", 0x0B, 0x04, HDA_INPUT),
1651 HDA_CODEC_MUTE("CD Playback Switch", 0x0B, 0x04, HDA_INPUT),
1652 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0B, 0x0, HDA_INPUT),
1653 HDA_CODEC_MUTE("Mic Playback Switch", 0x0B, 0x0, HDA_INPUT),
1654 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
1655 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01001656 { } /* end */
1657};
1658
Kailang Yangccc656c2006-10-17 12:32:26 +02001659/* Uniwill */
1660static struct snd_kcontrol_new alc880_uniwill_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01001661 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1662 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
1663 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1664 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02001665 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1666 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
1667 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1668 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
1669 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1670 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1671 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1672 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1673 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1674 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1675 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1676 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
1677 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
1678 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
1679 {
1680 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1681 .name = "Channel Mode",
1682 .info = alc_ch_mode_info,
1683 .get = alc_ch_mode_get,
1684 .put = alc_ch_mode_put,
1685 },
1686 { } /* end */
1687};
1688
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01001689static struct snd_kcontrol_new alc880_fujitsu_mixer[] = {
1690 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1691 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
1692 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1693 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
1694 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1695 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1696 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1697 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1698 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1699 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
1700 { } /* end */
1701};
1702
Kailang Yangccc656c2006-10-17 12:32:26 +02001703static struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01001704 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1705 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
1706 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1707 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02001708 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1709 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1710 { } /* end */
1711};
1712
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713/*
Takashi Iwai2134ea42008-01-10 16:53:55 +01001714 * virtual master controls
1715 */
1716
1717/*
1718 * slave controls for virtual master
1719 */
1720static const char *alc_slave_vols[] = {
1721 "Front Playback Volume",
1722 "Surround Playback Volume",
1723 "Center Playback Volume",
1724 "LFE Playback Volume",
1725 "Side Playback Volume",
1726 "Headphone Playback Volume",
1727 "Speaker Playback Volume",
1728 "Mono Playback Volume",
Takashi Iwai2134ea42008-01-10 16:53:55 +01001729 "Line-Out Playback Volume",
Takashi Iwai26f5df22008-11-03 17:39:46 +01001730 "PCM Playback Volume",
Takashi Iwai2134ea42008-01-10 16:53:55 +01001731 NULL,
1732};
1733
1734static const char *alc_slave_sws[] = {
1735 "Front Playback Switch",
1736 "Surround Playback Switch",
1737 "Center Playback Switch",
1738 "LFE Playback Switch",
1739 "Side Playback Switch",
1740 "Headphone Playback Switch",
1741 "Speaker Playback Switch",
1742 "Mono Playback Switch",
Takashi Iwaiedb54a52008-01-29 12:47:02 +01001743 "IEC958 Playback Switch",
Takashi Iwai2134ea42008-01-10 16:53:55 +01001744 NULL,
1745};
1746
1747/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001748 * build control elements
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749 */
Takashi Iwai603c4012008-07-30 15:01:44 +02001750
1751static void alc_free_kctls(struct hda_codec *codec);
1752
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753static int alc_build_controls(struct hda_codec *codec)
1754{
1755 struct alc_spec *spec = codec->spec;
1756 int err;
1757 int i;
1758
1759 for (i = 0; i < spec->num_mixers; i++) {
1760 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
1761 if (err < 0)
1762 return err;
1763 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001764 if (spec->cap_mixer) {
1765 err = snd_hda_add_new_ctls(codec, spec->cap_mixer);
1766 if (err < 0)
1767 return err;
1768 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769 if (spec->multiout.dig_out_nid) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001770 err = snd_hda_create_spdif_out_ctls(codec,
1771 spec->multiout.dig_out_nid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772 if (err < 0)
1773 return err;
Takashi Iwai9a081602008-02-12 18:37:26 +01001774 err = snd_hda_create_spdif_share_sw(codec,
1775 &spec->multiout);
1776 if (err < 0)
1777 return err;
1778 spec->multiout.share_spdif = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779 }
1780 if (spec->dig_in_nid) {
1781 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
1782 if (err < 0)
1783 return err;
1784 }
Takashi Iwai2134ea42008-01-10 16:53:55 +01001785
1786 /* if we have no master control, let's create it */
1787 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001788 unsigned int vmaster_tlv[4];
Takashi Iwai2134ea42008-01-10 16:53:55 +01001789 snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001790 HDA_OUTPUT, vmaster_tlv);
Takashi Iwai2134ea42008-01-10 16:53:55 +01001791 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001792 vmaster_tlv, alc_slave_vols);
Takashi Iwai2134ea42008-01-10 16:53:55 +01001793 if (err < 0)
1794 return err;
1795 }
1796 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
1797 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
1798 NULL, alc_slave_sws);
1799 if (err < 0)
1800 return err;
1801 }
1802
Takashi Iwai603c4012008-07-30 15:01:44 +02001803 alc_free_kctls(codec); /* no longer needed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804 return 0;
1805}
1806
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001807
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808/*
1809 * initialize the codec volumes, etc
1810 */
1811
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001812/*
1813 * generic initialization of ADC, input mixers and output mixers
1814 */
1815static struct hda_verb alc880_volume_init_verbs[] = {
1816 /*
1817 * Unmute ADC0-2 and set the default input to mic-in
1818 */
Takashi Iwai71fe7b82005-05-25 18:11:40 +02001819 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001820 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02001821 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001822 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02001823 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001824 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001826 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
1827 * mixer widget
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001828 * Note: PASD motherboards uses the Line In 2 as the input for front
1829 * panel mic (mic 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001831 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02001832 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1833 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
1834 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
1835 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
1836 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
1837 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
1838 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001840 /*
1841 * Set up output mixers (0x0c - 0x0f)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001843 /* set vol=0 to output mixers */
1844 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1845 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1846 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1847 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1848 /* set up input amps for analog loopback */
1849 /* Amp Indices: DAC = 0, mixer = 1 */
Takashi Iwai05acb862005-06-10 19:50:25 +02001850 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1851 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02001852 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1853 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02001854 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1855 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02001856 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1857 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858
1859 { }
1860};
1861
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001862/*
1863 * 3-stack pin configuration:
1864 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
1865 */
1866static struct hda_verb alc880_pin_3stack_init_verbs[] = {
1867 /*
1868 * preset connection lists of input pins
1869 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
1870 */
1871 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
1872 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1873 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
1874
1875 /*
1876 * Set pin mode and muting
1877 */
1878 /* set front pin widgets 0x14 for output */
1879 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1880 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1881 /* Mic1 (rear panel) pin widget for input and vref at 80% */
1882 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1883 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1884 /* Mic2 (as headphone out) for HP output */
1885 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1886 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1887 /* Line In pin widget for input */
1888 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1889 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1890 /* Line2 (as front mic) pin widget for input and vref at 80% */
1891 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1892 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1893 /* CD pin widget for input */
1894 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1895
1896 { }
1897};
1898
1899/*
1900 * 5-stack pin configuration:
1901 * front = 0x14, surround = 0x17, clfe = 0x16, mic = 0x18, HP = 0x19,
1902 * line-in/side = 0x1a, f-mic = 0x1b
1903 */
1904static struct hda_verb alc880_pin_5stack_init_verbs[] = {
1905 /*
1906 * preset connection lists of input pins
1907 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
1908 */
1909 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1910 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/side */
1911
1912 /*
1913 * Set pin mode and muting
1914 */
1915 /* set pin widgets 0x14-0x17 for output */
Takashi Iwai05acb862005-06-10 19:50:25 +02001916 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1917 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1918 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1919 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001920 /* unmute pins for output (no gain on this amp) */
1921 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1922 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1923 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1924 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1925
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02001927 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001928 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1929 /* Mic2 (as headphone out) for HP output */
1930 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02001931 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001932 /* Line In pin widget for input */
1933 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1934 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1935 /* Line2 (as front mic) pin widget for input and vref at 80% */
1936 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1937 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1938 /* CD pin widget for input */
1939 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940
1941 { }
1942};
1943
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001944/*
1945 * W810 pin configuration:
1946 * front = 0x14, surround = 0x15, clfe = 0x16, HP = 0x1b
1947 */
1948static struct hda_verb alc880_pin_w810_init_verbs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949 /* hphone/speaker input selector: front DAC */
1950 {0x13, AC_VERB_SET_CONNECT_SEL, 0x0},
1951
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001952 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1953 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1954 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1955 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1956 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1957 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1958
1959 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02001960 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961
Linus Torvalds1da177e2005-04-16 15:20:36 -07001962 { }
1963};
1964
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001965/*
1966 * Z71V pin configuration:
1967 * Speaker-out = 0x14, HP = 0x15, Mic = 0x18, Line-in = 0x1a, Mic2 = 0x1b (?)
1968 */
1969static struct hda_verb alc880_pin_z71v_init_verbs[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02001970 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001971 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai05acb862005-06-10 19:50:25 +02001972 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001973 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02001974
Takashi Iwai16ded522005-06-10 19:58:24 +02001975 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001976 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02001977 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001978 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02001979
1980 { }
1981};
1982
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001983/*
1984 * 6-stack pin configuration:
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001985 * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18,
1986 * f-mic = 0x19, line = 0x1a, HP = 0x1b
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001987 */
1988static struct hda_verb alc880_pin_6stack_init_verbs[] = {
1989 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1990
Takashi Iwai16ded522005-06-10 19:58:24 +02001991 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001992 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001993 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001994 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001995 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001996 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001997 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001998 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1999
Takashi Iwai16ded522005-06-10 19:58:24 +02002000 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002001 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002002 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002003 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002004 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002005 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002006 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai16ded522005-06-10 19:58:24 +02002007 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002008 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangea1fb292008-08-26 12:58:38 +02002009
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002010 { }
2011};
Takashi Iwai16ded522005-06-10 19:58:24 +02002012
Kailang Yangccc656c2006-10-17 12:32:26 +02002013/*
2014 * Uniwill pin configuration:
2015 * HP = 0x14, InternalSpeaker = 0x15, mic = 0x18, internal mic = 0x19,
2016 * line = 0x1a
2017 */
2018static struct hda_verb alc880_uniwill_init_verbs[] = {
2019 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2020
2021 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2022 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2023 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2024 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2025 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2026 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2027 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2028 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2029 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2030 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2031 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2032 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2033 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2034 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2035
2036 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2037 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2038 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2039 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2040 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2041 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2042 /* {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, */
2043 /* {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
2044 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2045
2046 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
2047 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
2048
2049 { }
2050};
2051
2052/*
2053* Uniwill P53
Kailang Yangea1fb292008-08-26 12:58:38 +02002054* HP = 0x14, InternalSpeaker = 0x15, mic = 0x19,
Kailang Yangccc656c2006-10-17 12:32:26 +02002055 */
2056static struct hda_verb alc880_uniwill_p53_init_verbs[] = {
2057 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2058
2059 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2060 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2061 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2062 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2063 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2064 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2065 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2066 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2067 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2068 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2069 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2070 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2071
2072 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2073 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2074 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2075 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2076 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2077 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2078
2079 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
2080 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_DCVOL_EVENT},
2081
2082 { }
2083};
2084
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01002085static struct hda_verb alc880_beep_init_verbs[] = {
2086 { 0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) },
2087 { }
2088};
2089
Kailang Yangccc656c2006-10-17 12:32:26 +02002090/* toggle speaker-output according to the hp-jack state */
Takashi Iwai458a4fa2007-05-05 12:18:40 +02002091static void alc880_uniwill_hp_automute(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02002092{
2093 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002094 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02002095
2096 present = snd_hda_codec_read(codec, 0x14, 0,
2097 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02002098 bits = present ? HDA_AMP_MUTE : 0;
2099 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
2100 HDA_AMP_MUTE, bits);
2101 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
2102 HDA_AMP_MUTE, bits);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02002103}
2104
2105/* auto-toggle front mic */
2106static void alc880_uniwill_mic_automute(struct hda_codec *codec)
2107{
2108 unsigned int present;
2109 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02002110
2111 present = snd_hda_codec_read(codec, 0x18, 0,
2112 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02002113 bits = present ? HDA_AMP_MUTE : 0;
2114 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02002115}
2116
2117static void alc880_uniwill_automute(struct hda_codec *codec)
2118{
2119 alc880_uniwill_hp_automute(codec);
2120 alc880_uniwill_mic_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02002121}
2122
2123static void alc880_uniwill_unsol_event(struct hda_codec *codec,
2124 unsigned int res)
2125{
2126 /* Looks like the unsol event is incompatible with the standard
2127 * definition. 4bit tag is placed at 28 bit!
2128 */
Takashi Iwai458a4fa2007-05-05 12:18:40 +02002129 switch (res >> 28) {
2130 case ALC880_HP_EVENT:
2131 alc880_uniwill_hp_automute(codec);
2132 break;
2133 case ALC880_MIC_EVENT:
2134 alc880_uniwill_mic_automute(codec);
2135 break;
2136 }
Kailang Yangccc656c2006-10-17 12:32:26 +02002137}
2138
2139static void alc880_uniwill_p53_hp_automute(struct hda_codec *codec)
2140{
2141 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002142 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02002143
2144 present = snd_hda_codec_read(codec, 0x14, 0,
2145 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02002146 bits = present ? HDA_AMP_MUTE : 0;
Jiang zhe64654c22008-04-14 13:26:21 +02002147 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, HDA_AMP_MUTE, bits);
Kailang Yangccc656c2006-10-17 12:32:26 +02002148}
2149
2150static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec)
2151{
2152 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02002153
Kailang Yangccc656c2006-10-17 12:32:26 +02002154 present = snd_hda_codec_read(codec, 0x21, 0,
Takashi Iwai47fd8302007-08-10 17:11:07 +02002155 AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
2156 present &= HDA_AMP_VOLMASK;
2157 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0,
2158 HDA_AMP_VOLMASK, present);
2159 snd_hda_codec_amp_stereo(codec, 0x0d, HDA_OUTPUT, 0,
2160 HDA_AMP_VOLMASK, present);
Kailang Yangccc656c2006-10-17 12:32:26 +02002161}
Takashi Iwai47fd8302007-08-10 17:11:07 +02002162
Kailang Yangccc656c2006-10-17 12:32:26 +02002163static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec,
2164 unsigned int res)
2165{
2166 /* Looks like the unsol event is incompatible with the standard
2167 * definition. 4bit tag is placed at 28 bit!
2168 */
2169 if ((res >> 28) == ALC880_HP_EVENT)
2170 alc880_uniwill_p53_hp_automute(codec);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002171 if ((res >> 28) == ALC880_DCVOL_EVENT)
Kailang Yangccc656c2006-10-17 12:32:26 +02002172 alc880_uniwill_p53_dcvol_automute(codec);
2173}
2174
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002175/*
2176 * F1734 pin configuration:
2177 * HP = 0x14, speaker-out = 0x15, mic = 0x18
2178 */
2179static struct hda_verb alc880_pin_f1734_init_verbs[] = {
Michael Gruberee7a9c72008-03-10 11:30:59 +01002180 {0x07, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002181 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
2182 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
2183 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
2184 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
2185
2186 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2187 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2188 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2189 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2190
2191 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2192 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Michael Gruberee7a9c72008-03-10 11:30:59 +01002193 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002194 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2195 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2196 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2197 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2198 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2199 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02002200
Takashi Iwai937b4162008-02-11 14:52:36 +01002201 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
2202 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_DCVOL_EVENT},
2203
Takashi Iwai16ded522005-06-10 19:58:24 +02002204 { }
2205};
2206
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002207/*
2208 * ASUS pin configuration:
2209 * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a
2210 */
2211static struct hda_verb alc880_pin_asus_init_verbs[] = {
2212 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
2213 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
2214 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
2215 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
2216
2217 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2218 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2219 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2220 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2221 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2222 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2223 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2224 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2225
2226 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2227 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2228 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2229 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2230 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2231 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2232 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2233 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2234 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangea1fb292008-08-26 12:58:38 +02002235
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002236 { }
2237};
2238
2239/* Enable GPIO mask and set output */
Kailang Yangbc9f98a2007-04-12 13:06:07 +02002240#define alc880_gpio1_init_verbs alc_gpio1_init_verbs
2241#define alc880_gpio2_init_verbs alc_gpio2_init_verbs
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002242
Kailang Yangdf694da2005-12-05 19:42:22 +01002243/* Clevo m520g init */
2244static struct hda_verb alc880_pin_clevo_init_verbs[] = {
2245 /* headphone output */
2246 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
2247 /* line-out */
2248 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2249 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2250 /* Line-in */
2251 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2252 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2253 /* CD */
2254 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2255 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2256 /* Mic1 (rear panel) */
2257 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2258 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2259 /* Mic2 (front panel) */
2260 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2261 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2262 /* headphone */
2263 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2264 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2265 /* change to EAPD mode */
2266 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
2267 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
2268
2269 { }
2270};
2271
2272static struct hda_verb alc880_pin_tcl_S700_init_verbs[] = {
Takashi Iwai4b146cb2006-07-28 14:42:36 +02002273 /* change to EAPD mode */
2274 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
2275 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
2276
Kailang Yangdf694da2005-12-05 19:42:22 +01002277 /* Headphone output */
2278 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2279 /* Front output*/
2280 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2281 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
2282
2283 /* Line In pin widget for input */
2284 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2285 /* CD pin widget for input */
2286 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2287 /* Mic1 (rear panel) pin widget for input and vref at 80% */
2288 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2289
2290 /* change to EAPD mode */
2291 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
2292 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
2293
2294 { }
2295};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002296
2297/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002298 * LG m1 express dual
2299 *
2300 * Pin assignment:
2301 * Rear Line-In/Out (blue): 0x14
2302 * Build-in Mic-In: 0x15
2303 * Speaker-out: 0x17
2304 * HP-Out (green): 0x1b
2305 * Mic-In/Out (red): 0x19
2306 * SPDIF-Out: 0x1e
2307 */
2308
2309/* To make 5.1 output working (green=Front, blue=Surr, red=CLFE) */
2310static hda_nid_t alc880_lg_dac_nids[3] = {
2311 0x05, 0x02, 0x03
2312};
2313
2314/* seems analog CD is not working */
2315static struct hda_input_mux alc880_lg_capture_source = {
2316 .num_items = 3,
2317 .items = {
2318 { "Mic", 0x1 },
2319 { "Line", 0x5 },
2320 { "Internal Mic", 0x6 },
2321 },
2322};
2323
2324/* 2,4,6 channel modes */
2325static struct hda_verb alc880_lg_ch2_init[] = {
2326 /* set line-in and mic-in to input */
2327 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2328 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2329 { }
2330};
2331
2332static struct hda_verb alc880_lg_ch4_init[] = {
2333 /* set line-in to out and mic-in to input */
2334 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
2335 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2336 { }
2337};
2338
2339static struct hda_verb alc880_lg_ch6_init[] = {
2340 /* set line-in and mic-in to output */
2341 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
2342 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
2343 { }
2344};
2345
2346static struct hda_channel_mode alc880_lg_ch_modes[3] = {
2347 { 2, alc880_lg_ch2_init },
2348 { 4, alc880_lg_ch4_init },
2349 { 6, alc880_lg_ch6_init },
2350};
2351
2352static struct snd_kcontrol_new alc880_lg_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01002353 HDA_CODEC_VOLUME("Front Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
2354 HDA_BIND_MUTE("Front Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002355 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2356 HDA_BIND_MUTE("Surround Playback Switch", 0x0c, 2, HDA_INPUT),
2357 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
2358 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
2359 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
2360 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
2361 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2362 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
2363 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x06, HDA_INPUT),
2364 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x06, HDA_INPUT),
2365 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x07, HDA_INPUT),
2366 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x07, HDA_INPUT),
2367 {
2368 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2369 .name = "Channel Mode",
2370 .info = alc_ch_mode_info,
2371 .get = alc_ch_mode_get,
2372 .put = alc_ch_mode_put,
2373 },
2374 { } /* end */
2375};
2376
2377static struct hda_verb alc880_lg_init_verbs[] = {
2378 /* set capture source to mic-in */
2379 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2380 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2381 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2382 /* mute all amp mixer inputs */
2383 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02002384 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
2385 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002386 /* line-in to input */
2387 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2388 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2389 /* built-in mic */
2390 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2391 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2392 /* speaker-out */
2393 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2394 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2395 /* mic-in to input */
2396 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
2397 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2398 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2399 /* HP-out */
2400 {0x13, AC_VERB_SET_CONNECT_SEL, 0x03},
2401 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2402 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2403 /* jack sense */
2404 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | 0x1},
2405 { }
2406};
2407
2408/* toggle speaker-output according to the hp-jack state */
2409static void alc880_lg_automute(struct hda_codec *codec)
2410{
2411 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002412 unsigned char bits;
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002413
2414 present = snd_hda_codec_read(codec, 0x1b, 0,
2415 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02002416 bits = present ? HDA_AMP_MUTE : 0;
2417 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
2418 HDA_AMP_MUTE, bits);
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002419}
2420
2421static void alc880_lg_unsol_event(struct hda_codec *codec, unsigned int res)
2422{
2423 /* Looks like the unsol event is incompatible with the standard
2424 * definition. 4bit tag is placed at 28 bit!
2425 */
2426 if ((res >> 28) == 0x01)
2427 alc880_lg_automute(codec);
2428}
2429
2430/*
Takashi Iwaid6815182006-03-23 16:06:23 +01002431 * LG LW20
2432 *
2433 * Pin assignment:
2434 * Speaker-out: 0x14
2435 * Mic-In: 0x18
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02002436 * Built-in Mic-In: 0x19
2437 * Line-In: 0x1b
2438 * HP-Out: 0x1a
Takashi Iwaid6815182006-03-23 16:06:23 +01002439 * SPDIF-Out: 0x1e
2440 */
2441
Takashi Iwaid6815182006-03-23 16:06:23 +01002442static struct hda_input_mux alc880_lg_lw_capture_source = {
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02002443 .num_items = 3,
Takashi Iwaid6815182006-03-23 16:06:23 +01002444 .items = {
2445 { "Mic", 0x0 },
2446 { "Internal Mic", 0x1 },
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02002447 { "Line In", 0x2 },
Takashi Iwaid6815182006-03-23 16:06:23 +01002448 },
2449};
2450
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002451#define alc880_lg_lw_modes alc880_threestack_modes
2452
Takashi Iwaid6815182006-03-23 16:06:23 +01002453static struct snd_kcontrol_new alc880_lg_lw_mixer[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002454 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2455 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
2456 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
2457 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
2458 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2459 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
2460 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2461 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
2462 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2463 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaid6815182006-03-23 16:06:23 +01002464 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2465 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2466 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
2467 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002468 {
2469 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2470 .name = "Channel Mode",
2471 .info = alc_ch_mode_info,
2472 .get = alc_ch_mode_get,
2473 .put = alc_ch_mode_put,
2474 },
Takashi Iwaid6815182006-03-23 16:06:23 +01002475 { } /* end */
2476};
2477
2478static struct hda_verb alc880_lg_lw_init_verbs[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002479 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2480 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
2481 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
2482
Takashi Iwaid6815182006-03-23 16:06:23 +01002483 /* set capture source to mic-in */
2484 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2485 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2486 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02002487 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaid6815182006-03-23 16:06:23 +01002488 /* speaker-out */
2489 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2490 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2491 /* HP-out */
Takashi Iwaid6815182006-03-23 16:06:23 +01002492 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2493 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2494 /* mic-in to input */
2495 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2496 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2497 /* built-in mic */
2498 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2499 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2500 /* jack sense */
2501 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | 0x1},
2502 { }
2503};
2504
2505/* toggle speaker-output according to the hp-jack state */
2506static void alc880_lg_lw_automute(struct hda_codec *codec)
2507{
2508 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002509 unsigned char bits;
Takashi Iwaid6815182006-03-23 16:06:23 +01002510
2511 present = snd_hda_codec_read(codec, 0x1b, 0,
2512 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02002513 bits = present ? HDA_AMP_MUTE : 0;
2514 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
2515 HDA_AMP_MUTE, bits);
Takashi Iwaid6815182006-03-23 16:06:23 +01002516}
2517
2518static void alc880_lg_lw_unsol_event(struct hda_codec *codec, unsigned int res)
2519{
2520 /* Looks like the unsol event is incompatible with the standard
2521 * definition. 4bit tag is placed at 28 bit!
2522 */
2523 if ((res >> 28) == 0x01)
2524 alc880_lg_lw_automute(codec);
2525}
2526
Takashi Iwaidf99cd32008-04-25 15:25:04 +02002527static struct snd_kcontrol_new alc880_medion_rim_mixer[] = {
2528 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2529 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
2530 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2531 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2532 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2533 HDA_CODEC_MUTE("Internal Playback Switch", 0x0b, 0x1, HDA_INPUT),
2534 { } /* end */
2535};
2536
2537static struct hda_input_mux alc880_medion_rim_capture_source = {
2538 .num_items = 2,
2539 .items = {
2540 { "Mic", 0x0 },
2541 { "Internal Mic", 0x1 },
2542 },
2543};
2544
2545static struct hda_verb alc880_medion_rim_init_verbs[] = {
2546 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2547
2548 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2549 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2550
2551 /* Mic1 (rear panel) pin widget for input and vref at 80% */
2552 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2553 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2554 /* Mic2 (as headphone out) for HP output */
2555 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2556 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2557 /* Internal Speaker */
2558 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2559 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2560
2561 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
2562 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
2563
2564 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
2565 { }
2566};
2567
2568/* toggle speaker-output according to the hp-jack state */
2569static void alc880_medion_rim_automute(struct hda_codec *codec)
2570{
2571 unsigned int present;
2572 unsigned char bits;
2573
2574 present = snd_hda_codec_read(codec, 0x14, 0,
2575 AC_VERB_GET_PIN_SENSE, 0)
2576 & AC_PINSENSE_PRESENCE;
2577 bits = present ? HDA_AMP_MUTE : 0;
2578 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
2579 HDA_AMP_MUTE, bits);
2580 if (present)
2581 snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0);
2582 else
2583 snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 2);
2584}
2585
2586static void alc880_medion_rim_unsol_event(struct hda_codec *codec,
2587 unsigned int res)
2588{
2589 /* Looks like the unsol event is incompatible with the standard
2590 * definition. 4bit tag is placed at 28 bit!
2591 */
2592 if ((res >> 28) == ALC880_HP_EVENT)
2593 alc880_medion_rim_automute(codec);
2594}
2595
Takashi Iwaicb53c622007-08-10 17:21:45 +02002596#ifdef CONFIG_SND_HDA_POWER_SAVE
2597static struct hda_amp_list alc880_loopbacks[] = {
2598 { 0x0b, HDA_INPUT, 0 },
2599 { 0x0b, HDA_INPUT, 1 },
2600 { 0x0b, HDA_INPUT, 2 },
2601 { 0x0b, HDA_INPUT, 3 },
2602 { 0x0b, HDA_INPUT, 4 },
2603 { } /* end */
2604};
2605
2606static struct hda_amp_list alc880_lg_loopbacks[] = {
2607 { 0x0b, HDA_INPUT, 1 },
2608 { 0x0b, HDA_INPUT, 6 },
2609 { 0x0b, HDA_INPUT, 7 },
2610 { } /* end */
2611};
2612#endif
2613
Takashi Iwaid6815182006-03-23 16:06:23 +01002614/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002615 * Common callbacks
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002616 */
Takashi Iwai16ded522005-06-10 19:58:24 +02002617
Linus Torvalds1da177e2005-04-16 15:20:36 -07002618static int alc_init(struct hda_codec *codec)
2619{
2620 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002621 unsigned int i;
2622
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02002623 alc_fix_pll(codec);
Takashi Iwai1082c742008-08-22 15:24:22 +02002624 if (codec->vendor_id == 0x10ec0888)
2625 alc888_coef_init(codec);
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02002626
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002627 for (i = 0; i < spec->num_init_verbs; i++)
2628 snd_hda_sequence_write(codec, spec->init_verbs[i]);
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002629
2630 if (spec->init_hook)
2631 spec->init_hook(codec);
2632
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633 return 0;
2634}
2635
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002636static void alc_unsol_event(struct hda_codec *codec, unsigned int res)
2637{
2638 struct alc_spec *spec = codec->spec;
2639
2640 if (spec->unsol_event)
2641 spec->unsol_event(codec, res);
2642}
2643
Takashi Iwaicb53c622007-08-10 17:21:45 +02002644#ifdef CONFIG_SND_HDA_POWER_SAVE
2645static int alc_check_power_status(struct hda_codec *codec, hda_nid_t nid)
2646{
2647 struct alc_spec *spec = codec->spec;
2648 return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
2649}
2650#endif
2651
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652/*
2653 * Analog playback callbacks
2654 */
2655static int alc880_playback_pcm_open(struct hda_pcm_stream *hinfo,
2656 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002657 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002658{
2659 struct alc_spec *spec = codec->spec;
Takashi Iwai9a081602008-02-12 18:37:26 +01002660 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
2661 hinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002662}
2663
2664static int alc880_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
2665 struct hda_codec *codec,
2666 unsigned int stream_tag,
2667 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002668 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669{
2670 struct alc_spec *spec = codec->spec;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002671 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
2672 stream_tag, format, substream);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002673}
2674
2675static int alc880_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
2676 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002677 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678{
2679 struct alc_spec *spec = codec->spec;
2680 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
2681}
2682
2683/*
2684 * Digital out
2685 */
2686static int alc880_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
2687 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002688 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689{
2690 struct alc_spec *spec = codec->spec;
2691 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
2692}
2693
Takashi Iwai6b97eb42007-04-05 14:51:48 +02002694static int alc880_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
2695 struct hda_codec *codec,
2696 unsigned int stream_tag,
2697 unsigned int format,
2698 struct snd_pcm_substream *substream)
2699{
2700 struct alc_spec *spec = codec->spec;
2701 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
2702 stream_tag, format, substream);
2703}
2704
Linus Torvalds1da177e2005-04-16 15:20:36 -07002705static int alc880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
2706 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002707 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002708{
2709 struct alc_spec *spec = codec->spec;
2710 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
2711}
2712
2713/*
2714 * Analog capture
2715 */
Takashi Iwai63300792008-01-24 15:31:36 +01002716static int alc880_alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002717 struct hda_codec *codec,
2718 unsigned int stream_tag,
2719 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002720 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002721{
2722 struct alc_spec *spec = codec->spec;
2723
Takashi Iwai63300792008-01-24 15:31:36 +01002724 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1],
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725 stream_tag, 0, format);
2726 return 0;
2727}
2728
Takashi Iwai63300792008-01-24 15:31:36 +01002729static int alc880_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002731 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732{
2733 struct alc_spec *spec = codec->spec;
2734
Takashi Iwai888afa12008-03-18 09:57:50 +01002735 snd_hda_codec_cleanup_stream(codec,
2736 spec->adc_nids[substream->number + 1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737 return 0;
2738}
2739
2740
2741/*
2742 */
2743static struct hda_pcm_stream alc880_pcm_analog_playback = {
2744 .substreams = 1,
2745 .channels_min = 2,
2746 .channels_max = 8,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002747 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748 .ops = {
2749 .open = alc880_playback_pcm_open,
2750 .prepare = alc880_playback_pcm_prepare,
2751 .cleanup = alc880_playback_pcm_cleanup
2752 },
2753};
2754
2755static struct hda_pcm_stream alc880_pcm_analog_capture = {
Takashi Iwai63300792008-01-24 15:31:36 +01002756 .substreams = 1,
2757 .channels_min = 2,
2758 .channels_max = 2,
2759 /* NID is set in alc_build_pcms */
2760};
2761
2762static struct hda_pcm_stream alc880_pcm_analog_alt_playback = {
2763 .substreams = 1,
2764 .channels_min = 2,
2765 .channels_max = 2,
2766 /* NID is set in alc_build_pcms */
2767};
2768
2769static struct hda_pcm_stream alc880_pcm_analog_alt_capture = {
2770 .substreams = 2, /* can be overridden */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771 .channels_min = 2,
2772 .channels_max = 2,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002773 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774 .ops = {
Takashi Iwai63300792008-01-24 15:31:36 +01002775 .prepare = alc880_alt_capture_pcm_prepare,
2776 .cleanup = alc880_alt_capture_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07002777 },
2778};
2779
2780static struct hda_pcm_stream alc880_pcm_digital_playback = {
2781 .substreams = 1,
2782 .channels_min = 2,
2783 .channels_max = 2,
2784 /* NID is set in alc_build_pcms */
2785 .ops = {
2786 .open = alc880_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02002787 .close = alc880_dig_playback_pcm_close,
2788 .prepare = alc880_dig_playback_pcm_prepare
Linus Torvalds1da177e2005-04-16 15:20:36 -07002789 },
2790};
2791
2792static struct hda_pcm_stream alc880_pcm_digital_capture = {
2793 .substreams = 1,
2794 .channels_min = 2,
2795 .channels_max = 2,
2796 /* NID is set in alc_build_pcms */
2797};
2798
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01002799/* Used by alc_build_pcms to flag that a PCM has no playback stream */
Takashi Iwai63300792008-01-24 15:31:36 +01002800static struct hda_pcm_stream alc_pcm_null_stream = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01002801 .substreams = 0,
2802 .channels_min = 0,
2803 .channels_max = 0,
2804};
2805
Linus Torvalds1da177e2005-04-16 15:20:36 -07002806static int alc_build_pcms(struct hda_codec *codec)
2807{
2808 struct alc_spec *spec = codec->spec;
2809 struct hda_pcm *info = spec->pcm_rec;
2810 int i;
2811
2812 codec->num_pcms = 1;
2813 codec->pcm_info = info;
2814
2815 info->name = spec->stream_name_analog;
Takashi Iwai4a471b72005-12-07 13:56:29 +01002816 if (spec->stream_analog_playback) {
Takashi Iwaida3cec32008-08-08 17:12:14 +02002817 if (snd_BUG_ON(!spec->multiout.dac_nids))
2818 return -EINVAL;
Takashi Iwai4a471b72005-12-07 13:56:29 +01002819 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
2820 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
2821 }
2822 if (spec->stream_analog_capture) {
Takashi Iwaida3cec32008-08-08 17:12:14 +02002823 if (snd_BUG_ON(!spec->adc_nids))
2824 return -EINVAL;
Takashi Iwai4a471b72005-12-07 13:56:29 +01002825 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
2826 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
2827 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002828
Takashi Iwai4a471b72005-12-07 13:56:29 +01002829 if (spec->channel_mode) {
2830 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0;
2831 for (i = 0; i < spec->num_channel_mode; i++) {
2832 if (spec->channel_mode[i].channels > info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max) {
2833 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->channel_mode[i].channels;
2834 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002835 }
2836 }
2837
Takashi Iwaie08a0072006-09-07 17:52:14 +02002838 /* SPDIF for stream index #1 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002839 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
Takashi Iwaie08a0072006-09-07 17:52:14 +02002840 codec->num_pcms = 2;
Takashi Iwaic06134d2006-10-11 18:49:13 +02002841 info = spec->pcm_rec + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002842 info->name = spec->stream_name_digital;
Takashi Iwai7ba72ba2008-02-06 14:03:20 +01002843 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Takashi Iwai4a471b72005-12-07 13:56:29 +01002844 if (spec->multiout.dig_out_nid &&
2845 spec->stream_digital_playback) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002846 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_digital_playback);
2847 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
2848 }
Takashi Iwai4a471b72005-12-07 13:56:29 +01002849 if (spec->dig_in_nid &&
2850 spec->stream_digital_capture) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002851 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_digital_capture);
2852 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
2853 }
Takashi Iwai963f8032008-08-11 10:04:40 +02002854 /* FIXME: do we need this for all Realtek codec models? */
2855 codec->spdif_status_reset = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002856 }
2857
Takashi Iwaie08a0072006-09-07 17:52:14 +02002858 /* If the use of more than one ADC is requested for the current
2859 * model, configure a second analog capture-only PCM.
2860 */
2861 /* Additional Analaog capture for index #2 */
Takashi Iwai63300792008-01-24 15:31:36 +01002862 if ((spec->alt_dac_nid && spec->stream_analog_alt_playback) ||
2863 (spec->num_adc_nids > 1 && spec->stream_analog_alt_capture)) {
Takashi Iwaie08a0072006-09-07 17:52:14 +02002864 codec->num_pcms = 3;
Takashi Iwaic06134d2006-10-11 18:49:13 +02002865 info = spec->pcm_rec + 2;
Takashi Iwaie08a0072006-09-07 17:52:14 +02002866 info->name = spec->stream_name_analog;
Takashi Iwai63300792008-01-24 15:31:36 +01002867 if (spec->alt_dac_nid) {
2868 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
2869 *spec->stream_analog_alt_playback;
2870 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
2871 spec->alt_dac_nid;
2872 } else {
2873 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
2874 alc_pcm_null_stream;
2875 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
2876 }
2877 if (spec->num_adc_nids > 1) {
2878 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
2879 *spec->stream_analog_alt_capture;
2880 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
2881 spec->adc_nids[1];
2882 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams =
2883 spec->num_adc_nids - 1;
2884 } else {
2885 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
2886 alc_pcm_null_stream;
2887 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0;
Takashi Iwaie08a0072006-09-07 17:52:14 +02002888 }
2889 }
2890
Linus Torvalds1da177e2005-04-16 15:20:36 -07002891 return 0;
2892}
2893
Takashi Iwai603c4012008-07-30 15:01:44 +02002894static void alc_free_kctls(struct hda_codec *codec)
2895{
2896 struct alc_spec *spec = codec->spec;
2897
2898 if (spec->kctls.list) {
2899 struct snd_kcontrol_new *kctl = spec->kctls.list;
2900 int i;
2901 for (i = 0; i < spec->kctls.used; i++)
2902 kfree(kctl[i].name);
2903 }
2904 snd_array_free(&spec->kctls);
2905}
2906
Linus Torvalds1da177e2005-04-16 15:20:36 -07002907static void alc_free(struct hda_codec *codec)
2908{
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002909 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002910
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002911 if (!spec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002912 return;
2913
Takashi Iwai603c4012008-07-30 15:01:44 +02002914 alc_free_kctls(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002915 kfree(spec);
Takashi Iwai7943a8a2008-04-16 17:29:09 +02002916 codec->spec = NULL; /* to be sure */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002917}
2918
Takashi Iwaie044c392008-10-27 16:56:24 +01002919#ifdef SND_HDA_NEEDS_RESUME
2920static void store_pin_configs(struct hda_codec *codec)
2921{
2922 struct alc_spec *spec = codec->spec;
2923 hda_nid_t nid, end_nid;
2924
2925 end_nid = codec->start_nid + codec->num_nodes;
2926 for (nid = codec->start_nid; nid < end_nid; nid++) {
2927 unsigned int wid_caps = get_wcaps(codec, nid);
2928 unsigned int wid_type =
2929 (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
2930 if (wid_type != AC_WID_PIN)
2931 continue;
2932 if (spec->num_pins >= ARRAY_SIZE(spec->pin_nids))
2933 break;
2934 spec->pin_nids[spec->num_pins] = nid;
2935 spec->pin_cfgs[spec->num_pins] =
2936 snd_hda_codec_read(codec, nid, 0,
2937 AC_VERB_GET_CONFIG_DEFAULT, 0);
2938 spec->num_pins++;
2939 }
2940}
2941
2942static void resume_pin_configs(struct hda_codec *codec)
2943{
2944 struct alc_spec *spec = codec->spec;
2945 int i;
2946
2947 for (i = 0; i < spec->num_pins; i++) {
2948 hda_nid_t pin_nid = spec->pin_nids[i];
2949 unsigned int pin_config = spec->pin_cfgs[i];
2950 snd_hda_codec_write(codec, pin_nid, 0,
2951 AC_VERB_SET_CONFIG_DEFAULT_BYTES_0,
2952 pin_config & 0x000000ff);
2953 snd_hda_codec_write(codec, pin_nid, 0,
2954 AC_VERB_SET_CONFIG_DEFAULT_BYTES_1,
2955 (pin_config & 0x0000ff00) >> 8);
2956 snd_hda_codec_write(codec, pin_nid, 0,
2957 AC_VERB_SET_CONFIG_DEFAULT_BYTES_2,
2958 (pin_config & 0x00ff0000) >> 16);
2959 snd_hda_codec_write(codec, pin_nid, 0,
2960 AC_VERB_SET_CONFIG_DEFAULT_BYTES_3,
2961 pin_config >> 24);
2962 }
2963}
2964
2965static int alc_resume(struct hda_codec *codec)
2966{
2967 resume_pin_configs(codec);
2968 codec->patch_ops.init(codec);
2969 snd_hda_codec_resume_amp(codec);
2970 snd_hda_codec_resume_cache(codec);
2971 return 0;
2972}
2973#else
2974#define store_pin_configs(codec)
2975#endif
2976
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977/*
2978 */
2979static struct hda_codec_ops alc_patch_ops = {
2980 .build_controls = alc_build_controls,
2981 .build_pcms = alc_build_pcms,
2982 .init = alc_init,
2983 .free = alc_free,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002984 .unsol_event = alc_unsol_event,
Takashi Iwaie044c392008-10-27 16:56:24 +01002985#ifdef SND_HDA_NEEDS_RESUME
2986 .resume = alc_resume,
2987#endif
Takashi Iwaicb53c622007-08-10 17:21:45 +02002988#ifdef CONFIG_SND_HDA_POWER_SAVE
2989 .check_power_status = alc_check_power_status,
2990#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002991};
2992
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002993
2994/*
2995 * Test configuration for debugging
2996 *
2997 * Almost all inputs/outputs are enabled. I/O pins can be configured via
2998 * enum controls.
2999 */
3000#ifdef CONFIG_SND_DEBUG
3001static hda_nid_t alc880_test_dac_nids[4] = {
3002 0x02, 0x03, 0x04, 0x05
3003};
3004
3005static struct hda_input_mux alc880_test_capture_source = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003006 .num_items = 7,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003007 .items = {
3008 { "In-1", 0x0 },
3009 { "In-2", 0x1 },
3010 { "In-3", 0x2 },
3011 { "In-4", 0x3 },
3012 { "CD", 0x4 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003013 { "Front", 0x5 },
3014 { "Surround", 0x6 },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003015 },
3016};
3017
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01003018static struct hda_channel_mode alc880_test_modes[4] = {
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003019 { 2, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02003020 { 4, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003021 { 6, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02003022 { 8, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003023};
3024
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003025static int alc_test_pin_ctl_info(struct snd_kcontrol *kcontrol,
3026 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003027{
3028 static char *texts[] = {
3029 "N/A", "Line Out", "HP Out",
3030 "In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%"
3031 };
3032 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
3033 uinfo->count = 1;
3034 uinfo->value.enumerated.items = 8;
3035 if (uinfo->value.enumerated.item >= 8)
3036 uinfo->value.enumerated.item = 7;
3037 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
3038 return 0;
3039}
3040
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003041static int alc_test_pin_ctl_get(struct snd_kcontrol *kcontrol,
3042 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003043{
3044 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3045 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
3046 unsigned int pin_ctl, item = 0;
3047
3048 pin_ctl = snd_hda_codec_read(codec, nid, 0,
3049 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
3050 if (pin_ctl & AC_PINCTL_OUT_EN) {
3051 if (pin_ctl & AC_PINCTL_HP_EN)
3052 item = 2;
3053 else
3054 item = 1;
3055 } else if (pin_ctl & AC_PINCTL_IN_EN) {
3056 switch (pin_ctl & AC_PINCTL_VREFEN) {
3057 case AC_PINCTL_VREF_HIZ: item = 3; break;
3058 case AC_PINCTL_VREF_50: item = 4; break;
3059 case AC_PINCTL_VREF_GRD: item = 5; break;
3060 case AC_PINCTL_VREF_80: item = 6; break;
3061 case AC_PINCTL_VREF_100: item = 7; break;
3062 }
3063 }
3064 ucontrol->value.enumerated.item[0] = item;
3065 return 0;
3066}
3067
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003068static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol,
3069 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003070{
3071 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3072 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
3073 static unsigned int ctls[] = {
3074 0, AC_PINCTL_OUT_EN, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN,
3075 AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ,
3076 AC_PINCTL_IN_EN | AC_PINCTL_VREF_50,
3077 AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD,
3078 AC_PINCTL_IN_EN | AC_PINCTL_VREF_80,
3079 AC_PINCTL_IN_EN | AC_PINCTL_VREF_100,
3080 };
3081 unsigned int old_ctl, new_ctl;
3082
3083 old_ctl = snd_hda_codec_read(codec, nid, 0,
3084 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
3085 new_ctl = ctls[ucontrol->value.enumerated.item[0]];
3086 if (old_ctl != new_ctl) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003087 int val;
3088 snd_hda_codec_write_cache(codec, nid, 0,
3089 AC_VERB_SET_PIN_WIDGET_CONTROL,
3090 new_ctl);
Takashi Iwai47fd8302007-08-10 17:11:07 +02003091 val = ucontrol->value.enumerated.item[0] >= 3 ?
3092 HDA_AMP_MUTE : 0;
3093 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
3094 HDA_AMP_MUTE, val);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003095 return 1;
3096 }
3097 return 0;
3098}
3099
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003100static int alc_test_pin_src_info(struct snd_kcontrol *kcontrol,
3101 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003102{
3103 static char *texts[] = {
3104 "Front", "Surround", "CLFE", "Side"
3105 };
3106 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
3107 uinfo->count = 1;
3108 uinfo->value.enumerated.items = 4;
3109 if (uinfo->value.enumerated.item >= 4)
3110 uinfo->value.enumerated.item = 3;
3111 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
3112 return 0;
3113}
3114
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003115static int alc_test_pin_src_get(struct snd_kcontrol *kcontrol,
3116 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003117{
3118 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3119 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
3120 unsigned int sel;
3121
3122 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0);
3123 ucontrol->value.enumerated.item[0] = sel & 3;
3124 return 0;
3125}
3126
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003127static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol,
3128 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003129{
3130 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3131 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
3132 unsigned int sel;
3133
3134 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3;
3135 if (ucontrol->value.enumerated.item[0] != sel) {
3136 sel = ucontrol->value.enumerated.item[0] & 3;
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003137 snd_hda_codec_write_cache(codec, nid, 0,
3138 AC_VERB_SET_CONNECT_SEL, sel);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003139 return 1;
3140 }
3141 return 0;
3142}
3143
3144#define PIN_CTL_TEST(xname,nid) { \
3145 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
3146 .name = xname, \
3147 .info = alc_test_pin_ctl_info, \
3148 .get = alc_test_pin_ctl_get, \
3149 .put = alc_test_pin_ctl_put, \
3150 .private_value = nid \
3151 }
3152
3153#define PIN_SRC_TEST(xname,nid) { \
3154 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
3155 .name = xname, \
3156 .info = alc_test_pin_src_info, \
3157 .get = alc_test_pin_src_get, \
3158 .put = alc_test_pin_src_put, \
3159 .private_value = nid \
3160 }
3161
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003162static struct snd_kcontrol_new alc880_test_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02003163 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3164 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
3165 HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
3166 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003167 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
3168 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
3169 HDA_BIND_MUTE("CLFE Playback Switch", 0x0e, 2, HDA_INPUT),
3170 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003171 PIN_CTL_TEST("Front Pin Mode", 0x14),
3172 PIN_CTL_TEST("Surround Pin Mode", 0x15),
3173 PIN_CTL_TEST("CLFE Pin Mode", 0x16),
3174 PIN_CTL_TEST("Side Pin Mode", 0x17),
3175 PIN_CTL_TEST("In-1 Pin Mode", 0x18),
3176 PIN_CTL_TEST("In-2 Pin Mode", 0x19),
3177 PIN_CTL_TEST("In-3 Pin Mode", 0x1a),
3178 PIN_CTL_TEST("In-4 Pin Mode", 0x1b),
3179 PIN_SRC_TEST("In-1 Pin Source", 0x18),
3180 PIN_SRC_TEST("In-2 Pin Source", 0x19),
3181 PIN_SRC_TEST("In-3 Pin Source", 0x1a),
3182 PIN_SRC_TEST("In-4 Pin Source", 0x1b),
3183 HDA_CODEC_VOLUME("In-1 Playback Volume", 0x0b, 0x0, HDA_INPUT),
3184 HDA_CODEC_MUTE("In-1 Playback Switch", 0x0b, 0x0, HDA_INPUT),
3185 HDA_CODEC_VOLUME("In-2 Playback Volume", 0x0b, 0x1, HDA_INPUT),
3186 HDA_CODEC_MUTE("In-2 Playback Switch", 0x0b, 0x1, HDA_INPUT),
3187 HDA_CODEC_VOLUME("In-3 Playback Volume", 0x0b, 0x2, HDA_INPUT),
3188 HDA_CODEC_MUTE("In-3 Playback Switch", 0x0b, 0x2, HDA_INPUT),
3189 HDA_CODEC_VOLUME("In-4 Playback Volume", 0x0b, 0x3, HDA_INPUT),
3190 HDA_CODEC_MUTE("In-4 Playback Switch", 0x0b, 0x3, HDA_INPUT),
3191 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x4, HDA_INPUT),
3192 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x4, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003193 {
3194 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3195 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01003196 .info = alc_ch_mode_info,
3197 .get = alc_ch_mode_get,
3198 .put = alc_ch_mode_put,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003199 },
3200 { } /* end */
3201};
3202
3203static struct hda_verb alc880_test_init_verbs[] = {
3204 /* Unmute inputs of 0x0c - 0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02003205 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3206 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3207 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3208 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3209 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3210 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3211 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3212 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003213 /* Vol output for 0x0c-0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02003214 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3215 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3216 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3217 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003218 /* Set output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02003219 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3220 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3221 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3222 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003223 /* Unmute output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02003224 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3225 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3226 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3227 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003228 /* Set input pins 0x18-0x1c */
Takashi Iwai16ded522005-06-10 19:58:24 +02003229 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3230 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwai05acb862005-06-10 19:50:25 +02003231 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3232 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3233 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003234 /* Mute input pins 0x18-0x1b */
Takashi Iwai05acb862005-06-10 19:50:25 +02003235 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3236 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3237 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3238 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003239 /* ADC set up */
Takashi Iwai05acb862005-06-10 19:50:25 +02003240 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003241 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02003242 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003243 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02003244 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003245 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02003246 /* Analog input/passthru */
3247 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3248 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
3249 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
3250 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
3251 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003252 { }
3253};
3254#endif
3255
Linus Torvalds1da177e2005-04-16 15:20:36 -07003256/*
3257 */
3258
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003259static const char *alc880_models[ALC880_MODEL_LAST] = {
3260 [ALC880_3ST] = "3stack",
3261 [ALC880_TCL_S700] = "tcl",
3262 [ALC880_3ST_DIG] = "3stack-digout",
3263 [ALC880_CLEVO] = "clevo",
3264 [ALC880_5ST] = "5stack",
3265 [ALC880_5ST_DIG] = "5stack-digout",
3266 [ALC880_W810] = "w810",
3267 [ALC880_Z71V] = "z71v",
3268 [ALC880_6ST] = "6stack",
3269 [ALC880_6ST_DIG] = "6stack-digout",
3270 [ALC880_ASUS] = "asus",
3271 [ALC880_ASUS_W1V] = "asus-w1v",
3272 [ALC880_ASUS_DIG] = "asus-dig",
3273 [ALC880_ASUS_DIG2] = "asus-dig2",
3274 [ALC880_UNIWILL_DIG] = "uniwill",
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003275 [ALC880_UNIWILL_P53] = "uniwill-p53",
3276 [ALC880_FUJITSU] = "fujitsu",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003277 [ALC880_F1734] = "F1734",
3278 [ALC880_LG] = "lg",
3279 [ALC880_LG_LW] = "lg-lw",
Takashi Iwaidf99cd32008-04-25 15:25:04 +02003280 [ALC880_MEDION_RIM] = "medion",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003281#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003282 [ALC880_TEST] = "test",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003283#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003284 [ALC880_AUTO] = "auto",
3285};
3286
3287static struct snd_pci_quirk alc880_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003288 SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003289 SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG),
3290 SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST),
3291 SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_3ST_DIG),
3292 SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_6ST_DIG),
3293 SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_6ST_DIG),
3294 SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_6ST_DIG),
3295 SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_3ST_DIG),
3296 SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003297 SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_6ST_DIG),
3298 SND_PCI_QUIRK(0x103c, 0x2a09, "HP", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003299 SND_PCI_QUIRK(0x1043, 0x10b3, "ASUS W1V", ALC880_ASUS_W1V),
3300 SND_PCI_QUIRK(0x1043, 0x10c2, "ASUS W6A", ALC880_ASUS_DIG),
3301 SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS Wxx", ALC880_ASUS_DIG),
3302 SND_PCI_QUIRK(0x1043, 0x1113, "ASUS", ALC880_ASUS_DIG),
3303 SND_PCI_QUIRK(0x1043, 0x1123, "ASUS", ALC880_ASUS_DIG),
3304 SND_PCI_QUIRK(0x1043, 0x1173, "ASUS", ALC880_ASUS_DIG),
3305 SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_Z71V),
3306 /* SND_PCI_QUIRK(0x1043, 0x1964, "ASUS", ALC880_ASUS_DIG), */
3307 SND_PCI_QUIRK(0x1043, 0x1973, "ASUS", ALC880_ASUS_DIG),
3308 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS", ALC880_ASUS_DIG),
Travis Place186c3112008-05-20 11:54:41 +02003309 SND_PCI_QUIRK(0x1043, 0x814e, "ASUS P5GD1 w/SPDIF", ALC880_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003310 SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG),
3311 SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST),
3312 SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003313 SND_PCI_QUIRK(0x1043, 0, "ASUS", ALC880_ASUS), /* default ASUS */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003314 SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003315 SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST),
3316 SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003317 SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_5ST),
3318 SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003319 SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_6ST_DIG),
3320 SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_6ST_DIG),
3321 SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_6ST_DIG),
3322 SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003323 SND_PCI_QUIRK(0x1558, 0x0520, "Clevo m520G", ALC880_CLEVO),
3324 SND_PCI_QUIRK(0x1558, 0x0660, "Clevo m655n", ALC880_CLEVO),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003325 SND_PCI_QUIRK(0x1558, 0x5401, "ASUS", ALC880_ASUS_DIG2),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003326 SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003327 SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_UNIWILL_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003328 SND_PCI_QUIRK(0x1584, 0x9054, "Uniwlll", ALC880_F1734),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003329 SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL),
3330 SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003331 SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810),
Takashi Iwaidf99cd32008-04-25 15:25:04 +02003332 SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_MEDION_RIM),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003333 SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003334 SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003335 SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734),
Travis Place1d116042008-06-23 11:42:30 +02003336 SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FUJITSU),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003337 SND_PCI_QUIRK(0x1734, 0x10ac, "FSC", ALC880_UNIWILL),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003338 SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003339 SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003340 SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG),
3341 SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003342 SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003343 SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700),
3344 SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG), /* broken BIOS */
3345 SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG),
3346 SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003347 SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_5ST_DIG),
3348 SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003349 SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003350 SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003351 SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_3ST_DIG),
3352 SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003353 SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_5ST_DIG),
3354 SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_5ST_DIG),
3355 SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003356 SND_PCI_QUIRK(0x8086, 0, "Intel mobo", ALC880_3ST), /* default Intel */
3357 SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG),
3358 SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003359 {}
3360};
3361
Takashi Iwai16ded522005-06-10 19:58:24 +02003362/*
Kailang Yangdf694da2005-12-05 19:42:22 +01003363 * ALC880 codec presets
Takashi Iwai16ded522005-06-10 19:58:24 +02003364 */
Takashi Iwai16ded522005-06-10 19:58:24 +02003365static struct alc_config_preset alc880_presets[] = {
3366 [ALC880_3ST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003367 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003368 .init_verbs = { alc880_volume_init_verbs,
3369 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003370 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02003371 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003372 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
3373 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003374 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003375 .input_mux = &alc880_capture_source,
3376 },
3377 [ALC880_3ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003378 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003379 .init_verbs = { alc880_volume_init_verbs,
3380 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003381 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02003382 .dac_nids = alc880_dac_nids,
3383 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003384 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
3385 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003386 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003387 .input_mux = &alc880_capture_source,
3388 },
Kailang Yangdf694da2005-12-05 19:42:22 +01003389 [ALC880_TCL_S700] = {
3390 .mixers = { alc880_tcl_s700_mixer },
3391 .init_verbs = { alc880_volume_init_verbs,
3392 alc880_pin_tcl_S700_init_verbs,
3393 alc880_gpio2_init_verbs },
3394 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3395 .dac_nids = alc880_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01003396 .adc_nids = alc880_adc_nids_alt, /* FIXME: correct? */
3397 .num_adc_nids = 1, /* single ADC */
Kailang Yangdf694da2005-12-05 19:42:22 +01003398 .hp_nid = 0x03,
3399 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3400 .channel_mode = alc880_2_jack_modes,
3401 .input_mux = &alc880_capture_source,
3402 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003403 [ALC880_5ST] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003404 .mixers = { alc880_three_stack_mixer,
3405 alc880_five_stack_mixer},
3406 .init_verbs = { alc880_volume_init_verbs,
3407 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003408 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3409 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003410 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
3411 .channel_mode = alc880_fivestack_modes,
3412 .input_mux = &alc880_capture_source,
3413 },
3414 [ALC880_5ST_DIG] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003415 .mixers = { alc880_three_stack_mixer,
3416 alc880_five_stack_mixer },
3417 .init_verbs = { alc880_volume_init_verbs,
3418 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003419 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3420 .dac_nids = alc880_dac_nids,
3421 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003422 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
3423 .channel_mode = alc880_fivestack_modes,
3424 .input_mux = &alc880_capture_source,
3425 },
Takashi Iwaib6482d42005-06-27 15:32:43 +02003426 [ALC880_6ST] = {
3427 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003428 .init_verbs = { alc880_volume_init_verbs,
3429 alc880_pin_6stack_init_verbs },
Takashi Iwaib6482d42005-06-27 15:32:43 +02003430 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
3431 .dac_nids = alc880_6st_dac_nids,
3432 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
3433 .channel_mode = alc880_sixstack_modes,
3434 .input_mux = &alc880_6stack_capture_source,
3435 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003436 [ALC880_6ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003437 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003438 .init_verbs = { alc880_volume_init_verbs,
3439 alc880_pin_6stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003440 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
3441 .dac_nids = alc880_6st_dac_nids,
3442 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003443 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
3444 .channel_mode = alc880_sixstack_modes,
3445 .input_mux = &alc880_6stack_capture_source,
3446 },
3447 [ALC880_W810] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003448 .mixers = { alc880_w810_base_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003449 .init_verbs = { alc880_volume_init_verbs,
3450 alc880_pin_w810_init_verbs,
Takashi Iwaib0af0de2005-06-21 14:49:19 +02003451 alc880_gpio2_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003452 .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids),
3453 .dac_nids = alc880_w810_dac_nids,
3454 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003455 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
3456 .channel_mode = alc880_w810_modes,
3457 .input_mux = &alc880_capture_source,
3458 },
3459 [ALC880_Z71V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003460 .mixers = { alc880_z71v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003461 .init_verbs = { alc880_volume_init_verbs,
3462 alc880_pin_z71v_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003463 .num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids),
3464 .dac_nids = alc880_z71v_dac_nids,
3465 .dig_out_nid = ALC880_DIGOUT_NID,
3466 .hp_nid = 0x03,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003467 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3468 .channel_mode = alc880_2_jack_modes,
Takashi Iwai16ded522005-06-10 19:58:24 +02003469 .input_mux = &alc880_capture_source,
3470 },
3471 [ALC880_F1734] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003472 .mixers = { alc880_f1734_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003473 .init_verbs = { alc880_volume_init_verbs,
3474 alc880_pin_f1734_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003475 .num_dacs = ARRAY_SIZE(alc880_f1734_dac_nids),
3476 .dac_nids = alc880_f1734_dac_nids,
3477 .hp_nid = 0x02,
3478 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3479 .channel_mode = alc880_2_jack_modes,
Takashi Iwai937b4162008-02-11 14:52:36 +01003480 .input_mux = &alc880_f1734_capture_source,
3481 .unsol_event = alc880_uniwill_p53_unsol_event,
3482 .init_hook = alc880_uniwill_p53_hp_automute,
Takashi Iwai16ded522005-06-10 19:58:24 +02003483 },
3484 [ALC880_ASUS] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003485 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003486 .init_verbs = { alc880_volume_init_verbs,
3487 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003488 alc880_gpio1_init_verbs },
3489 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3490 .dac_nids = alc880_asus_dac_nids,
3491 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3492 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003493 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003494 .input_mux = &alc880_capture_source,
3495 },
3496 [ALC880_ASUS_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003497 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003498 .init_verbs = { alc880_volume_init_verbs,
3499 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003500 alc880_gpio1_init_verbs },
3501 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3502 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003503 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003504 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3505 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003506 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003507 .input_mux = &alc880_capture_source,
3508 },
Kailang Yangdf694da2005-12-05 19:42:22 +01003509 [ALC880_ASUS_DIG2] = {
3510 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003511 .init_verbs = { alc880_volume_init_verbs,
3512 alc880_pin_asus_init_verbs,
Kailang Yangdf694da2005-12-05 19:42:22 +01003513 alc880_gpio2_init_verbs }, /* use GPIO2 */
3514 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3515 .dac_nids = alc880_asus_dac_nids,
3516 .dig_out_nid = ALC880_DIGOUT_NID,
3517 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3518 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003519 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01003520 .input_mux = &alc880_capture_source,
3521 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003522 [ALC880_ASUS_W1V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003523 .mixers = { alc880_asus_mixer, alc880_asus_w1v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003524 .init_verbs = { alc880_volume_init_verbs,
3525 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003526 alc880_gpio1_init_verbs },
3527 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3528 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003529 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003530 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3531 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003532 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003533 .input_mux = &alc880_capture_source,
3534 },
3535 [ALC880_UNIWILL_DIG] = {
Takashi Iwai3c10a9d2005-08-23 20:02:27 +02003536 .mixers = { alc880_asus_mixer, alc880_pcbeep_mixer },
Kailang Yangccc656c2006-10-17 12:32:26 +02003537 .init_verbs = { alc880_volume_init_verbs,
3538 alc880_pin_asus_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003539 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3540 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003541 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003542 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3543 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003544 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003545 .input_mux = &alc880_capture_source,
3546 },
Kailang Yangccc656c2006-10-17 12:32:26 +02003547 [ALC880_UNIWILL] = {
3548 .mixers = { alc880_uniwill_mixer },
3549 .init_verbs = { alc880_volume_init_verbs,
3550 alc880_uniwill_init_verbs },
3551 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3552 .dac_nids = alc880_asus_dac_nids,
3553 .dig_out_nid = ALC880_DIGOUT_NID,
3554 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
3555 .channel_mode = alc880_threestack_modes,
3556 .need_dac_fix = 1,
3557 .input_mux = &alc880_capture_source,
3558 .unsol_event = alc880_uniwill_unsol_event,
3559 .init_hook = alc880_uniwill_automute,
3560 },
3561 [ALC880_UNIWILL_P53] = {
3562 .mixers = { alc880_uniwill_p53_mixer },
3563 .init_verbs = { alc880_volume_init_verbs,
3564 alc880_uniwill_p53_init_verbs },
3565 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3566 .dac_nids = alc880_asus_dac_nids,
3567 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003568 .channel_mode = alc880_threestack_modes,
3569 .input_mux = &alc880_capture_source,
3570 .unsol_event = alc880_uniwill_p53_unsol_event,
3571 .init_hook = alc880_uniwill_p53_hp_automute,
3572 },
3573 [ALC880_FUJITSU] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003574 .mixers = { alc880_fujitsu_mixer,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003575 alc880_pcbeep_mixer, },
3576 .init_verbs = { alc880_volume_init_verbs,
3577 alc880_uniwill_p53_init_verbs,
3578 alc880_beep_init_verbs },
3579 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3580 .dac_nids = alc880_dac_nids,
Takashi Iwaid53d7d92007-08-20 15:20:02 +02003581 .dig_out_nid = ALC880_DIGOUT_NID,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003582 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3583 .channel_mode = alc880_2_jack_modes,
Kailang Yangccc656c2006-10-17 12:32:26 +02003584 .input_mux = &alc880_capture_source,
3585 .unsol_event = alc880_uniwill_p53_unsol_event,
3586 .init_hook = alc880_uniwill_p53_hp_automute,
3587 },
Kailang Yangdf694da2005-12-05 19:42:22 +01003588 [ALC880_CLEVO] = {
3589 .mixers = { alc880_three_stack_mixer },
3590 .init_verbs = { alc880_volume_init_verbs,
3591 alc880_pin_clevo_init_verbs },
3592 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3593 .dac_nids = alc880_dac_nids,
3594 .hp_nid = 0x03,
3595 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
3596 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003597 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01003598 .input_mux = &alc880_capture_source,
3599 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003600 [ALC880_LG] = {
3601 .mixers = { alc880_lg_mixer },
3602 .init_verbs = { alc880_volume_init_verbs,
3603 alc880_lg_init_verbs },
3604 .num_dacs = ARRAY_SIZE(alc880_lg_dac_nids),
3605 .dac_nids = alc880_lg_dac_nids,
3606 .dig_out_nid = ALC880_DIGOUT_NID,
3607 .num_channel_mode = ARRAY_SIZE(alc880_lg_ch_modes),
3608 .channel_mode = alc880_lg_ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003609 .need_dac_fix = 1,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003610 .input_mux = &alc880_lg_capture_source,
3611 .unsol_event = alc880_lg_unsol_event,
3612 .init_hook = alc880_lg_automute,
Takashi Iwaicb53c622007-08-10 17:21:45 +02003613#ifdef CONFIG_SND_HDA_POWER_SAVE
3614 .loopbacks = alc880_lg_loopbacks,
3615#endif
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003616 },
Takashi Iwaid6815182006-03-23 16:06:23 +01003617 [ALC880_LG_LW] = {
3618 .mixers = { alc880_lg_lw_mixer },
3619 .init_verbs = { alc880_volume_init_verbs,
3620 alc880_lg_lw_init_verbs },
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003621 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwaid6815182006-03-23 16:06:23 +01003622 .dac_nids = alc880_dac_nids,
3623 .dig_out_nid = ALC880_DIGOUT_NID,
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003624 .num_channel_mode = ARRAY_SIZE(alc880_lg_lw_modes),
3625 .channel_mode = alc880_lg_lw_modes,
Takashi Iwaid6815182006-03-23 16:06:23 +01003626 .input_mux = &alc880_lg_lw_capture_source,
3627 .unsol_event = alc880_lg_lw_unsol_event,
3628 .init_hook = alc880_lg_lw_automute,
3629 },
Takashi Iwaidf99cd32008-04-25 15:25:04 +02003630 [ALC880_MEDION_RIM] = {
3631 .mixers = { alc880_medion_rim_mixer },
3632 .init_verbs = { alc880_volume_init_verbs,
3633 alc880_medion_rim_init_verbs,
3634 alc_gpio2_init_verbs },
3635 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3636 .dac_nids = alc880_dac_nids,
3637 .dig_out_nid = ALC880_DIGOUT_NID,
3638 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3639 .channel_mode = alc880_2_jack_modes,
3640 .input_mux = &alc880_medion_rim_capture_source,
3641 .unsol_event = alc880_medion_rim_unsol_event,
3642 .init_hook = alc880_medion_rim_automute,
3643 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003644#ifdef CONFIG_SND_DEBUG
3645 [ALC880_TEST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003646 .mixers = { alc880_test_mixer },
3647 .init_verbs = { alc880_test_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003648 .num_dacs = ARRAY_SIZE(alc880_test_dac_nids),
3649 .dac_nids = alc880_test_dac_nids,
3650 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003651 .num_channel_mode = ARRAY_SIZE(alc880_test_modes),
3652 .channel_mode = alc880_test_modes,
3653 .input_mux = &alc880_test_capture_source,
3654 },
3655#endif
3656};
3657
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003658/*
3659 * Automatic parse of I/O pins from the BIOS configuration
3660 */
3661
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003662enum {
3663 ALC_CTL_WIDGET_VOL,
3664 ALC_CTL_WIDGET_MUTE,
3665 ALC_CTL_BIND_MUTE,
3666};
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003667static struct snd_kcontrol_new alc880_control_templates[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003668 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
3669 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Takashi Iwai985be542005-11-02 18:26:49 +01003670 HDA_BIND_MUTE(NULL, 0, 0, 0),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003671};
3672
3673/* add dynamic controls */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003674static int add_control(struct alc_spec *spec, int type, const char *name,
3675 unsigned long val)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003676{
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003677 struct snd_kcontrol_new *knew;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003678
Takashi Iwai603c4012008-07-30 15:01:44 +02003679 snd_array_init(&spec->kctls, sizeof(*knew), 32);
3680 knew = snd_array_new(&spec->kctls);
3681 if (!knew)
3682 return -ENOMEM;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003683 *knew = alc880_control_templates[type];
Paulo Marques543537b2005-06-23 00:09:02 -07003684 knew->name = kstrdup(name, GFP_KERNEL);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003685 if (!knew->name)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003686 return -ENOMEM;
3687 knew->private_value = val;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003688 return 0;
3689}
3690
3691#define alc880_is_fixed_pin(nid) ((nid) >= 0x14 && (nid) <= 0x17)
3692#define alc880_fixed_pin_idx(nid) ((nid) - 0x14)
3693#define alc880_is_multi_pin(nid) ((nid) >= 0x18)
3694#define alc880_multi_pin_idx(nid) ((nid) - 0x18)
3695#define alc880_is_input_pin(nid) ((nid) >= 0x18)
3696#define alc880_input_pin_idx(nid) ((nid) - 0x18)
3697#define alc880_idx_to_dac(nid) ((nid) + 0x02)
3698#define alc880_dac_to_idx(nid) ((nid) - 0x02)
3699#define alc880_idx_to_mixer(nid) ((nid) + 0x0c)
3700#define alc880_idx_to_selector(nid) ((nid) + 0x10)
3701#define ALC880_PIN_CD_NID 0x1c
3702
3703/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003704static int alc880_auto_fill_dac_nids(struct alc_spec *spec,
3705 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003706{
3707 hda_nid_t nid;
3708 int assigned[4];
3709 int i, j;
3710
3711 memset(assigned, 0, sizeof(assigned));
Takashi Iwaib0af0de2005-06-21 14:49:19 +02003712 spec->multiout.dac_nids = spec->private_dac_nids;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003713
3714 /* check the pins hardwired to audio widget */
3715 for (i = 0; i < cfg->line_outs; i++) {
3716 nid = cfg->line_out_pins[i];
3717 if (alc880_is_fixed_pin(nid)) {
3718 int idx = alc880_fixed_pin_idx(nid);
Libin Yang5014f192005-11-23 15:48:36 +01003719 spec->multiout.dac_nids[i] = alc880_idx_to_dac(idx);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003720 assigned[idx] = 1;
3721 }
3722 }
3723 /* left pins can be connect to any audio widget */
3724 for (i = 0; i < cfg->line_outs; i++) {
3725 nid = cfg->line_out_pins[i];
3726 if (alc880_is_fixed_pin(nid))
3727 continue;
3728 /* search for an empty channel */
3729 for (j = 0; j < cfg->line_outs; j++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003730 if (!assigned[j]) {
3731 spec->multiout.dac_nids[i] =
3732 alc880_idx_to_dac(j);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003733 assigned[j] = 1;
3734 break;
3735 }
3736 }
3737 }
3738 spec->multiout.num_dacs = cfg->line_outs;
3739 return 0;
3740}
3741
3742/* add playback controls from the parsed DAC table */
Kailang Yangdf694da2005-12-05 19:42:22 +01003743static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
3744 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003745{
3746 char name[32];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003747 static const char *chname[4] = {
3748 "Front", "Surround", NULL /*CLFE*/, "Side"
3749 };
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003750 hda_nid_t nid;
3751 int i, err;
3752
3753 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003754 if (!spec->multiout.dac_nids[i])
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003755 continue;
3756 nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i]));
3757 if (i == 2) {
3758 /* Center/LFE */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003759 err = add_control(spec, ALC_CTL_WIDGET_VOL,
3760 "Center Playback Volume",
3761 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
3762 HDA_OUTPUT));
3763 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003764 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003765 err = add_control(spec, ALC_CTL_WIDGET_VOL,
3766 "LFE Playback Volume",
3767 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
3768 HDA_OUTPUT));
3769 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003770 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003771 err = add_control(spec, ALC_CTL_BIND_MUTE,
3772 "Center Playback Switch",
3773 HDA_COMPOSE_AMP_VAL(nid, 1, 2,
3774 HDA_INPUT));
3775 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003776 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003777 err = add_control(spec, ALC_CTL_BIND_MUTE,
3778 "LFE Playback Switch",
3779 HDA_COMPOSE_AMP_VAL(nid, 2, 2,
3780 HDA_INPUT));
3781 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003782 return err;
3783 } else {
3784 sprintf(name, "%s Playback Volume", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003785 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
3786 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
3787 HDA_OUTPUT));
3788 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003789 return err;
3790 sprintf(name, "%s Playback Switch", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003791 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
3792 HDA_COMPOSE_AMP_VAL(nid, 3, 2,
3793 HDA_INPUT));
3794 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003795 return err;
3796 }
3797 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003798 return 0;
3799}
3800
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003801/* add playback controls for speaker and HP outputs */
3802static int alc880_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
3803 const char *pfx)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003804{
3805 hda_nid_t nid;
3806 int err;
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003807 char name[32];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003808
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003809 if (!pin)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003810 return 0;
3811
3812 if (alc880_is_fixed_pin(pin)) {
3813 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
Takashi Iwai82bc9552006-03-21 11:24:42 +01003814 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003815 if (!spec->multiout.hp_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003816 spec->multiout.hp_nid = nid;
Takashi Iwai82bc9552006-03-21 11:24:42 +01003817 else
3818 spec->multiout.extra_out_nid[0] = nid;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003819 /* control HP volume/switch on the output mixer amp */
3820 nid = alc880_idx_to_mixer(alc880_fixed_pin_idx(pin));
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003821 sprintf(name, "%s Playback Volume", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003822 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
3823 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
3824 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003825 return err;
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003826 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003827 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
3828 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
3829 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003830 return err;
3831 } else if (alc880_is_multi_pin(pin)) {
3832 /* set manual connection */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003833 /* we have only a switch on HP-out PIN */
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003834 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003835 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
3836 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
3837 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003838 return err;
3839 }
3840 return 0;
3841}
3842
3843/* create input playback/capture controls for the given pin */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003844static int new_analog_input(struct alc_spec *spec, hda_nid_t pin,
3845 const char *ctlname,
Kailang Yangdf694da2005-12-05 19:42:22 +01003846 int idx, hda_nid_t mix_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003847{
3848 char name[32];
Kailang Yangdf694da2005-12-05 19:42:22 +01003849 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003850
3851 sprintf(name, "%s Playback Volume", ctlname);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003852 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
3853 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
3854 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003855 return err;
3856 sprintf(name, "%s Playback Switch", ctlname);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003857 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
3858 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
3859 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003860 return err;
3861 return 0;
3862}
3863
3864/* create playback/capture controls for input pins */
Kailang Yangdf694da2005-12-05 19:42:22 +01003865static int alc880_auto_create_analog_input_ctls(struct alc_spec *spec,
3866 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003867{
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003868 struct hda_input_mux *imux = &spec->private_imux;
Kailang Yangdf694da2005-12-05 19:42:22 +01003869 int i, err, idx;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003870
3871 for (i = 0; i < AUTO_PIN_LAST; i++) {
3872 if (alc880_is_input_pin(cfg->input_pins[i])) {
Kailang Yangdf694da2005-12-05 19:42:22 +01003873 idx = alc880_input_pin_idx(cfg->input_pins[i]);
Takashi Iwai4a471b72005-12-07 13:56:29 +01003874 err = new_analog_input(spec, cfg->input_pins[i],
3875 auto_pin_cfg_labels[i],
Kailang Yangdf694da2005-12-05 19:42:22 +01003876 idx, 0x0b);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003877 if (err < 0)
3878 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003879 imux->items[imux->num_items].label =
3880 auto_pin_cfg_labels[i];
3881 imux->items[imux->num_items].index =
3882 alc880_input_pin_idx(cfg->input_pins[i]);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003883 imux->num_items++;
3884 }
3885 }
3886 return 0;
3887}
3888
Takashi Iwaif6c7e542008-02-12 18:32:23 +01003889static void alc_set_pin_output(struct hda_codec *codec, hda_nid_t nid,
3890 unsigned int pin_type)
3891{
3892 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
3893 pin_type);
3894 /* unmute pin */
Takashi Iwaid260cdf2008-02-13 17:19:35 +01003895 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
3896 AMP_OUT_UNMUTE);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01003897}
3898
Kailang Yangdf694da2005-12-05 19:42:22 +01003899static void alc880_auto_set_output_and_unmute(struct hda_codec *codec,
3900 hda_nid_t nid, int pin_type,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003901 int dac_idx)
3902{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01003903 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003904 /* need the manual connection? */
3905 if (alc880_is_multi_pin(nid)) {
3906 struct alc_spec *spec = codec->spec;
3907 int idx = alc880_multi_pin_idx(nid);
3908 snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
3909 AC_VERB_SET_CONNECT_SEL,
3910 alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
3911 }
3912}
3913
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02003914static int get_pin_type(int line_out_type)
3915{
3916 if (line_out_type == AUTO_PIN_HP_OUT)
3917 return PIN_HP;
3918 else
3919 return PIN_OUT;
3920}
3921
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003922static void alc880_auto_init_multi_out(struct hda_codec *codec)
3923{
3924 struct alc_spec *spec = codec->spec;
3925 int i;
Kailang Yangea1fb292008-08-26 12:58:38 +02003926
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003927 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003928 for (i = 0; i < spec->autocfg.line_outs; i++) {
3929 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02003930 int pin_type = get_pin_type(spec->autocfg.line_out_type);
3931 alc880_auto_set_output_and_unmute(codec, nid, pin_type, i);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003932 }
3933}
3934
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003935static void alc880_auto_init_extra_out(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003936{
3937 struct alc_spec *spec = codec->spec;
3938 hda_nid_t pin;
3939
Takashi Iwai82bc9552006-03-21 11:24:42 +01003940 pin = spec->autocfg.speaker_pins[0];
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003941 if (pin) /* connect to front */
3942 alc880_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003943 pin = spec->autocfg.hp_pins[0];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003944 if (pin) /* connect to front */
3945 alc880_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
3946}
3947
3948static void alc880_auto_init_analog_input(struct hda_codec *codec)
3949{
3950 struct alc_spec *spec = codec->spec;
3951 int i;
3952
3953 for (i = 0; i < AUTO_PIN_LAST; i++) {
3954 hda_nid_t nid = spec->autocfg.input_pins[i];
3955 if (alc880_is_input_pin(nid)) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003956 snd_hda_codec_write(codec, nid, 0,
3957 AC_VERB_SET_PIN_WIDGET_CONTROL,
3958 i <= AUTO_PIN_FRONT_MIC ?
3959 PIN_VREF80 : PIN_IN);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003960 if (nid != ALC880_PIN_CD_NID)
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003961 snd_hda_codec_write(codec, nid, 0,
3962 AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003963 AMP_OUT_MUTE);
3964 }
3965 }
3966}
3967
3968/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003969/* return 1 if successful, 0 if the proper config is not found,
3970 * or a negative error code
3971 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003972static int alc880_parse_auto_config(struct hda_codec *codec)
3973{
3974 struct alc_spec *spec = codec->spec;
3975 int err;
Kailang Yangdf694da2005-12-05 19:42:22 +01003976 static hda_nid_t alc880_ignore[] = { 0x1d, 0 };
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003977
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003978 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
3979 alc880_ignore);
3980 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003981 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003982 if (!spec->autocfg.line_outs)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003983 return 0; /* can't find valid BIOS pin config */
Kailang Yangdf694da2005-12-05 19:42:22 +01003984
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003985 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
3986 if (err < 0)
3987 return err;
3988 err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
3989 if (err < 0)
3990 return err;
3991 err = alc880_auto_create_extra_out(spec,
3992 spec->autocfg.speaker_pins[0],
3993 "Speaker");
3994 if (err < 0)
3995 return err;
3996 err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
3997 "Headphone");
3998 if (err < 0)
3999 return err;
4000 err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg);
4001 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004002 return err;
4003
4004 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
4005
4006 if (spec->autocfg.dig_out_pin)
4007 spec->multiout.dig_out_nid = ALC880_DIGOUT_NID;
4008 if (spec->autocfg.dig_in_pin)
4009 spec->dig_in_nid = ALC880_DIGIN_NID;
4010
Takashi Iwai603c4012008-07-30 15:01:44 +02004011 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +01004012 add_mixer(spec, spec->kctls.list);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004013
Takashi Iwaid88897e2008-10-31 15:01:37 +01004014 add_verb(spec, alc880_volume_init_verbs);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004015
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004016 spec->num_mux_defs = 1;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004017 spec->input_mux = &spec->private_imux;
4018
Takashi Iwaie044c392008-10-27 16:56:24 +01004019 store_pin_configs(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004020 return 1;
4021}
4022
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004023/* additional initialization for auto-configuration model */
4024static void alc880_auto_init(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004025{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004026 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004027 alc880_auto_init_multi_out(codec);
Takashi Iwai8d88bc32005-11-17 11:09:23 +01004028 alc880_auto_init_extra_out(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004029 alc880_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004030 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02004031 alc_inithook(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004032}
4033
4034/*
4035 * OK, here we have finally the patch for ALC880
4036 */
4037
Takashi Iwaif9e336f2008-10-31 16:37:07 +01004038static void set_capture_mixer(struct alc_spec *spec)
4039{
4040 static struct snd_kcontrol_new *caps[3] = {
4041 alc_capture_mixer1,
4042 alc_capture_mixer2,
4043 alc_capture_mixer3,
4044 };
4045 if (spec->num_adc_nids > 0 && spec->num_adc_nids < 3)
4046 spec->cap_mixer = caps[spec->num_adc_nids - 1];
4047}
4048
Linus Torvalds1da177e2005-04-16 15:20:36 -07004049static int patch_alc880(struct hda_codec *codec)
4050{
4051 struct alc_spec *spec;
4052 int board_config;
Kailang Yangdf694da2005-12-05 19:42:22 +01004053 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004054
Takashi Iwaie560d8d2005-09-09 14:21:46 +02004055 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004056 if (spec == NULL)
4057 return -ENOMEM;
4058
4059 codec->spec = spec;
4060
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004061 board_config = snd_hda_check_board_config(codec, ALC880_MODEL_LAST,
4062 alc880_models,
4063 alc880_cfg_tbl);
4064 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004065 printk(KERN_INFO "hda_codec: Unknown model for ALC880, "
4066 "trying auto-probe from BIOS...\n");
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004067 board_config = ALC880_AUTO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004068 }
4069
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004070 if (board_config == ALC880_AUTO) {
4071 /* automatic parse from the BIOS config */
4072 err = alc880_parse_auto_config(codec);
4073 if (err < 0) {
4074 alc_free(codec);
4075 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004076 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004077 printk(KERN_INFO
4078 "hda_codec: Cannot set up configuration "
4079 "from BIOS. Using 3-stack mode...\n");
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004080 board_config = ALC880_3ST;
4081 }
4082 }
4083
Kailang Yangdf694da2005-12-05 19:42:22 +01004084 if (board_config != ALC880_AUTO)
4085 setup_preset(spec, &alc880_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004086
4087 spec->stream_name_analog = "ALC880 Analog";
4088 spec->stream_analog_playback = &alc880_pcm_analog_playback;
4089 spec->stream_analog_capture = &alc880_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01004090 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004091
4092 spec->stream_name_digital = "ALC880 Digital";
4093 spec->stream_digital_playback = &alc880_pcm_digital_playback;
4094 spec->stream_digital_capture = &alc880_pcm_digital_capture;
4095
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004096 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004097 /* check whether NID 0x07 is valid */
Takashi Iwai54d17402005-11-21 16:33:22 +01004098 unsigned int wcap = get_wcaps(codec, alc880_adc_nids[0]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004099 /* get type */
4100 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004101 if (wcap != AC_WID_AUD_IN) {
4102 spec->adc_nids = alc880_adc_nids_alt;
4103 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids_alt);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004104 } else {
4105 spec->adc_nids = alc880_adc_nids;
4106 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004107 }
4108 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01004109 set_capture_mixer(spec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004110
Takashi Iwai2134ea42008-01-10 16:53:55 +01004111 spec->vmaster_nid = 0x0c;
4112
Linus Torvalds1da177e2005-04-16 15:20:36 -07004113 codec->patch_ops = alc_patch_ops;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004114 if (board_config == ALC880_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004115 spec->init_hook = alc880_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02004116#ifdef CONFIG_SND_HDA_POWER_SAVE
4117 if (!spec->loopback.amplist)
4118 spec->loopback.amplist = alc880_loopbacks;
4119#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07004120
4121 return 0;
4122}
4123
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004124
Linus Torvalds1da177e2005-04-16 15:20:36 -07004125/*
4126 * ALC260 support
4127 */
4128
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004129static hda_nid_t alc260_dac_nids[1] = {
4130 /* front */
4131 0x02,
4132};
4133
4134static hda_nid_t alc260_adc_nids[1] = {
4135 /* ADC0 */
4136 0x04,
4137};
4138
Kailang Yangdf694da2005-12-05 19:42:22 +01004139static hda_nid_t alc260_adc_nids_alt[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004140 /* ADC1 */
4141 0x05,
4142};
4143
Jonathan Woithed57fdac2006-02-28 11:38:35 +01004144/* NIDs used when simultaneous access to both ADCs makes sense. Note that
4145 * alc260_capture_mixer assumes ADC0 (nid 0x04) is the first ADC.
4146 */
4147static hda_nid_t alc260_dual_adc_nids[2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004148 /* ADC0, ADC1 */
4149 0x04, 0x05
4150};
4151
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004152#define ALC260_DIGOUT_NID 0x03
4153#define ALC260_DIGIN_NID 0x06
4154
4155static struct hda_input_mux alc260_capture_source = {
4156 .num_items = 4,
4157 .items = {
4158 { "Mic", 0x0 },
4159 { "Front Mic", 0x1 },
4160 { "Line", 0x2 },
4161 { "CD", 0x4 },
4162 },
4163};
4164
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01004165/* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004166 * headphone jack and the internal CD lines since these are the only pins at
4167 * which audio can appear. For flexibility, also allow the option of
4168 * recording the mixer output on the second ADC (ADC0 doesn't have a
4169 * connection to the mixer output).
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004170 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004171static struct hda_input_mux alc260_fujitsu_capture_sources[2] = {
4172 {
4173 .num_items = 3,
4174 .items = {
4175 { "Mic/Line", 0x0 },
4176 { "CD", 0x4 },
4177 { "Headphone", 0x2 },
4178 },
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004179 },
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004180 {
4181 .num_items = 4,
4182 .items = {
4183 { "Mic/Line", 0x0 },
4184 { "CD", 0x4 },
4185 { "Headphone", 0x2 },
4186 { "Mixer", 0x5 },
4187 },
4188 },
4189
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004190};
4191
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004192/* Acer TravelMate(/Extensa/Aspire) notebooks have similar configuration to
4193 * the Fujitsu S702x, but jacks are marked differently.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004194 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004195static struct hda_input_mux alc260_acer_capture_sources[2] = {
4196 {
4197 .num_items = 4,
4198 .items = {
4199 { "Mic", 0x0 },
4200 { "Line", 0x2 },
4201 { "CD", 0x4 },
4202 { "Headphone", 0x5 },
4203 },
4204 },
4205 {
4206 .num_items = 5,
4207 .items = {
4208 { "Mic", 0x0 },
4209 { "Line", 0x2 },
4210 { "CD", 0x4 },
4211 { "Headphone", 0x6 },
4212 { "Mixer", 0x5 },
4213 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004214 },
4215};
Linus Torvalds1da177e2005-04-16 15:20:36 -07004216/*
4217 * This is just place-holder, so there's something for alc_build_pcms to look
4218 * at when it calculates the maximum number of channels. ALC260 has no mixer
4219 * element which allows changing the channel mode, so the verb list is
4220 * never used.
4221 */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01004222static struct hda_channel_mode alc260_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004223 { 2, NULL },
4224};
4225
Kailang Yangdf694da2005-12-05 19:42:22 +01004226
4227/* Mixer combinations
4228 *
4229 * basic: base_output + input + pc_beep + capture
4230 * HP: base_output + input + capture_alt
4231 * HP_3013: hp_3013 + input + capture
4232 * fujitsu: fujitsu + capture
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004233 * acer: acer + capture
Kailang Yangdf694da2005-12-05 19:42:22 +01004234 */
4235
4236static struct snd_kcontrol_new alc260_base_output_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02004237 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01004238 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01004239 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
4240 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
4241 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
4242 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
4243 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004244};
Kailang Yangdf694da2005-12-05 19:42:22 +01004245
4246static struct snd_kcontrol_new alc260_input_mixer[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004247 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4248 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
4249 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
4250 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
4251 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
4252 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
4253 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT),
4254 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004255 { } /* end */
4256};
4257
Kailang Yangdf694da2005-12-05 19:42:22 +01004258static struct snd_kcontrol_new alc260_pc_beep_mixer[] = {
4259 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x07, 0x05, HDA_INPUT),
4260 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x07, 0x05, HDA_INPUT),
4261 { } /* end */
4262};
4263
Takashi Iwaibec15c32008-01-28 18:16:30 +01004264/* update HP, line and mono out pins according to the master switch */
4265static void alc260_hp_master_update(struct hda_codec *codec,
4266 hda_nid_t hp, hda_nid_t line,
4267 hda_nid_t mono)
4268{
4269 struct alc_spec *spec = codec->spec;
4270 unsigned int val = spec->master_sw ? PIN_HP : 0;
4271 /* change HP and line-out pins */
4272 snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
4273 val);
4274 snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
4275 val);
4276 /* mono (speaker) depending on the HP jack sense */
4277 val = (val && !spec->jack_present) ? PIN_OUT : 0;
4278 snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
4279 val);
4280}
4281
4282static int alc260_hp_master_sw_get(struct snd_kcontrol *kcontrol,
4283 struct snd_ctl_elem_value *ucontrol)
4284{
4285 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4286 struct alc_spec *spec = codec->spec;
4287 *ucontrol->value.integer.value = spec->master_sw;
4288 return 0;
4289}
4290
4291static int alc260_hp_master_sw_put(struct snd_kcontrol *kcontrol,
4292 struct snd_ctl_elem_value *ucontrol)
4293{
4294 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4295 struct alc_spec *spec = codec->spec;
4296 int val = !!*ucontrol->value.integer.value;
4297 hda_nid_t hp, line, mono;
4298
4299 if (val == spec->master_sw)
4300 return 0;
4301 spec->master_sw = val;
4302 hp = (kcontrol->private_value >> 16) & 0xff;
4303 line = (kcontrol->private_value >> 8) & 0xff;
4304 mono = kcontrol->private_value & 0xff;
4305 alc260_hp_master_update(codec, hp, line, mono);
4306 return 1;
4307}
4308
4309static struct snd_kcontrol_new alc260_hp_output_mixer[] = {
4310 {
4311 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4312 .name = "Master Playback Switch",
4313 .info = snd_ctl_boolean_mono_info,
4314 .get = alc260_hp_master_sw_get,
4315 .put = alc260_hp_master_sw_put,
4316 .private_value = (0x0f << 16) | (0x10 << 8) | 0x11
4317 },
4318 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4319 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
4320 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
4321 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
4322 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
4323 HDA_OUTPUT),
4324 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2, HDA_INPUT),
4325 { } /* end */
4326};
4327
4328static struct hda_verb alc260_hp_unsol_verbs[] = {
4329 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
4330 {},
4331};
4332
4333static void alc260_hp_automute(struct hda_codec *codec)
4334{
4335 struct alc_spec *spec = codec->spec;
4336 unsigned int present;
4337
4338 present = snd_hda_codec_read(codec, 0x10, 0,
4339 AC_VERB_GET_PIN_SENSE, 0);
4340 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
4341 alc260_hp_master_update(codec, 0x0f, 0x10, 0x11);
4342}
4343
4344static void alc260_hp_unsol_event(struct hda_codec *codec, unsigned int res)
4345{
4346 if ((res >> 26) == ALC880_HP_EVENT)
4347 alc260_hp_automute(codec);
4348}
4349
Kailang Yangdf694da2005-12-05 19:42:22 +01004350static struct snd_kcontrol_new alc260_hp_3013_mixer[] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01004351 {
4352 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4353 .name = "Master Playback Switch",
4354 .info = snd_ctl_boolean_mono_info,
4355 .get = alc260_hp_master_sw_get,
4356 .put = alc260_hp_master_sw_put,
4357 .private_value = (0x10 << 16) | (0x15 << 8) | 0x11
4358 },
Kailang Yangdf694da2005-12-05 19:42:22 +01004359 HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT),
4360 HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT),
4361 HDA_CODEC_VOLUME("Aux-In Playback Volume", 0x07, 0x06, HDA_INPUT),
4362 HDA_CODEC_MUTE("Aux-In Playback Switch", 0x07, 0x06, HDA_INPUT),
4363 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4364 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01004365 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
4366 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02004367 { } /* end */
4368};
4369
Kailang Yang3f878302008-08-26 13:02:23 +02004370static struct hda_bind_ctls alc260_dc7600_bind_master_vol = {
4371 .ops = &snd_hda_bind_vol,
4372 .values = {
4373 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_OUTPUT),
4374 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_OUTPUT),
4375 HDA_COMPOSE_AMP_VAL(0x0a, 3, 0, HDA_OUTPUT),
4376 0
4377 },
4378};
4379
4380static struct hda_bind_ctls alc260_dc7600_bind_switch = {
4381 .ops = &snd_hda_bind_sw,
4382 .values = {
4383 HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT),
4384 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
4385 0
4386 },
4387};
4388
4389static struct snd_kcontrol_new alc260_hp_dc7600_mixer[] = {
4390 HDA_BIND_VOL("Master Playback Volume", &alc260_dc7600_bind_master_vol),
4391 HDA_BIND_SW("LineOut Playback Switch", &alc260_dc7600_bind_switch),
4392 HDA_CODEC_MUTE("Speaker Playback Switch", 0x0f, 0x0, HDA_OUTPUT),
4393 HDA_CODEC_MUTE("Headphone Playback Switch", 0x10, 0x0, HDA_OUTPUT),
4394 { } /* end */
4395};
4396
Takashi Iwaibec15c32008-01-28 18:16:30 +01004397static struct hda_verb alc260_hp_3013_unsol_verbs[] = {
4398 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
4399 {},
4400};
4401
4402static void alc260_hp_3013_automute(struct hda_codec *codec)
4403{
4404 struct alc_spec *spec = codec->spec;
4405 unsigned int present;
4406
4407 present = snd_hda_codec_read(codec, 0x15, 0,
4408 AC_VERB_GET_PIN_SENSE, 0);
4409 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
4410 alc260_hp_master_update(codec, 0x10, 0x15, 0x11);
4411}
4412
4413static void alc260_hp_3013_unsol_event(struct hda_codec *codec,
4414 unsigned int res)
4415{
4416 if ((res >> 26) == ALC880_HP_EVENT)
4417 alc260_hp_3013_automute(codec);
4418}
4419
Kailang Yang3f878302008-08-26 13:02:23 +02004420static void alc260_hp_3012_automute(struct hda_codec *codec)
4421{
4422 unsigned int present, bits;
4423
4424 present = snd_hda_codec_read(codec, 0x10, 0,
4425 AC_VERB_GET_PIN_SENSE, 0) & AC_PINSENSE_PRESENCE;
4426
4427 bits = present ? 0 : PIN_OUT;
4428 snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
4429 bits);
4430 snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
4431 bits);
4432 snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
4433 bits);
4434}
4435
4436static void alc260_hp_3012_unsol_event(struct hda_codec *codec,
4437 unsigned int res)
4438{
4439 if ((res >> 26) == ALC880_HP_EVENT)
4440 alc260_hp_3012_automute(codec);
4441}
4442
4443/* Fujitsu S702x series laptops. ALC260 pin usage: Mic/Line jack = 0x12,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004444 * HP jack = 0x14, CD audio = 0x16, internal speaker = 0x10.
4445 */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01004446static struct snd_kcontrol_new alc260_fujitsu_mixer[] = {
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004447 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01004448 HDA_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004449 ALC_PIN_MODE("Headphone Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004450 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4451 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
4452 HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT),
4453 HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004454 ALC_PIN_MODE("Mic/Line Jack Mode", 0x12, ALC_PIN_DIR_IN),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004455 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
4456 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01004457 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT),
4458 HDA_BIND_MUTE("Speaker Playback Switch", 0x09, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01004459 { } /* end */
4460};
4461
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004462/* Mixer for Acer TravelMate(/Extensa/Aspire) notebooks. Note that current
4463 * versions of the ALC260 don't act on requests to enable mic bias from NID
4464 * 0x0f (used to drive the headphone jack in these laptops). The ALC260
4465 * datasheet doesn't mention this restriction. At this stage it's not clear
4466 * whether this behaviour is intentional or is a hardware bug in chip
4467 * revisions available in early 2006. Therefore for now allow the
4468 * "Headphone Jack Mode" control to span all choices, but if it turns out
4469 * that the lack of mic bias for this NID is intentional we could change the
4470 * mode from ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
4471 *
4472 * In addition, Acer TravelMate(/Extensa/Aspire) notebooks in early 2006
4473 * don't appear to make the mic bias available from the "line" jack, even
4474 * though the NID used for this jack (0x14) can supply it. The theory is
4475 * that perhaps Acer have included blocking capacitors between the ALC260
4476 * and the output jack. If this turns out to be the case for all such
4477 * models the "Line Jack Mode" mode could be changed from ALC_PIN_DIR_INOUT
4478 * to ALC_PIN_DIR_INOUT_NOMICBIAS.
Jonathan Woithebd869482006-11-28 11:35:52 +01004479 *
4480 * The C20x Tablet series have a mono internal speaker which is controlled
4481 * via the chip's Mono sum widget and pin complex, so include the necessary
4482 * controls for such models. On models without a "mono speaker" the control
4483 * won't do anything.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004484 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004485static struct snd_kcontrol_new alc260_acer_mixer[] = {
4486 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4487 HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004488 ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01004489 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
Jonathan Woithebd869482006-11-28 11:35:52 +01004490 HDA_OUTPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01004491 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2,
Jonathan Woithebd869482006-11-28 11:35:52 +01004492 HDA_INPUT),
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004493 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4494 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
4495 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
4496 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
4497 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
4498 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
4499 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
4500 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
4501 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
4502 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
4503 { } /* end */
4504};
4505
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004506/* Packard bell V7900 ALC260 pin usage: HP = 0x0f, Mic jack = 0x12,
4507 * Line In jack = 0x14, CD audio = 0x16, pc beep = 0x17.
4508 */
4509static struct snd_kcontrol_new alc260_will_mixer[] = {
4510 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4511 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
4512 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
4513 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
4514 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
4515 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
4516 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
4517 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
4518 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4519 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
4520 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
4521 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
4522 { } /* end */
4523};
4524
4525/* Replacer 672V ALC260 pin usage: Mic jack = 0x12,
4526 * Line In jack = 0x14, ATAPI Mic = 0x13, speaker = 0x0f.
4527 */
4528static struct snd_kcontrol_new alc260_replacer_672v_mixer[] = {
4529 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4530 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
4531 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
4532 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
4533 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
4534 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x07, 0x1, HDA_INPUT),
4535 HDA_CODEC_MUTE("ATATI Mic Playback Switch", 0x07, 0x1, HDA_INPUT),
4536 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
4537 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
4538 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
4539 { } /* end */
4540};
4541
Kailang Yangdf694da2005-12-05 19:42:22 +01004542/*
4543 * initialization verbs
4544 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004545static struct hda_verb alc260_init_verbs[] = {
4546 /* Line In pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02004547 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004548 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02004549 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004550 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02004551 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004552 /* Mic2 (front panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02004553 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004554 /* LINE-2 is used for line-out in rear */
Takashi Iwai05acb862005-06-10 19:50:25 +02004555 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004556 /* select line-out */
Jonathan Woithefd56f2d2006-01-24 10:35:46 +01004557 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004558 /* LINE-OUT pin */
Takashi Iwai05acb862005-06-10 19:50:25 +02004559 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004560 /* enable HP */
Takashi Iwai05acb862005-06-10 19:50:25 +02004561 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004562 /* enable Mono */
Takashi Iwai05acb862005-06-10 19:50:25 +02004563 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4564 /* mute capture amp left and right */
Takashi Iwai16ded522005-06-10 19:58:24 +02004565 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004566 /* set connection select to line in (default select for this ADC) */
4567 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai16ded522005-06-10 19:58:24 +02004568 /* mute capture amp left and right */
4569 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4570 /* set connection select to line in (default select for this ADC) */
4571 {0x05, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai05acb862005-06-10 19:50:25 +02004572 /* set vol=0 Line-Out mixer amp left and right */
4573 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4574 /* unmute pin widget amp left and right (no gain on this amp) */
4575 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4576 /* set vol=0 HP mixer amp left and right */
4577 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4578 /* unmute pin widget amp left and right (no gain on this amp) */
4579 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4580 /* set vol=0 Mono mixer amp left and right */
4581 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4582 /* unmute pin widget amp left and right (no gain on this amp) */
4583 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4584 /* unmute LINE-2 out pin */
4585 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004586 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
4587 * Line In 2 = 0x03
4588 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02004589 /* mute analog inputs */
4590 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4591 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4592 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4593 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4594 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004595 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
Takashi Iwai05acb862005-06-10 19:50:25 +02004596 /* mute Front out path */
4597 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4598 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4599 /* mute Headphone out path */
4600 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4601 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4602 /* mute Mono out path */
4603 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4604 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004605 { }
4606};
4607
Takashi Iwai474167d2006-05-17 17:17:43 +02004608#if 0 /* should be identical with alc260_init_verbs? */
Kailang Yangdf694da2005-12-05 19:42:22 +01004609static struct hda_verb alc260_hp_init_verbs[] = {
4610 /* Headphone and output */
4611 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
4612 /* mono output */
4613 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4614 /* Mic1 (rear panel) pin widget for input and vref at 80% */
4615 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4616 /* Mic2 (front panel) pin widget for input and vref at 80% */
4617 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4618 /* Line In pin widget for input */
4619 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4620 /* Line-2 pin widget for output */
4621 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4622 /* CD pin widget for input */
4623 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4624 /* unmute amp left and right */
4625 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
4626 /* set connection select to line in (default select for this ADC) */
4627 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
4628 /* unmute Line-Out mixer amp left and right (volume = 0) */
4629 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
4630 /* mute pin widget amp left and right (no gain on this amp) */
4631 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
4632 /* unmute HP mixer amp left and right (volume = 0) */
4633 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
4634 /* mute pin widget amp left and right (no gain on this amp) */
4635 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004636 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
4637 * Line In 2 = 0x03
4638 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02004639 /* mute analog inputs */
4640 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4641 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4642 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4643 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4644 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01004645 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
4646 /* Unmute Front out path */
4647 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4648 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4649 /* Unmute Headphone out path */
4650 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4651 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4652 /* Unmute Mono out path */
4653 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4654 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4655 { }
4656};
Takashi Iwai474167d2006-05-17 17:17:43 +02004657#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01004658
4659static struct hda_verb alc260_hp_3013_init_verbs[] = {
4660 /* Line out and output */
4661 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4662 /* mono output */
4663 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4664 /* Mic1 (rear panel) pin widget for input and vref at 80% */
4665 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4666 /* Mic2 (front panel) pin widget for input and vref at 80% */
4667 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4668 /* Line In pin widget for input */
4669 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4670 /* Headphone pin widget for output */
4671 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
4672 /* CD pin widget for input */
4673 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4674 /* unmute amp left and right */
4675 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
4676 /* set connection select to line in (default select for this ADC) */
4677 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
4678 /* unmute Line-Out mixer amp left and right (volume = 0) */
4679 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
4680 /* mute pin widget amp left and right (no gain on this amp) */
4681 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
4682 /* unmute HP mixer amp left and right (volume = 0) */
4683 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
4684 /* mute pin widget amp left and right (no gain on this amp) */
4685 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004686 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
4687 * Line In 2 = 0x03
4688 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02004689 /* mute analog inputs */
4690 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4691 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4692 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4693 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4694 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01004695 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
4696 /* Unmute Front out path */
4697 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4698 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4699 /* Unmute Headphone out path */
4700 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4701 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4702 /* Unmute Mono out path */
4703 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4704 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4705 { }
4706};
4707
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004708/* Initialisation sequence for ALC260 as configured in Fujitsu S702x
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004709 * laptops. ALC260 pin usage: Mic/Line jack = 0x12, HP jack = 0x14, CD
4710 * audio = 0x16, internal speaker = 0x10.
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004711 */
4712static struct hda_verb alc260_fujitsu_init_verbs[] = {
4713 /* Disable all GPIOs */
4714 {0x01, AC_VERB_SET_GPIO_MASK, 0},
4715 /* Internal speaker is connected to headphone pin */
4716 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4717 /* Headphone/Line-out jack connects to Line1 pin; make it an output */
4718 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Jonathan Woithef7ace402006-02-28 11:46:14 +01004719 /* Mic/Line-in jack is connected to mic1 pin, so make it an input */
4720 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4721 /* Ensure all other unused pins are disabled and muted. */
4722 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4723 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004724 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01004725 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004726 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01004727 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4728 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4729 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004730
Jonathan Woithef7ace402006-02-28 11:46:14 +01004731 /* Disable digital (SPDIF) pins */
4732 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
4733 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004734
Kailang Yangea1fb292008-08-26 12:58:38 +02004735 /* Ensure Line1 pin widget takes its input from the OUT1 sum bus
Jonathan Woithef7ace402006-02-28 11:46:14 +01004736 * when acting as an output.
4737 */
4738 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
4739
4740 /* Start with output sum widgets muted and their output gains at min */
Takashi Iwai8b33a5a2006-02-09 11:57:01 +01004741 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4742 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4743 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4744 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4745 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4746 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4747 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4748 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4749 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004750
Jonathan Woithef7ace402006-02-28 11:46:14 +01004751 /* Unmute HP pin widget amp left and right (no equiv mixer ctrl) */
4752 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4753 /* Unmute Line1 pin widget output buffer since it starts as an output.
4754 * If the pin mode is changed by the user the pin mode control will
4755 * take care of enabling the pin's input/output buffers as needed.
4756 * Therefore there's no need to enable the input buffer at this
4757 * stage.
Jonathan Woithecdcd9262006-02-28 11:36:42 +01004758 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01004759 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +02004760 /* Unmute input buffer of pin widget used for Line-in (no equiv
Jonathan Woithecdcd9262006-02-28 11:36:42 +01004761 * mixer ctrl)
4762 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01004763 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004764
Jonathan Woithef7ace402006-02-28 11:46:14 +01004765 /* Mute capture amp left and right */
4766 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +02004767 /* Set ADC connection select to match default mixer setting - line
Jonathan Woithef7ace402006-02-28 11:46:14 +01004768 * in (on mic1 pin)
4769 */
4770 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004771
Jonathan Woithef7ace402006-02-28 11:46:14 +01004772 /* Do the same for the second ADC: mute capture input amp and
4773 * set ADC connection to line in (on mic1 pin)
4774 */
4775 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4776 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004777
Jonathan Woithef7ace402006-02-28 11:46:14 +01004778 /* Mute all inputs to mixer widget (even unconnected ones) */
4779 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
4780 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
4781 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
4782 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
4783 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
4784 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
4785 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
4786 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
Takashi Iwai4a471b72005-12-07 13:56:29 +01004787
4788 { }
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004789};
4790
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004791/* Initialisation sequence for ALC260 as configured in Acer TravelMate and
4792 * similar laptops (adapted from Fujitsu init verbs).
4793 */
4794static struct hda_verb alc260_acer_init_verbs[] = {
4795 /* On TravelMate laptops, GPIO 0 enables the internal speaker and
4796 * the headphone jack. Turn this on and rely on the standard mute
4797 * methods whenever the user wants to turn these outputs off.
4798 */
4799 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
4800 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
4801 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
4802 /* Internal speaker/Headphone jack is connected to Line-out pin */
4803 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4804 /* Internal microphone/Mic jack is connected to Mic1 pin */
4805 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
4806 /* Line In jack is connected to Line1 pin */
4807 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Jonathan Woithebd869482006-11-28 11:35:52 +01004808 /* Some Acers (eg: C20x Tablets) use Mono pin for internal speaker */
4809 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004810 /* Ensure all other unused pins are disabled and muted. */
4811 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4812 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004813 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4814 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4815 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4816 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4817 /* Disable digital (SPDIF) pins */
4818 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
4819 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
4820
Kailang Yangea1fb292008-08-26 12:58:38 +02004821 /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004822 * bus when acting as outputs.
4823 */
4824 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
4825 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
4826
4827 /* Start with output sum widgets muted and their output gains at min */
4828 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4829 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4830 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4831 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4832 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4833 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4834 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4835 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4836 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4837
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004838 /* Unmute Line-out pin widget amp left and right
4839 * (no equiv mixer ctrl)
4840 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004841 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithebd869482006-11-28 11:35:52 +01004842 /* Unmute mono pin widget amp output (no equiv mixer ctrl) */
4843 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004844 /* Unmute Mic1 and Line1 pin widget input buffers since they start as
4845 * inputs. If the pin mode is changed by the user the pin mode control
4846 * will take care of enabling the pin's input/output buffers as needed.
4847 * Therefore there's no need to enable the input buffer at this
4848 * stage.
4849 */
4850 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4851 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4852
4853 /* Mute capture amp left and right */
4854 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4855 /* Set ADC connection select to match default mixer setting - mic
4856 * (on mic1 pin)
4857 */
4858 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
4859
4860 /* Do similar with the second ADC: mute capture input amp and
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004861 * set ADC connection to mic to match ALSA's default state.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004862 */
4863 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004864 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004865
4866 /* Mute all inputs to mixer widget (even unconnected ones) */
4867 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
4868 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
4869 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
4870 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
4871 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
4872 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
4873 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
4874 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
4875
4876 { }
4877};
4878
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004879static struct hda_verb alc260_will_verbs[] = {
4880 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4881 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x00},
4882 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
4883 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
4884 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
4885 {0x1a, AC_VERB_SET_PROC_COEF, 0x3040},
4886 {}
4887};
4888
4889static struct hda_verb alc260_replacer_672v_verbs[] = {
4890 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
4891 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
4892 {0x1a, AC_VERB_SET_PROC_COEF, 0x3050},
4893
4894 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
4895 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
4896 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
4897
4898 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
4899 {}
4900};
4901
4902/* toggle speaker-output according to the hp-jack state */
4903static void alc260_replacer_672v_automute(struct hda_codec *codec)
4904{
4905 unsigned int present;
4906
4907 /* speaker --> GPIO Data 0, hp or spdif --> GPIO data 1 */
4908 present = snd_hda_codec_read(codec, 0x0f, 0,
4909 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
4910 if (present) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02004911 snd_hda_codec_write_cache(codec, 0x01, 0,
4912 AC_VERB_SET_GPIO_DATA, 1);
4913 snd_hda_codec_write_cache(codec, 0x0f, 0,
4914 AC_VERB_SET_PIN_WIDGET_CONTROL,
4915 PIN_HP);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004916 } else {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02004917 snd_hda_codec_write_cache(codec, 0x01, 0,
4918 AC_VERB_SET_GPIO_DATA, 0);
4919 snd_hda_codec_write_cache(codec, 0x0f, 0,
4920 AC_VERB_SET_PIN_WIDGET_CONTROL,
4921 PIN_OUT);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004922 }
4923}
4924
4925static void alc260_replacer_672v_unsol_event(struct hda_codec *codec,
4926 unsigned int res)
4927{
4928 if ((res >> 26) == ALC880_HP_EVENT)
4929 alc260_replacer_672v_automute(codec);
4930}
4931
Kailang Yang3f878302008-08-26 13:02:23 +02004932static struct hda_verb alc260_hp_dc7600_verbs[] = {
4933 {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
4934 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
4935 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4936 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4937 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4938 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4939 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4940 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
4941 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
4942 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
4943 {}
4944};
4945
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004946/* Test configuration for debugging, modelled after the ALC880 test
4947 * configuration.
4948 */
4949#ifdef CONFIG_SND_DEBUG
4950static hda_nid_t alc260_test_dac_nids[1] = {
4951 0x02,
4952};
4953static hda_nid_t alc260_test_adc_nids[2] = {
4954 0x04, 0x05,
4955};
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004956/* For testing the ALC260, each input MUX needs its own definition since
Kailang Yangea1fb292008-08-26 12:58:38 +02004957 * the signal assignments are different. This assumes that the first ADC
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004958 * is NID 0x04.
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01004959 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004960static struct hda_input_mux alc260_test_capture_sources[2] = {
4961 {
4962 .num_items = 7,
4963 .items = {
4964 { "MIC1 pin", 0x0 },
4965 { "MIC2 pin", 0x1 },
4966 { "LINE1 pin", 0x2 },
4967 { "LINE2 pin", 0x3 },
4968 { "CD pin", 0x4 },
4969 { "LINE-OUT pin", 0x5 },
4970 { "HP-OUT pin", 0x6 },
4971 },
4972 },
4973 {
4974 .num_items = 8,
4975 .items = {
4976 { "MIC1 pin", 0x0 },
4977 { "MIC2 pin", 0x1 },
4978 { "LINE1 pin", 0x2 },
4979 { "LINE2 pin", 0x3 },
4980 { "CD pin", 0x4 },
4981 { "Mixer", 0x5 },
4982 { "LINE-OUT pin", 0x6 },
4983 { "HP-OUT pin", 0x7 },
4984 },
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01004985 },
4986};
4987static struct snd_kcontrol_new alc260_test_mixer[] = {
4988 /* Output driver widgets */
4989 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
4990 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
4991 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x09, 0x0, HDA_OUTPUT),
4992 HDA_BIND_MUTE("LOUT2 Playback Switch", 0x09, 2, HDA_INPUT),
4993 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4994 HDA_BIND_MUTE("LOUT1 Playback Switch", 0x08, 2, HDA_INPUT),
4995
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004996 /* Modes for retasking pin widgets
4997 * Note: the ALC260 doesn't seem to act on requests to enable mic
4998 * bias from NIDs 0x0f and 0x10. The ALC260 datasheet doesn't
4999 * mention this restriction. At this stage it's not clear whether
5000 * this behaviour is intentional or is a hardware bug in chip
5001 * revisions available at least up until early 2006. Therefore for
5002 * now allow the "HP-OUT" and "LINE-OUT" Mode controls to span all
5003 * choices, but if it turns out that the lack of mic bias for these
5004 * NIDs is intentional we could change their modes from
5005 * ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
5006 */
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005007 ALC_PIN_MODE("HP-OUT pin mode", 0x10, ALC_PIN_DIR_INOUT),
5008 ALC_PIN_MODE("LINE-OUT pin mode", 0x0f, ALC_PIN_DIR_INOUT),
5009 ALC_PIN_MODE("LINE2 pin mode", 0x15, ALC_PIN_DIR_INOUT),
5010 ALC_PIN_MODE("LINE1 pin mode", 0x14, ALC_PIN_DIR_INOUT),
5011 ALC_PIN_MODE("MIC2 pin mode", 0x13, ALC_PIN_DIR_INOUT),
5012 ALC_PIN_MODE("MIC1 pin mode", 0x12, ALC_PIN_DIR_INOUT),
5013
5014 /* Loopback mixer controls */
5015 HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x07, 0x00, HDA_INPUT),
5016 HDA_CODEC_MUTE("MIC1 Playback Switch", 0x07, 0x00, HDA_INPUT),
5017 HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x07, 0x01, HDA_INPUT),
5018 HDA_CODEC_MUTE("MIC2 Playback Switch", 0x07, 0x01, HDA_INPUT),
5019 HDA_CODEC_VOLUME("LINE1 Playback Volume", 0x07, 0x02, HDA_INPUT),
5020 HDA_CODEC_MUTE("LINE1 Playback Switch", 0x07, 0x02, HDA_INPUT),
5021 HDA_CODEC_VOLUME("LINE2 Playback Volume", 0x07, 0x03, HDA_INPUT),
5022 HDA_CODEC_MUTE("LINE2 Playback Switch", 0x07, 0x03, HDA_INPUT),
5023 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
5024 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
5025 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
5026 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
5027 HDA_CODEC_VOLUME("LINE-OUT loopback Playback Volume", 0x07, 0x06, HDA_INPUT),
5028 HDA_CODEC_MUTE("LINE-OUT loopback Playback Switch", 0x07, 0x06, HDA_INPUT),
5029 HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x07, 0x7, HDA_INPUT),
5030 HDA_CODEC_MUTE("HP-OUT loopback Playback Switch", 0x07, 0x7, HDA_INPUT),
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01005031
5032 /* Controls for GPIO pins, assuming they are configured as outputs */
5033 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
5034 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
5035 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
5036 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
5037
Jonathan Woithe92621f12006-02-28 11:47:47 +01005038 /* Switches to allow the digital IO pins to be enabled. The datasheet
5039 * is ambigious as to which NID is which; testing on laptops which
Kailang Yangea1fb292008-08-26 12:58:38 +02005040 * make this output available should provide clarification.
Jonathan Woithe92621f12006-02-28 11:47:47 +01005041 */
5042 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x03, 0x01),
5043 ALC_SPDIF_CTRL_SWITCH("SPDIF Capture Switch", 0x06, 0x01),
5044
Jonathan Woithef8225f62008-01-08 12:16:54 +01005045 /* A switch allowing EAPD to be enabled. Some laptops seem to use
5046 * this output to turn on an external amplifier.
5047 */
5048 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
5049 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
5050
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005051 { } /* end */
5052};
5053static struct hda_verb alc260_test_init_verbs[] = {
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01005054 /* Enable all GPIOs as outputs with an initial value of 0 */
5055 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f},
5056 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
5057 {0x01, AC_VERB_SET_GPIO_MASK, 0x0f},
5058
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005059 /* Enable retasking pins as output, initially without power amp */
5060 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5061 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5062 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5063 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5064 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5065 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5066
Jonathan Woithe92621f12006-02-28 11:47:47 +01005067 /* Disable digital (SPDIF) pins initially, but users can enable
5068 * them via a mixer switch. In the case of SPDIF-out, this initverb
5069 * payload also sets the generation to 0, output to be in "consumer"
5070 * PCM format, copyright asserted, no pre-emphasis and no validity
5071 * control.
5072 */
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005073 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
5074 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
5075
Kailang Yangea1fb292008-08-26 12:58:38 +02005076 /* Ensure mic1, mic2, line1 and line2 pin widgets take input from the
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005077 * OUT1 sum bus when acting as an output.
5078 */
5079 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
5080 {0x0c, AC_VERB_SET_CONNECT_SEL, 0},
5081 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
5082 {0x0e, AC_VERB_SET_CONNECT_SEL, 0},
5083
5084 /* Start with output sum widgets muted and their output gains at min */
5085 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5086 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5087 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5088 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5089 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5090 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5091 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5092 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5093 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5094
Jonathan Woithecdcd9262006-02-28 11:36:42 +01005095 /* Unmute retasking pin widget output buffers since the default
5096 * state appears to be output. As the pin mode is changed by the
5097 * user the pin mode control will take care of enabling the pin's
5098 * input/output buffers as needed.
5099 */
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005100 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5101 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5102 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5103 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5104 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5105 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5106 /* Also unmute the mono-out pin widget */
5107 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5108
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005109 /* Mute capture amp left and right */
5110 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithef7ace402006-02-28 11:46:14 +01005111 /* Set ADC connection select to match default mixer setting (mic1
5112 * pin)
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005113 */
5114 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
5115
5116 /* Do the same for the second ADC: mute capture input amp and
Jonathan Woithef7ace402006-02-28 11:46:14 +01005117 * set ADC connection to mic1 pin
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005118 */
5119 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5120 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
5121
5122 /* Mute all inputs to mixer widget (even unconnected ones) */
5123 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
5124 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
5125 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
5126 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
5127 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
5128 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
5129 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
5130 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
5131
5132 { }
5133};
5134#endif
5135
Takashi Iwai63300792008-01-24 15:31:36 +01005136#define alc260_pcm_analog_playback alc880_pcm_analog_alt_playback
5137#define alc260_pcm_analog_capture alc880_pcm_analog_capture
Linus Torvalds1da177e2005-04-16 15:20:36 -07005138
Takashi Iwaia3bcba32005-12-06 19:05:29 +01005139#define alc260_pcm_digital_playback alc880_pcm_digital_playback
5140#define alc260_pcm_digital_capture alc880_pcm_digital_capture
5141
Kailang Yangdf694da2005-12-05 19:42:22 +01005142/*
5143 * for BIOS auto-configuration
5144 */
5145
5146static int alc260_add_playback_controls(struct alc_spec *spec, hda_nid_t nid,
Takashi Iwai863b4512008-10-21 17:01:47 +02005147 const char *pfx, int *vol_bits)
Kailang Yangdf694da2005-12-05 19:42:22 +01005148{
5149 hda_nid_t nid_vol;
5150 unsigned long vol_val, sw_val;
5151 char name[32];
5152 int err;
5153
5154 if (nid >= 0x0f && nid < 0x11) {
5155 nid_vol = nid - 0x7;
5156 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
5157 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
5158 } else if (nid == 0x11) {
5159 nid_vol = nid - 0x7;
5160 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT);
5161 sw_val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
5162 } else if (nid >= 0x12 && nid <= 0x15) {
5163 nid_vol = 0x08;
5164 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
5165 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
5166 } else
5167 return 0; /* N/A */
Kailang Yangea1fb292008-08-26 12:58:38 +02005168
Takashi Iwai863b4512008-10-21 17:01:47 +02005169 if (!(*vol_bits & (1 << nid_vol))) {
5170 /* first control for the volume widget */
5171 snprintf(name, sizeof(name), "%s Playback Volume", pfx);
5172 err = add_control(spec, ALC_CTL_WIDGET_VOL, name, vol_val);
5173 if (err < 0)
5174 return err;
5175 *vol_bits |= (1 << nid_vol);
5176 }
Kailang Yangdf694da2005-12-05 19:42:22 +01005177 snprintf(name, sizeof(name), "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005178 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, sw_val);
5179 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01005180 return err;
5181 return 1;
5182}
5183
5184/* add playback controls from the parsed DAC table */
5185static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec,
5186 const struct auto_pin_cfg *cfg)
5187{
5188 hda_nid_t nid;
5189 int err;
Takashi Iwai863b4512008-10-21 17:01:47 +02005190 int vols = 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01005191
5192 spec->multiout.num_dacs = 1;
5193 spec->multiout.dac_nids = spec->private_dac_nids;
5194 spec->multiout.dac_nids[0] = 0x02;
5195
5196 nid = cfg->line_out_pins[0];
5197 if (nid) {
Takashi Iwai863b4512008-10-21 17:01:47 +02005198 err = alc260_add_playback_controls(spec, nid, "Front", &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01005199 if (err < 0)
5200 return err;
5201 }
5202
Takashi Iwai82bc9552006-03-21 11:24:42 +01005203 nid = cfg->speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01005204 if (nid) {
Takashi Iwai863b4512008-10-21 17:01:47 +02005205 err = alc260_add_playback_controls(spec, nid, "Speaker", &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01005206 if (err < 0)
5207 return err;
5208 }
5209
Takashi Iwaieb06ed82006-09-20 17:10:27 +02005210 nid = cfg->hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01005211 if (nid) {
Takashi Iwai863b4512008-10-21 17:01:47 +02005212 err = alc260_add_playback_controls(spec, nid, "Headphone",
5213 &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01005214 if (err < 0)
5215 return err;
5216 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005217 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01005218}
5219
5220/* create playback/capture controls for input pins */
5221static int alc260_auto_create_analog_input_ctls(struct alc_spec *spec,
5222 const struct auto_pin_cfg *cfg)
5223{
Kailang Yangdf694da2005-12-05 19:42:22 +01005224 struct hda_input_mux *imux = &spec->private_imux;
5225 int i, err, idx;
5226
5227 for (i = 0; i < AUTO_PIN_LAST; i++) {
5228 if (cfg->input_pins[i] >= 0x12) {
5229 idx = cfg->input_pins[i] - 0x12;
Takashi Iwai4a471b72005-12-07 13:56:29 +01005230 err = new_analog_input(spec, cfg->input_pins[i],
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005231 auto_pin_cfg_labels[i], idx,
5232 0x07);
Kailang Yangdf694da2005-12-05 19:42:22 +01005233 if (err < 0)
5234 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005235 imux->items[imux->num_items].label =
5236 auto_pin_cfg_labels[i];
Kailang Yangdf694da2005-12-05 19:42:22 +01005237 imux->items[imux->num_items].index = idx;
5238 imux->num_items++;
5239 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005240 if (cfg->input_pins[i] >= 0x0f && cfg->input_pins[i] <= 0x10){
Kailang Yangdf694da2005-12-05 19:42:22 +01005241 idx = cfg->input_pins[i] - 0x09;
Takashi Iwai4a471b72005-12-07 13:56:29 +01005242 err = new_analog_input(spec, cfg->input_pins[i],
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005243 auto_pin_cfg_labels[i], idx,
5244 0x07);
Kailang Yangdf694da2005-12-05 19:42:22 +01005245 if (err < 0)
5246 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005247 imux->items[imux->num_items].label =
5248 auto_pin_cfg_labels[i];
Kailang Yangdf694da2005-12-05 19:42:22 +01005249 imux->items[imux->num_items].index = idx;
5250 imux->num_items++;
5251 }
5252 }
5253 return 0;
5254}
5255
5256static void alc260_auto_set_output_and_unmute(struct hda_codec *codec,
5257 hda_nid_t nid, int pin_type,
5258 int sel_idx)
5259{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005260 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01005261 /* need the manual connection? */
5262 if (nid >= 0x12) {
5263 int idx = nid - 0x12;
5264 snd_hda_codec_write(codec, idx + 0x0b, 0,
5265 AC_VERB_SET_CONNECT_SEL, sel_idx);
Kailang Yangdf694da2005-12-05 19:42:22 +01005266 }
5267}
5268
5269static void alc260_auto_init_multi_out(struct hda_codec *codec)
5270{
5271 struct alc_spec *spec = codec->spec;
5272 hda_nid_t nid;
5273
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005274 alc_subsystem_id(codec, 0x10, 0x15, 0x0f);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005275 nid = spec->autocfg.line_out_pins[0];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02005276 if (nid) {
5277 int pin_type = get_pin_type(spec->autocfg.line_out_type);
5278 alc260_auto_set_output_and_unmute(codec, nid, pin_type, 0);
5279 }
Kailang Yangea1fb292008-08-26 12:58:38 +02005280
Takashi Iwai82bc9552006-03-21 11:24:42 +01005281 nid = spec->autocfg.speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01005282 if (nid)
5283 alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
5284
Takashi Iwaieb06ed82006-09-20 17:10:27 +02005285 nid = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01005286 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02005287 alc260_auto_set_output_and_unmute(codec, nid, PIN_HP, 0);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005288}
Kailang Yangdf694da2005-12-05 19:42:22 +01005289
5290#define ALC260_PIN_CD_NID 0x16
5291static void alc260_auto_init_analog_input(struct hda_codec *codec)
5292{
5293 struct alc_spec *spec = codec->spec;
5294 int i;
5295
5296 for (i = 0; i < AUTO_PIN_LAST; i++) {
5297 hda_nid_t nid = spec->autocfg.input_pins[i];
5298 if (nid >= 0x12) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005299 snd_hda_codec_write(codec, nid, 0,
5300 AC_VERB_SET_PIN_WIDGET_CONTROL,
5301 i <= AUTO_PIN_FRONT_MIC ?
5302 PIN_VREF80 : PIN_IN);
Kailang Yangdf694da2005-12-05 19:42:22 +01005303 if (nid != ALC260_PIN_CD_NID)
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005304 snd_hda_codec_write(codec, nid, 0,
5305 AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangdf694da2005-12-05 19:42:22 +01005306 AMP_OUT_MUTE);
5307 }
5308 }
5309}
5310
5311/*
5312 * generic initialization of ADC, input mixers and output mixers
5313 */
5314static struct hda_verb alc260_volume_init_verbs[] = {
5315 /*
5316 * Unmute ADC0-1 and set the default input to mic-in
5317 */
5318 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
5319 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5320 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
5321 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +02005322
Kailang Yangdf694da2005-12-05 19:42:22 +01005323 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
5324 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005325 * Note: PASD motherboards uses the Line In 2 as the input for
5326 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01005327 */
5328 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02005329 /* mute analog inputs */
5330 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5331 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5332 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5333 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5334 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01005335
5336 /*
5337 * Set up output mixers (0x08 - 0x0a)
5338 */
5339 /* set vol=0 to output mixers */
5340 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5341 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5342 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5343 /* set up input amps for analog loopback */
5344 /* Amp Indices: DAC = 0, mixer = 1 */
5345 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5346 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5347 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5348 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5349 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5350 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +02005351
Kailang Yangdf694da2005-12-05 19:42:22 +01005352 { }
5353};
5354
5355static int alc260_parse_auto_config(struct hda_codec *codec)
5356{
5357 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01005358 int err;
5359 static hda_nid_t alc260_ignore[] = { 0x17, 0 };
5360
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005361 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
5362 alc260_ignore);
5363 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01005364 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005365 err = alc260_auto_create_multi_out_ctls(spec, &spec->autocfg);
5366 if (err < 0)
Takashi Iwai4a471b72005-12-07 13:56:29 +01005367 return err;
Takashi Iwai603c4012008-07-30 15:01:44 +02005368 if (!spec->kctls.list)
Kailang Yangdf694da2005-12-05 19:42:22 +01005369 return 0; /* can't find valid BIOS pin config */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005370 err = alc260_auto_create_analog_input_ctls(spec, &spec->autocfg);
5371 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01005372 return err;
5373
5374 spec->multiout.max_channels = 2;
5375
5376 if (spec->autocfg.dig_out_pin)
5377 spec->multiout.dig_out_nid = ALC260_DIGOUT_NID;
Takashi Iwai603c4012008-07-30 15:01:44 +02005378 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +01005379 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +01005380
Takashi Iwaid88897e2008-10-31 15:01:37 +01005381 add_verb(spec, alc260_volume_init_verbs);
Kailang Yangdf694da2005-12-05 19:42:22 +01005382
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005383 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +01005384 spec->input_mux = &spec->private_imux;
5385
Takashi Iwaie044c392008-10-27 16:56:24 +01005386 store_pin_configs(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01005387 return 1;
5388}
5389
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005390/* additional initialization for auto-configuration model */
5391static void alc260_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01005392{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005393 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01005394 alc260_auto_init_multi_out(codec);
5395 alc260_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005396 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02005397 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01005398}
5399
Takashi Iwaicb53c622007-08-10 17:21:45 +02005400#ifdef CONFIG_SND_HDA_POWER_SAVE
5401static struct hda_amp_list alc260_loopbacks[] = {
5402 { 0x07, HDA_INPUT, 0 },
5403 { 0x07, HDA_INPUT, 1 },
5404 { 0x07, HDA_INPUT, 2 },
5405 { 0x07, HDA_INPUT, 3 },
5406 { 0x07, HDA_INPUT, 4 },
5407 { } /* end */
5408};
5409#endif
5410
Kailang Yangdf694da2005-12-05 19:42:22 +01005411/*
5412 * ALC260 configurations
5413 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005414static const char *alc260_models[ALC260_MODEL_LAST] = {
5415 [ALC260_BASIC] = "basic",
5416 [ALC260_HP] = "hp",
5417 [ALC260_HP_3013] = "hp-3013",
Takashi Iwai2922c9a2008-08-27 18:12:42 +02005418 [ALC260_HP_DC7600] = "hp-dc7600",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005419 [ALC260_FUJITSU_S702X] = "fujitsu",
5420 [ALC260_ACER] = "acer",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005421 [ALC260_WILL] = "will",
5422 [ALC260_REPLACER_672V] = "replacer",
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005423#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005424 [ALC260_TEST] = "test",
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005425#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005426 [ALC260_AUTO] = "auto",
5427};
5428
5429static struct snd_pci_quirk alc260_cfg_tbl[] = {
Jonathan Woithebd869482006-11-28 11:35:52 +01005430 SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005431 SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER),
Takashi Iwai9720b712007-03-13 21:46:23 +01005432 SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013),
Takashi Iwaia8a5d062007-03-15 15:10:28 +01005433 SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_HP_3013),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005434 SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013),
Jaroslav Kysela34ec8a02008-07-10 14:49:19 +02005435 SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP_3013),
Kailang Yang3f878302008-08-26 13:02:23 +02005436 SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_DC7600),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005437 SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013),
5438 SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP),
5439 SND_PCI_QUIRK(0x103c, 0x3015, "HP", ALC260_HP),
5440 SND_PCI_QUIRK(0x103c, 0x3016, "HP", ALC260_HP),
5441 SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_BASIC),
5442 SND_PCI_QUIRK(0x104d, 0x81cc, "Sony VAIO", ALC260_BASIC),
5443 SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC),
5444 SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X),
5445 SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005446 SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_REPLACER_672V),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01005447 SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_WILL),
Takashi Iwai16ded522005-06-10 19:58:24 +02005448 {}
5449};
5450
Kailang Yangdf694da2005-12-05 19:42:22 +01005451static struct alc_config_preset alc260_presets[] = {
5452 [ALC260_BASIC] = {
5453 .mixers = { alc260_base_output_mixer,
5454 alc260_input_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005455 alc260_pc_beep_mixer },
Kailang Yangdf694da2005-12-05 19:42:22 +01005456 .init_verbs = { alc260_init_verbs },
5457 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5458 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005459 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
Kailang Yangdf694da2005-12-05 19:42:22 +01005460 .adc_nids = alc260_adc_nids,
5461 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5462 .channel_mode = alc260_modes,
5463 .input_mux = &alc260_capture_source,
5464 },
5465 [ALC260_HP] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01005466 .mixers = { alc260_hp_output_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005467 alc260_input_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01005468 .init_verbs = { alc260_init_verbs,
5469 alc260_hp_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01005470 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5471 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005472 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
5473 .adc_nids = alc260_adc_nids_alt,
Kailang Yangdf694da2005-12-05 19:42:22 +01005474 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5475 .channel_mode = alc260_modes,
5476 .input_mux = &alc260_capture_source,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005477 .unsol_event = alc260_hp_unsol_event,
5478 .init_hook = alc260_hp_automute,
Kailang Yangdf694da2005-12-05 19:42:22 +01005479 },
Kailang Yang3f878302008-08-26 13:02:23 +02005480 [ALC260_HP_DC7600] = {
5481 .mixers = { alc260_hp_dc7600_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005482 alc260_input_mixer },
Kailang Yang3f878302008-08-26 13:02:23 +02005483 .init_verbs = { alc260_init_verbs,
5484 alc260_hp_dc7600_verbs },
5485 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5486 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005487 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
5488 .adc_nids = alc260_adc_nids_alt,
Kailang Yang3f878302008-08-26 13:02:23 +02005489 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5490 .channel_mode = alc260_modes,
5491 .input_mux = &alc260_capture_source,
5492 .unsol_event = alc260_hp_3012_unsol_event,
5493 .init_hook = alc260_hp_3012_automute,
5494 },
Kailang Yangdf694da2005-12-05 19:42:22 +01005495 [ALC260_HP_3013] = {
5496 .mixers = { alc260_hp_3013_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005497 alc260_input_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01005498 .init_verbs = { alc260_hp_3013_init_verbs,
5499 alc260_hp_3013_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01005500 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5501 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005502 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
5503 .adc_nids = alc260_adc_nids_alt,
Kailang Yangdf694da2005-12-05 19:42:22 +01005504 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5505 .channel_mode = alc260_modes,
5506 .input_mux = &alc260_capture_source,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005507 .unsol_event = alc260_hp_3013_unsol_event,
5508 .init_hook = alc260_hp_3013_automute,
Kailang Yangdf694da2005-12-05 19:42:22 +01005509 },
5510 [ALC260_FUJITSU_S702X] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005511 .mixers = { alc260_fujitsu_mixer },
Kailang Yangdf694da2005-12-05 19:42:22 +01005512 .init_verbs = { alc260_fujitsu_init_verbs },
5513 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5514 .dac_nids = alc260_dac_nids,
Jonathan Woithed57fdac2006-02-28 11:38:35 +01005515 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
5516 .adc_nids = alc260_dual_adc_nids,
Kailang Yangdf694da2005-12-05 19:42:22 +01005517 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5518 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005519 .num_mux_defs = ARRAY_SIZE(alc260_fujitsu_capture_sources),
5520 .input_mux = alc260_fujitsu_capture_sources,
Kailang Yangdf694da2005-12-05 19:42:22 +01005521 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005522 [ALC260_ACER] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005523 .mixers = { alc260_acer_mixer },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005524 .init_verbs = { alc260_acer_init_verbs },
5525 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5526 .dac_nids = alc260_dac_nids,
5527 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
5528 .adc_nids = alc260_dual_adc_nids,
5529 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5530 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005531 .num_mux_defs = ARRAY_SIZE(alc260_acer_capture_sources),
5532 .input_mux = alc260_acer_capture_sources,
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005533 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005534 [ALC260_WILL] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005535 .mixers = { alc260_will_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005536 .init_verbs = { alc260_init_verbs, alc260_will_verbs },
5537 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5538 .dac_nids = alc260_dac_nids,
5539 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
5540 .adc_nids = alc260_adc_nids,
5541 .dig_out_nid = ALC260_DIGOUT_NID,
5542 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5543 .channel_mode = alc260_modes,
5544 .input_mux = &alc260_capture_source,
5545 },
5546 [ALC260_REPLACER_672V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005547 .mixers = { alc260_replacer_672v_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005548 .init_verbs = { alc260_init_verbs, alc260_replacer_672v_verbs },
5549 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5550 .dac_nids = alc260_dac_nids,
5551 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
5552 .adc_nids = alc260_adc_nids,
5553 .dig_out_nid = ALC260_DIGOUT_NID,
5554 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5555 .channel_mode = alc260_modes,
5556 .input_mux = &alc260_capture_source,
5557 .unsol_event = alc260_replacer_672v_unsol_event,
5558 .init_hook = alc260_replacer_672v_automute,
5559 },
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005560#ifdef CONFIG_SND_DEBUG
5561 [ALC260_TEST] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005562 .mixers = { alc260_test_mixer },
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005563 .init_verbs = { alc260_test_init_verbs },
5564 .num_dacs = ARRAY_SIZE(alc260_test_dac_nids),
5565 .dac_nids = alc260_test_dac_nids,
5566 .num_adc_nids = ARRAY_SIZE(alc260_test_adc_nids),
5567 .adc_nids = alc260_test_adc_nids,
5568 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5569 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005570 .num_mux_defs = ARRAY_SIZE(alc260_test_capture_sources),
5571 .input_mux = alc260_test_capture_sources,
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01005572 },
5573#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01005574};
5575
Linus Torvalds1da177e2005-04-16 15:20:36 -07005576static int patch_alc260(struct hda_codec *codec)
5577{
5578 struct alc_spec *spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01005579 int err, board_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005580
Takashi Iwaie560d8d2005-09-09 14:21:46 +02005581 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005582 if (spec == NULL)
5583 return -ENOMEM;
5584
5585 codec->spec = spec;
5586
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005587 board_config = snd_hda_check_board_config(codec, ALC260_MODEL_LAST,
5588 alc260_models,
5589 alc260_cfg_tbl);
5590 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02005591 snd_printd(KERN_INFO "hda_codec: Unknown model for ALC260, "
5592 "trying auto-probe from BIOS...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01005593 board_config = ALC260_AUTO;
Takashi Iwai16ded522005-06-10 19:58:24 +02005594 }
5595
Kailang Yangdf694da2005-12-05 19:42:22 +01005596 if (board_config == ALC260_AUTO) {
5597 /* automatic parse from the BIOS config */
5598 err = alc260_parse_auto_config(codec);
5599 if (err < 0) {
5600 alc_free(codec);
5601 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005602 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02005603 printk(KERN_INFO
5604 "hda_codec: Cannot set up configuration "
5605 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01005606 board_config = ALC260_BASIC;
5607 }
Takashi Iwai16ded522005-06-10 19:58:24 +02005608 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005609
Kailang Yangdf694da2005-12-05 19:42:22 +01005610 if (board_config != ALC260_AUTO)
5611 setup_preset(spec, &alc260_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005612
5613 spec->stream_name_analog = "ALC260 Analog";
5614 spec->stream_analog_playback = &alc260_pcm_analog_playback;
5615 spec->stream_analog_capture = &alc260_pcm_analog_capture;
5616
Takashi Iwaia3bcba32005-12-06 19:05:29 +01005617 spec->stream_name_digital = "ALC260 Digital";
5618 spec->stream_digital_playback = &alc260_pcm_digital_playback;
5619 spec->stream_digital_capture = &alc260_pcm_digital_capture;
5620
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005621 set_capture_mixer(spec);
5622
Takashi Iwai2134ea42008-01-10 16:53:55 +01005623 spec->vmaster_nid = 0x08;
5624
Linus Torvalds1da177e2005-04-16 15:20:36 -07005625 codec->patch_ops = alc_patch_ops;
Kailang Yangdf694da2005-12-05 19:42:22 +01005626 if (board_config == ALC260_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005627 spec->init_hook = alc260_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02005628#ifdef CONFIG_SND_HDA_POWER_SAVE
5629 if (!spec->loopback.amplist)
5630 spec->loopback.amplist = alc260_loopbacks;
5631#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005632
5633 return 0;
5634}
5635
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005636
Linus Torvalds1da177e2005-04-16 15:20:36 -07005637/*
5638 * ALC882 support
5639 *
5640 * ALC882 is almost identical with ALC880 but has cleaner and more flexible
5641 * configuration. Each pin widget can choose any input DACs and a mixer.
5642 * Each ADC is connected from a mixer of all inputs. This makes possible
5643 * 6-channel independent captures.
5644 *
5645 * In addition, an independent DAC for the multi-playback (not used in this
5646 * driver yet).
5647 */
Kailang Yangdf694da2005-12-05 19:42:22 +01005648#define ALC882_DIGOUT_NID 0x06
5649#define ALC882_DIGIN_NID 0x0a
Linus Torvalds1da177e2005-04-16 15:20:36 -07005650
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01005651static struct hda_channel_mode alc882_ch_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005652 { 8, NULL }
5653};
5654
5655static hda_nid_t alc882_dac_nids[4] = {
5656 /* front, rear, clfe, rear_surr */
5657 0x02, 0x03, 0x04, 0x05
5658};
5659
Kailang Yangdf694da2005-12-05 19:42:22 +01005660/* identical with ALC880 */
5661#define alc882_adc_nids alc880_adc_nids
5662#define alc882_adc_nids_alt alc880_adc_nids_alt
Linus Torvalds1da177e2005-04-16 15:20:36 -07005663
Takashi Iwaie1406342008-02-11 18:32:32 +01005664static hda_nid_t alc882_capsrc_nids[3] = { 0x24, 0x23, 0x22 };
5665static hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 };
5666
Linus Torvalds1da177e2005-04-16 15:20:36 -07005667/* input MUX */
5668/* FIXME: should be a matrix-type input source selection */
5669
5670static struct hda_input_mux alc882_capture_source = {
5671 .num_items = 4,
5672 .items = {
5673 { "Mic", 0x0 },
5674 { "Front Mic", 0x1 },
5675 { "Line", 0x2 },
5676 { "CD", 0x4 },
5677 },
5678};
Kailang Yangdf694da2005-12-05 19:42:22 +01005679/*
Kailang Yang272a5272007-05-14 11:00:38 +02005680 * 2ch mode
5681 */
5682static struct hda_verb alc882_3ST_ch2_init[] = {
5683 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
5684 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
5685 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
5686 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
5687 { } /* end */
5688};
5689
5690/*
5691 * 6ch mode
5692 */
5693static struct hda_verb alc882_3ST_ch6_init[] = {
5694 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5695 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
5696 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
5697 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5698 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
5699 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
5700 { } /* end */
5701};
5702
5703static struct hda_channel_mode alc882_3ST_6ch_modes[2] = {
5704 { 2, alc882_3ST_ch2_init },
5705 { 6, alc882_3ST_ch6_init },
5706};
5707
5708/*
Kailang Yangdf694da2005-12-05 19:42:22 +01005709 * 6ch mode
5710 */
5711static struct hda_verb alc882_sixstack_ch6_init[] = {
5712 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
5713 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5714 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5715 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5716 { } /* end */
5717};
5718
5719/*
5720 * 8ch mode
5721 */
5722static struct hda_verb alc882_sixstack_ch8_init[] = {
5723 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5724 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5725 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5726 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5727 { } /* end */
5728};
5729
5730static struct hda_channel_mode alc882_sixstack_modes[2] = {
5731 { 6, alc882_sixstack_ch6_init },
5732 { 8, alc882_sixstack_ch8_init },
5733};
5734
Takashi Iwai87350ad2007-08-16 18:19:38 +02005735/*
5736 * macbook pro ALC885 can switch LineIn to LineOut without loosing Mic
5737 */
5738
5739/*
5740 * 2ch mode
5741 */
5742static struct hda_verb alc885_mbp_ch2_init[] = {
5743 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
5744 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5745 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5746 { } /* end */
5747};
5748
5749/*
5750 * 6ch mode
5751 */
5752static struct hda_verb alc885_mbp_ch6_init[] = {
5753 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5754 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5755 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
5756 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5757 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5758 { } /* end */
5759};
5760
5761static struct hda_channel_mode alc885_mbp_6ch_modes[2] = {
5762 { 2, alc885_mbp_ch2_init },
5763 { 6, alc885_mbp_ch6_init },
5764};
5765
5766
Linus Torvalds1da177e2005-04-16 15:20:36 -07005767/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
5768 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
5769 */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01005770static struct snd_kcontrol_new alc882_base_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02005771 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005772 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02005773 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005774 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02005775 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
5776 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005777 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
5778 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02005779 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005780 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005781 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
5782 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5783 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5784 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5785 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5786 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01005787 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005788 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
5789 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01005790 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005791 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
5792 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
5793 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005794 { } /* end */
5795};
5796
Takashi Iwai87350ad2007-08-16 18:19:38 +02005797static struct snd_kcontrol_new alc885_mbp3_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01005798 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
5799 HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
5800 HDA_CODEC_MUTE ("Speaker Playback Switch", 0x14, 0x00, HDA_OUTPUT),
5801 HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
5802 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5803 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02005804 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
5805 HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01005806 HDA_CODEC_VOLUME("Line Boost", 0x1a, 0x00, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02005807 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT),
5808 { } /* end */
5809};
Kailang Yangbdd148a2007-05-08 15:19:08 +02005810static struct snd_kcontrol_new alc882_w2jc_mixer[] = {
5811 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5812 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
5813 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5814 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5815 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5816 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5817 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5818 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
5819 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
5820 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
5821 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
5822 { } /* end */
5823};
5824
Kailang Yang272a5272007-05-14 11:00:38 +02005825static struct snd_kcontrol_new alc882_targa_mixer[] = {
5826 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5827 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
5828 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
5829 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5830 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5831 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5832 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5833 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5834 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai96fe7cc82007-09-07 10:57:44 +02005835 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02005836 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
5837 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai96fe7cc82007-09-07 10:57:44 +02005838 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02005839 { } /* end */
5840};
5841
5842/* Pin assignment: Front=0x14, HP = 0x15, Front = 0x16, ???
5843 * Front Mic=0x18, Line In = 0x1a, Line In = 0x1b, CD = 0x1c
5844 */
5845static struct snd_kcontrol_new alc882_asus_a7j_mixer[] = {
5846 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5847 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
5848 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
5849 HDA_CODEC_MUTE("Mobile Front Playback Switch", 0x16, 0x0, HDA_OUTPUT),
5850 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5851 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5852 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5853 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5854 HDA_CODEC_VOLUME("Mobile Line Playback Volume", 0x0b, 0x03, HDA_INPUT),
5855 HDA_CODEC_MUTE("Mobile Line Playback Switch", 0x0b, 0x03, HDA_INPUT),
5856 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5857 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai96fe7cc82007-09-07 10:57:44 +02005858 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02005859 { } /* end */
5860};
5861
Takashi Iwai914759b2007-09-06 14:52:04 +02005862static struct snd_kcontrol_new alc882_asus_a7m_mixer[] = {
5863 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5864 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
5865 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
5866 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5867 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5868 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5869 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5870 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5871 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
5872 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
5873 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
5874 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
5875 { } /* end */
5876};
5877
Kailang Yangdf694da2005-12-05 19:42:22 +01005878static struct snd_kcontrol_new alc882_chmode_mixer[] = {
5879 {
5880 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5881 .name = "Channel Mode",
5882 .info = alc_ch_mode_info,
5883 .get = alc_ch_mode_get,
5884 .put = alc_ch_mode_put,
5885 },
5886 { } /* end */
5887};
5888
Linus Torvalds1da177e2005-04-16 15:20:36 -07005889static struct hda_verb alc882_init_verbs[] = {
5890 /* Front mixer: unmute input/output amp left and right (volume = 0) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005891 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5892 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5893 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005894 /* Rear mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02005895 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5896 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5897 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005898 /* CLFE mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02005899 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5900 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5901 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005902 /* Side mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02005903 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5904 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5905 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005906
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005907 /* Front Pin: output 0 (0x0c) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005908 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02005909 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005910 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005911 /* Rear Pin: output 1 (0x0d) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005912 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02005913 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005914 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005915 /* CLFE Pin: output 2 (0x0e) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005916 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02005917 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005918 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005919 /* Side Pin: output 3 (0x0f) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005920 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02005921 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005922 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005923 /* Mic (rear) pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02005924 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005925 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5926 /* Front Mic pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02005927 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005928 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5929 /* Line In pin: input */
Takashi Iwai05acb862005-06-10 19:50:25 +02005930 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005931 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5932 /* Line-2 In: Headphone output (output 0 - 0x0c) */
5933 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5934 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5935 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005936 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02005937 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005938
5939 /* FIXME: use matrix-type input source selection */
5940 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
5941 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
Takashi Iwai05acb862005-06-10 19:50:25 +02005942 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5943 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5944 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5945 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005946 /* Input mixer2 */
Takashi Iwai05acb862005-06-10 19:50:25 +02005947 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5948 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5949 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5950 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005951 /* Input mixer3 */
Takashi Iwai05acb862005-06-10 19:50:25 +02005952 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5953 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5954 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5955 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5956 /* ADC1: mute amp left and right */
5957 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02005958 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02005959 /* ADC2: mute amp left and right */
5960 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02005961 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02005962 /* ADC3: mute amp left and right */
5963 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02005964 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005965
5966 { }
5967};
5968
Takashi Iwai4b146cb2006-07-28 14:42:36 +02005969static struct hda_verb alc882_eapd_verbs[] = {
5970 /* change to EAPD mode */
5971 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01005972 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005973 { }
Takashi Iwai4b146cb2006-07-28 14:42:36 +02005974};
5975
Tobin Davis9102cd12006-12-15 10:02:12 +01005976/* Mac Pro test */
5977static struct snd_kcontrol_new alc882_macpro_mixer[] = {
5978 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5979 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
5980 HDA_CODEC_MUTE("Headphone Playback Switch", 0x18, 0x0, HDA_OUTPUT),
5981 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
5982 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
5983 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x02, HDA_INPUT),
5984 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x02, HDA_INPUT),
5985 { } /* end */
5986};
5987
5988static struct hda_verb alc882_macpro_init_verbs[] = {
5989 /* Front mixer: unmute input/output amp left and right (volume = 0) */
5990 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5991 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5992 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5993 /* Front Pin: output 0 (0x0c) */
5994 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5995 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5996 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
5997 /* Front Mic pin: input vref at 80% */
5998 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
5999 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6000 /* Speaker: output */
6001 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6002 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6003 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x04},
6004 /* Headphone output (output 0 - 0x0c) */
6005 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6006 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6007 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
6008
6009 /* FIXME: use matrix-type input source selection */
6010 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
6011 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
6012 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6013 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6014 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6015 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6016 /* Input mixer2 */
6017 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6018 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6019 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6020 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6021 /* Input mixer3 */
6022 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6023 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6024 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6025 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6026 /* ADC1: mute amp left and right */
6027 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6028 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
6029 /* ADC2: mute amp left and right */
6030 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6031 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
6032 /* ADC3: mute amp left and right */
6033 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6034 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
6035
6036 { }
6037};
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006038
Takashi Iwai87350ad2007-08-16 18:19:38 +02006039/* Macbook Pro rev3 */
6040static struct hda_verb alc885_mbp3_init_verbs[] = {
6041 /* Front mixer: unmute input/output amp left and right (volume = 0) */
6042 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6043 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6044 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6045 /* Rear mixer */
6046 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6047 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6048 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6049 /* Front Pin: output 0 (0x0c) */
6050 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6051 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6052 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
6053 /* HP Pin: output 0 (0x0d) */
6054 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
6055 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6056 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
6057 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
6058 /* Mic (rear) pin: input vref at 80% */
6059 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
6060 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6061 /* Front Mic pin: input vref at 80% */
6062 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
6063 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6064 /* Line In pin: use output 1 when in LineOut mode */
6065 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
6066 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6067 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
6068
6069 /* FIXME: use matrix-type input source selection */
6070 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
6071 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
6072 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6073 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6074 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6075 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6076 /* Input mixer2 */
6077 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6078 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6079 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6080 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6081 /* Input mixer3 */
6082 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6083 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6084 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6085 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6086 /* ADC1: mute amp left and right */
6087 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6088 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
6089 /* ADC2: mute amp left and right */
6090 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6091 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
6092 /* ADC3: mute amp left and right */
6093 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6094 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
6095
6096 { }
6097};
6098
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006099/* iMac 24 mixer. */
6100static struct snd_kcontrol_new alc885_imac24_mixer[] = {
6101 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
6102 HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x00, HDA_INPUT),
6103 { } /* end */
6104};
6105
6106/* iMac 24 init verbs. */
6107static struct hda_verb alc885_imac24_init_verbs[] = {
6108 /* Internal speakers: output 0 (0x0c) */
6109 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6110 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6111 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
6112 /* Internal speakers: output 0 (0x0c) */
6113 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6114 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6115 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
6116 /* Headphone: output 0 (0x0c) */
6117 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6118 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6119 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
6120 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
6121 /* Front Mic: input vref at 80% */
6122 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
6123 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6124 { }
6125};
6126
6127/* Toggle speaker-output according to the hp-jack state */
6128static void alc885_imac24_automute(struct hda_codec *codec)
6129{
6130 unsigned int present;
6131
6132 present = snd_hda_codec_read(codec, 0x14, 0,
6133 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02006134 snd_hda_codec_amp_stereo(codec, 0x18, HDA_OUTPUT, 0,
6135 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
6136 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0,
6137 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006138}
6139
6140/* Processes unsolicited events. */
6141static void alc885_imac24_unsol_event(struct hda_codec *codec,
6142 unsigned int res)
6143{
6144 /* Headphone insertion or removal. */
6145 if ((res >> 26) == ALC880_HP_EVENT)
6146 alc885_imac24_automute(codec);
6147}
6148
Takashi Iwai87350ad2007-08-16 18:19:38 +02006149static void alc885_mbp3_automute(struct hda_codec *codec)
6150{
6151 unsigned int present;
6152
6153 present = snd_hda_codec_read(codec, 0x15, 0,
6154 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
6155 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
6156 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
6157 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
6158 HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE);
6159
6160}
6161static void alc885_mbp3_unsol_event(struct hda_codec *codec,
6162 unsigned int res)
6163{
6164 /* Headphone insertion or removal. */
6165 if ((res >> 26) == ALC880_HP_EVENT)
6166 alc885_mbp3_automute(codec);
6167}
6168
6169
Kailang Yang272a5272007-05-14 11:00:38 +02006170static struct hda_verb alc882_targa_verbs[] = {
6171 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6172 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6173
6174 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6175 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02006176
Kailang Yang272a5272007-05-14 11:00:38 +02006177 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
6178 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
6179 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
6180
6181 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
6182 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
6183 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
6184 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
6185 { } /* end */
6186};
6187
6188/* toggle speaker-output according to the hp-jack state */
6189static void alc882_targa_automute(struct hda_codec *codec)
6190{
6191 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02006192
Kailang Yang272a5272007-05-14 11:00:38 +02006193 present = snd_hda_codec_read(codec, 0x14, 0,
6194 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02006195 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
6196 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02006197 snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
6198 present ? 1 : 3);
Kailang Yang272a5272007-05-14 11:00:38 +02006199}
6200
6201static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res)
6202{
6203 /* Looks like the unsol event is incompatible with the standard
6204 * definition. 4bit tag is placed at 26 bit!
6205 */
6206 if (((res >> 26) == ALC880_HP_EVENT)) {
6207 alc882_targa_automute(codec);
6208 }
6209}
6210
6211static struct hda_verb alc882_asus_a7j_verbs[] = {
6212 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6213 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6214
6215 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6216 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6217 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02006218
Kailang Yang272a5272007-05-14 11:00:38 +02006219 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
6220 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
6221 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
6222
6223 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
6224 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
6225 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
6226 { } /* end */
6227};
6228
Takashi Iwai914759b2007-09-06 14:52:04 +02006229static struct hda_verb alc882_asus_a7m_verbs[] = {
6230 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6231 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6232
6233 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6234 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6235 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02006236
Takashi Iwai914759b2007-09-06 14:52:04 +02006237 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
6238 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
6239 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
6240
6241 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
6242 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
6243 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
6244 { } /* end */
6245};
6246
Tobin Davis9102cd12006-12-15 10:02:12 +01006247static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted)
6248{
6249 unsigned int gpiostate, gpiomask, gpiodir;
6250
6251 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
6252 AC_VERB_GET_GPIO_DATA, 0);
6253
6254 if (!muted)
6255 gpiostate |= (1 << pin);
6256 else
6257 gpiostate &= ~(1 << pin);
6258
6259 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
6260 AC_VERB_GET_GPIO_MASK, 0);
6261 gpiomask |= (1 << pin);
6262
6263 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
6264 AC_VERB_GET_GPIO_DIRECTION, 0);
6265 gpiodir |= (1 << pin);
6266
6267
6268 snd_hda_codec_write(codec, codec->afg, 0,
6269 AC_VERB_SET_GPIO_MASK, gpiomask);
6270 snd_hda_codec_write(codec, codec->afg, 0,
6271 AC_VERB_SET_GPIO_DIRECTION, gpiodir);
6272
6273 msleep(1);
6274
6275 snd_hda_codec_write(codec, codec->afg, 0,
6276 AC_VERB_SET_GPIO_DATA, gpiostate);
6277}
6278
Takashi Iwai7debbe52007-08-16 15:01:03 +02006279/* set up GPIO at initialization */
6280static void alc885_macpro_init_hook(struct hda_codec *codec)
6281{
6282 alc882_gpio_mute(codec, 0, 0);
6283 alc882_gpio_mute(codec, 1, 0);
6284}
6285
6286/* set up GPIO and update auto-muting at initialization */
6287static void alc885_imac24_init_hook(struct hda_codec *codec)
6288{
6289 alc885_macpro_init_hook(codec);
6290 alc885_imac24_automute(codec);
6291}
6292
Kailang Yangdf694da2005-12-05 19:42:22 +01006293/*
6294 * generic initialization of ADC, input mixers and output mixers
6295 */
6296static struct hda_verb alc882_auto_init_verbs[] = {
6297 /*
6298 * Unmute ADC0-2 and set the default input to mic-in
6299 */
6300 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
6301 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6302 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
6303 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6304 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
6305 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6306
Takashi Iwaicb53c622007-08-10 17:21:45 +02006307 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +01006308 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006309 * Note: PASD motherboards uses the Line In 2 as the input for
6310 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01006311 */
6312 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02006313 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6314 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6315 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6316 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6317 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01006318
6319 /*
6320 * Set up output mixers (0x0c - 0x0f)
6321 */
6322 /* set vol=0 to output mixers */
6323 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6324 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6325 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6326 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6327 /* set up input amps for analog loopback */
6328 /* Amp Indices: DAC = 0, mixer = 1 */
6329 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6330 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6331 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6332 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6333 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6334 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6335 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6336 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6337 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6338 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6339
6340 /* FIXME: use matrix-type input source selection */
6341 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
6342 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
6343 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6344 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
6345 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
6346 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
6347 /* Input mixer2 */
6348 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6349 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
6350 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
6351 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
6352 /* Input mixer3 */
6353 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6354 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
6355 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
6356 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
6357
6358 { }
6359};
6360
Takashi Iwaicb53c622007-08-10 17:21:45 +02006361#ifdef CONFIG_SND_HDA_POWER_SAVE
6362#define alc882_loopbacks alc880_loopbacks
6363#endif
6364
Kailang Yangdf694da2005-12-05 19:42:22 +01006365/* pcm configuration: identiacal with ALC880 */
6366#define alc882_pcm_analog_playback alc880_pcm_analog_playback
6367#define alc882_pcm_analog_capture alc880_pcm_analog_capture
6368#define alc882_pcm_digital_playback alc880_pcm_digital_playback
6369#define alc882_pcm_digital_capture alc880_pcm_digital_capture
6370
6371/*
6372 * configuration and preset
6373 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006374static const char *alc882_models[ALC882_MODEL_LAST] = {
6375 [ALC882_3ST_DIG] = "3stack-dig",
6376 [ALC882_6ST_DIG] = "6stack-dig",
6377 [ALC882_ARIMA] = "arima",
Kailang Yangbdd148a2007-05-08 15:19:08 +02006378 [ALC882_W2JC] = "w2jc",
Takashi Iwai0438a002007-09-06 14:54:11 +02006379 [ALC882_TARGA] = "targa",
6380 [ALC882_ASUS_A7J] = "asus-a7j",
6381 [ALC882_ASUS_A7M] = "asus-a7m",
Tobin Davis9102cd12006-12-15 10:02:12 +01006382 [ALC885_MACPRO] = "macpro",
Takashi Iwai87350ad2007-08-16 18:19:38 +02006383 [ALC885_MBP3] = "mbp3",
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006384 [ALC885_IMAC24] = "imac24",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006385 [ALC882_AUTO] = "auto",
6386};
6387
6388static struct snd_pci_quirk alc882_cfg_tbl[] = {
6389 SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG),
Kailang Yang272a5272007-05-14 11:00:38 +02006390 SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J),
Kailang Yangac8842a2007-09-20 12:51:39 +02006391 SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J),
Takashi Iwai914759b2007-09-06 14:52:04 +02006392 SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01006393 SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC),
Claudio Matsuokac5d9f1c2007-07-19 23:18:32 +02006394 SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG),
Tobin Davis7b9470d2006-12-28 13:56:48 +01006395 SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01006396 SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG),
Jiang zhe44447042008-01-28 12:28:24 +01006397 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01006398 SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */
6399 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG),
6400 SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA),
Kailang Yangdf694da2005-12-05 19:42:22 +01006401 {}
6402};
6403
6404static struct alc_config_preset alc882_presets[] = {
6405 [ALC882_3ST_DIG] = {
6406 .mixers = { alc882_base_mixer },
6407 .init_verbs = { alc882_init_verbs },
6408 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6409 .dac_nids = alc882_dac_nids,
6410 .dig_out_nid = ALC882_DIGOUT_NID,
Kailang Yangdf694da2005-12-05 19:42:22 +01006411 .dig_in_nid = ALC882_DIGIN_NID,
6412 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
6413 .channel_mode = alc882_ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02006414 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01006415 .input_mux = &alc882_capture_source,
6416 },
6417 [ALC882_6ST_DIG] = {
6418 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
6419 .init_verbs = { alc882_init_verbs },
6420 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6421 .dac_nids = alc882_dac_nids,
6422 .dig_out_nid = ALC882_DIGOUT_NID,
Kailang Yangdf694da2005-12-05 19:42:22 +01006423 .dig_in_nid = ALC882_DIGIN_NID,
6424 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
6425 .channel_mode = alc882_sixstack_modes,
6426 .input_mux = &alc882_capture_source,
6427 },
Takashi Iwai4b146cb2006-07-28 14:42:36 +02006428 [ALC882_ARIMA] = {
6429 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
6430 .init_verbs = { alc882_init_verbs, alc882_eapd_verbs },
6431 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6432 .dac_nids = alc882_dac_nids,
6433 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
6434 .channel_mode = alc882_sixstack_modes,
6435 .input_mux = &alc882_capture_source,
6436 },
Kailang Yangbdd148a2007-05-08 15:19:08 +02006437 [ALC882_W2JC] = {
6438 .mixers = { alc882_w2jc_mixer, alc882_chmode_mixer },
6439 .init_verbs = { alc882_init_verbs, alc882_eapd_verbs,
6440 alc880_gpio1_init_verbs },
6441 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6442 .dac_nids = alc882_dac_nids,
6443 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
6444 .channel_mode = alc880_threestack_modes,
6445 .need_dac_fix = 1,
6446 .input_mux = &alc882_capture_source,
6447 .dig_out_nid = ALC882_DIGOUT_NID,
6448 },
Takashi Iwai87350ad2007-08-16 18:19:38 +02006449 [ALC885_MBP3] = {
6450 .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer },
6451 .init_verbs = { alc885_mbp3_init_verbs,
6452 alc880_gpio1_init_verbs },
6453 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6454 .dac_nids = alc882_dac_nids,
6455 .channel_mode = alc885_mbp_6ch_modes,
6456 .num_channel_mode = ARRAY_SIZE(alc885_mbp_6ch_modes),
6457 .input_mux = &alc882_capture_source,
6458 .dig_out_nid = ALC882_DIGOUT_NID,
6459 .dig_in_nid = ALC882_DIGIN_NID,
6460 .unsol_event = alc885_mbp3_unsol_event,
6461 .init_hook = alc885_mbp3_automute,
6462 },
Tobin Davis9102cd12006-12-15 10:02:12 +01006463 [ALC885_MACPRO] = {
6464 .mixers = { alc882_macpro_mixer },
6465 .init_verbs = { alc882_macpro_init_verbs },
6466 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6467 .dac_nids = alc882_dac_nids,
6468 .dig_out_nid = ALC882_DIGOUT_NID,
6469 .dig_in_nid = ALC882_DIGIN_NID,
6470 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
6471 .channel_mode = alc882_ch_modes,
6472 .input_mux = &alc882_capture_source,
Takashi Iwai7debbe52007-08-16 15:01:03 +02006473 .init_hook = alc885_macpro_init_hook,
Tobin Davis9102cd12006-12-15 10:02:12 +01006474 },
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006475 [ALC885_IMAC24] = {
6476 .mixers = { alc885_imac24_mixer },
6477 .init_verbs = { alc885_imac24_init_verbs },
6478 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6479 .dac_nids = alc882_dac_nids,
6480 .dig_out_nid = ALC882_DIGOUT_NID,
6481 .dig_in_nid = ALC882_DIGIN_NID,
6482 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
6483 .channel_mode = alc882_ch_modes,
6484 .input_mux = &alc882_capture_source,
6485 .unsol_event = alc885_imac24_unsol_event,
Takashi Iwai7debbe52007-08-16 15:01:03 +02006486 .init_hook = alc885_imac24_init_hook,
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006487 },
Kailang Yang272a5272007-05-14 11:00:38 +02006488 [ALC882_TARGA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006489 .mixers = { alc882_targa_mixer, alc882_chmode_mixer },
Kailang Yang272a5272007-05-14 11:00:38 +02006490 .init_verbs = { alc882_init_verbs, alc882_targa_verbs},
6491 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6492 .dac_nids = alc882_dac_nids,
6493 .dig_out_nid = ALC882_DIGOUT_NID,
6494 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
6495 .adc_nids = alc882_adc_nids,
Takashi Iwaie1406342008-02-11 18:32:32 +01006496 .capsrc_nids = alc882_capsrc_nids,
Kailang Yang272a5272007-05-14 11:00:38 +02006497 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
6498 .channel_mode = alc882_3ST_6ch_modes,
6499 .need_dac_fix = 1,
6500 .input_mux = &alc882_capture_source,
6501 .unsol_event = alc882_targa_unsol_event,
6502 .init_hook = alc882_targa_automute,
6503 },
6504 [ALC882_ASUS_A7J] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006505 .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer },
Kailang Yang272a5272007-05-14 11:00:38 +02006506 .init_verbs = { alc882_init_verbs, alc882_asus_a7j_verbs},
6507 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6508 .dac_nids = alc882_dac_nids,
6509 .dig_out_nid = ALC882_DIGOUT_NID,
6510 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
6511 .adc_nids = alc882_adc_nids,
Takashi Iwaie1406342008-02-11 18:32:32 +01006512 .capsrc_nids = alc882_capsrc_nids,
Kailang Yang272a5272007-05-14 11:00:38 +02006513 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
6514 .channel_mode = alc882_3ST_6ch_modes,
6515 .need_dac_fix = 1,
6516 .input_mux = &alc882_capture_source,
Kailang Yangea1fb292008-08-26 12:58:38 +02006517 },
Takashi Iwai914759b2007-09-06 14:52:04 +02006518 [ALC882_ASUS_A7M] = {
6519 .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer },
6520 .init_verbs = { alc882_init_verbs, alc882_eapd_verbs,
6521 alc880_gpio1_init_verbs,
6522 alc882_asus_a7m_verbs },
6523 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6524 .dac_nids = alc882_dac_nids,
6525 .dig_out_nid = ALC882_DIGOUT_NID,
6526 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
6527 .channel_mode = alc880_threestack_modes,
6528 .need_dac_fix = 1,
6529 .input_mux = &alc882_capture_source,
Kailang Yangea1fb292008-08-26 12:58:38 +02006530 },
Kailang Yangdf694da2005-12-05 19:42:22 +01006531};
6532
6533
6534/*
Takashi Iwaif95474e2007-07-10 00:47:43 +02006535 * Pin config fixes
6536 */
Kailang Yangea1fb292008-08-26 12:58:38 +02006537enum {
Takashi Iwaif95474e2007-07-10 00:47:43 +02006538 PINFIX_ABIT_AW9D_MAX
6539};
6540
6541static struct alc_pincfg alc882_abit_aw9d_pinfix[] = {
6542 { 0x15, 0x01080104 }, /* side */
6543 { 0x16, 0x01011012 }, /* rear */
6544 { 0x17, 0x01016011 }, /* clfe */
6545 { }
6546};
6547
6548static const struct alc_pincfg *alc882_pin_fixes[] = {
6549 [PINFIX_ABIT_AW9D_MAX] = alc882_abit_aw9d_pinfix,
6550};
6551
6552static struct snd_pci_quirk alc882_pinfix_tbl[] = {
6553 SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
6554 {}
6555};
6556
6557/*
Kailang Yangdf694da2005-12-05 19:42:22 +01006558 * BIOS auto configuration
6559 */
6560static void alc882_auto_set_output_and_unmute(struct hda_codec *codec,
6561 hda_nid_t nid, int pin_type,
6562 int dac_idx)
6563{
6564 /* set as output */
6565 struct alc_spec *spec = codec->spec;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006566 int idx;
6567
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006568 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01006569 if (spec->multiout.dac_nids[dac_idx] == 0x25)
6570 idx = 4;
6571 else
6572 idx = spec->multiout.dac_nids[dac_idx] - 2;
Kailang Yangdf694da2005-12-05 19:42:22 +01006573 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
6574
6575}
6576
6577static void alc882_auto_init_multi_out(struct hda_codec *codec)
6578{
6579 struct alc_spec *spec = codec->spec;
6580 int i;
6581
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006582 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Kailang Yangdf694da2005-12-05 19:42:22 +01006583 for (i = 0; i <= HDA_SIDE; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006584 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02006585 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01006586 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02006587 alc882_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006588 i);
Kailang Yangdf694da2005-12-05 19:42:22 +01006589 }
6590}
6591
6592static void alc882_auto_init_hp_out(struct hda_codec *codec)
6593{
6594 struct alc_spec *spec = codec->spec;
6595 hda_nid_t pin;
6596
Takashi Iwaieb06ed82006-09-20 17:10:27 +02006597 pin = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006598 if (pin) /* connect to front */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006599 /* use dac 0 */
6600 alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006601 pin = spec->autocfg.speaker_pins[0];
6602 if (pin)
6603 alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Kailang Yangdf694da2005-12-05 19:42:22 +01006604}
6605
6606#define alc882_is_input_pin(nid) alc880_is_input_pin(nid)
6607#define ALC882_PIN_CD_NID ALC880_PIN_CD_NID
6608
6609static void alc882_auto_init_analog_input(struct hda_codec *codec)
6610{
6611 struct alc_spec *spec = codec->spec;
6612 int i;
6613
6614 for (i = 0; i < AUTO_PIN_LAST; i++) {
6615 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwai7194cae2008-03-06 16:58:17 +01006616 unsigned int vref;
6617 if (!nid)
6618 continue;
6619 vref = PIN_IN;
6620 if (1 /*i <= AUTO_PIN_FRONT_MIC*/) {
Kailang Yang531240f2008-05-27 12:10:25 +02006621 unsigned int pincap;
6622 pincap = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
6623 if ((pincap >> AC_PINCAP_VREF_SHIFT) &
Takashi Iwai7194cae2008-03-06 16:58:17 +01006624 AC_PINCAP_VREF_80)
6625 vref = PIN_VREF80;
Kailang Yangdf694da2005-12-05 19:42:22 +01006626 }
Takashi Iwai7194cae2008-03-06 16:58:17 +01006627 snd_hda_codec_write(codec, nid, 0,
6628 AC_VERB_SET_PIN_WIDGET_CONTROL, vref);
6629 if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
6630 snd_hda_codec_write(codec, nid, 0,
6631 AC_VERB_SET_AMP_GAIN_MUTE,
6632 AMP_OUT_MUTE);
Kailang Yangdf694da2005-12-05 19:42:22 +01006633 }
6634}
6635
Takashi Iwaif511b012008-08-15 16:46:42 +02006636static void alc882_auto_init_input_src(struct hda_codec *codec)
6637{
6638 struct alc_spec *spec = codec->spec;
6639 const struct hda_input_mux *imux = spec->input_mux;
6640 int c;
6641
6642 for (c = 0; c < spec->num_adc_nids; c++) {
6643 hda_nid_t conn_list[HDA_MAX_NUM_INPUTS];
6644 hda_nid_t nid = spec->capsrc_nids[c];
6645 int conns, mute, idx, item;
6646
6647 conns = snd_hda_get_connections(codec, nid, conn_list,
6648 ARRAY_SIZE(conn_list));
6649 if (conns < 0)
6650 continue;
6651 for (idx = 0; idx < conns; idx++) {
6652 /* if the current connection is the selected one,
6653 * unmute it as default - otherwise mute it
6654 */
6655 mute = AMP_IN_MUTE(idx);
6656 for (item = 0; item < imux->num_items; item++) {
6657 if (imux->items[item].index == idx) {
6658 if (spec->cur_mux[c] == item)
6659 mute = AMP_IN_UNMUTE(idx);
6660 break;
6661 }
6662 }
6663 snd_hda_codec_write(codec, nid, 0,
6664 AC_VERB_SET_AMP_GAIN_MUTE, mute);
6665 }
6666 }
6667}
6668
Takashi Iwai776e1842007-08-29 15:07:11 +02006669/* add mic boosts if needed */
6670static int alc_auto_add_mic_boost(struct hda_codec *codec)
6671{
6672 struct alc_spec *spec = codec->spec;
6673 int err;
6674 hda_nid_t nid;
6675
6676 nid = spec->autocfg.input_pins[AUTO_PIN_MIC];
Takashi Iwaice22e032008-01-11 17:38:35 +01006677 if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
Takashi Iwai776e1842007-08-29 15:07:11 +02006678 err = add_control(spec, ALC_CTL_WIDGET_VOL,
6679 "Mic Boost",
6680 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
6681 if (err < 0)
6682 return err;
6683 }
6684 nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC];
Takashi Iwaice22e032008-01-11 17:38:35 +01006685 if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
Takashi Iwai776e1842007-08-29 15:07:11 +02006686 err = add_control(spec, ALC_CTL_WIDGET_VOL,
6687 "Front Mic Boost",
6688 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
6689 if (err < 0)
6690 return err;
6691 }
6692 return 0;
6693}
6694
Kailang Yangdf694da2005-12-05 19:42:22 +01006695/* almost identical with ALC880 parser... */
6696static int alc882_parse_auto_config(struct hda_codec *codec)
6697{
6698 struct alc_spec *spec = codec->spec;
6699 int err = alc880_parse_auto_config(codec);
6700
6701 if (err < 0)
6702 return err;
Takashi Iwai776e1842007-08-29 15:07:11 +02006703 else if (!err)
6704 return 0; /* no config found */
6705
6706 err = alc_auto_add_mic_boost(codec);
6707 if (err < 0)
6708 return err;
6709
6710 /* hack - override the init verbs */
6711 spec->init_verbs[0] = alc882_auto_init_verbs;
6712
6713 return 1; /* config found */
Kailang Yangdf694da2005-12-05 19:42:22 +01006714}
6715
Takashi Iwaiae6b8132006-03-03 16:47:17 +01006716/* additional initialization for auto-configuration model */
6717static void alc882_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01006718{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006719 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01006720 alc882_auto_init_multi_out(codec);
6721 alc882_auto_init_hp_out(codec);
6722 alc882_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +02006723 alc882_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006724 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02006725 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01006726}
6727
Takashi Iwai7943a8a2008-04-16 17:29:09 +02006728static int patch_alc883(struct hda_codec *codec); /* called in patch_alc882() */
6729
Linus Torvalds1da177e2005-04-16 15:20:36 -07006730static int patch_alc882(struct hda_codec *codec)
6731{
6732 struct alc_spec *spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01006733 int err, board_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006734
Takashi Iwaie560d8d2005-09-09 14:21:46 +02006735 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006736 if (spec == NULL)
6737 return -ENOMEM;
6738
Linus Torvalds1da177e2005-04-16 15:20:36 -07006739 codec->spec = spec;
6740
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006741 board_config = snd_hda_check_board_config(codec, ALC882_MODEL_LAST,
6742 alc882_models,
6743 alc882_cfg_tbl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006744
Kailang Yangdf694da2005-12-05 19:42:22 +01006745 if (board_config < 0 || board_config >= ALC882_MODEL_LAST) {
Tobin Davis081d17c2007-02-15 17:46:18 +01006746 /* Pick up systems that don't supply PCI SSID */
6747 switch (codec->subsystem_id) {
6748 case 0x106b0c00: /* Mac Pro */
6749 board_config = ALC885_MACPRO;
6750 break;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006751 case 0x106b1000: /* iMac 24 */
Peter Korsgaardf3911c52008-09-27 09:13:45 +02006752 case 0x106b2800: /* AppleTV */
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006753 board_config = ALC885_IMAC24;
6754 break;
Takashi Iwaic7e07572008-06-26 14:42:51 +02006755 case 0x106b00a1: /* Macbook (might be wrong - PCI SSID?) */
David Woodhouse9c95c432008-09-18 13:37:13 -07006756 case 0x106b00a4: /* MacbookPro4,1 */
Takashi Iwai87350ad2007-08-16 18:19:38 +02006757 case 0x106b2c00: /* Macbook Pro rev3 */
Takashi Iwaic7e07572008-06-26 14:42:51 +02006758 case 0x106b3600: /* Macbook 3.1 */
Takashi Iwai87350ad2007-08-16 18:19:38 +02006759 board_config = ALC885_MBP3;
6760 break;
Tobin Davis081d17c2007-02-15 17:46:18 +01006761 default:
Takashi Iwai7943a8a2008-04-16 17:29:09 +02006762 /* ALC889A is handled better as ALC888-compatible */
Clive Messer669faba2008-09-30 15:49:13 +02006763 if (codec->revision_id == 0x100101 ||
6764 codec->revision_id == 0x100103) {
Takashi Iwai7943a8a2008-04-16 17:29:09 +02006765 alc_free(codec);
6766 return patch_alc883(codec);
6767 }
Tobin Davis081d17c2007-02-15 17:46:18 +01006768 printk(KERN_INFO "hda_codec: Unknown model for ALC882, "
6769 "trying auto-probe from BIOS...\n");
6770 board_config = ALC882_AUTO;
6771 }
Kailang Yangdf694da2005-12-05 19:42:22 +01006772 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006773
Takashi Iwaif95474e2007-07-10 00:47:43 +02006774 alc_fix_pincfg(codec, alc882_pinfix_tbl, alc882_pin_fixes);
6775
Kailang Yangdf694da2005-12-05 19:42:22 +01006776 if (board_config == ALC882_AUTO) {
6777 /* automatic parse from the BIOS config */
6778 err = alc882_parse_auto_config(codec);
6779 if (err < 0) {
6780 alc_free(codec);
6781 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006782 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006783 printk(KERN_INFO
6784 "hda_codec: Cannot set up configuration "
6785 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01006786 board_config = ALC882_3ST_DIG;
6787 }
6788 }
6789
6790 if (board_config != ALC882_AUTO)
6791 setup_preset(spec, &alc882_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006792
Kailang Yang2f893282008-05-27 12:14:47 +02006793 if (codec->vendor_id == 0x10ec0885) {
6794 spec->stream_name_analog = "ALC885 Analog";
6795 spec->stream_name_digital = "ALC885 Digital";
6796 } else {
6797 spec->stream_name_analog = "ALC882 Analog";
6798 spec->stream_name_digital = "ALC882 Digital";
6799 }
6800
Kailang Yangdf694da2005-12-05 19:42:22 +01006801 spec->stream_analog_playback = &alc882_pcm_analog_playback;
6802 spec->stream_analog_capture = &alc882_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01006803 /* FIXME: setup DAC5 */
6804 /*spec->stream_analog_alt_playback = &alc880_pcm_analog_alt_playback;*/
6805 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006806
Kailang Yangdf694da2005-12-05 19:42:22 +01006807 spec->stream_digital_playback = &alc882_pcm_digital_playback;
6808 spec->stream_digital_capture = &alc882_pcm_digital_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006809
Takashi Iwai54cbc9a2008-10-31 15:24:04 +01006810 spec->is_mix_capture = 1; /* matrix-style capture */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006811 if (!spec->adc_nids && spec->input_mux) {
Kailang Yangdf694da2005-12-05 19:42:22 +01006812 /* check whether NID 0x07 is valid */
Takashi Iwai4a471b72005-12-07 13:56:29 +01006813 unsigned int wcap = get_wcaps(codec, 0x07);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006814 /* get type */
6815 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Kailang Yangdf694da2005-12-05 19:42:22 +01006816 if (wcap != AC_WID_AUD_IN) {
6817 spec->adc_nids = alc882_adc_nids_alt;
6818 spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids_alt);
Takashi Iwaie1406342008-02-11 18:32:32 +01006819 spec->capsrc_nids = alc882_capsrc_nids_alt;
Kailang Yangdf694da2005-12-05 19:42:22 +01006820 } else {
6821 spec->adc_nids = alc882_adc_nids;
6822 spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids);
Takashi Iwaie1406342008-02-11 18:32:32 +01006823 spec->capsrc_nids = alc882_capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +01006824 }
6825 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006826 set_capture_mixer(spec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006827
Takashi Iwai2134ea42008-01-10 16:53:55 +01006828 spec->vmaster_nid = 0x0c;
6829
Linus Torvalds1da177e2005-04-16 15:20:36 -07006830 codec->patch_ops = alc_patch_ops;
Kailang Yangdf694da2005-12-05 19:42:22 +01006831 if (board_config == ALC882_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01006832 spec->init_hook = alc882_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02006833#ifdef CONFIG_SND_HDA_POWER_SAVE
6834 if (!spec->loopback.amplist)
6835 spec->loopback.amplist = alc882_loopbacks;
6836#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006837
6838 return 0;
6839}
6840
6841/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006842 * ALC883 support
6843 *
6844 * ALC883 is almost identical with ALC880 but has cleaner and more flexible
6845 * configuration. Each pin widget can choose any input DACs and a mixer.
6846 * Each ADC is connected from a mixer of all inputs. This makes possible
6847 * 6-channel independent captures.
6848 *
6849 * In addition, an independent DAC for the multi-playback (not used in this
6850 * driver yet).
6851 */
6852#define ALC883_DIGOUT_NID 0x06
6853#define ALC883_DIGIN_NID 0x0a
6854
6855static hda_nid_t alc883_dac_nids[4] = {
6856 /* front, rear, clfe, rear_surr */
Herton Ronaldo Krzesinskif32a19e2008-03-18 09:27:08 +01006857 0x02, 0x03, 0x04, 0x05
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006858};
6859
6860static hda_nid_t alc883_adc_nids[2] = {
6861 /* ADC1-2 */
6862 0x08, 0x09,
6863};
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006864
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006865static hda_nid_t alc883_adc_nids_alt[1] = {
6866 /* ADC1 */
6867 0x08,
6868};
6869
Takashi Iwaie1406342008-02-11 18:32:32 +01006870static hda_nid_t alc883_capsrc_nids[2] = { 0x23, 0x22 };
6871
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006872/* input MUX */
6873/* FIXME: should be a matrix-type input source selection */
6874
6875static struct hda_input_mux alc883_capture_source = {
6876 .num_items = 4,
6877 .items = {
6878 { "Mic", 0x0 },
6879 { "Front Mic", 0x1 },
6880 { "Line", 0x2 },
6881 { "CD", 0x4 },
6882 },
6883};
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006884
Jiang zhe17bba1b2008-06-04 12:11:07 +02006885static struct hda_input_mux alc883_3stack_6ch_intel = {
6886 .num_items = 4,
6887 .items = {
6888 { "Mic", 0x1 },
6889 { "Front Mic", 0x0 },
6890 { "Line", 0x2 },
6891 { "CD", 0x4 },
6892 },
6893};
6894
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006895static struct hda_input_mux alc883_lenovo_101e_capture_source = {
6896 .num_items = 2,
6897 .items = {
6898 { "Mic", 0x1 },
6899 { "Line", 0x2 },
6900 },
6901};
6902
Kailang Yang272a5272007-05-14 11:00:38 +02006903static struct hda_input_mux alc883_lenovo_nb0763_capture_source = {
6904 .num_items = 4,
6905 .items = {
6906 { "Mic", 0x0 },
6907 { "iMic", 0x1 },
6908 { "Line", 0x2 },
6909 { "CD", 0x4 },
6910 },
6911};
6912
Jiang zhefb97dc62008-03-06 11:07:11 +01006913static struct hda_input_mux alc883_fujitsu_pi2515_capture_source = {
6914 .num_items = 2,
6915 .items = {
6916 { "Mic", 0x0 },
6917 { "Int Mic", 0x1 },
6918 },
6919};
6920
Kailang Yange2757d52008-08-26 13:17:46 +02006921static struct hda_input_mux alc883_lenovo_sky_capture_source = {
6922 .num_items = 3,
6923 .items = {
6924 { "Mic", 0x0 },
6925 { "Front Mic", 0x1 },
6926 { "Line", 0x4 },
6927 },
6928};
6929
6930static struct hda_input_mux alc883_asus_eee1601_capture_source = {
6931 .num_items = 2,
6932 .items = {
6933 { "Mic", 0x0 },
6934 { "Line", 0x2 },
6935 },
6936};
6937
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006938/*
6939 * 2ch mode
6940 */
6941static struct hda_channel_mode alc883_3ST_2ch_modes[1] = {
6942 { 2, NULL }
6943};
6944
6945/*
6946 * 2ch mode
6947 */
6948static struct hda_verb alc883_3ST_ch2_init[] = {
6949 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
6950 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6951 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
6952 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6953 { } /* end */
6954};
6955
6956/*
Tobin Davisb2011312007-09-17 12:45:11 +02006957 * 4ch mode
6958 */
6959static struct hda_verb alc883_3ST_ch4_init[] = {
6960 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
6961 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6962 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6963 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6964 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6965 { } /* end */
6966};
6967
6968/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006969 * 6ch mode
6970 */
6971static struct hda_verb alc883_3ST_ch6_init[] = {
6972 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6973 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6974 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
6975 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6976 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6977 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6978 { } /* end */
6979};
6980
Tobin Davisb2011312007-09-17 12:45:11 +02006981static struct hda_channel_mode alc883_3ST_6ch_modes[3] = {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006982 { 2, alc883_3ST_ch2_init },
Tobin Davisb2011312007-09-17 12:45:11 +02006983 { 4, alc883_3ST_ch4_init },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006984 { 6, alc883_3ST_ch6_init },
6985};
6986
6987/*
Jiang zhe17bba1b2008-06-04 12:11:07 +02006988 * 2ch mode
6989 */
6990static struct hda_verb alc883_3ST_ch2_intel_init[] = {
6991 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
6992 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6993 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
6994 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6995 { } /* end */
6996};
6997
6998/*
6999 * 4ch mode
7000 */
7001static struct hda_verb alc883_3ST_ch4_intel_init[] = {
7002 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7003 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7004 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7005 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7006 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7007 { } /* end */
7008};
7009
7010/*
7011 * 6ch mode
7012 */
7013static struct hda_verb alc883_3ST_ch6_intel_init[] = {
7014 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7015 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7016 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x02 },
7017 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7018 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7019 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7020 { } /* end */
7021};
7022
7023static struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = {
7024 { 2, alc883_3ST_ch2_intel_init },
7025 { 4, alc883_3ST_ch4_intel_init },
7026 { 6, alc883_3ST_ch6_intel_init },
7027};
7028
7029/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007030 * 6ch mode
7031 */
7032static struct hda_verb alc883_sixstack_ch6_init[] = {
7033 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
7034 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7035 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7036 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7037 { } /* end */
7038};
7039
7040/*
7041 * 8ch mode
7042 */
7043static struct hda_verb alc883_sixstack_ch8_init[] = {
7044 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7045 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7046 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7047 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7048 { } /* end */
7049};
7050
7051static struct hda_channel_mode alc883_sixstack_modes[2] = {
7052 { 6, alc883_sixstack_ch6_init },
7053 { 8, alc883_sixstack_ch8_init },
7054};
7055
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01007056static struct hda_verb alc883_medion_eapd_verbs[] = {
7057 /* eanable EAPD on medion laptop */
7058 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
7059 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
7060 { }
7061};
7062
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007063/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
7064 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
7065 */
7066
7067static struct snd_kcontrol_new alc883_base_mixer[] = {
7068 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7069 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7070 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7071 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
7072 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7073 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
7074 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7075 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
7076 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
7077 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
7078 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7079 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7080 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7081 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7082 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7083 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007084 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007085 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7086 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007087 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007088 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
7089 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
7090 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007091 { } /* end */
7092};
7093
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01007094static struct snd_kcontrol_new alc883_mitac_mixer[] = {
7095 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7096 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7097 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7098 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
7099 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7100 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
7101 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
7102 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7103 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7104 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7105 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7106 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
7107 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01007108 { } /* end */
7109};
7110
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007111static struct snd_kcontrol_new alc883_clevo_m720_mixer[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01007112 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7113 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
7114 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7115 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
7116 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7117 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7118 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7119 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7120 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
7121 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Jiang zhe368c7a92008-03-04 11:20:33 +01007122 { } /* end */
7123};
7124
Jiang zhefb97dc62008-03-06 11:07:11 +01007125static struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = {
7126 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7127 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
7128 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7129 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
7130 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7131 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7132 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7133 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7134 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
7135 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Jiang zhefb97dc62008-03-06 11:07:11 +01007136 { } /* end */
7137};
7138
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007139static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = {
7140 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7141 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7142 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7143 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7144 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7145 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7146 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7147 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007148 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007149 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7150 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007151 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007152 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
7153 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
7154 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007155 { } /* end */
7156};
7157
7158static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
7159 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7160 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7161 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7162 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
7163 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, 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", 0x1b, 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, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007173 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007174 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7175 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007176 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007177 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, 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),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007180 { } /* end */
7181};
7182
Jiang zhe17bba1b2008-06-04 12:11:07 +02007183static struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = {
7184 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7185 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7186 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7187 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
7188 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
7189 HDA_OUTPUT),
7190 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
7191 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7192 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
7193 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
7194 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7195 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7196 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7197 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7198 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7199 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
7200 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
7201 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7202 HDA_CODEC_VOLUME("Front Mic Boost", 0x18, 0, HDA_INPUT),
7203 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7204 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
7205 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Jiang zhe17bba1b2008-06-04 12:11:07 +02007206 { } /* end */
7207};
7208
Takashi Iwaid1d985f2006-11-23 19:27:12 +01007209static struct snd_kcontrol_new alc883_fivestack_mixer[] = {
Tobin Davisc07584c2006-10-13 12:32:16 +02007210 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02007211 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007212 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02007213 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007214 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7215 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02007216 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7217 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007218 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7219 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7220 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7221 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7222 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7223 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007224 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007225 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7226 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007227 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007228 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
7229 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
7230 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007231 { } /* end */
7232};
7233
Kailang Yangccc656c2006-10-17 12:32:26 +02007234static struct snd_kcontrol_new alc883_tagra_mixer[] = {
7235 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7236 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7237 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7238 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7239 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
7240 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7241 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
7242 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7243 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
7244 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7245 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7246 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7247 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7248 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007249 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02007250 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02007251 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007252};
Kailang Yangccc656c2006-10-17 12:32:26 +02007253
7254static struct snd_kcontrol_new alc883_tagra_2ch_mixer[] = {
7255 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7256 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7257 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7258 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7259 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7260 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007261 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02007262 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Jiang zhe4383fae2008-04-14 12:58:57 +02007263 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7264 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
7265 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02007266 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007267};
Kailang Yangccc656c2006-10-17 12:32:26 +02007268
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007269static struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = {
7270 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7271 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01007272 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7273 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007274 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7275 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7276 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7277 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007278 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007279};
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007280
Kailang Yang272a5272007-05-14 11:00:38 +02007281static struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = {
7282 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7283 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
7284 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7285 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7286 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7287 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7288 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7289 HDA_CODEC_VOLUME("iMic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7290 HDA_CODEC_MUTE("iMic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02007291 { } /* end */
7292};
7293
7294static struct snd_kcontrol_new alc883_medion_md2_mixer[] = {
7295 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7296 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7297 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
7298 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7299 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7300 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7301 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7302 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7303 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02007304 { } /* end */
Kailang Yangea1fb292008-08-26 12:58:38 +02007305};
Kailang Yang272a5272007-05-14 11:00:38 +02007306
Tobin Davis2880a862007-08-07 11:50:26 +02007307static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = {
Kailang Yangd1a991a2007-08-15 16:21:59 +02007308 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7309 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02007310 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02007311 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7312 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Kailang Yangd1a991a2007-08-15 16:21:59 +02007313 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7314 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7315 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02007316 { } /* end */
Kailang Yangd1a991a2007-08-15 16:21:59 +02007317};
Tobin Davis2880a862007-08-07 11:50:26 +02007318
Kailang Yange2757d52008-08-26 13:17:46 +02007319static struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = {
7320 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7321 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7322 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
7323 HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
7324 HDA_CODEC_VOLUME_MONO("Center Playback Volume",
7325 0x0d, 1, 0x0, HDA_OUTPUT),
7326 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
7327 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
7328 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
7329 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
7330 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
7331 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7332 HDA_CODEC_MUTE("iSpeaker Playback Switch", 0x1a, 0x0, HDA_OUTPUT),
7333 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7334 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7335 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7336 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7337 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7338 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7339 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7340 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7341 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
7342 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02007343 { } /* end */
7344};
7345
7346static struct hda_bind_ctls alc883_bind_cap_vol = {
7347 .ops = &snd_hda_bind_vol,
7348 .values = {
7349 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
7350 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
7351 0
7352 },
7353};
7354
7355static struct hda_bind_ctls alc883_bind_cap_switch = {
7356 .ops = &snd_hda_bind_sw,
7357 .values = {
7358 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
7359 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
7360 0
7361 },
7362};
7363
7364static struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = {
7365 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7366 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7367 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7368 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7369 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7370 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7371 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7372 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007373 { } /* end */
7374};
7375
7376static struct snd_kcontrol_new alc883_asus_eee1601_cap_mixer[] = {
Kailang Yange2757d52008-08-26 13:17:46 +02007377 HDA_BIND_VOL("Capture Volume", &alc883_bind_cap_vol),
7378 HDA_BIND_SW("Capture Switch", &alc883_bind_cap_switch),
7379 {
7380 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7381 /* .name = "Capture Source", */
7382 .name = "Input Source",
7383 .count = 1,
Takashi Iwai54cbc9a2008-10-31 15:24:04 +01007384 .info = alc_mux_enum_info,
7385 .get = alc_mux_enum_get,
7386 .put = alc_mux_enum_put,
Kailang Yange2757d52008-08-26 13:17:46 +02007387 },
7388 { } /* end */
7389};
7390
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007391static struct snd_kcontrol_new alc883_chmode_mixer[] = {
7392 {
7393 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7394 .name = "Channel Mode",
7395 .info = alc_ch_mode_info,
7396 .get = alc_ch_mode_get,
7397 .put = alc_ch_mode_put,
7398 },
7399 { } /* end */
7400};
7401
7402static struct hda_verb alc883_init_verbs[] = {
7403 /* ADC1: mute amp left and right */
Kailang Yange2757d52008-08-26 13:17:46 +02007404 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007405 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
7406 /* ADC2: mute amp left and right */
7407 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7408 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
7409 /* Front mixer: unmute input/output amp left and right (volume = 0) */
7410 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7411 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7412 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7413 /* Rear mixer */
7414 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7415 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7416 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7417 /* CLFE mixer */
7418 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7419 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7420 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7421 /* Side mixer */
7422 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7423 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7424 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7425
Takashi Iwaicb53c622007-08-10 17:21:45 +02007426 /* mute analog input loopbacks */
7427 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7428 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7429 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7430 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7431 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007432
7433 /* Front Pin: output 0 (0x0c) */
7434 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7435 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7436 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
7437 /* Rear Pin: output 1 (0x0d) */
7438 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7439 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7440 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
7441 /* CLFE Pin: output 2 (0x0e) */
7442 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7443 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7444 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
7445 /* Side Pin: output 3 (0x0f) */
7446 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7447 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7448 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
7449 /* Mic (rear) pin: input vref at 80% */
7450 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7451 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7452 /* Front Mic pin: input vref at 80% */
7453 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7454 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7455 /* Line In pin: input */
7456 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
7457 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7458 /* Line-2 In: Headphone output (output 0 - 0x0c) */
7459 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7460 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7461 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
7462 /* CD pin widget for input */
7463 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
7464
7465 /* FIXME: use matrix-type input source selection */
7466 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
7467 /* Input mixer2 */
7468 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yange2757d52008-08-26 13:17:46 +02007469 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7470 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7471 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007472 /* Input mixer3 */
7473 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yange2757d52008-08-26 13:17:46 +02007474 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7475 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7476 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007477 { }
7478};
7479
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01007480/* toggle speaker-output according to the hp-jack state */
7481static void alc883_mitac_hp_automute(struct hda_codec *codec)
7482{
7483 unsigned int present;
7484
7485 present = snd_hda_codec_read(codec, 0x15, 0,
7486 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7487 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7488 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7489 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
7490 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7491}
7492
7493/* auto-toggle front mic */
7494/*
7495static void alc883_mitac_mic_automute(struct hda_codec *codec)
7496{
7497 unsigned int present;
7498 unsigned char bits;
7499
7500 present = snd_hda_codec_read(codec, 0x18, 0,
7501 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7502 bits = present ? HDA_AMP_MUTE : 0;
7503 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
7504}
7505*/
7506
7507static void alc883_mitac_automute(struct hda_codec *codec)
7508{
7509 alc883_mitac_hp_automute(codec);
7510 /* alc883_mitac_mic_automute(codec); */
7511}
7512
7513static void alc883_mitac_unsol_event(struct hda_codec *codec,
7514 unsigned int res)
7515{
7516 switch (res >> 26) {
7517 case ALC880_HP_EVENT:
7518 alc883_mitac_hp_automute(codec);
7519 break;
7520 case ALC880_MIC_EVENT:
7521 /* alc883_mitac_mic_automute(codec); */
7522 break;
7523 }
7524}
7525
7526static struct hda_verb alc883_mitac_verbs[] = {
7527 /* HP */
7528 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7529 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7530 /* Subwoofer */
7531 {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
7532 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7533
7534 /* enable unsolicited event */
7535 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7536 /* {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, */
7537
7538 { } /* end */
7539};
7540
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007541static struct hda_verb alc883_clevo_m720_verbs[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01007542 /* HP */
7543 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7544 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7545 /* Int speaker */
7546 {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
7547 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7548
7549 /* enable unsolicited event */
7550 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007551 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Jiang zhe368c7a92008-03-04 11:20:33 +01007552
7553 { } /* end */
7554};
7555
Jiang zhefb97dc62008-03-06 11:07:11 +01007556static struct hda_verb alc883_2ch_fujitsu_pi2515_verbs[] = {
7557 /* HP */
7558 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
7559 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7560 /* Subwoofer */
7561 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
7562 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7563
7564 /* enable unsolicited event */
7565 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7566
7567 { } /* end */
7568};
7569
Kailang Yangccc656c2006-10-17 12:32:26 +02007570static struct hda_verb alc883_tagra_verbs[] = {
7571 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7572 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7573
7574 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7575 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02007576
Kailang Yangccc656c2006-10-17 12:32:26 +02007577 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
7578 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
7579 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
7580
7581 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007582 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
7583 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
7584 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
Kailang Yangccc656c2006-10-17 12:32:26 +02007585
7586 { } /* end */
7587};
7588
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007589static struct hda_verb alc883_lenovo_101e_verbs[] = {
7590 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7591 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT|AC_USRSP_EN},
7592 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT|AC_USRSP_EN},
7593 { } /* end */
7594};
7595
Kailang Yang272a5272007-05-14 11:00:38 +02007596static struct hda_verb alc883_lenovo_nb0763_verbs[] = {
7597 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7598 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7599 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7600 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7601 { } /* end */
7602};
7603
7604static struct hda_verb alc888_lenovo_ms7195_verbs[] = {
7605 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7606 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7607 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7608 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT | AC_USRSP_EN},
7609 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7610 { } /* end */
7611};
7612
Kailang Yang189609a2007-08-20 11:31:23 +02007613static struct hda_verb alc883_haier_w66_verbs[] = {
7614 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7615 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7616
7617 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7618
7619 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
7620 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7621 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7622 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7623 { } /* end */
7624};
7625
Kailang Yange2757d52008-08-26 13:17:46 +02007626static struct hda_verb alc888_lenovo_sky_verbs[] = {
7627 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7628 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7629 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7630 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7631 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7632 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7633 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
7634 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7635 { } /* end */
7636};
7637
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007638static struct hda_verb alc888_3st_hp_verbs[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007639 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */
Herton Ronaldo Krzesinskif32a19e2008-03-18 09:27:08 +01007640 {0x16, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Rear : output 1 (0x0d) */
7641 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* CLFE : output 2 (0x0e) */
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007642 { }
7643};
7644
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007645static struct hda_verb alc888_6st_dell_verbs[] = {
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007646 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7647 { }
7648};
7649
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007650static struct hda_verb alc888_3st_hp_2ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007651 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7652 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7653 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7654 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7655 { }
7656};
7657
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007658static struct hda_verb alc888_3st_hp_6ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007659 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7660 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7661 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7662 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7663 { }
7664};
7665
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007666static struct hda_channel_mode alc888_3st_hp_modes[2] = {
7667 { 2, alc888_3st_hp_2ch_init },
7668 { 6, alc888_3st_hp_6ch_init },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007669};
7670
Kailang Yang272a5272007-05-14 11:00:38 +02007671/* toggle front-jack and RCA according to the hp-jack state */
7672static void alc888_lenovo_ms7195_front_automute(struct hda_codec *codec)
7673{
7674 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02007675
Kailang Yang272a5272007-05-14 11:00:38 +02007676 present = snd_hda_codec_read(codec, 0x1b, 0,
7677 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007678 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7679 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7680 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7681 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02007682}
7683
7684/* toggle RCA according to the front-jack state */
7685static void alc888_lenovo_ms7195_rca_automute(struct hda_codec *codec)
7686{
7687 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02007688
Kailang Yang272a5272007-05-14 11:00:38 +02007689 present = snd_hda_codec_read(codec, 0x14, 0,
7690 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007691 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7692 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02007693}
Takashi Iwai47fd8302007-08-10 17:11:07 +02007694
Kailang Yang272a5272007-05-14 11:00:38 +02007695static void alc883_lenovo_ms7195_unsol_event(struct hda_codec *codec,
7696 unsigned int res)
7697{
7698 if ((res >> 26) == ALC880_HP_EVENT)
7699 alc888_lenovo_ms7195_front_automute(codec);
7700 if ((res >> 26) == ALC880_FRONT_EVENT)
7701 alc888_lenovo_ms7195_rca_automute(codec);
7702}
7703
7704static struct hda_verb alc883_medion_md2_verbs[] = {
7705 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7706 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7707
7708 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7709
7710 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7711 { } /* end */
7712};
7713
7714/* toggle speaker-output according to the hp-jack state */
7715static void alc883_medion_md2_automute(struct hda_codec *codec)
7716{
7717 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02007718
Kailang Yang272a5272007-05-14 11:00:38 +02007719 present = snd_hda_codec_read(codec, 0x14, 0,
7720 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007721 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7722 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02007723}
7724
7725static void alc883_medion_md2_unsol_event(struct hda_codec *codec,
7726 unsigned int res)
7727{
7728 if ((res >> 26) == ALC880_HP_EVENT)
7729 alc883_medion_md2_automute(codec);
7730}
7731
Kailang Yangccc656c2006-10-17 12:32:26 +02007732/* toggle speaker-output according to the hp-jack state */
7733static void alc883_tagra_automute(struct hda_codec *codec)
7734{
7735 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007736 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02007737
7738 present = snd_hda_codec_read(codec, 0x14, 0,
7739 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007740 bits = present ? HDA_AMP_MUTE : 0;
7741 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
7742 HDA_AMP_MUTE, bits);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02007743 snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
7744 present ? 1 : 3);
Kailang Yangccc656c2006-10-17 12:32:26 +02007745}
7746
7747static void alc883_tagra_unsol_event(struct hda_codec *codec, unsigned int res)
7748{
7749 if ((res >> 26) == ALC880_HP_EVENT)
7750 alc883_tagra_automute(codec);
7751}
7752
Jiang zhe368c7a92008-03-04 11:20:33 +01007753/* toggle speaker-output according to the hp-jack state */
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007754static void alc883_clevo_m720_hp_automute(struct hda_codec *codec)
Jiang zhe368c7a92008-03-04 11:20:33 +01007755{
7756 unsigned int present;
7757 unsigned char bits;
7758
7759 present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0)
7760 & AC_PINSENSE_PRESENCE;
7761 bits = present ? HDA_AMP_MUTE : 0;
7762 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7763 HDA_AMP_MUTE, bits);
7764}
7765
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007766static void alc883_clevo_m720_mic_automute(struct hda_codec *codec)
7767{
7768 unsigned int present;
7769
7770 present = snd_hda_codec_read(codec, 0x18, 0,
7771 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7772 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
7773 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7774}
7775
7776static void alc883_clevo_m720_automute(struct hda_codec *codec)
7777{
7778 alc883_clevo_m720_hp_automute(codec);
7779 alc883_clevo_m720_mic_automute(codec);
7780}
7781
7782static void alc883_clevo_m720_unsol_event(struct hda_codec *codec,
Jiang zhe368c7a92008-03-04 11:20:33 +01007783 unsigned int res)
7784{
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007785 switch (res >> 26) {
7786 case ALC880_HP_EVENT:
7787 alc883_clevo_m720_hp_automute(codec);
7788 break;
7789 case ALC880_MIC_EVENT:
7790 alc883_clevo_m720_mic_automute(codec);
7791 break;
7792 }
Jiang zhe368c7a92008-03-04 11:20:33 +01007793}
7794
Jiang zhefb97dc62008-03-06 11:07:11 +01007795/* toggle speaker-output according to the hp-jack state */
7796static void alc883_2ch_fujitsu_pi2515_automute(struct hda_codec *codec)
7797{
7798 unsigned int present;
7799 unsigned char bits;
7800
7801 present = snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0)
7802 & AC_PINSENSE_PRESENCE;
7803 bits = present ? HDA_AMP_MUTE : 0;
7804 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7805 HDA_AMP_MUTE, bits);
7806}
7807
7808static void alc883_2ch_fujitsu_pi2515_unsol_event(struct hda_codec *codec,
7809 unsigned int res)
7810{
7811 if ((res >> 26) == ALC880_HP_EVENT)
7812 alc883_2ch_fujitsu_pi2515_automute(codec);
7813}
7814
Kailang Yang189609a2007-08-20 11:31:23 +02007815static void alc883_haier_w66_automute(struct hda_codec *codec)
7816{
7817 unsigned int present;
7818 unsigned char bits;
7819
7820 present = snd_hda_codec_read(codec, 0x1b, 0,
7821 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7822 bits = present ? 0x80 : 0;
7823 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7824 0x80, bits);
7825}
7826
7827static void alc883_haier_w66_unsol_event(struct hda_codec *codec,
7828 unsigned int res)
7829{
7830 if ((res >> 26) == ALC880_HP_EVENT)
7831 alc883_haier_w66_automute(codec);
7832}
7833
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007834static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
7835{
7836 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007837 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007838
7839 present = snd_hda_codec_read(codec, 0x14, 0,
7840 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007841 bits = present ? HDA_AMP_MUTE : 0;
7842 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7843 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007844}
7845
7846static void alc883_lenovo_101e_all_automute(struct hda_codec *codec)
7847{
7848 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007849 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007850
7851 present = snd_hda_codec_read(codec, 0x1b, 0,
7852 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007853 bits = present ? HDA_AMP_MUTE : 0;
7854 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7855 HDA_AMP_MUTE, bits);
7856 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7857 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007858}
7859
7860static void alc883_lenovo_101e_unsol_event(struct hda_codec *codec,
7861 unsigned int res)
7862{
7863 if ((res >> 26) == ALC880_HP_EVENT)
7864 alc883_lenovo_101e_all_automute(codec);
7865 if ((res >> 26) == ALC880_FRONT_EVENT)
7866 alc883_lenovo_101e_ispeaker_automute(codec);
7867}
7868
Takashi Iwai676a9b52007-08-16 15:23:35 +02007869/* toggle speaker-output according to the hp-jack state */
7870static void alc883_acer_aspire_automute(struct hda_codec *codec)
7871{
7872 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02007873
Takashi Iwai676a9b52007-08-16 15:23:35 +02007874 present = snd_hda_codec_read(codec, 0x14, 0,
7875 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7876 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7877 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7878 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
7879 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7880}
7881
7882static void alc883_acer_aspire_unsol_event(struct hda_codec *codec,
7883 unsigned int res)
7884{
7885 if ((res >> 26) == ALC880_HP_EVENT)
7886 alc883_acer_aspire_automute(codec);
7887}
7888
Kailang Yangd1a991a2007-08-15 16:21:59 +02007889static struct hda_verb alc883_acer_eapd_verbs[] = {
7890 /* HP Pin: output 0 (0x0c) */
7891 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7892 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7893 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
7894 /* Front Pin: output 0 (0x0c) */
Takashi Iwai676a9b52007-08-16 15:23:35 +02007895 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7896 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangd1a991a2007-08-15 16:21:59 +02007897 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangd1a991a2007-08-15 16:21:59 +02007898 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
7899 /* eanable EAPD on medion laptop */
7900 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
7901 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
Takashi Iwai676a9b52007-08-16 15:23:35 +02007902 /* enable unsolicited event */
7903 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yangd1a991a2007-08-15 16:21:59 +02007904 { }
7905};
7906
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007907static void alc888_6st_dell_front_automute(struct hda_codec *codec)
7908{
7909 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02007910
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007911 present = snd_hda_codec_read(codec, 0x1b, 0,
7912 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7913 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7914 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7915 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7916 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7917 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
7918 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7919 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
7920 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7921}
7922
7923static void alc888_6st_dell_unsol_event(struct hda_codec *codec,
7924 unsigned int res)
7925{
7926 switch (res >> 26) {
7927 case ALC880_HP_EVENT:
7928 printk("hp_event\n");
7929 alc888_6st_dell_front_automute(codec);
7930 break;
7931 }
7932}
7933
Kailang Yange2757d52008-08-26 13:17:46 +02007934static void alc888_lenovo_sky_front_automute(struct hda_codec *codec)
7935{
7936 unsigned int mute;
7937 unsigned int present;
7938
7939 snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
7940 present = snd_hda_codec_read(codec, 0x1b, 0,
7941 AC_VERB_GET_PIN_SENSE, 0);
7942 present = (present & 0x80000000) != 0;
7943 if (present) {
7944 /* mute internal speaker */
7945 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7946 HDA_AMP_MUTE, HDA_AMP_MUTE);
7947 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7948 HDA_AMP_MUTE, HDA_AMP_MUTE);
7949 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
7950 HDA_AMP_MUTE, HDA_AMP_MUTE);
7951 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
7952 HDA_AMP_MUTE, HDA_AMP_MUTE);
7953 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0,
7954 HDA_AMP_MUTE, HDA_AMP_MUTE);
7955 } else {
7956 /* unmute internal speaker if necessary */
7957 mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
7958 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7959 HDA_AMP_MUTE, mute);
7960 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7961 HDA_AMP_MUTE, mute);
7962 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
7963 HDA_AMP_MUTE, mute);
7964 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
7965 HDA_AMP_MUTE, mute);
7966 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0,
7967 HDA_AMP_MUTE, mute);
7968 }
7969}
7970
7971static void alc883_lenovo_sky_unsol_event(struct hda_codec *codec,
7972 unsigned int res)
7973{
7974 if ((res >> 26) == ALC880_HP_EVENT)
7975 alc888_lenovo_sky_front_automute(codec);
7976}
7977
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007978/*
7979 * generic initialization of ADC, input mixers and output mixers
7980 */
7981static struct hda_verb alc883_auto_init_verbs[] = {
7982 /*
7983 * Unmute ADC0-2 and set the default input to mic-in
7984 */
7985 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
7986 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7987 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
7988 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7989
Takashi Iwaicb53c622007-08-10 17:21:45 +02007990 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007991 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007992 * Note: PASD motherboards uses the Line In 2 as the input for
7993 * front panel mic (mic 2)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007994 */
7995 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02007996 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7997 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7998 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7999 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8000 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008001
8002 /*
8003 * Set up output mixers (0x0c - 0x0f)
8004 */
8005 /* set vol=0 to output mixers */
8006 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8007 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8008 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8009 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8010 /* set up input amps for analog loopback */
8011 /* Amp Indices: DAC = 0, mixer = 1 */
8012 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8013 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8014 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8015 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8016 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8017 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8018 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8019 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8020 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8021 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8022
8023 /* FIXME: use matrix-type input source selection */
8024 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
8025 /* Input mixer1 */
8026 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8027 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8028 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008029 /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, */
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008030 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
8031 /* Input mixer2 */
8032 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8033 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8034 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008035 /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, */
Andy Shevchenkoe3cde642007-12-03 16:50:58 +01008036 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008037
8038 { }
8039};
8040
Kailang Yange2757d52008-08-26 13:17:46 +02008041static struct hda_verb alc888_asus_m90v_verbs[] = {
8042 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8043 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8044 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8045 /* enable unsolicited event */
8046 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8047 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
8048 { } /* end */
8049};
8050
8051static void alc883_nb_mic_automute(struct hda_codec *codec)
8052{
8053 unsigned int present;
8054
8055 present = snd_hda_codec_read(codec, 0x18, 0,
8056 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
8057 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
8058 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
8059 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
8060 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
8061}
8062
8063static void alc883_M90V_speaker_automute(struct hda_codec *codec)
8064{
8065 unsigned int present;
8066 unsigned char bits;
8067
8068 present = snd_hda_codec_read(codec, 0x1b, 0,
8069 AC_VERB_GET_PIN_SENSE, 0)
8070 & AC_PINSENSE_PRESENCE;
8071 bits = present ? 0 : PIN_OUT;
8072 snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
8073 bits);
8074 snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
8075 bits);
8076 snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
8077 bits);
8078}
8079
8080static void alc883_mode2_unsol_event(struct hda_codec *codec,
8081 unsigned int res)
8082{
8083 switch (res >> 26) {
8084 case ALC880_HP_EVENT:
8085 alc883_M90V_speaker_automute(codec);
8086 break;
8087 case ALC880_MIC_EVENT:
8088 alc883_nb_mic_automute(codec);
8089 break;
8090 }
8091}
8092
8093static void alc883_mode2_inithook(struct hda_codec *codec)
8094{
8095 alc883_M90V_speaker_automute(codec);
8096 alc883_nb_mic_automute(codec);
8097}
8098
8099static struct hda_verb alc888_asus_eee1601_verbs[] = {
8100 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8101 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8102 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8103 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8104 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8105 {0x20, AC_VERB_SET_COEF_INDEX, 0x0b},
8106 {0x20, AC_VERB_SET_PROC_COEF, 0x0838},
8107 /* enable unsolicited event */
8108 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8109 { } /* end */
8110};
8111
8112static void alc883_eee1601_speaker_automute(struct hda_codec *codec)
8113{
8114 unsigned int present;
8115 unsigned char bits;
8116
8117 present = snd_hda_codec_read(codec, 0x14, 0,
8118 AC_VERB_GET_PIN_SENSE, 0)
8119 & AC_PINSENSE_PRESENCE;
8120 bits = present ? 0 : PIN_OUT;
8121 snd_hda_codec_write(codec, 0x1b, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
8122 bits);
8123}
8124
8125static void alc883_eee1601_unsol_event(struct hda_codec *codec,
8126 unsigned int res)
8127{
8128 switch (res >> 26) {
8129 case ALC880_HP_EVENT:
8130 alc883_eee1601_speaker_automute(codec);
8131 break;
8132 }
8133}
8134
8135static void alc883_eee1601_inithook(struct hda_codec *codec)
8136{
8137 alc883_eee1601_speaker_automute(codec);
8138}
8139
Takashi Iwaicb53c622007-08-10 17:21:45 +02008140#ifdef CONFIG_SND_HDA_POWER_SAVE
8141#define alc883_loopbacks alc880_loopbacks
8142#endif
8143
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008144/* pcm configuration: identiacal with ALC880 */
8145#define alc883_pcm_analog_playback alc880_pcm_analog_playback
8146#define alc883_pcm_analog_capture alc880_pcm_analog_capture
Takashi Iwai63300792008-01-24 15:31:36 +01008147#define alc883_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008148#define alc883_pcm_digital_playback alc880_pcm_digital_playback
8149#define alc883_pcm_digital_capture alc880_pcm_digital_capture
8150
8151/*
8152 * configuration and preset
8153 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008154static const char *alc883_models[ALC883_MODEL_LAST] = {
8155 [ALC883_3ST_2ch_DIG] = "3stack-dig",
8156 [ALC883_3ST_6ch_DIG] = "3stack-6ch-dig",
8157 [ALC883_3ST_6ch] = "3stack-6ch",
8158 [ALC883_6ST_DIG] = "6stack-dig",
8159 [ALC883_TARGA_DIG] = "targa-dig",
8160 [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008161 [ALC883_ACER] = "acer",
Tobin Davis2880a862007-08-07 11:50:26 +02008162 [ALC883_ACER_ASPIRE] = "acer-aspire",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008163 [ALC883_MEDION] = "medion",
Kailang Yang272a5272007-05-14 11:00:38 +02008164 [ALC883_MEDION_MD2] = "medion-md2",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008165 [ALC883_LAPTOP_EAPD] = "laptop-eapd",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008166 [ALC883_LENOVO_101E_2ch] = "lenovo-101e",
Kailang Yang272a5272007-05-14 11:00:38 +02008167 [ALC883_LENOVO_NB0763] = "lenovo-nb0763",
8168 [ALC888_LENOVO_MS7195_DIG] = "lenovo-ms7195-dig",
Kailang Yange2757d52008-08-26 13:17:46 +02008169 [ALC888_LENOVO_SKY] = "lenovo-sky",
Kailang Yang189609a2007-08-20 11:31:23 +02008170 [ALC883_HAIER_W66] = "haier-w66",
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008171 [ALC888_3ST_HP] = "3stack-hp",
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008172 [ALC888_6ST_DELL] = "6stack-dell",
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008173 [ALC883_MITAC] = "mitac",
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008174 [ALC883_CLEVO_M720] = "clevo-m720",
Jiang zhefb97dc62008-03-06 11:07:11 +01008175 [ALC883_FUJITSU_PI2515] = "fujitsu-pi2515",
Jiang zhe17bba1b2008-06-04 12:11:07 +02008176 [ALC883_3ST_6ch_INTEL] = "3stack-6ch-intel",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008177 [ALC883_AUTO] = "auto",
8178};
8179
8180static struct snd_pci_quirk alc883_cfg_tbl[] = {
8181 SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC883_3ST_6ch_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008182 SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE),
8183 SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE),
8184 SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE),
Jaroslav Kysela0b18cb12008-07-28 17:07:07 +02008185 SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_ACER_ASPIRE),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008186 SND_PCI_QUIRK(0x1025, 0, "Acer laptop", ALC883_ACER), /* default Acer */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008187 SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL),
Tobin Davisfebe3372007-06-12 11:27:46 +02008188 SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008189 SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP),
8190 SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP),
Herton Ronaldo Krzesinski5d85f8d2008-03-20 12:13:46 +01008191 SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG),
Kailang Yanga01c30c2008-10-15 11:14:58 +02008192 SND_PCI_QUIRK(0x1043, 0x1873, "Asus M90V", ALC888_ASUS_M90V),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008193 SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG),
Kailang Yange2757d52008-08-26 13:17:46 +02008194 SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_ASUS_EEE1601),
Travis Place97ec7102008-05-23 18:31:46 +02008195 SND_PCI_QUIRK(0x105b, 0x0ce8, "Foxconn P35AX-S", ALC883_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008196 SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008197 SND_PCI_QUIRK(0x1071, 0x8253, "Mitac 8252d", ALC883_MITAC),
8198 SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD),
Kailang Yange2757d52008-08-26 13:17:46 +02008199 SND_PCI_QUIRK(0x10f1, 0x2350, "TYAN-S2350", ALC888_6ST_DELL),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008200 SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch),
Tobin Davis57b14f22007-04-18 23:05:36 +02008201 SND_PCI_QUIRK(0x1458, 0xa002, "MSI", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008202 SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG),
8203 SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG),
8204 SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG),
Jiang zhe4383fae2008-04-14 12:58:57 +02008205 SND_PCI_QUIRK(0x1462, 0x2fb3, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008206 SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG),
Pascal Terjan82808232008-03-04 11:33:28 +01008207 SND_PCI_QUIRK(0x1462, 0x3783, "NEC S970", ALC883_TARGA_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008208 SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG),
8209 SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG),
8210 SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG),
8211 SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG),
8212 SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG),
8213 SND_PCI_QUIRK(0x1462, 0x3fdf, "MSI", ALC883_TARGA_DIG),
8214 SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG),
8215 SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG),
8216 SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008217 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG),
8218 SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG),
Tobin Davis799f88a2007-05-29 14:29:08 +02008219 SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG),
Herton Ronaldo Krzesinski86d34b72008-03-18 09:27:59 +01008220 SND_PCI_QUIRK(0x1462, 0x7267, "MSI", ALC883_3ST_6ch_DIG),
Leonard Norrgard2a296cb2007-01-08 11:28:22 +01008221 SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG),
Tobin Davis2dcd5222007-07-10 17:04:57 +02008222 SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008223 SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008224 SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG),
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008225 SND_PCI_QUIRK(0x1558, 0x0721, "Clevo laptop M720R", ALC883_CLEVO_M720),
8226 SND_PCI_QUIRK(0x1558, 0x0722, "Clevo laptop M720SR", ALC883_CLEVO_M720),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008227 SND_PCI_QUIRK(0x1558, 0, "Clevo laptop", ALC883_LAPTOP_EAPD),
Daniel T Chene60623b2007-05-29 03:41:55 -04008228 SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008229 SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION),
Jiang zhefb97dc62008-03-06 11:07:11 +01008230 SND_PCI_QUIRK(0x1734, 0x1108, "Fujitsu AMILO Pi2515", ALC883_FUJITSU_PI2515),
Kailang Yang272a5272007-05-14 11:00:38 +02008231 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch),
Kailang Yang272a5272007-05-14 11:00:38 +02008232 SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008233 SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763),
8234 SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Kailang Yange2757d52008-08-26 13:17:46 +02008235 SND_PCI_QUIRK(0x17aa, 0x101d, "Lenovo Sky", ALC888_LENOVO_SKY),
Kailang Yang272a5272007-05-14 11:00:38 +02008236 SND_PCI_QUIRK(0x17c0, 0x4071, "MEDION MD2", ALC883_MEDION_MD2),
Andrew Paprocki0b167bf2008-02-03 10:15:44 +01008237 SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG),
Kailang Yang189609a2007-08-20 11:31:23 +02008238 SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66),
Jiang zhe17bba1b2008-06-04 12:11:07 +02008239 SND_PCI_QUIRK(0x8086, 0x0001, "DG33BUC", ALC883_3ST_6ch_INTEL),
8240 SND_PCI_QUIRK(0x8086, 0x0002, "DG33FBC", ALC883_3ST_6ch_INTEL),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008241 SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008242 {}
8243};
8244
8245static struct alc_config_preset alc883_presets[] = {
8246 [ALC883_3ST_2ch_DIG] = {
8247 .mixers = { alc883_3ST_2ch_mixer },
8248 .init_verbs = { alc883_init_verbs },
8249 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8250 .dac_nids = alc883_dac_nids,
8251 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008252 .dig_in_nid = ALC883_DIGIN_NID,
8253 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8254 .channel_mode = alc883_3ST_2ch_modes,
8255 .input_mux = &alc883_capture_source,
8256 },
8257 [ALC883_3ST_6ch_DIG] = {
8258 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
8259 .init_verbs = { alc883_init_verbs },
8260 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8261 .dac_nids = alc883_dac_nids,
8262 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008263 .dig_in_nid = ALC883_DIGIN_NID,
8264 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
8265 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02008266 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008267 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008268 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008269 [ALC883_3ST_6ch] = {
8270 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
8271 .init_verbs = { alc883_init_verbs },
8272 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8273 .dac_nids = alc883_dac_nids,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008274 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
8275 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02008276 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008277 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008278 },
Jiang zhe17bba1b2008-06-04 12:11:07 +02008279 [ALC883_3ST_6ch_INTEL] = {
8280 .mixers = { alc883_3ST_6ch_intel_mixer, alc883_chmode_mixer },
8281 .init_verbs = { alc883_init_verbs },
8282 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8283 .dac_nids = alc883_dac_nids,
8284 .dig_out_nid = ALC883_DIGOUT_NID,
8285 .dig_in_nid = ALC883_DIGIN_NID,
8286 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_intel_modes),
8287 .channel_mode = alc883_3ST_6ch_intel_modes,
8288 .need_dac_fix = 1,
8289 .input_mux = &alc883_3stack_6ch_intel,
8290 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008291 [ALC883_6ST_DIG] = {
8292 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
8293 .init_verbs = { alc883_init_verbs },
8294 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8295 .dac_nids = alc883_dac_nids,
8296 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008297 .dig_in_nid = ALC883_DIGIN_NID,
8298 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
8299 .channel_mode = alc883_sixstack_modes,
8300 .input_mux = &alc883_capture_source,
8301 },
Kailang Yangccc656c2006-10-17 12:32:26 +02008302 [ALC883_TARGA_DIG] = {
8303 .mixers = { alc883_tagra_mixer, alc883_chmode_mixer },
8304 .init_verbs = { alc883_init_verbs, alc883_tagra_verbs},
8305 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8306 .dac_nids = alc883_dac_nids,
8307 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +02008308 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
8309 .channel_mode = alc883_3ST_6ch_modes,
8310 .need_dac_fix = 1,
8311 .input_mux = &alc883_capture_source,
8312 .unsol_event = alc883_tagra_unsol_event,
8313 .init_hook = alc883_tagra_automute,
8314 },
8315 [ALC883_TARGA_2ch_DIG] = {
8316 .mixers = { alc883_tagra_2ch_mixer},
8317 .init_verbs = { alc883_init_verbs, alc883_tagra_verbs},
8318 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8319 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01008320 .adc_nids = alc883_adc_nids_alt,
8321 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Kailang Yangccc656c2006-10-17 12:32:26 +02008322 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +02008323 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8324 .channel_mode = alc883_3ST_2ch_modes,
8325 .input_mux = &alc883_capture_source,
8326 .unsol_event = alc883_tagra_unsol_event,
8327 .init_hook = alc883_tagra_automute,
8328 },
Vladimir Avdoninbab282b92006-08-22 13:31:58 +02008329 [ALC883_ACER] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02008330 .mixers = { alc883_base_mixer },
Vladimir Avdoninbab282b92006-08-22 13:31:58 +02008331 /* On TravelMate laptops, GPIO 0 enables the internal speaker
8332 * and the headphone jack. Turn this on and rely on the
8333 * standard mute methods whenever the user wants to turn
8334 * these outputs off.
8335 */
8336 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs },
8337 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8338 .dac_nids = alc883_dac_nids,
Vladimir Avdoninbab282b92006-08-22 13:31:58 +02008339 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8340 .channel_mode = alc883_3ST_2ch_modes,
8341 .input_mux = &alc883_capture_source,
8342 },
Tobin Davis2880a862007-08-07 11:50:26 +02008343 [ALC883_ACER_ASPIRE] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02008344 .mixers = { alc883_acer_aspire_mixer },
Kailang Yangd1a991a2007-08-15 16:21:59 +02008345 .init_verbs = { alc883_init_verbs, alc883_acer_eapd_verbs },
Tobin Davis2880a862007-08-07 11:50:26 +02008346 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8347 .dac_nids = alc883_dac_nids,
8348 .dig_out_nid = ALC883_DIGOUT_NID,
Tobin Davis2880a862007-08-07 11:50:26 +02008349 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8350 .channel_mode = alc883_3ST_2ch_modes,
8351 .input_mux = &alc883_capture_source,
Takashi Iwai676a9b52007-08-16 15:23:35 +02008352 .unsol_event = alc883_acer_aspire_unsol_event,
8353 .init_hook = alc883_acer_aspire_automute,
Kailang Yangd1a991a2007-08-15 16:21:59 +02008354 },
Tobin Davisc07584c2006-10-13 12:32:16 +02008355 [ALC883_MEDION] = {
8356 .mixers = { alc883_fivestack_mixer,
8357 alc883_chmode_mixer },
8358 .init_verbs = { alc883_init_verbs,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008359 alc883_medion_eapd_verbs },
Tobin Davisc07584c2006-10-13 12:32:16 +02008360 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8361 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01008362 .adc_nids = alc883_adc_nids_alt,
8363 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Tobin Davisc07584c2006-10-13 12:32:16 +02008364 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
8365 .channel_mode = alc883_sixstack_modes,
8366 .input_mux = &alc883_capture_source,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008367 },
Kailang Yang272a5272007-05-14 11:00:38 +02008368 [ALC883_MEDION_MD2] = {
8369 .mixers = { alc883_medion_md2_mixer},
8370 .init_verbs = { alc883_init_verbs, alc883_medion_md2_verbs},
8371 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8372 .dac_nids = alc883_dac_nids,
8373 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang272a5272007-05-14 11:00:38 +02008374 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8375 .channel_mode = alc883_3ST_2ch_modes,
8376 .input_mux = &alc883_capture_source,
8377 .unsol_event = alc883_medion_md2_unsol_event,
8378 .init_hook = alc883_medion_md2_automute,
Kailang Yangea1fb292008-08-26 12:58:38 +02008379 },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008380 [ALC883_LAPTOP_EAPD] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02008381 .mixers = { alc883_base_mixer },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008382 .init_verbs = { alc883_init_verbs, alc882_eapd_verbs },
8383 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8384 .dac_nids = alc883_dac_nids,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008385 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8386 .channel_mode = alc883_3ST_2ch_modes,
8387 .input_mux = &alc883_capture_source,
8388 },
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008389 [ALC883_CLEVO_M720] = {
8390 .mixers = { alc883_clevo_m720_mixer },
8391 .init_verbs = { alc883_init_verbs, alc883_clevo_m720_verbs },
Jiang zhe368c7a92008-03-04 11:20:33 +01008392 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8393 .dac_nids = alc883_dac_nids,
8394 .dig_out_nid = ALC883_DIGOUT_NID,
8395 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8396 .channel_mode = alc883_3ST_2ch_modes,
8397 .input_mux = &alc883_capture_source,
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008398 .unsol_event = alc883_clevo_m720_unsol_event,
8399 .init_hook = alc883_clevo_m720_automute,
Jiang zhe368c7a92008-03-04 11:20:33 +01008400 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008401 [ALC883_LENOVO_101E_2ch] = {
8402 .mixers = { alc883_lenovo_101e_2ch_mixer},
8403 .init_verbs = { alc883_init_verbs, alc883_lenovo_101e_verbs},
8404 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8405 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01008406 .adc_nids = alc883_adc_nids_alt,
8407 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008408 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8409 .channel_mode = alc883_3ST_2ch_modes,
8410 .input_mux = &alc883_lenovo_101e_capture_source,
8411 .unsol_event = alc883_lenovo_101e_unsol_event,
8412 .init_hook = alc883_lenovo_101e_all_automute,
8413 },
Kailang Yang272a5272007-05-14 11:00:38 +02008414 [ALC883_LENOVO_NB0763] = {
8415 .mixers = { alc883_lenovo_nb0763_mixer },
8416 .init_verbs = { alc883_init_verbs, alc883_lenovo_nb0763_verbs},
8417 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8418 .dac_nids = alc883_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +02008419 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8420 .channel_mode = alc883_3ST_2ch_modes,
8421 .need_dac_fix = 1,
8422 .input_mux = &alc883_lenovo_nb0763_capture_source,
8423 .unsol_event = alc883_medion_md2_unsol_event,
8424 .init_hook = alc883_medion_md2_automute,
8425 },
8426 [ALC888_LENOVO_MS7195_DIG] = {
8427 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
8428 .init_verbs = { alc883_init_verbs, alc888_lenovo_ms7195_verbs},
8429 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8430 .dac_nids = alc883_dac_nids,
8431 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang272a5272007-05-14 11:00:38 +02008432 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
8433 .channel_mode = alc883_3ST_6ch_modes,
8434 .need_dac_fix = 1,
8435 .input_mux = &alc883_capture_source,
8436 .unsol_event = alc883_lenovo_ms7195_unsol_event,
8437 .init_hook = alc888_lenovo_ms7195_front_automute,
Kailang Yang189609a2007-08-20 11:31:23 +02008438 },
8439 [ALC883_HAIER_W66] = {
8440 .mixers = { alc883_tagra_2ch_mixer},
8441 .init_verbs = { alc883_init_verbs, alc883_haier_w66_verbs},
8442 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8443 .dac_nids = alc883_dac_nids,
8444 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang189609a2007-08-20 11:31:23 +02008445 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8446 .channel_mode = alc883_3ST_2ch_modes,
8447 .input_mux = &alc883_capture_source,
8448 .unsol_event = alc883_haier_w66_unsol_event,
8449 .init_hook = alc883_haier_w66_automute,
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +01008450 },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008451 [ALC888_3ST_HP] = {
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +01008452 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008453 .init_verbs = { alc883_init_verbs, alc888_3st_hp_verbs },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008454 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8455 .dac_nids = alc883_dac_nids,
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008456 .num_channel_mode = ARRAY_SIZE(alc888_3st_hp_modes),
8457 .channel_mode = alc888_3st_hp_modes,
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008458 .need_dac_fix = 1,
8459 .input_mux = &alc883_capture_source,
8460 },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008461 [ALC888_6ST_DELL] = {
Herton Ronaldo Krzesinskif24dbdc2008-03-20 12:14:28 +01008462 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008463 .init_verbs = { alc883_init_verbs, alc888_6st_dell_verbs },
8464 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8465 .dac_nids = alc883_dac_nids,
8466 .dig_out_nid = ALC883_DIGOUT_NID,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008467 .dig_in_nid = ALC883_DIGIN_NID,
8468 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
8469 .channel_mode = alc883_sixstack_modes,
8470 .input_mux = &alc883_capture_source,
8471 .unsol_event = alc888_6st_dell_unsol_event,
8472 .init_hook = alc888_6st_dell_front_automute,
8473 },
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008474 [ALC883_MITAC] = {
8475 .mixers = { alc883_mitac_mixer },
8476 .init_verbs = { alc883_init_verbs, alc883_mitac_verbs },
8477 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8478 .dac_nids = alc883_dac_nids,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008479 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8480 .channel_mode = alc883_3ST_2ch_modes,
8481 .input_mux = &alc883_capture_source,
8482 .unsol_event = alc883_mitac_unsol_event,
8483 .init_hook = alc883_mitac_automute,
8484 },
Jiang zhefb97dc62008-03-06 11:07:11 +01008485 [ALC883_FUJITSU_PI2515] = {
8486 .mixers = { alc883_2ch_fujitsu_pi2515_mixer },
8487 .init_verbs = { alc883_init_verbs,
8488 alc883_2ch_fujitsu_pi2515_verbs},
8489 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8490 .dac_nids = alc883_dac_nids,
8491 .dig_out_nid = ALC883_DIGOUT_NID,
8492 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8493 .channel_mode = alc883_3ST_2ch_modes,
8494 .input_mux = &alc883_fujitsu_pi2515_capture_source,
8495 .unsol_event = alc883_2ch_fujitsu_pi2515_unsol_event,
8496 .init_hook = alc883_2ch_fujitsu_pi2515_automute,
8497 },
Kailang Yange2757d52008-08-26 13:17:46 +02008498 [ALC888_LENOVO_SKY] = {
8499 .mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer },
8500 .init_verbs = { alc883_init_verbs, alc888_lenovo_sky_verbs},
8501 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8502 .dac_nids = alc883_dac_nids,
8503 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yange2757d52008-08-26 13:17:46 +02008504 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
8505 .channel_mode = alc883_sixstack_modes,
8506 .need_dac_fix = 1,
8507 .input_mux = &alc883_lenovo_sky_capture_source,
8508 .unsol_event = alc883_lenovo_sky_unsol_event,
8509 .init_hook = alc888_lenovo_sky_front_automute,
8510 },
8511 [ALC888_ASUS_M90V] = {
8512 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
8513 .init_verbs = { alc883_init_verbs, alc888_asus_m90v_verbs },
8514 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8515 .dac_nids = alc883_dac_nids,
8516 .dig_out_nid = ALC883_DIGOUT_NID,
8517 .dig_in_nid = ALC883_DIGIN_NID,
8518 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
8519 .channel_mode = alc883_3ST_6ch_modes,
8520 .need_dac_fix = 1,
8521 .input_mux = &alc883_fujitsu_pi2515_capture_source,
8522 .unsol_event = alc883_mode2_unsol_event,
8523 .init_hook = alc883_mode2_inithook,
8524 },
8525 [ALC888_ASUS_EEE1601] = {
8526 .mixers = { alc883_asus_eee1601_mixer },
Takashi Iwaif9e336f2008-10-31 16:37:07 +01008527 .cap_mixer = alc883_asus_eee1601_cap_mixer,
Kailang Yange2757d52008-08-26 13:17:46 +02008528 .init_verbs = { alc883_init_verbs, alc888_asus_eee1601_verbs },
8529 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8530 .dac_nids = alc883_dac_nids,
8531 .dig_out_nid = ALC883_DIGOUT_NID,
8532 .dig_in_nid = ALC883_DIGIN_NID,
8533 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8534 .channel_mode = alc883_3ST_2ch_modes,
8535 .need_dac_fix = 1,
8536 .input_mux = &alc883_asus_eee1601_capture_source,
8537 .unsol_event = alc883_eee1601_unsol_event,
8538 .init_hook = alc883_eee1601_inithook,
8539 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008540};
8541
8542
8543/*
8544 * BIOS auto configuration
8545 */
8546static void alc883_auto_set_output_and_unmute(struct hda_codec *codec,
8547 hda_nid_t nid, int pin_type,
8548 int dac_idx)
8549{
8550 /* set as output */
8551 struct alc_spec *spec = codec->spec;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008552 int idx;
8553
Takashi Iwaif6c7e542008-02-12 18:32:23 +01008554 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008555 if (spec->multiout.dac_nids[dac_idx] == 0x25)
8556 idx = 4;
8557 else
8558 idx = spec->multiout.dac_nids[dac_idx] - 2;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008559 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
8560
8561}
8562
8563static void alc883_auto_init_multi_out(struct hda_codec *codec)
8564{
8565 struct alc_spec *spec = codec->spec;
8566 int i;
8567
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008568 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008569 for (i = 0; i <= HDA_SIDE; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008570 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02008571 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008572 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02008573 alc883_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008574 i);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008575 }
8576}
8577
8578static void alc883_auto_init_hp_out(struct hda_codec *codec)
8579{
8580 struct alc_spec *spec = codec->spec;
8581 hda_nid_t pin;
8582
Takashi Iwaieb06ed82006-09-20 17:10:27 +02008583 pin = spec->autocfg.hp_pins[0];
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008584 if (pin) /* connect to front */
8585 /* use dac 0 */
8586 alc883_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01008587 pin = spec->autocfg.speaker_pins[0];
8588 if (pin)
8589 alc883_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008590}
8591
8592#define alc883_is_input_pin(nid) alc880_is_input_pin(nid)
8593#define ALC883_PIN_CD_NID ALC880_PIN_CD_NID
8594
8595static void alc883_auto_init_analog_input(struct hda_codec *codec)
8596{
8597 struct alc_spec *spec = codec->spec;
8598 int i;
8599
8600 for (i = 0; i < AUTO_PIN_LAST; i++) {
8601 hda_nid_t nid = spec->autocfg.input_pins[i];
8602 if (alc883_is_input_pin(nid)) {
8603 snd_hda_codec_write(codec, nid, 0,
8604 AC_VERB_SET_PIN_WIDGET_CONTROL,
8605 (i <= AUTO_PIN_FRONT_MIC ?
8606 PIN_VREF80 : PIN_IN));
8607 if (nid != ALC883_PIN_CD_NID)
8608 snd_hda_codec_write(codec, nid, 0,
8609 AC_VERB_SET_AMP_GAIN_MUTE,
8610 AMP_OUT_MUTE);
8611 }
8612 }
8613}
8614
Takashi Iwaif511b012008-08-15 16:46:42 +02008615#define alc883_auto_init_input_src alc882_auto_init_input_src
8616
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008617/* almost identical with ALC880 parser... */
8618static int alc883_parse_auto_config(struct hda_codec *codec)
8619{
8620 struct alc_spec *spec = codec->spec;
8621 int err = alc880_parse_auto_config(codec);
8622
8623 if (err < 0)
8624 return err;
Takashi Iwai776e1842007-08-29 15:07:11 +02008625 else if (!err)
8626 return 0; /* no config found */
8627
8628 err = alc_auto_add_mic_boost(codec);
8629 if (err < 0)
8630 return err;
8631
8632 /* hack - override the init verbs */
8633 spec->init_verbs[0] = alc883_auto_init_verbs;
Takashi Iwai776e1842007-08-29 15:07:11 +02008634
8635 return 1; /* config found */
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008636}
8637
8638/* additional initialization for auto-configuration model */
8639static void alc883_auto_init(struct hda_codec *codec)
8640{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01008641 struct alc_spec *spec = codec->spec;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008642 alc883_auto_init_multi_out(codec);
8643 alc883_auto_init_hp_out(codec);
8644 alc883_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +02008645 alc883_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01008646 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02008647 alc_inithook(codec);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008648}
8649
8650static int patch_alc883(struct hda_codec *codec)
8651{
8652 struct alc_spec *spec;
8653 int err, board_config;
8654
8655 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
8656 if (spec == NULL)
8657 return -ENOMEM;
8658
8659 codec->spec = spec;
8660
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02008661 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
8662
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008663 board_config = snd_hda_check_board_config(codec, ALC883_MODEL_LAST,
8664 alc883_models,
8665 alc883_cfg_tbl);
8666 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008667 printk(KERN_INFO "hda_codec: Unknown model for ALC883, "
8668 "trying auto-probe from BIOS...\n");
8669 board_config = ALC883_AUTO;
8670 }
8671
8672 if (board_config == ALC883_AUTO) {
8673 /* automatic parse from the BIOS config */
8674 err = alc883_parse_auto_config(codec);
8675 if (err < 0) {
8676 alc_free(codec);
8677 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008678 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008679 printk(KERN_INFO
8680 "hda_codec: Cannot set up configuration "
8681 "from BIOS. Using base mode...\n");
8682 board_config = ALC883_3ST_2ch_DIG;
8683 }
8684 }
8685
8686 if (board_config != ALC883_AUTO)
8687 setup_preset(spec, &alc883_presets[board_config]);
8688
Kailang Yang2f893282008-05-27 12:14:47 +02008689 switch (codec->vendor_id) {
8690 case 0x10ec0888:
Kailang Yang44426082008-10-15 11:18:05 +02008691 if (codec->revision_id == 0x100101) {
8692 spec->stream_name_analog = "ALC1200 Analog";
8693 spec->stream_name_digital = "ALC1200 Digital";
8694 } else {
8695 spec->stream_name_analog = "ALC888 Analog";
8696 spec->stream_name_digital = "ALC888 Digital";
8697 }
Kailang Yang2f893282008-05-27 12:14:47 +02008698 break;
8699 case 0x10ec0889:
8700 spec->stream_name_analog = "ALC889 Analog";
8701 spec->stream_name_digital = "ALC889 Digital";
8702 break;
8703 default:
8704 spec->stream_name_analog = "ALC883 Analog";
8705 spec->stream_name_digital = "ALC883 Digital";
8706 break;
8707 }
8708
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008709 spec->stream_analog_playback = &alc883_pcm_analog_playback;
8710 spec->stream_analog_capture = &alc883_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01008711 spec->stream_analog_alt_capture = &alc883_pcm_analog_alt_capture;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008712
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008713 spec->stream_digital_playback = &alc883_pcm_digital_playback;
8714 spec->stream_digital_capture = &alc883_pcm_digital_capture;
8715
Takashi Iwaif9e336f2008-10-31 16:37:07 +01008716 if (!spec->num_adc_nids) {
8717 spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids);
8718 spec->adc_nids = alc883_adc_nids;
8719 }
8720 if (!spec->capsrc_nids)
8721 spec->capsrc_nids = alc883_capsrc_nids;
Takashi Iwai54cbc9a2008-10-31 15:24:04 +01008722 spec->is_mix_capture = 1; /* matrix-style capture */
Takashi Iwaif9e336f2008-10-31 16:37:07 +01008723 if (!spec->cap_mixer)
8724 set_capture_mixer(spec);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008725
Takashi Iwai2134ea42008-01-10 16:53:55 +01008726 spec->vmaster_nid = 0x0c;
8727
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008728 codec->patch_ops = alc_patch_ops;
8729 if (board_config == ALC883_AUTO)
8730 spec->init_hook = alc883_auto_init;
Kailang Yangf9423e72008-05-27 12:32:25 +02008731
Takashi Iwaicb53c622007-08-10 17:21:45 +02008732#ifdef CONFIG_SND_HDA_POWER_SAVE
8733 if (!spec->loopback.amplist)
8734 spec->loopback.amplist = alc883_loopbacks;
8735#endif
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008736
8737 return 0;
8738}
8739
8740/*
Kailang Yangdf694da2005-12-05 19:42:22 +01008741 * ALC262 support
8742 */
8743
8744#define ALC262_DIGOUT_NID ALC880_DIGOUT_NID
8745#define ALC262_DIGIN_NID ALC880_DIGIN_NID
8746
8747#define alc262_dac_nids alc260_dac_nids
8748#define alc262_adc_nids alc882_adc_nids
8749#define alc262_adc_nids_alt alc882_adc_nids_alt
Takashi Iwai88c71a92008-02-14 17:27:17 +01008750#define alc262_capsrc_nids alc882_capsrc_nids
8751#define alc262_capsrc_nids_alt alc882_capsrc_nids_alt
Kailang Yangdf694da2005-12-05 19:42:22 +01008752
8753#define alc262_modes alc260_modes
Takashi Iwaic5f2ea02005-12-06 18:54:31 +01008754#define alc262_capture_source alc882_capture_source
Kailang Yangdf694da2005-12-05 19:42:22 +01008755
Kailang Yang4e555fe2008-08-26 13:05:55 +02008756static hda_nid_t alc262_dmic_adc_nids[1] = {
8757 /* ADC0 */
8758 0x09
8759};
8760
8761static hda_nid_t alc262_dmic_capsrc_nids[1] = { 0x22 };
8762
Kailang Yangdf694da2005-12-05 19:42:22 +01008763static struct snd_kcontrol_new alc262_base_mixer[] = {
8764 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8765 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8766 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8767 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8768 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8769 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8770 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8771 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008772 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01008773 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
8774 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008775 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01008776 /* HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01008777 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT), */
Kailang Yangdf694da2005-12-05 19:42:22 +01008778 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),
8779 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8780 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8781 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01008782 { } /* end */
Takashi Iwai834be882006-03-01 14:16:17 +01008783};
8784
Kailang Yangccc656c2006-10-17 12:32:26 +02008785static struct snd_kcontrol_new alc262_hippo1_mixer[] = {
8786 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8787 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8788 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8789 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8790 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8791 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8792 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8793 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008794 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008795 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
8796 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008797 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008798 /* HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01008799 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT), */
Kailang Yangccc656c2006-10-17 12:32:26 +02008800 /*HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),*/
8801 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8802 { } /* end */
8803};
8804
Takashi Iwaice875f02008-01-28 18:17:43 +01008805/* update HP, line and mono-out pins according to the master switch */
8806static void alc262_hp_master_update(struct hda_codec *codec)
8807{
8808 struct alc_spec *spec = codec->spec;
8809 int val = spec->master_sw;
8810
8811 /* HP & line-out */
8812 snd_hda_codec_write_cache(codec, 0x1b, 0,
8813 AC_VERB_SET_PIN_WIDGET_CONTROL,
8814 val ? PIN_HP : 0);
8815 snd_hda_codec_write_cache(codec, 0x15, 0,
8816 AC_VERB_SET_PIN_WIDGET_CONTROL,
8817 val ? PIN_HP : 0);
8818 /* mono (speaker) depending on the HP jack sense */
8819 val = val && !spec->jack_present;
8820 snd_hda_codec_write_cache(codec, 0x16, 0,
8821 AC_VERB_SET_PIN_WIDGET_CONTROL,
8822 val ? PIN_OUT : 0);
8823}
8824
8825static void alc262_hp_bpc_automute(struct hda_codec *codec)
8826{
8827 struct alc_spec *spec = codec->spec;
8828 unsigned int presence;
8829 presence = snd_hda_codec_read(codec, 0x1b, 0,
8830 AC_VERB_GET_PIN_SENSE, 0);
8831 spec->jack_present = !!(presence & AC_PINSENSE_PRESENCE);
8832 alc262_hp_master_update(codec);
8833}
8834
8835static void alc262_hp_bpc_unsol_event(struct hda_codec *codec, unsigned int res)
8836{
8837 if ((res >> 26) != ALC880_HP_EVENT)
8838 return;
8839 alc262_hp_bpc_automute(codec);
8840}
8841
8842static void alc262_hp_wildwest_automute(struct hda_codec *codec)
8843{
8844 struct alc_spec *spec = codec->spec;
8845 unsigned int presence;
8846 presence = snd_hda_codec_read(codec, 0x15, 0,
8847 AC_VERB_GET_PIN_SENSE, 0);
8848 spec->jack_present = !!(presence & AC_PINSENSE_PRESENCE);
8849 alc262_hp_master_update(codec);
8850}
8851
8852static void alc262_hp_wildwest_unsol_event(struct hda_codec *codec,
8853 unsigned int res)
8854{
8855 if ((res >> 26) != ALC880_HP_EVENT)
8856 return;
8857 alc262_hp_wildwest_automute(codec);
8858}
8859
8860static int alc262_hp_master_sw_get(struct snd_kcontrol *kcontrol,
8861 struct snd_ctl_elem_value *ucontrol)
8862{
8863 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
8864 struct alc_spec *spec = codec->spec;
8865 *ucontrol->value.integer.value = spec->master_sw;
8866 return 0;
8867}
8868
8869static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol,
8870 struct snd_ctl_elem_value *ucontrol)
8871{
8872 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
8873 struct alc_spec *spec = codec->spec;
8874 int val = !!*ucontrol->value.integer.value;
8875
8876 if (val == spec->master_sw)
8877 return 0;
8878 spec->master_sw = val;
8879 alc262_hp_master_update(codec);
8880 return 1;
8881}
8882
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008883static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
Takashi Iwaice875f02008-01-28 18:17:43 +01008884 {
8885 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8886 .name = "Master Playback Switch",
8887 .info = snd_ctl_boolean_mono_info,
8888 .get = alc262_hp_master_sw_get,
8889 .put = alc262_hp_master_sw_put,
8890 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008891 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8892 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8893 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +01008894 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
8895 HDA_OUTPUT),
8896 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
8897 HDA_OUTPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008898 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8899 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008900 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008901 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
8902 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008903 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008904 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8905 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8906 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8907 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8908 HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
8909 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT),
8910 HDA_CODEC_VOLUME("AUX IN Playback Volume", 0x0b, 0x06, HDA_INPUT),
8911 HDA_CODEC_MUTE("AUX IN Playback Switch", 0x0b, 0x06, HDA_INPUT),
8912 { } /* end */
8913};
8914
Kailang Yangcd7509a2007-01-26 18:33:17 +01008915static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = {
Takashi Iwaice875f02008-01-28 18:17:43 +01008916 {
8917 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8918 .name = "Master Playback Switch",
8919 .info = snd_ctl_boolean_mono_info,
8920 .get = alc262_hp_master_sw_get,
8921 .put = alc262_hp_master_sw_put,
8922 },
Kailang Yangcd7509a2007-01-26 18:33:17 +01008923 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8924 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8925 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8926 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +01008927 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
8928 HDA_OUTPUT),
8929 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
8930 HDA_OUTPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +01008931 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT),
8932 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008933 HDA_CODEC_VOLUME("Front Mic Boost", 0x1a, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +01008934 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
8935 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
8936 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8937 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8938 HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
8939 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT),
8940 { } /* end */
8941};
8942
8943static struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = {
8944 HDA_CODEC_VOLUME("Rear Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8945 HDA_CODEC_MUTE("Rear Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008946 HDA_CODEC_VOLUME("Rear Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +01008947 { } /* end */
8948};
8949
Kailang Yang66d2a9d2007-11-14 12:06:21 +01008950/* mute/unmute internal speaker according to the hp jack and mute state */
8951static void alc262_hp_t5735_automute(struct hda_codec *codec, int force)
8952{
8953 struct alc_spec *spec = codec->spec;
Kailang Yang66d2a9d2007-11-14 12:06:21 +01008954
8955 if (force || !spec->sense_updated) {
8956 unsigned int present;
8957 present = snd_hda_codec_read(codec, 0x15, 0,
8958 AC_VERB_GET_PIN_SENSE, 0);
Takashi Iwai4bb26132008-01-28 18:12:42 +01008959 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
Kailang Yang66d2a9d2007-11-14 12:06:21 +01008960 spec->sense_updated = 1;
8961 }
Takashi Iwai4bb26132008-01-28 18:12:42 +01008962 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0, HDA_AMP_MUTE,
8963 spec->jack_present ? HDA_AMP_MUTE : 0);
Kailang Yang66d2a9d2007-11-14 12:06:21 +01008964}
8965
8966static void alc262_hp_t5735_unsol_event(struct hda_codec *codec,
8967 unsigned int res)
8968{
8969 if ((res >> 26) != ALC880_HP_EVENT)
8970 return;
8971 alc262_hp_t5735_automute(codec, 1);
8972}
8973
8974static void alc262_hp_t5735_init_hook(struct hda_codec *codec)
8975{
8976 alc262_hp_t5735_automute(codec, 1);
8977}
8978
8979static struct snd_kcontrol_new alc262_hp_t5735_mixer[] = {
Takashi Iwai86cd9292008-01-28 18:09:56 +01008980 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8981 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang66d2a9d2007-11-14 12:06:21 +01008982 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8983 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8984 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8985 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8986 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8987 { } /* end */
8988};
8989
8990static struct hda_verb alc262_hp_t5735_verbs[] = {
8991 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8992 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8993
8994 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8995 { }
8996};
8997
Kailang Yang8c427222008-01-10 13:03:59 +01008998static struct snd_kcontrol_new alc262_hp_rp5700_mixer[] = {
Takashi Iwaif2f48e12008-01-28 18:14:43 +01008999 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9000 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01009001 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
9002 HDA_CODEC_MUTE("Speaker Playback Switch", 0x16, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +01009003 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
9004 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
9005 { } /* end */
9006};
9007
9008static struct hda_verb alc262_hp_rp5700_verbs[] = {
9009 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9010 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9011 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9012 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9013 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
9014 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
9015 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
9016 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
9017 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
9018 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
9019 {}
9020};
9021
9022static struct hda_input_mux alc262_hp_rp5700_capture_source = {
9023 .num_items = 1,
9024 .items = {
9025 { "Line", 0x1 },
9026 },
9027};
9028
Takashi Iwai0724ea22007-08-23 00:31:43 +02009029/* bind hp and internal speaker mute (with plug check) */
9030static int alc262_sony_master_sw_put(struct snd_kcontrol *kcontrol,
9031 struct snd_ctl_elem_value *ucontrol)
9032{
9033 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
9034 long *valp = ucontrol->value.integer.value;
9035 int change;
9036
9037 /* change hp mute */
9038 change = snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0,
9039 HDA_AMP_MUTE,
9040 valp[0] ? 0 : HDA_AMP_MUTE);
9041 change |= snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0,
9042 HDA_AMP_MUTE,
9043 valp[1] ? 0 : HDA_AMP_MUTE);
9044 if (change) {
9045 /* change speaker according to HP jack state */
9046 struct alc_spec *spec = codec->spec;
9047 unsigned int mute;
9048 if (spec->jack_present)
9049 mute = HDA_AMP_MUTE;
9050 else
9051 mute = snd_hda_codec_amp_read(codec, 0x15, 0,
9052 HDA_OUTPUT, 0);
9053 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9054 HDA_AMP_MUTE, mute);
9055 }
9056 return change;
9057}
Takashi Iwai5b319542007-07-26 11:49:22 +02009058
Kailang Yang272a5272007-05-14 11:00:38 +02009059static struct snd_kcontrol_new alc262_sony_mixer[] = {
Takashi Iwai0724ea22007-08-23 00:31:43 +02009060 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9061 {
9062 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9063 .name = "Master Playback Switch",
9064 .info = snd_hda_mixer_amp_switch_info,
9065 .get = snd_hda_mixer_amp_switch_get,
9066 .put = alc262_sony_master_sw_put,
9067 .private_value = HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
9068 },
Kailang Yang272a5272007-05-14 11:00:38 +02009069 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9070 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9071 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
9072 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
9073 { } /* end */
9074};
9075
Kailang Yang83c34212007-07-05 11:43:05 +02009076static struct snd_kcontrol_new alc262_benq_t31_mixer[] = {
9077 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9078 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9079 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9080 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9081 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9082 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
9083 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
9084 { } /* end */
9085};
Kailang Yang272a5272007-05-14 11:00:38 +02009086
Kailang Yangdf694da2005-12-05 19:42:22 +01009087#define alc262_capture_mixer alc882_capture_mixer
9088#define alc262_capture_alt_mixer alc882_capture_alt_mixer
9089
9090/*
9091 * generic initialization of ADC, input mixers and output mixers
9092 */
9093static struct hda_verb alc262_init_verbs[] = {
9094 /*
9095 * Unmute ADC0-2 and set the default input to mic-in
9096 */
9097 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
9098 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9099 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
9100 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9101 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
9102 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9103
Takashi Iwaicb53c622007-08-10 17:21:45 +02009104 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +01009105 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009106 * Note: PASD motherboards uses the Line In 2 as the input for
9107 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01009108 */
9109 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02009110 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9111 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
9112 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
9113 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
9114 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01009115
9116 /*
9117 * Set up output mixers (0x0c - 0x0e)
9118 */
9119 /* set vol=0 to output mixers */
9120 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9121 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9122 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9123 /* set up input amps for analog loopback */
9124 /* Amp Indices: DAC = 0, mixer = 1 */
9125 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9126 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9127 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9128 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9129 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9130 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9131
9132 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
9133 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
9134 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
9135 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9136 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9137 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9138
9139 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
9140 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
9141 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
9142 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
9143 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Kailang Yangea1fb292008-08-26 12:58:38 +02009144
Kailang Yangdf694da2005-12-05 19:42:22 +01009145 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
9146 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Kailang Yangea1fb292008-08-26 12:58:38 +02009147
Kailang Yangdf694da2005-12-05 19:42:22 +01009148 /* FIXME: use matrix-type input source selection */
9149 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
9150 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
9151 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9152 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
9153 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
9154 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
9155 /* Input mixer2 */
9156 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9157 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
9158 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
9159 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
9160 /* Input mixer3 */
9161 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9162 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
9163 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009164 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
Kailang Yangdf694da2005-12-05 19:42:22 +01009165
9166 { }
9167};
9168
Kailang Yang4e555fe2008-08-26 13:05:55 +02009169static struct hda_verb alc262_eapd_verbs[] = {
9170 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
9171 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
9172 { }
9173};
9174
Kailang Yangccc656c2006-10-17 12:32:26 +02009175static struct hda_verb alc262_hippo_unsol_verbs[] = {
9176 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
9177 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9178 {}
9179};
9180
9181static struct hda_verb alc262_hippo1_unsol_verbs[] = {
9182 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
9183 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
9184 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
9185
9186 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
9187 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9188 {}
9189};
9190
Kailang Yang272a5272007-05-14 11:00:38 +02009191static struct hda_verb alc262_sony_unsol_verbs[] = {
9192 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
9193 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9194 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, // Front Mic
9195
9196 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
9197 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Akio Idehara7b1e8792008-06-09 22:46:07 +09009198 {}
Kailang Yang272a5272007-05-14 11:00:38 +02009199};
9200
Kailang Yang4e555fe2008-08-26 13:05:55 +02009201static struct hda_input_mux alc262_dmic_capture_source = {
9202 .num_items = 2,
9203 .items = {
9204 { "Int DMic", 0x9 },
9205 { "Mic", 0x0 },
9206 },
9207};
9208
9209static struct snd_kcontrol_new alc262_toshiba_s06_mixer[] = {
9210 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9211 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9212 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9213 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9214 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang4e555fe2008-08-26 13:05:55 +02009215 { } /* end */
9216};
9217
9218static struct hda_verb alc262_toshiba_s06_verbs[] = {
9219 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
9220 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9221 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9222 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9223 {0x22, AC_VERB_SET_CONNECT_SEL, 0x09},
9224 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9225 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
9226 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
9227 {}
9228};
9229
9230static void alc262_dmic_automute(struct hda_codec *codec)
9231{
9232 unsigned int present;
9233
9234 present = snd_hda_codec_read(codec, 0x18, 0,
9235 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
9236 snd_hda_codec_write(codec, 0x22, 0,
9237 AC_VERB_SET_CONNECT_SEL, present ? 0x0 : 0x09);
9238}
9239
9240/* toggle speaker-output according to the hp-jack state */
9241static void alc262_toshiba_s06_speaker_automute(struct hda_codec *codec)
9242{
9243 unsigned int present;
9244 unsigned char bits;
9245
9246 present = snd_hda_codec_read(codec, 0x15, 0,
9247 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
9248 bits = present ? 0 : PIN_OUT;
9249 snd_hda_codec_write(codec, 0x14, 0,
9250 AC_VERB_SET_PIN_WIDGET_CONTROL, bits);
9251}
9252
9253
9254
9255/* unsolicited event for HP jack sensing */
9256static void alc262_toshiba_s06_unsol_event(struct hda_codec *codec,
9257 unsigned int res)
9258{
9259 if ((res >> 26) == ALC880_HP_EVENT)
9260 alc262_toshiba_s06_speaker_automute(codec);
9261 if ((res >> 26) == ALC880_MIC_EVENT)
9262 alc262_dmic_automute(codec);
9263
9264}
9265
9266static void alc262_toshiba_s06_init_hook(struct hda_codec *codec)
9267{
9268 alc262_toshiba_s06_speaker_automute(codec);
9269 alc262_dmic_automute(codec);
9270}
9271
Kailang Yangccc656c2006-10-17 12:32:26 +02009272/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwai5b319542007-07-26 11:49:22 +02009273static void alc262_hippo_automute(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02009274{
9275 struct alc_spec *spec = codec->spec;
9276 unsigned int mute;
Takashi Iwai5b319542007-07-26 11:49:22 +02009277 unsigned int present;
Kailang Yangccc656c2006-10-17 12:32:26 +02009278
Takashi Iwai5b319542007-07-26 11:49:22 +02009279 /* need to execute and sync at first */
9280 snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0);
9281 present = snd_hda_codec_read(codec, 0x15, 0,
9282 AC_VERB_GET_PIN_SENSE, 0);
9283 spec->jack_present = (present & 0x80000000) != 0;
Kailang Yangccc656c2006-10-17 12:32:26 +02009284 if (spec->jack_present) {
9285 /* mute internal speaker */
Takashi Iwai47fd8302007-08-10 17:11:07 +02009286 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9287 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yangccc656c2006-10-17 12:32:26 +02009288 } else {
9289 /* unmute internal speaker if necessary */
9290 mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0);
Takashi Iwai47fd8302007-08-10 17:11:07 +02009291 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9292 HDA_AMP_MUTE, mute);
Kailang Yangccc656c2006-10-17 12:32:26 +02009293 }
9294}
9295
9296/* unsolicited event for HP jack sensing */
9297static void alc262_hippo_unsol_event(struct hda_codec *codec,
9298 unsigned int res)
9299{
9300 if ((res >> 26) != ALC880_HP_EVENT)
9301 return;
Takashi Iwai5b319542007-07-26 11:49:22 +02009302 alc262_hippo_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02009303}
9304
Takashi Iwai5b319542007-07-26 11:49:22 +02009305static void alc262_hippo1_automute(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02009306{
Kailang Yangccc656c2006-10-17 12:32:26 +02009307 unsigned int mute;
Takashi Iwai5b319542007-07-26 11:49:22 +02009308 unsigned int present;
Kailang Yangccc656c2006-10-17 12:32:26 +02009309
Takashi Iwai5b319542007-07-26 11:49:22 +02009310 snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
9311 present = snd_hda_codec_read(codec, 0x1b, 0,
9312 AC_VERB_GET_PIN_SENSE, 0);
9313 present = (present & 0x80000000) != 0;
9314 if (present) {
Kailang Yangccc656c2006-10-17 12:32:26 +02009315 /* mute internal speaker */
Takashi Iwai47fd8302007-08-10 17:11:07 +02009316 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9317 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yangccc656c2006-10-17 12:32:26 +02009318 } else {
9319 /* unmute internal speaker if necessary */
9320 mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
Takashi Iwai47fd8302007-08-10 17:11:07 +02009321 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9322 HDA_AMP_MUTE, mute);
Kailang Yangccc656c2006-10-17 12:32:26 +02009323 }
9324}
9325
9326/* unsolicited event for HP jack sensing */
9327static void alc262_hippo1_unsol_event(struct hda_codec *codec,
9328 unsigned int res)
9329{
9330 if ((res >> 26) != ALC880_HP_EVENT)
9331 return;
Takashi Iwai5b319542007-07-26 11:49:22 +02009332 alc262_hippo1_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02009333}
9334
Takashi Iwai834be882006-03-01 14:16:17 +01009335/*
Pascal Terjane8f9ae22008-08-04 14:36:05 +02009336 * nec model
9337 * 0x15 = headphone
9338 * 0x16 = internal speaker
9339 * 0x18 = external mic
9340 */
9341
9342static struct snd_kcontrol_new alc262_nec_mixer[] = {
9343 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
9344 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 0, 0x0, HDA_OUTPUT),
9345
9346 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9347 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9348 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9349
9350 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
9351 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9352 { } /* end */
9353};
9354
9355static struct hda_verb alc262_nec_verbs[] = {
9356 /* Unmute Speaker */
9357 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9358
9359 /* Headphone */
9360 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
9361 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9362
9363 /* External mic to headphone */
9364 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9365 /* External mic to speaker */
9366 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9367 {}
9368};
9369
9370/*
Takashi Iwai834be882006-03-01 14:16:17 +01009371 * fujitsu model
Tony Vroon5d9fab22008-03-14 17:09:18 +01009372 * 0x14 = headphone/spdif-out, 0x15 = internal speaker,
9373 * 0x1b = port replicator headphone out
Takashi Iwai834be882006-03-01 14:16:17 +01009374 */
9375
9376#define ALC_HP_EVENT 0x37
9377
9378static struct hda_verb alc262_fujitsu_unsol_verbs[] = {
9379 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
9380 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Tony Vroon5d9fab22008-03-14 17:09:18 +01009381 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
9382 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai834be882006-03-01 14:16:17 +01009383 {}
9384};
9385
Jiang zhe0e31daf2008-03-20 12:12:39 +01009386static struct hda_verb alc262_lenovo_3000_unsol_verbs[] = {
9387 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
9388 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9389 {}
9390};
9391
Takashi Iwai834be882006-03-01 14:16:17 +01009392static struct hda_input_mux alc262_fujitsu_capture_source = {
Takashi Iwai39d3ed32007-10-12 15:03:48 +02009393 .num_items = 3,
Takashi Iwai834be882006-03-01 14:16:17 +01009394 .items = {
9395 { "Mic", 0x0 },
Takashi Iwai39d3ed32007-10-12 15:03:48 +02009396 { "Int Mic", 0x1 },
Takashi Iwai834be882006-03-01 14:16:17 +01009397 { "CD", 0x4 },
9398 },
9399};
9400
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009401static struct hda_input_mux alc262_HP_capture_source = {
9402 .num_items = 5,
9403 .items = {
9404 { "Mic", 0x0 },
zhejiangaccbe492007-08-31 12:36:05 +02009405 { "Front Mic", 0x1 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009406 { "Line", 0x2 },
9407 { "CD", 0x4 },
9408 { "AUX IN", 0x6 },
9409 },
9410};
9411
zhejiangaccbe492007-08-31 12:36:05 +02009412static struct hda_input_mux alc262_HP_D7000_capture_source = {
9413 .num_items = 4,
9414 .items = {
9415 { "Mic", 0x0 },
9416 { "Front Mic", 0x2 },
9417 { "Line", 0x1 },
9418 { "CD", 0x4 },
9419 },
9420};
9421
Takashi Iwaiebc7a402008-05-20 09:23:05 +02009422/* mute/unmute internal speaker according to the hp jacks and mute state */
Takashi Iwai834be882006-03-01 14:16:17 +01009423static void alc262_fujitsu_automute(struct hda_codec *codec, int force)
9424{
9425 struct alc_spec *spec = codec->spec;
9426 unsigned int mute;
9427
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009428 if (force || !spec->sense_updated) {
Takashi Iwaiebc7a402008-05-20 09:23:05 +02009429 unsigned int present;
Takashi Iwai834be882006-03-01 14:16:17 +01009430 /* need to execute and sync at first */
9431 snd_hda_codec_read(codec, 0x14, 0, AC_VERB_SET_PIN_SENSE, 0);
Takashi Iwaiebc7a402008-05-20 09:23:05 +02009432 /* check laptop HP jack */
9433 present = snd_hda_codec_read(codec, 0x14, 0,
9434 AC_VERB_GET_PIN_SENSE, 0);
9435 /* need to execute and sync at first */
9436 snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
9437 /* check docking HP jack */
9438 present |= snd_hda_codec_read(codec, 0x1b, 0,
9439 AC_VERB_GET_PIN_SENSE, 0);
9440 if (present & AC_PINSENSE_PRESENCE)
9441 spec->jack_present = 1;
9442 else
9443 spec->jack_present = 0;
Takashi Iwai834be882006-03-01 14:16:17 +01009444 spec->sense_updated = 1;
9445 }
Takashi Iwaiebc7a402008-05-20 09:23:05 +02009446 /* unmute internal speaker only if both HPs are unplugged and
9447 * master switch is on
9448 */
9449 if (spec->jack_present)
9450 mute = HDA_AMP_MUTE;
9451 else
Takashi Iwai834be882006-03-01 14:16:17 +01009452 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
Takashi Iwaiebc7a402008-05-20 09:23:05 +02009453 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9454 HDA_AMP_MUTE, mute);
Takashi Iwai834be882006-03-01 14:16:17 +01009455}
9456
9457/* unsolicited event for HP jack sensing */
9458static void alc262_fujitsu_unsol_event(struct hda_codec *codec,
9459 unsigned int res)
9460{
9461 if ((res >> 26) != ALC_HP_EVENT)
9462 return;
9463 alc262_fujitsu_automute(codec, 1);
9464}
9465
Takashi Iwaiebc7a402008-05-20 09:23:05 +02009466static void alc262_fujitsu_init_hook(struct hda_codec *codec)
9467{
9468 alc262_fujitsu_automute(codec, 1);
9469}
9470
Takashi Iwai834be882006-03-01 14:16:17 +01009471/* bind volumes of both NID 0x0c and 0x0d */
Takashi Iwaicca3b372007-08-10 17:12:15 +02009472static struct hda_bind_ctls alc262_fujitsu_bind_master_vol = {
9473 .ops = &snd_hda_bind_vol,
9474 .values = {
9475 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT),
9476 HDA_COMPOSE_AMP_VAL(0x0d, 3, 0, HDA_OUTPUT),
9477 0
9478 },
9479};
Takashi Iwai834be882006-03-01 14:16:17 +01009480
Jiang zhe0e31daf2008-03-20 12:12:39 +01009481/* mute/unmute internal speaker according to the hp jack and mute state */
9482static void alc262_lenovo_3000_automute(struct hda_codec *codec, int force)
9483{
9484 struct alc_spec *spec = codec->spec;
9485 unsigned int mute;
9486
9487 if (force || !spec->sense_updated) {
9488 unsigned int present_int_hp;
9489 /* need to execute and sync at first */
9490 snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
9491 present_int_hp = snd_hda_codec_read(codec, 0x1b, 0,
9492 AC_VERB_GET_PIN_SENSE, 0);
9493 spec->jack_present = (present_int_hp & 0x80000000) != 0;
9494 spec->sense_updated = 1;
9495 }
9496 if (spec->jack_present) {
9497 /* mute internal speaker */
9498 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9499 HDA_AMP_MUTE, HDA_AMP_MUTE);
9500 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
9501 HDA_AMP_MUTE, HDA_AMP_MUTE);
9502 } else {
9503 /* unmute internal speaker if necessary */
9504 mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
9505 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9506 HDA_AMP_MUTE, mute);
9507 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
9508 HDA_AMP_MUTE, mute);
9509 }
9510}
9511
9512/* unsolicited event for HP jack sensing */
9513static void alc262_lenovo_3000_unsol_event(struct hda_codec *codec,
9514 unsigned int res)
9515{
9516 if ((res >> 26) != ALC_HP_EVENT)
9517 return;
9518 alc262_lenovo_3000_automute(codec, 1);
9519}
9520
Takashi Iwai834be882006-03-01 14:16:17 +01009521/* bind hp and internal speaker mute (with plug check) */
9522static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol,
9523 struct snd_ctl_elem_value *ucontrol)
9524{
9525 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
9526 long *valp = ucontrol->value.integer.value;
9527 int change;
9528
Tony Vroon5d9fab22008-03-14 17:09:18 +01009529 change = snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9530 HDA_AMP_MUTE,
9531 valp ? 0 : HDA_AMP_MUTE);
9532 change |= snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
9533 HDA_AMP_MUTE,
9534 valp ? 0 : HDA_AMP_MUTE);
9535
Takashi Iwai82beb8f2007-08-10 17:09:26 +02009536 if (change)
9537 alc262_fujitsu_automute(codec, 0);
Takashi Iwai834be882006-03-01 14:16:17 +01009538 return change;
9539}
9540
9541static struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02009542 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
Takashi Iwai834be882006-03-01 14:16:17 +01009543 {
9544 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9545 .name = "Master Playback Switch",
9546 .info = snd_hda_mixer_amp_switch_info,
9547 .get = snd_hda_mixer_amp_switch_get,
9548 .put = alc262_fujitsu_master_sw_put,
9549 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
9550 },
9551 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9552 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Tony Vroon06a9c302008-04-14 13:31:45 +02009553 HDA_CODEC_VOLUME("PC Speaker Volume", 0x0b, 0x05, HDA_INPUT),
9554 HDA_CODEC_MUTE("PC Speaker Switch", 0x0b, 0x05, HDA_INPUT),
Takashi Iwai834be882006-03-01 14:16:17 +01009555 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9556 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9557 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai39d3ed32007-10-12 15:03:48 +02009558 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
9559 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
9560 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai834be882006-03-01 14:16:17 +01009561 { } /* end */
9562};
9563
Jiang zhe0e31daf2008-03-20 12:12:39 +01009564/* bind hp and internal speaker mute (with plug check) */
9565static int alc262_lenovo_3000_master_sw_put(struct snd_kcontrol *kcontrol,
9566 struct snd_ctl_elem_value *ucontrol)
9567{
9568 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
9569 long *valp = ucontrol->value.integer.value;
9570 int change;
9571
9572 change = snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
9573 HDA_AMP_MUTE,
9574 valp ? 0 : HDA_AMP_MUTE);
9575
9576 if (change)
9577 alc262_lenovo_3000_automute(codec, 0);
9578 return change;
9579}
9580
9581static struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = {
9582 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
9583 {
9584 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9585 .name = "Master Playback Switch",
9586 .info = snd_hda_mixer_amp_switch_info,
9587 .get = snd_hda_mixer_amp_switch_get,
9588 .put = alc262_lenovo_3000_master_sw_put,
9589 .private_value = HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
9590 },
9591 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9592 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9593 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9594 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9595 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9596 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
9597 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
9598 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
9599 { } /* end */
9600};
9601
Hiroshi Miura9f99a632008-08-28 16:09:06 +02009602static struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = {
9603 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
9604 {
9605 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9606 .name = "Master Playback Switch",
9607 .info = snd_hda_mixer_amp_switch_info,
9608 .get = snd_hda_mixer_amp_switch_get,
9609 .put = alc262_sony_master_sw_put,
9610 .private_value = HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
9611 },
9612 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9613 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9614 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9615 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
9616 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
9617 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
9618 { } /* end */
9619};
9620
Takashi Iwai304dcaa2006-07-25 14:51:16 +02009621/* additional init verbs for Benq laptops */
9622static struct hda_verb alc262_EAPD_verbs[] = {
9623 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
9624 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
9625 {}
9626};
9627
Kailang Yang83c34212007-07-05 11:43:05 +02009628static struct hda_verb alc262_benq_t31_EAPD_verbs[] = {
9629 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9630 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9631
9632 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
9633 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
9634 {}
9635};
9636
Tobin Davisf651b502007-10-26 12:40:47 +02009637/* Samsung Q1 Ultra Vista model setup */
9638static struct snd_kcontrol_new alc262_ultra_mixer[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01009639 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9640 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +02009641 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
9642 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
9643 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01009644 HDA_CODEC_VOLUME("Headphone Mic Boost", 0x15, 0, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +02009645 { } /* end */
9646};
9647
9648static struct hda_verb alc262_ultra_verbs[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01009649 /* output mixer */
9650 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9651 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
9652 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9653 /* speaker */
9654 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9655 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9656 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9657 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
9658 /* HP */
Tobin Davisf651b502007-10-26 12:40:47 +02009659 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01009660 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9661 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9662 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9663 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
9664 /* internal mic */
9665 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
9666 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
9667 /* ADC, choose mic */
9668 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9669 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9670 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9671 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
9672 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
9673 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
9674 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
9675 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
9676 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
9677 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(8)},
Tobin Davisf651b502007-10-26 12:40:47 +02009678 {}
9679};
9680
Tobin Davisf651b502007-10-26 12:40:47 +02009681/* mute/unmute internal speaker according to the hp jack and mute state */
9682static void alc262_ultra_automute(struct hda_codec *codec)
9683{
9684 struct alc_spec *spec = codec->spec;
9685 unsigned int mute;
Tobin Davisf651b502007-10-26 12:40:47 +02009686
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01009687 mute = 0;
9688 /* auto-mute only when HP is used as HP */
9689 if (!spec->cur_mux[0]) {
9690 unsigned int present;
9691 /* need to execute and sync at first */
9692 snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0);
9693 present = snd_hda_codec_read(codec, 0x15, 0,
9694 AC_VERB_GET_PIN_SENSE, 0);
9695 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
9696 if (spec->jack_present)
9697 mute = HDA_AMP_MUTE;
Tobin Davisf651b502007-10-26 12:40:47 +02009698 }
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01009699 /* mute/unmute internal speaker */
9700 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9701 HDA_AMP_MUTE, mute);
9702 /* mute/unmute HP */
9703 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9704 HDA_AMP_MUTE, mute ? 0 : HDA_AMP_MUTE);
Tobin Davisf651b502007-10-26 12:40:47 +02009705}
9706
9707/* unsolicited event for HP jack sensing */
9708static void alc262_ultra_unsol_event(struct hda_codec *codec,
9709 unsigned int res)
9710{
9711 if ((res >> 26) != ALC880_HP_EVENT)
9712 return;
9713 alc262_ultra_automute(codec);
9714}
9715
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01009716static struct hda_input_mux alc262_ultra_capture_source = {
9717 .num_items = 2,
9718 .items = {
9719 { "Mic", 0x1 },
9720 { "Headphone", 0x7 },
9721 },
9722};
9723
9724static int alc262_ultra_mux_enum_put(struct snd_kcontrol *kcontrol,
9725 struct snd_ctl_elem_value *ucontrol)
9726{
9727 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
9728 struct alc_spec *spec = codec->spec;
9729 int ret;
9730
Takashi Iwai54cbc9a2008-10-31 15:24:04 +01009731 ret = alc_mux_enum_put(kcontrol, ucontrol);
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01009732 if (!ret)
9733 return 0;
9734 /* reprogram the HP pin as mic or HP according to the input source */
9735 snd_hda_codec_write_cache(codec, 0x15, 0,
9736 AC_VERB_SET_PIN_WIDGET_CONTROL,
9737 spec->cur_mux[0] ? PIN_VREF80 : PIN_HP);
9738 alc262_ultra_automute(codec); /* mute/unmute HP */
9739 return ret;
9740}
9741
9742static struct snd_kcontrol_new alc262_ultra_capture_mixer[] = {
9743 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
9744 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
9745 {
9746 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9747 .name = "Capture Source",
Takashi Iwai54cbc9a2008-10-31 15:24:04 +01009748 .info = alc_mux_enum_info,
9749 .get = alc_mux_enum_get,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01009750 .put = alc262_ultra_mux_enum_put,
9751 },
9752 { } /* end */
9753};
9754
Kailang Yangdf694da2005-12-05 19:42:22 +01009755/* add playback controls from the parsed DAC table */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009756static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
9757 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +01009758{
9759 hda_nid_t nid;
9760 int err;
9761
9762 spec->multiout.num_dacs = 1; /* only use one dac */
9763 spec->multiout.dac_nids = spec->private_dac_nids;
9764 spec->multiout.dac_nids[0] = 2;
9765
9766 nid = cfg->line_out_pins[0];
9767 if (nid) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009768 err = add_control(spec, ALC_CTL_WIDGET_VOL,
9769 "Front Playback Volume",
9770 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT));
9771 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009772 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009773 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
9774 "Front Playback Switch",
9775 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
9776 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009777 return err;
9778 }
9779
Takashi Iwai82bc9552006-03-21 11:24:42 +01009780 nid = cfg->speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01009781 if (nid) {
9782 if (nid == 0x16) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009783 err = add_control(spec, ALC_CTL_WIDGET_VOL,
9784 "Speaker Playback Volume",
9785 HDA_COMPOSE_AMP_VAL(0x0e, 2, 0,
9786 HDA_OUTPUT));
9787 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009788 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009789 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
9790 "Speaker Playback Switch",
9791 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
9792 HDA_OUTPUT));
9793 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009794 return err;
9795 } else {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009796 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
9797 "Speaker Playback Switch",
9798 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
9799 HDA_OUTPUT));
9800 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009801 return err;
9802 }
9803 }
Takashi Iwaieb06ed82006-09-20 17:10:27 +02009804 nid = cfg->hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01009805 if (nid) {
9806 /* spec->multiout.hp_nid = 2; */
9807 if (nid == 0x16) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009808 err = add_control(spec, ALC_CTL_WIDGET_VOL,
9809 "Headphone Playback Volume",
9810 HDA_COMPOSE_AMP_VAL(0x0e, 2, 0,
9811 HDA_OUTPUT));
9812 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009813 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009814 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
9815 "Headphone Playback Switch",
9816 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
9817 HDA_OUTPUT));
9818 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009819 return err;
9820 } else {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009821 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
9822 "Headphone Playback Switch",
9823 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
9824 HDA_OUTPUT));
9825 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009826 return err;
9827 }
9828 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009829 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01009830}
9831
9832/* identical with ALC880 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009833#define alc262_auto_create_analog_input_ctls \
9834 alc880_auto_create_analog_input_ctls
Kailang Yangdf694da2005-12-05 19:42:22 +01009835
9836/*
9837 * generic initialization of ADC, input mixers and output mixers
9838 */
9839static struct hda_verb alc262_volume_init_verbs[] = {
9840 /*
9841 * Unmute ADC0-2 and set the default input to mic-in
9842 */
9843 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
9844 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9845 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
9846 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9847 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
9848 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9849
Takashi Iwaicb53c622007-08-10 17:21:45 +02009850 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +01009851 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009852 * Note: PASD motherboards uses the Line In 2 as the input for
9853 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01009854 */
9855 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02009856 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9857 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
9858 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
9859 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
9860 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01009861
9862 /*
9863 * Set up output mixers (0x0c - 0x0f)
9864 */
9865 /* set vol=0 to output mixers */
9866 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9867 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9868 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yangea1fb292008-08-26 12:58:38 +02009869
Kailang Yangdf694da2005-12-05 19:42:22 +01009870 /* set up input amps for analog loopback */
9871 /* Amp Indices: DAC = 0, mixer = 1 */
9872 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9873 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9874 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9875 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9876 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9877 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9878
9879 /* FIXME: use matrix-type input source selection */
9880 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
9881 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
9882 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9883 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
9884 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
9885 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
9886 /* Input mixer2 */
9887 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9888 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
9889 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
9890 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
9891 /* Input mixer3 */
9892 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9893 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
9894 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
9895 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
9896
9897 { }
9898};
9899
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009900static struct hda_verb alc262_HP_BPC_init_verbs[] = {
9901 /*
9902 * Unmute ADC0-2 and set the default input to mic-in
9903 */
9904 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
9905 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9906 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
9907 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9908 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
9909 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9910
Takashi Iwaicb53c622007-08-10 17:21:45 +02009911 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009912 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009913 * Note: PASD motherboards uses the Line In 2 as the input for
9914 * front panel mic (mic 2)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009915 */
9916 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02009917 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9918 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
9919 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
9920 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
9921 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
9922 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
9923 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
Kailang Yangea1fb292008-08-26 12:58:38 +02009924
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009925 /*
9926 * Set up output mixers (0x0c - 0x0e)
9927 */
9928 /* set vol=0 to output mixers */
9929 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9930 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9931 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9932
9933 /* set up input amps for analog loopback */
9934 /* Amp Indices: DAC = 0, mixer = 1 */
9935 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9936 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9937 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9938 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9939 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9940 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9941
Takashi Iwaice875f02008-01-28 18:17:43 +01009942 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009943 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9944 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9945
9946 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
9947 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
9948
9949 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
9950 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9951
9952 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9953 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9954 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9955 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9956 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9957
9958 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
9959 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
9960 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
9961 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
9962 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
9963 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
9964
9965
9966 /* FIXME: use matrix-type input source selection */
9967 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
9968 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
9969 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9970 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
9971 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
9972 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
9973 /* Input mixer2 */
9974 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9975 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
9976 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
9977 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
9978 /* Input mixer3 */
9979 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9980 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
9981 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
9982 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
9983
Takashi Iwaice875f02008-01-28 18:17:43 +01009984 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9985
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009986 { }
9987};
9988
Kailang Yangcd7509a2007-01-26 18:33:17 +01009989static struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = {
9990 /*
9991 * Unmute ADC0-2 and set the default input to mic-in
9992 */
9993 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
9994 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9995 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
9996 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9997 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
9998 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9999
Takashi Iwaicb53c622007-08-10 17:21:45 +020010000 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangcd7509a2007-01-26 18:33:17 +010010001 * mixer widget
10002 * Note: PASD motherboards uses the Line In 2 as the input for front
10003 * panel mic (mic 2)
10004 */
10005 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020010006 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
10007 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10008 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
10009 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
10010 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
10011 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
10012 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
10013 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Kailang Yangcd7509a2007-01-26 18:33:17 +010010014 /*
10015 * Set up output mixers (0x0c - 0x0e)
10016 */
10017 /* set vol=0 to output mixers */
10018 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10019 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10020 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10021
10022 /* set up input amps for analog loopback */
10023 /* Amp Indices: DAC = 0, mixer = 1 */
10024 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10025 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10026 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10027 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10028 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10029 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10030
10031
10032 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP */
10033 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Mono */
10034 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* rear MIC */
10035 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* Line in */
10036 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
10037 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Line out */
10038 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD in */
10039
10040 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
10041 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
10042
10043 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
10044 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
10045
10046 /* {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, */
10047 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10048 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10049 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
10050 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10051 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10052
10053 /* FIXME: use matrix-type input source selection */
10054 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
10055 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
10056 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, /*rear MIC*/
10057 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, /*Line in*/
10058 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, /*F MIC*/
10059 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, /*Front*/
10060 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, /*CD*/
10061 /* {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
10062 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, /*HP*/
10063 /* Input mixer2 */
10064 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10065 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
10066 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
10067 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
10068 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
10069 /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
10070 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
10071 /* Input mixer3 */
10072 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10073 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
10074 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
10075 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
10076 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
10077 /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
10078 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
10079
Takashi Iwaice875f02008-01-28 18:17:43 +010010080 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
10081
Kailang Yangcd7509a2007-01-26 18:33:17 +010010082 { }
10083};
10084
Hiroshi Miura9f99a632008-08-28 16:09:06 +020010085static struct hda_verb alc262_toshiba_rx1_unsol_verbs[] = {
10086
10087 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Front Speaker */
10088 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
10089 {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
10090
10091 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* MIC jack */
10092 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
10093 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
10094 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
10095
10096 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP jack */
10097 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
10098 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
10099 {}
10100};
10101
10102
Takashi Iwaicb53c622007-08-10 17:21:45 +020010103#ifdef CONFIG_SND_HDA_POWER_SAVE
10104#define alc262_loopbacks alc880_loopbacks
10105#endif
10106
Kailang Yangdf694da2005-12-05 19:42:22 +010010107/* pcm configuration: identiacal with ALC880 */
10108#define alc262_pcm_analog_playback alc880_pcm_analog_playback
10109#define alc262_pcm_analog_capture alc880_pcm_analog_capture
10110#define alc262_pcm_digital_playback alc880_pcm_digital_playback
10111#define alc262_pcm_digital_capture alc880_pcm_digital_capture
10112
10113/*
10114 * BIOS auto configuration
10115 */
10116static int alc262_parse_auto_config(struct hda_codec *codec)
10117{
10118 struct alc_spec *spec = codec->spec;
10119 int err;
10120 static hda_nid_t alc262_ignore[] = { 0x1d, 0 };
10121
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010122 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
10123 alc262_ignore);
10124 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010125 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010126 if (!spec->autocfg.line_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +010010127 return 0; /* can't find valid BIOS pin config */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010128 err = alc262_auto_create_multi_out_ctls(spec, &spec->autocfg);
10129 if (err < 0)
10130 return err;
10131 err = alc262_auto_create_analog_input_ctls(spec, &spec->autocfg);
10132 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010133 return err;
10134
10135 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
10136
10137 if (spec->autocfg.dig_out_pin)
10138 spec->multiout.dig_out_nid = ALC262_DIGOUT_NID;
10139 if (spec->autocfg.dig_in_pin)
10140 spec->dig_in_nid = ALC262_DIGIN_NID;
10141
Takashi Iwai603c4012008-07-30 15:01:44 +020010142 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010010143 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +010010144
Takashi Iwaid88897e2008-10-31 15:01:37 +010010145 add_verb(spec, alc262_volume_init_verbs);
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020010146 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +010010147 spec->input_mux = &spec->private_imux;
10148
Takashi Iwai776e1842007-08-29 15:07:11 +020010149 err = alc_auto_add_mic_boost(codec);
10150 if (err < 0)
10151 return err;
10152
Takashi Iwaie044c392008-10-27 16:56:24 +010010153 store_pin_configs(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010010154 return 1;
10155}
10156
10157#define alc262_auto_init_multi_out alc882_auto_init_multi_out
10158#define alc262_auto_init_hp_out alc882_auto_init_hp_out
10159#define alc262_auto_init_analog_input alc882_auto_init_analog_input
Takashi Iwaif511b012008-08-15 16:46:42 +020010160#define alc262_auto_init_input_src alc882_auto_init_input_src
Kailang Yangdf694da2005-12-05 19:42:22 +010010161
10162
10163/* init callback for auto-configuration model -- overriding the default init */
Takashi Iwaiae6b8132006-03-03 16:47:17 +010010164static void alc262_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010010165{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010166 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010010167 alc262_auto_init_multi_out(codec);
10168 alc262_auto_init_hp_out(codec);
10169 alc262_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020010170 alc262_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010171 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020010172 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010010173}
10174
10175/*
10176 * configuration and preset
10177 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010178static const char *alc262_models[ALC262_MODEL_LAST] = {
10179 [ALC262_BASIC] = "basic",
10180 [ALC262_HIPPO] = "hippo",
10181 [ALC262_HIPPO_1] = "hippo_1",
10182 [ALC262_FUJITSU] = "fujitsu",
10183 [ALC262_HP_BPC] = "hp-bpc",
Kailang Yangcd7509a2007-01-26 18:33:17 +010010184 [ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000",
Takashi Iwai61dc35d2007-11-14 12:26:44 +010010185 [ALC262_HP_TC_T5735] = "hp-tc-t5735",
Kailang Yang8c427222008-01-10 13:03:59 +010010186 [ALC262_HP_RP5700] = "hp-rp5700",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010187 [ALC262_BENQ_ED8] = "benq",
Takashi Iwai0f405022007-07-06 12:24:11 +020010188 [ALC262_BENQ_T31] = "benq-t31",
10189 [ALC262_SONY_ASSAMD] = "sony-assamd",
Takashi Iwai2922c9a2008-08-27 18:12:42 +020010190 [ALC262_TOSHIBA_S06] = "toshiba-s06",
Hiroshi Miura9f99a632008-08-28 16:09:06 +020010191 [ALC262_TOSHIBA_RX1] = "toshiba-rx1",
Tobin Davisf651b502007-10-26 12:40:47 +020010192 [ALC262_ULTRA] = "ultra",
Jiang zhe0e31daf2008-03-20 12:12:39 +010010193 [ALC262_LENOVO_3000] = "lenovo-3000",
Pascal Terjane8f9ae22008-08-04 14:36:05 +020010194 [ALC262_NEC] = "nec",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010195 [ALC262_AUTO] = "auto",
10196};
10197
10198static struct snd_pci_quirk alc262_cfg_tbl[] = {
10199 SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO),
Pascal Terjane8f9ae22008-08-04 14:36:05 +020010200 SND_PCI_QUIRK(0x1033, 0x8895, "NEC Versa S9100", ALC262_NEC),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010201 SND_PCI_QUIRK(0x103c, 0x12fe, "HP xw9400", ALC262_HP_BPC),
Kailang Yang7d87de22007-06-05 12:17:21 +020010202 SND_PCI_QUIRK(0x103c, 0x12ff, "HP xw4550", ALC262_HP_BPC),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010203 SND_PCI_QUIRK(0x103c, 0x1306, "HP xw8600", ALC262_HP_BPC),
10204 SND_PCI_QUIRK(0x103c, 0x1307, "HP xw6600", ALC262_HP_BPC),
Kailang Yang7d87de22007-06-05 12:17:21 +020010205 SND_PCI_QUIRK(0x103c, 0x1308, "HP xw4600", ALC262_HP_BPC),
Takashi Iwaib98f9332007-11-07 14:18:01 +010010206 SND_PCI_QUIRK(0x103c, 0x1309, "HP xw4*00", ALC262_HP_BPC),
Takashi Iwaib98f9332007-11-07 14:18:01 +010010207 SND_PCI_QUIRK(0x103c, 0x130a, "HP xw6*00", ALC262_HP_BPC),
Takashi Iwaib98f9332007-11-07 14:18:01 +010010208 SND_PCI_QUIRK(0x103c, 0x130b, "HP xw8*00", ALC262_HP_BPC),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010209 SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010210 SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010211 SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010212 SND_PCI_QUIRK(0x103c, 0x2803, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010213 SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010214 SND_PCI_QUIRK(0x103c, 0x2805, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010215 SND_PCI_QUIRK(0x103c, 0x2806, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010216 SND_PCI_QUIRK(0x103c, 0x2807, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010217 SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC),
10218 SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC),
10219 SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC),
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010220 SND_PCI_QUIRK(0x103c, 0x302f, "HP Thin Client T5735",
10221 ALC262_HP_TC_T5735),
Kailang Yang8c427222008-01-10 13:03:59 +010010222 SND_PCI_QUIRK(0x103c, 0x2817, "HP RP5700", ALC262_HP_RP5700),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010223 SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010224 SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010225 SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD),
10226 SND_PCI_QUIRK(0x104d, 0x900e, "Sony ASSAMD", ALC262_SONY_ASSAMD),
10227 SND_PCI_QUIRK(0x104d, 0x9015, "Sony 0x9015", ALC262_SONY_ASSAMD),
Akio Idehara36ca6e12008-06-09 22:57:40 +090010228 SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1",
Hiroshi Miura9f99a632008-08-28 16:09:06 +020010229 ALC262_TOSHIBA_RX1),
Kailang Yang80ffe862008-10-15 11:23:27 +020010230 SND_PCI_QUIRK(0x1179, 0xff7b, "Toshiba S06", ALC262_TOSHIBA_S06),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010231 SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU),
Tony Vroon3f1eeae2008-02-25 16:44:13 +010010232 SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010233 SND_PCI_QUIRK(0x144d, 0xc032, "Samsung Q1 Ultra", ALC262_ULTRA),
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010234 SND_PCI_QUIRK(0x144d, 0xc039, "Samsung Q1U EL", ALC262_ULTRA),
Jiang zhe0e31daf2008-03-20 12:12:39 +010010235 SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 y410", ALC262_LENOVO_3000),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010236 SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8),
Kailang Yang83c34212007-07-05 11:43:05 +020010237 SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010238 SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1),
Kailang Yangdf694da2005-12-05 19:42:22 +010010239 {}
10240};
10241
10242static struct alc_config_preset alc262_presets[] = {
10243 [ALC262_BASIC] = {
10244 .mixers = { alc262_base_mixer },
10245 .init_verbs = { alc262_init_verbs },
10246 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10247 .dac_nids = alc262_dac_nids,
10248 .hp_nid = 0x03,
10249 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10250 .channel_mode = alc262_modes,
Takashi Iwaia3bcba32005-12-06 19:05:29 +010010251 .input_mux = &alc262_capture_source,
Kailang Yangdf694da2005-12-05 19:42:22 +010010252 },
Kailang Yangccc656c2006-10-17 12:32:26 +020010253 [ALC262_HIPPO] = {
10254 .mixers = { alc262_base_mixer },
10255 .init_verbs = { alc262_init_verbs, alc262_hippo_unsol_verbs},
10256 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10257 .dac_nids = alc262_dac_nids,
10258 .hp_nid = 0x03,
10259 .dig_out_nid = ALC262_DIGOUT_NID,
10260 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10261 .channel_mode = alc262_modes,
10262 .input_mux = &alc262_capture_source,
10263 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +020010264 .init_hook = alc262_hippo_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020010265 },
10266 [ALC262_HIPPO_1] = {
10267 .mixers = { alc262_hippo1_mixer },
10268 .init_verbs = { alc262_init_verbs, alc262_hippo1_unsol_verbs},
10269 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10270 .dac_nids = alc262_dac_nids,
10271 .hp_nid = 0x02,
10272 .dig_out_nid = ALC262_DIGOUT_NID,
10273 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10274 .channel_mode = alc262_modes,
10275 .input_mux = &alc262_capture_source,
10276 .unsol_event = alc262_hippo1_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +020010277 .init_hook = alc262_hippo1_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020010278 },
Takashi Iwai834be882006-03-01 14:16:17 +010010279 [ALC262_FUJITSU] = {
10280 .mixers = { alc262_fujitsu_mixer },
Takashi Iwai39d3ed32007-10-12 15:03:48 +020010281 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
10282 alc262_fujitsu_unsol_verbs },
Takashi Iwai834be882006-03-01 14:16:17 +010010283 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10284 .dac_nids = alc262_dac_nids,
10285 .hp_nid = 0x03,
10286 .dig_out_nid = ALC262_DIGOUT_NID,
10287 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10288 .channel_mode = alc262_modes,
10289 .input_mux = &alc262_fujitsu_capture_source,
Takashi Iwaiae6b8132006-03-03 16:47:17 +010010290 .unsol_event = alc262_fujitsu_unsol_event,
Takashi Iwaiebc7a402008-05-20 09:23:05 +020010291 .init_hook = alc262_fujitsu_init_hook,
Takashi Iwai834be882006-03-01 14:16:17 +010010292 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010293 [ALC262_HP_BPC] = {
10294 .mixers = { alc262_HP_BPC_mixer },
10295 .init_verbs = { alc262_HP_BPC_init_verbs },
10296 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10297 .dac_nids = alc262_dac_nids,
10298 .hp_nid = 0x03,
10299 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10300 .channel_mode = alc262_modes,
10301 .input_mux = &alc262_HP_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010010302 .unsol_event = alc262_hp_bpc_unsol_event,
10303 .init_hook = alc262_hp_bpc_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010304 },
Kailang Yangcd7509a2007-01-26 18:33:17 +010010305 [ALC262_HP_BPC_D7000_WF] = {
10306 .mixers = { alc262_HP_BPC_WildWest_mixer },
10307 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
10308 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10309 .dac_nids = alc262_dac_nids,
10310 .hp_nid = 0x03,
10311 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10312 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +020010313 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010010314 .unsol_event = alc262_hp_wildwest_unsol_event,
10315 .init_hook = alc262_hp_wildwest_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010316 },
Kailang Yangcd7509a2007-01-26 18:33:17 +010010317 [ALC262_HP_BPC_D7000_WL] = {
10318 .mixers = { alc262_HP_BPC_WildWest_mixer,
10319 alc262_HP_BPC_WildWest_option_mixer },
10320 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
10321 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10322 .dac_nids = alc262_dac_nids,
10323 .hp_nid = 0x03,
10324 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10325 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +020010326 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010010327 .unsol_event = alc262_hp_wildwest_unsol_event,
10328 .init_hook = alc262_hp_wildwest_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010329 },
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010330 [ALC262_HP_TC_T5735] = {
10331 .mixers = { alc262_hp_t5735_mixer },
10332 .init_verbs = { alc262_init_verbs, alc262_hp_t5735_verbs },
10333 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10334 .dac_nids = alc262_dac_nids,
10335 .hp_nid = 0x03,
10336 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10337 .channel_mode = alc262_modes,
10338 .input_mux = &alc262_capture_source,
10339 .unsol_event = alc262_hp_t5735_unsol_event,
10340 .init_hook = alc262_hp_t5735_init_hook,
Kailang Yang8c427222008-01-10 13:03:59 +010010341 },
10342 [ALC262_HP_RP5700] = {
10343 .mixers = { alc262_hp_rp5700_mixer },
10344 .init_verbs = { alc262_init_verbs, alc262_hp_rp5700_verbs },
10345 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10346 .dac_nids = alc262_dac_nids,
10347 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10348 .channel_mode = alc262_modes,
10349 .input_mux = &alc262_hp_rp5700_capture_source,
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010350 },
Takashi Iwai304dcaa2006-07-25 14:51:16 +020010351 [ALC262_BENQ_ED8] = {
10352 .mixers = { alc262_base_mixer },
10353 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs },
10354 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10355 .dac_nids = alc262_dac_nids,
10356 .hp_nid = 0x03,
10357 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10358 .channel_mode = alc262_modes,
10359 .input_mux = &alc262_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010360 },
Kailang Yang272a5272007-05-14 11:00:38 +020010361 [ALC262_SONY_ASSAMD] = {
10362 .mixers = { alc262_sony_mixer },
10363 .init_verbs = { alc262_init_verbs, alc262_sony_unsol_verbs},
10364 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10365 .dac_nids = alc262_dac_nids,
10366 .hp_nid = 0x02,
10367 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10368 .channel_mode = alc262_modes,
10369 .input_mux = &alc262_capture_source,
10370 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +020010371 .init_hook = alc262_hippo_automute,
Kailang Yang83c34212007-07-05 11:43:05 +020010372 },
10373 [ALC262_BENQ_T31] = {
10374 .mixers = { alc262_benq_t31_mixer },
10375 .init_verbs = { alc262_init_verbs, alc262_benq_t31_EAPD_verbs, alc262_hippo_unsol_verbs },
10376 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10377 .dac_nids = alc262_dac_nids,
10378 .hp_nid = 0x03,
10379 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10380 .channel_mode = alc262_modes,
10381 .input_mux = &alc262_capture_source,
10382 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +020010383 .init_hook = alc262_hippo_automute,
Kailang Yangea1fb292008-08-26 12:58:38 +020010384 },
Tobin Davisf651b502007-10-26 12:40:47 +020010385 [ALC262_ULTRA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010386 .mixers = { alc262_ultra_mixer },
10387 .cap_mixer = alc262_ultra_capture_mixer,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010388 .init_verbs = { alc262_ultra_verbs },
Tobin Davisf651b502007-10-26 12:40:47 +020010389 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10390 .dac_nids = alc262_dac_nids,
Tobin Davisf651b502007-10-26 12:40:47 +020010391 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10392 .channel_mode = alc262_modes,
10393 .input_mux = &alc262_ultra_capture_source,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010394 .adc_nids = alc262_adc_nids, /* ADC0 */
10395 .capsrc_nids = alc262_capsrc_nids,
10396 .num_adc_nids = 1, /* single ADC */
Tobin Davisf651b502007-10-26 12:40:47 +020010397 .unsol_event = alc262_ultra_unsol_event,
10398 .init_hook = alc262_ultra_automute,
10399 },
Jiang zhe0e31daf2008-03-20 12:12:39 +010010400 [ALC262_LENOVO_3000] = {
10401 .mixers = { alc262_lenovo_3000_mixer },
10402 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
10403 alc262_lenovo_3000_unsol_verbs },
10404 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10405 .dac_nids = alc262_dac_nids,
10406 .hp_nid = 0x03,
10407 .dig_out_nid = ALC262_DIGOUT_NID,
10408 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10409 .channel_mode = alc262_modes,
10410 .input_mux = &alc262_fujitsu_capture_source,
10411 .unsol_event = alc262_lenovo_3000_unsol_event,
10412 },
Pascal Terjane8f9ae22008-08-04 14:36:05 +020010413 [ALC262_NEC] = {
10414 .mixers = { alc262_nec_mixer },
10415 .init_verbs = { alc262_nec_verbs },
10416 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10417 .dac_nids = alc262_dac_nids,
10418 .hp_nid = 0x03,
10419 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10420 .channel_mode = alc262_modes,
10421 .input_mux = &alc262_capture_source,
10422 },
Kailang Yang4e555fe2008-08-26 13:05:55 +020010423 [ALC262_TOSHIBA_S06] = {
10424 .mixers = { alc262_toshiba_s06_mixer },
10425 .init_verbs = { alc262_init_verbs, alc262_toshiba_s06_verbs,
10426 alc262_eapd_verbs },
10427 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10428 .capsrc_nids = alc262_dmic_capsrc_nids,
10429 .dac_nids = alc262_dac_nids,
10430 .adc_nids = alc262_dmic_adc_nids, /* ADC0 */
10431 .dig_out_nid = ALC262_DIGOUT_NID,
10432 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10433 .channel_mode = alc262_modes,
10434 .input_mux = &alc262_dmic_capture_source,
10435 .unsol_event = alc262_toshiba_s06_unsol_event,
10436 .init_hook = alc262_toshiba_s06_init_hook,
10437 },
Hiroshi Miura9f99a632008-08-28 16:09:06 +020010438 [ALC262_TOSHIBA_RX1] = {
10439 .mixers = { alc262_toshiba_rx1_mixer },
10440 .init_verbs = { alc262_init_verbs, alc262_toshiba_rx1_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,
10448 .init_hook = alc262_hippo_automute,
10449 },
Kailang Yangdf694da2005-12-05 19:42:22 +010010450};
10451
10452static int patch_alc262(struct hda_codec *codec)
10453{
10454 struct alc_spec *spec;
10455 int board_config;
10456 int err;
10457
Robert P. J. Daydc041e02006-12-19 14:44:15 +010010458 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010010459 if (spec == NULL)
10460 return -ENOMEM;
10461
10462 codec->spec = spec;
10463#if 0
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010464 /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is
10465 * under-run
10466 */
Kailang Yangdf694da2005-12-05 19:42:22 +010010467 {
10468 int tmp;
10469 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
10470 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
10471 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
10472 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80);
10473 }
10474#endif
10475
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020010476 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
10477
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010478 board_config = snd_hda_check_board_config(codec, ALC262_MODEL_LAST,
10479 alc262_models,
10480 alc262_cfg_tbl);
Kailang Yangcd7509a2007-01-26 18:33:17 +010010481
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010482 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010483 printk(KERN_INFO "hda_codec: Unknown model for ALC262, "
10484 "trying auto-probe from BIOS...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010010485 board_config = ALC262_AUTO;
10486 }
10487
10488 if (board_config == ALC262_AUTO) {
10489 /* automatic parse from the BIOS config */
10490 err = alc262_parse_auto_config(codec);
10491 if (err < 0) {
10492 alc_free(codec);
10493 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010494 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010495 printk(KERN_INFO
10496 "hda_codec: Cannot set up configuration "
10497 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010010498 board_config = ALC262_BASIC;
10499 }
10500 }
10501
10502 if (board_config != ALC262_AUTO)
10503 setup_preset(spec, &alc262_presets[board_config]);
10504
10505 spec->stream_name_analog = "ALC262 Analog";
10506 spec->stream_analog_playback = &alc262_pcm_analog_playback;
10507 spec->stream_analog_capture = &alc262_pcm_analog_capture;
Kailang Yangea1fb292008-08-26 12:58:38 +020010508
Kailang Yangdf694da2005-12-05 19:42:22 +010010509 spec->stream_name_digital = "ALC262 Digital";
10510 spec->stream_digital_playback = &alc262_pcm_digital_playback;
10511 spec->stream_digital_capture = &alc262_pcm_digital_capture;
10512
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010010513 spec->is_mix_capture = 1;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010514 if (!spec->adc_nids && spec->input_mux) {
Kailang Yangdf694da2005-12-05 19:42:22 +010010515 /* check whether NID 0x07 is valid */
Takashi Iwai4a471b72005-12-07 13:56:29 +010010516 unsigned int wcap = get_wcaps(codec, 0x07);
10517
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010518 /* get type */
10519 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Kailang Yangdf694da2005-12-05 19:42:22 +010010520 if (wcap != AC_WID_AUD_IN) {
10521 spec->adc_nids = alc262_adc_nids_alt;
10522 spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids_alt);
Takashi Iwai88c71a92008-02-14 17:27:17 +010010523 spec->capsrc_nids = alc262_capsrc_nids_alt;
Kailang Yangdf694da2005-12-05 19:42:22 +010010524 } else {
10525 spec->adc_nids = alc262_adc_nids;
10526 spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids);
Takashi Iwai88c71a92008-02-14 17:27:17 +010010527 spec->capsrc_nids = alc262_capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +010010528 }
10529 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010530 if (!spec->cap_mixer)
10531 set_capture_mixer(spec);
Kailang Yangdf694da2005-12-05 19:42:22 +010010532
Takashi Iwai2134ea42008-01-10 16:53:55 +010010533 spec->vmaster_nid = 0x0c;
10534
Kailang Yangdf694da2005-12-05 19:42:22 +010010535 codec->patch_ops = alc_patch_ops;
10536 if (board_config == ALC262_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +010010537 spec->init_hook = alc262_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020010538#ifdef CONFIG_SND_HDA_POWER_SAVE
10539 if (!spec->loopback.amplist)
10540 spec->loopback.amplist = alc262_loopbacks;
10541#endif
Kailang Yangea1fb292008-08-26 12:58:38 +020010542
Kailang Yangdf694da2005-12-05 19:42:22 +010010543 return 0;
10544}
10545
Kailang Yangdf694da2005-12-05 19:42:22 +010010546/*
Kailang Yanga361d842007-06-05 12:30:55 +020010547 * ALC268 channel source setting (2 channel)
10548 */
10549#define ALC268_DIGOUT_NID ALC880_DIGOUT_NID
10550#define alc268_modes alc260_modes
Kailang Yangea1fb292008-08-26 12:58:38 +020010551
Kailang Yanga361d842007-06-05 12:30:55 +020010552static hda_nid_t alc268_dac_nids[2] = {
10553 /* front, hp */
10554 0x02, 0x03
10555};
10556
10557static hda_nid_t alc268_adc_nids[2] = {
10558 /* ADC0-1 */
10559 0x08, 0x07
10560};
10561
10562static hda_nid_t alc268_adc_nids_alt[1] = {
10563 /* ADC0 */
10564 0x08
10565};
10566
Takashi Iwaie1406342008-02-11 18:32:32 +010010567static hda_nid_t alc268_capsrc_nids[2] = { 0x23, 0x24 };
10568
Kailang Yanga361d842007-06-05 12:30:55 +020010569static struct snd_kcontrol_new alc268_base_mixer[] = {
10570 /* output mixer control */
10571 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
10572 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
10573 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
10574 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai33bf17a2007-08-21 11:51:42 +020010575 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10576 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
10577 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
Kailang Yanga361d842007-06-05 12:30:55 +020010578 { }
10579};
10580
Takashi Iwaiaef9d312008-02-19 13:16:41 +010010581/* bind Beep switches of both NID 0x0f and 0x10 */
10582static struct hda_bind_ctls alc268_bind_beep_sw = {
10583 .ops = &snd_hda_bind_sw,
10584 .values = {
10585 HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT),
10586 HDA_COMPOSE_AMP_VAL(0x10, 3, 1, HDA_INPUT),
10587 0
10588 },
10589};
10590
10591static struct snd_kcontrol_new alc268_beep_mixer[] = {
10592 HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT),
10593 HDA_BIND_SW("Beep Playback Switch", &alc268_bind_beep_sw),
10594 { }
10595};
10596
Kailang Yangd1a991a2007-08-15 16:21:59 +020010597static struct hda_verb alc268_eapd_verbs[] = {
10598 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
10599 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
10600 { }
10601};
10602
Takashi Iwaid2738092007-08-16 14:59:45 +020010603/* Toshiba specific */
10604#define alc268_toshiba_automute alc262_hippo_automute
10605
10606static struct hda_verb alc268_toshiba_verbs[] = {
10607 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
10608 { } /* end */
10609};
10610
Kailang Yang8ef355d2008-08-26 13:10:22 +020010611static struct hda_input_mux alc268_acer_lc_capture_source = {
10612 .num_items = 2,
10613 .items = {
10614 { "i-Mic", 0x6 },
10615 { "E-Mic", 0x0 },
10616 },
10617};
10618
Takashi Iwaid2738092007-08-16 14:59:45 +020010619/* Acer specific */
Takashi Iwai889c4392007-08-23 18:56:52 +020010620/* bind volumes of both NID 0x02 and 0x03 */
Takashi Iwai6bc96852007-08-17 09:02:12 +020010621static struct hda_bind_ctls alc268_acer_bind_master_vol = {
10622 .ops = &snd_hda_bind_vol,
10623 .values = {
10624 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
10625 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
10626 0
10627 },
10628};
10629
Takashi Iwai889c4392007-08-23 18:56:52 +020010630/* mute/unmute internal speaker according to the hp jack and mute state */
10631static void alc268_acer_automute(struct hda_codec *codec, int force)
10632{
10633 struct alc_spec *spec = codec->spec;
10634 unsigned int mute;
10635
10636 if (force || !spec->sense_updated) {
10637 unsigned int present;
10638 present = snd_hda_codec_read(codec, 0x14, 0,
10639 AC_VERB_GET_PIN_SENSE, 0);
10640 spec->jack_present = (present & 0x80000000) != 0;
10641 spec->sense_updated = 1;
10642 }
10643 if (spec->jack_present)
10644 mute = HDA_AMP_MUTE; /* mute internal speaker */
10645 else /* unmute internal speaker if necessary */
10646 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
10647 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
10648 HDA_AMP_MUTE, mute);
10649}
10650
10651
10652/* bind hp and internal speaker mute (with plug check) */
10653static int alc268_acer_master_sw_put(struct snd_kcontrol *kcontrol,
10654 struct snd_ctl_elem_value *ucontrol)
10655{
10656 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
10657 long *valp = ucontrol->value.integer.value;
10658 int change;
10659
10660 change = snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0,
10661 HDA_AMP_MUTE,
10662 valp[0] ? 0 : HDA_AMP_MUTE);
10663 change |= snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0,
10664 HDA_AMP_MUTE,
10665 valp[1] ? 0 : HDA_AMP_MUTE);
10666 if (change)
10667 alc268_acer_automute(codec, 0);
10668 return change;
10669}
Takashi Iwaid2738092007-08-16 14:59:45 +020010670
Kailang Yang8ef355d2008-08-26 13:10:22 +020010671static struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = {
10672 /* output mixer control */
10673 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
10674 {
10675 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10676 .name = "Master Playback Switch",
10677 .info = snd_hda_mixer_amp_switch_info,
10678 .get = snd_hda_mixer_amp_switch_get,
10679 .put = alc268_acer_master_sw_put,
10680 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
10681 },
10682 HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x18, 0, HDA_INPUT),
10683 { }
10684};
10685
Takashi Iwaid2738092007-08-16 14:59:45 +020010686static struct snd_kcontrol_new alc268_acer_mixer[] = {
10687 /* output mixer control */
10688 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
10689 {
10690 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10691 .name = "Master Playback Switch",
10692 .info = snd_hda_mixer_amp_switch_info,
10693 .get = snd_hda_mixer_amp_switch_get,
10694 .put = alc268_acer_master_sw_put,
10695 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
10696 },
Takashi Iwai33bf17a2007-08-21 11:51:42 +020010697 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10698 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
10699 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
Takashi Iwaid2738092007-08-16 14:59:45 +020010700 { }
10701};
10702
Kailang Yang8ef355d2008-08-26 13:10:22 +020010703static struct hda_verb alc268_acer_aspire_one_verbs[] = {
10704 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
10705 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
10706 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
10707 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
10708 {0x23, AC_VERB_SET_CONNECT_SEL, 0x06},
10709 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, 0xa017},
10710 { }
10711};
10712
Takashi Iwaid2738092007-08-16 14:59:45 +020010713static struct hda_verb alc268_acer_verbs[] = {
Takashi Iwai0ccb5412008-03-06 16:58:35 +010010714 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* internal dmic? */
10715 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaid2738092007-08-16 14:59:45 +020010716 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
10717 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai0ccb5412008-03-06 16:58:35 +010010718 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
10719 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaid2738092007-08-16 14:59:45 +020010720 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
10721 { }
10722};
10723
10724/* unsolicited event for HP jack sensing */
10725static void alc268_toshiba_unsol_event(struct hda_codec *codec,
10726 unsigned int res)
10727{
Takashi Iwai889c4392007-08-23 18:56:52 +020010728 if ((res >> 26) != ALC880_HP_EVENT)
Takashi Iwaid2738092007-08-16 14:59:45 +020010729 return;
10730 alc268_toshiba_automute(codec);
10731}
10732
10733static void alc268_acer_unsol_event(struct hda_codec *codec,
10734 unsigned int res)
10735{
Takashi Iwai889c4392007-08-23 18:56:52 +020010736 if ((res >> 26) != ALC880_HP_EVENT)
Takashi Iwaid2738092007-08-16 14:59:45 +020010737 return;
10738 alc268_acer_automute(codec, 1);
10739}
10740
Takashi Iwai889c4392007-08-23 18:56:52 +020010741static void alc268_acer_init_hook(struct hda_codec *codec)
10742{
10743 alc268_acer_automute(codec, 1);
10744}
10745
Kailang Yang8ef355d2008-08-26 13:10:22 +020010746/* toggle speaker-output according to the hp-jack state */
10747static void alc268_aspire_one_speaker_automute(struct hda_codec *codec)
10748{
10749 unsigned int present;
10750 unsigned char bits;
10751
10752 present = snd_hda_codec_read(codec, 0x15, 0,
10753 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
10754 bits = present ? AMP_IN_MUTE(0) : 0;
10755 snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 0,
10756 AMP_IN_MUTE(0), bits);
10757 snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 1,
10758 AMP_IN_MUTE(0), bits);
10759}
10760
10761
10762static void alc268_acer_mic_automute(struct hda_codec *codec)
10763{
10764 unsigned int present;
10765
10766 present = snd_hda_codec_read(codec, 0x18, 0,
10767 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
10768 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_CONNECT_SEL,
10769 present ? 0x0 : 0x6);
10770}
10771
10772static void alc268_acer_lc_unsol_event(struct hda_codec *codec,
10773 unsigned int res)
10774{
10775 if ((res >> 26) == ALC880_HP_EVENT)
10776 alc268_aspire_one_speaker_automute(codec);
10777 if ((res >> 26) == ALC880_MIC_EVENT)
10778 alc268_acer_mic_automute(codec);
10779}
10780
10781static void alc268_acer_lc_init_hook(struct hda_codec *codec)
10782{
10783 alc268_aspire_one_speaker_automute(codec);
10784 alc268_acer_mic_automute(codec);
10785}
10786
Takashi Iwai3866f0b2008-01-15 12:37:42 +010010787static struct snd_kcontrol_new alc268_dell_mixer[] = {
10788 /* output mixer control */
10789 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
10790 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
10791 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
10792 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
10793 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10794 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
10795 { }
10796};
10797
10798static struct hda_verb alc268_dell_verbs[] = {
10799 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
10800 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
10801 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
10802 { }
10803};
10804
10805/* mute/unmute internal speaker according to the hp jack and mute state */
10806static void alc268_dell_automute(struct hda_codec *codec)
10807{
10808 unsigned int present;
10809 unsigned int mute;
10810
10811 present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0);
10812 if (present & 0x80000000)
10813 mute = HDA_AMP_MUTE;
10814 else
10815 mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0);
10816 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
10817 HDA_AMP_MUTE, mute);
10818}
10819
10820static void alc268_dell_unsol_event(struct hda_codec *codec,
10821 unsigned int res)
10822{
10823 if ((res >> 26) != ALC880_HP_EVENT)
10824 return;
10825 alc268_dell_automute(codec);
10826}
10827
10828#define alc268_dell_init_hook alc268_dell_automute
10829
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020010830static struct snd_kcontrol_new alc267_quanta_il1_mixer[] = {
10831 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x2, 0x0, HDA_OUTPUT),
10832 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
10833 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
10834 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
10835 HDA_CODEC_VOLUME("Mic Capture Volume", 0x23, 0x0, HDA_OUTPUT),
10836 HDA_BIND_MUTE("Mic Capture Switch", 0x23, 2, HDA_OUTPUT),
10837 HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
10838 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
10839 { }
10840};
10841
10842static struct hda_verb alc267_quanta_il1_verbs[] = {
10843 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
10844 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
10845 { }
10846};
10847
10848static void alc267_quanta_il1_hp_automute(struct hda_codec *codec)
10849{
10850 unsigned int present;
10851
10852 present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0)
10853 & AC_PINSENSE_PRESENCE;
10854 snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
10855 present ? 0 : PIN_OUT);
10856}
10857
10858static void alc267_quanta_il1_mic_automute(struct hda_codec *codec)
10859{
10860 unsigned int present;
10861
10862 present = snd_hda_codec_read(codec, 0x18, 0,
10863 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
10864 snd_hda_codec_write(codec, 0x23, 0,
10865 AC_VERB_SET_CONNECT_SEL,
10866 present ? 0x00 : 0x01);
10867}
10868
10869static void alc267_quanta_il1_automute(struct hda_codec *codec)
10870{
10871 alc267_quanta_il1_hp_automute(codec);
10872 alc267_quanta_il1_mic_automute(codec);
10873}
10874
10875static void alc267_quanta_il1_unsol_event(struct hda_codec *codec,
10876 unsigned int res)
10877{
10878 switch (res >> 26) {
10879 case ALC880_HP_EVENT:
10880 alc267_quanta_il1_hp_automute(codec);
10881 break;
10882 case ALC880_MIC_EVENT:
10883 alc267_quanta_il1_mic_automute(codec);
10884 break;
10885 }
10886}
10887
Kailang Yanga361d842007-06-05 12:30:55 +020010888/*
10889 * generic initialization of ADC, input mixers and output mixers
10890 */
10891static struct hda_verb alc268_base_init_verbs[] = {
10892 /* Unmute DAC0-1 and set vol = 0 */
10893 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10894 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10895 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10896 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10897 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10898 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10899
10900 /*
10901 * Set up output mixers (0x0c - 0x0e)
10902 */
10903 /* set vol=0 to output mixers */
10904 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10905 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10906 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10907 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
10908
10909 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10910 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10911
10912 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
10913 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
10914 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
10915 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
10916 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
10917 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10918 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10919 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10920
10921 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10922 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10923 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10924 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10925 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10926 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10927 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwaiaef9d312008-02-19 13:16:41 +010010928
10929 /* set PCBEEP vol = 0, mute connections */
10930 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10931 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10932 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020010933
Jiang Zhea9b3aa82007-12-20 13:13:13 +010010934 /* Unmute Selector 23h,24h and set the default input to mic-in */
Kailang Yangea1fb292008-08-26 12:58:38 +020010935
Jiang Zhea9b3aa82007-12-20 13:13:13 +010010936 {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
10937 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10938 {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
10939 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020010940
Kailang Yanga361d842007-06-05 12:30:55 +020010941 { }
10942};
10943
10944/*
10945 * generic initialization of ADC, input mixers and output mixers
10946 */
10947static struct hda_verb alc268_volume_init_verbs[] = {
10948 /* set output DAC */
10949 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10950 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
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 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
10955 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
10956 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10957 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10958 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10959
10960 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10961 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10962 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
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 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10967 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10968 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10969 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10970
Takashi Iwaiaef9d312008-02-19 13:16:41 +010010971 /* set PCBEEP vol = 0, mute connections */
10972 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10973 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10974 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020010975
10976 { }
10977};
10978
Kailang Yanga361d842007-06-05 12:30:55 +020010979static struct snd_kcontrol_new alc268_capture_alt_mixer[] = {
10980 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
10981 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
10982 {
10983 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10984 /* The multiple "Capture Source" controls confuse alsamixer
10985 * So call somewhat different..
Kailang Yanga361d842007-06-05 12:30:55 +020010986 */
10987 /* .name = "Capture Source", */
10988 .name = "Input Source",
10989 .count = 1,
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010010990 .info = alc_mux_enum_info,
10991 .get = alc_mux_enum_get,
10992 .put = alc_mux_enum_put,
Kailang Yanga361d842007-06-05 12:30:55 +020010993 },
10994 { } /* end */
10995};
10996
10997static struct snd_kcontrol_new alc268_capture_mixer[] = {
10998 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
10999 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
11000 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x24, 0x0, HDA_OUTPUT),
11001 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x24, 0x0, HDA_OUTPUT),
11002 {
11003 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11004 /* The multiple "Capture Source" controls confuse alsamixer
11005 * So call somewhat different..
Kailang Yanga361d842007-06-05 12:30:55 +020011006 */
11007 /* .name = "Capture Source", */
11008 .name = "Input Source",
11009 .count = 2,
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010011010 .info = alc_mux_enum_info,
11011 .get = alc_mux_enum_get,
11012 .put = alc_mux_enum_put,
Kailang Yanga361d842007-06-05 12:30:55 +020011013 },
11014 { } /* end */
11015};
11016
11017static struct hda_input_mux alc268_capture_source = {
11018 .num_items = 4,
11019 .items = {
11020 { "Mic", 0x0 },
11021 { "Front Mic", 0x1 },
11022 { "Line", 0x2 },
11023 { "CD", 0x3 },
11024 },
11025};
11026
Takashi Iwai0ccb5412008-03-06 16:58:35 +010011027static struct hda_input_mux alc268_acer_capture_source = {
11028 .num_items = 3,
11029 .items = {
11030 { "Mic", 0x0 },
11031 { "Internal Mic", 0x6 },
11032 { "Line", 0x2 },
11033 },
11034};
11035
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010011036#ifdef CONFIG_SND_DEBUG
11037static struct snd_kcontrol_new alc268_test_mixer[] = {
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010011038 /* Volume widgets */
11039 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x02, 0x0, HDA_OUTPUT),
11040 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x03, 0x0, HDA_OUTPUT),
11041 HDA_BIND_MUTE_MONO("Mono sum Playback Switch", 0x0e, 1, 2, HDA_INPUT),
11042 HDA_BIND_MUTE("LINE-OUT sum Playback Switch", 0x0f, 2, HDA_INPUT),
11043 HDA_BIND_MUTE("HP-OUT sum Playback Switch", 0x10, 2, HDA_INPUT),
11044 HDA_BIND_MUTE("LINE-OUT Playback Switch", 0x14, 2, HDA_OUTPUT),
11045 HDA_BIND_MUTE("HP-OUT Playback Switch", 0x15, 2, HDA_OUTPUT),
11046 HDA_BIND_MUTE("Mono Playback Switch", 0x16, 2, HDA_OUTPUT),
11047 HDA_CODEC_VOLUME("MIC1 Capture Volume", 0x18, 0x0, HDA_INPUT),
11048 HDA_BIND_MUTE("MIC1 Capture Switch", 0x18, 2, HDA_OUTPUT),
11049 HDA_CODEC_VOLUME("MIC2 Capture Volume", 0x19, 0x0, HDA_INPUT),
11050 HDA_CODEC_VOLUME("LINE1 Capture Volume", 0x1a, 0x0, HDA_INPUT),
11051 HDA_BIND_MUTE("LINE1 Capture Switch", 0x1a, 2, HDA_OUTPUT),
Takashi Iwaif0747ee2008-01-15 11:41:41 +010011052 /* The below appears problematic on some hardwares */
11053 /*HDA_CODEC_VOLUME("PCBEEP Playback Volume", 0x1d, 0x0, HDA_INPUT),*/
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010011054 HDA_CODEC_VOLUME("PCM-IN1 Capture Volume", 0x23, 0x0, HDA_OUTPUT),
11055 HDA_BIND_MUTE("PCM-IN1 Capture Switch", 0x23, 2, HDA_OUTPUT),
11056 HDA_CODEC_VOLUME("PCM-IN2 Capture Volume", 0x24, 0x0, HDA_OUTPUT),
11057 HDA_BIND_MUTE("PCM-IN2 Capture Switch", 0x24, 2, HDA_OUTPUT),
11058
11059 /* Modes for retasking pin widgets */
11060 ALC_PIN_MODE("LINE-OUT pin mode", 0x14, ALC_PIN_DIR_INOUT),
11061 ALC_PIN_MODE("HP-OUT pin mode", 0x15, ALC_PIN_DIR_INOUT),
11062 ALC_PIN_MODE("MIC1 pin mode", 0x18, ALC_PIN_DIR_INOUT),
11063 ALC_PIN_MODE("LINE1 pin mode", 0x1a, ALC_PIN_DIR_INOUT),
11064
11065 /* Controls for GPIO pins, assuming they are configured as outputs */
11066 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
11067 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
11068 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
11069 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
11070
11071 /* Switches to allow the digital SPDIF output pin to be enabled.
11072 * The ALC268 does not have an SPDIF input.
11073 */
11074 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x06, 0x01),
11075
11076 /* A switch allowing EAPD to be enabled. Some laptops seem to use
11077 * this output to turn on an external amplifier.
11078 */
11079 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
11080 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
11081
11082 { } /* end */
11083};
11084#endif
11085
Kailang Yanga361d842007-06-05 12:30:55 +020011086/* create input playback/capture controls for the given pin */
11087static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
11088 const char *ctlname, int idx)
11089{
11090 char name[32];
11091 int err;
11092
11093 sprintf(name, "%s Playback Volume", ctlname);
11094 if (nid == 0x14) {
11095 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
11096 HDA_COMPOSE_AMP_VAL(0x02, 3, idx,
11097 HDA_OUTPUT));
11098 if (err < 0)
11099 return err;
11100 } else if (nid == 0x15) {
11101 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
11102 HDA_COMPOSE_AMP_VAL(0x03, 3, idx,
11103 HDA_OUTPUT));
11104 if (err < 0)
11105 return err;
11106 } else
11107 return -1;
11108 sprintf(name, "%s Playback Switch", ctlname);
11109 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
11110 HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
11111 if (err < 0)
11112 return err;
11113 return 0;
11114}
11115
11116/* add playback controls from the parsed DAC table */
11117static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
11118 const struct auto_pin_cfg *cfg)
11119{
11120 hda_nid_t nid;
11121 int err;
11122
11123 spec->multiout.num_dacs = 2; /* only use one dac */
11124 spec->multiout.dac_nids = spec->private_dac_nids;
11125 spec->multiout.dac_nids[0] = 2;
11126 spec->multiout.dac_nids[1] = 3;
11127
11128 nid = cfg->line_out_pins[0];
11129 if (nid)
Kailang Yangea1fb292008-08-26 12:58:38 +020011130 alc268_new_analog_output(spec, nid, "Front", 0);
Kailang Yanga361d842007-06-05 12:30:55 +020011131
11132 nid = cfg->speaker_pins[0];
11133 if (nid == 0x1d) {
11134 err = add_control(spec, ALC_CTL_WIDGET_VOL,
11135 "Speaker Playback Volume",
11136 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
11137 if (err < 0)
11138 return err;
11139 }
11140 nid = cfg->hp_pins[0];
11141 if (nid)
11142 alc268_new_analog_output(spec, nid, "Headphone", 0);
11143
11144 nid = cfg->line_out_pins[1] | cfg->line_out_pins[2];
11145 if (nid == 0x16) {
11146 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
11147 "Mono Playback Switch",
11148 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_INPUT));
11149 if (err < 0)
11150 return err;
11151 }
Kailang Yangea1fb292008-08-26 12:58:38 +020011152 return 0;
Kailang Yanga361d842007-06-05 12:30:55 +020011153}
11154
11155/* create playback/capture controls for input pins */
11156static int alc268_auto_create_analog_input_ctls(struct alc_spec *spec,
11157 const struct auto_pin_cfg *cfg)
11158{
11159 struct hda_input_mux *imux = &spec->private_imux;
11160 int i, idx1;
11161
11162 for (i = 0; i < AUTO_PIN_LAST; i++) {
11163 switch(cfg->input_pins[i]) {
11164 case 0x18:
11165 idx1 = 0; /* Mic 1 */
11166 break;
11167 case 0x19:
11168 idx1 = 1; /* Mic 2 */
11169 break;
11170 case 0x1a:
11171 idx1 = 2; /* Line In */
11172 break;
Kailang Yangea1fb292008-08-26 12:58:38 +020011173 case 0x1c:
Kailang Yanga361d842007-06-05 12:30:55 +020011174 idx1 = 3; /* CD */
11175 break;
Takashi Iwai7194cae2008-03-06 16:58:17 +010011176 case 0x12:
11177 case 0x13:
11178 idx1 = 6; /* digital mics */
11179 break;
Kailang Yanga361d842007-06-05 12:30:55 +020011180 default:
11181 continue;
11182 }
11183 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
11184 imux->items[imux->num_items].index = idx1;
Kailang Yangea1fb292008-08-26 12:58:38 +020011185 imux->num_items++;
Kailang Yanga361d842007-06-05 12:30:55 +020011186 }
11187 return 0;
11188}
11189
11190static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec)
11191{
11192 struct alc_spec *spec = codec->spec;
11193 hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
11194 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
11195 hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
11196 unsigned int dac_vol1, dac_vol2;
11197
11198 if (speaker_nid) {
11199 snd_hda_codec_write(codec, speaker_nid, 0,
11200 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
11201 snd_hda_codec_write(codec, 0x0f, 0,
11202 AC_VERB_SET_AMP_GAIN_MUTE,
11203 AMP_IN_UNMUTE(1));
11204 snd_hda_codec_write(codec, 0x10, 0,
11205 AC_VERB_SET_AMP_GAIN_MUTE,
11206 AMP_IN_UNMUTE(1));
11207 } else {
11208 snd_hda_codec_write(codec, 0x0f, 0,
11209 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
11210 snd_hda_codec_write(codec, 0x10, 0,
11211 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
11212 }
11213
11214 dac_vol1 = dac_vol2 = 0xb000 | 0x40; /* set max volume */
Kailang Yangea1fb292008-08-26 12:58:38 +020011215 if (line_nid == 0x14)
Kailang Yanga361d842007-06-05 12:30:55 +020011216 dac_vol2 = AMP_OUT_ZERO;
11217 else if (line_nid == 0x15)
11218 dac_vol1 = AMP_OUT_ZERO;
Kailang Yangea1fb292008-08-26 12:58:38 +020011219 if (hp_nid == 0x14)
Kailang Yanga361d842007-06-05 12:30:55 +020011220 dac_vol2 = AMP_OUT_ZERO;
11221 else if (hp_nid == 0x15)
11222 dac_vol1 = AMP_OUT_ZERO;
11223 if (line_nid != 0x16 || hp_nid != 0x16 ||
11224 spec->autocfg.line_out_pins[1] != 0x16 ||
11225 spec->autocfg.line_out_pins[2] != 0x16)
11226 dac_vol1 = dac_vol2 = AMP_OUT_ZERO;
11227
11228 snd_hda_codec_write(codec, 0x02, 0,
11229 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol1);
11230 snd_hda_codec_write(codec, 0x03, 0,
11231 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol2);
11232}
11233
11234/* pcm configuration: identiacal with ALC880 */
11235#define alc268_pcm_analog_playback alc880_pcm_analog_playback
11236#define alc268_pcm_analog_capture alc880_pcm_analog_capture
Takashi Iwai63300792008-01-24 15:31:36 +010011237#define alc268_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
Kailang Yanga361d842007-06-05 12:30:55 +020011238#define alc268_pcm_digital_playback alc880_pcm_digital_playback
11239
11240/*
11241 * BIOS auto configuration
11242 */
11243static int alc268_parse_auto_config(struct hda_codec *codec)
11244{
11245 struct alc_spec *spec = codec->spec;
11246 int err;
11247 static hda_nid_t alc268_ignore[] = { 0 };
11248
11249 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
11250 alc268_ignore);
11251 if (err < 0)
11252 return err;
11253 if (!spec->autocfg.line_outs)
11254 return 0; /* can't find valid BIOS pin config */
11255
11256 err = alc268_auto_create_multi_out_ctls(spec, &spec->autocfg);
11257 if (err < 0)
11258 return err;
11259 err = alc268_auto_create_analog_input_ctls(spec, &spec->autocfg);
11260 if (err < 0)
11261 return err;
11262
11263 spec->multiout.max_channels = 2;
11264
11265 /* digital only support output */
11266 if (spec->autocfg.dig_out_pin)
11267 spec->multiout.dig_out_nid = ALC268_DIGOUT_NID;
11268
Takashi Iwai603c4012008-07-30 15:01:44 +020011269 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010011270 add_mixer(spec, spec->kctls.list);
Kailang Yanga361d842007-06-05 12:30:55 +020011271
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011272 if (spec->autocfg.speaker_pins[0] != 0x1d)
Takashi Iwaid88897e2008-10-31 15:01:37 +010011273 add_mixer(spec, alc268_beep_mixer);
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011274
Takashi Iwaid88897e2008-10-31 15:01:37 +010011275 add_verb(spec, alc268_volume_init_verbs);
Kailang Yanga361d842007-06-05 12:30:55 +020011276 spec->num_mux_defs = 1;
11277 spec->input_mux = &spec->private_imux;
11278
Takashi Iwai776e1842007-08-29 15:07:11 +020011279 err = alc_auto_add_mic_boost(codec);
11280 if (err < 0)
11281 return err;
11282
Takashi Iwaie044c392008-10-27 16:56:24 +010011283 store_pin_configs(codec);
Kailang Yanga361d842007-06-05 12:30:55 +020011284 return 1;
11285}
11286
11287#define alc268_auto_init_multi_out alc882_auto_init_multi_out
11288#define alc268_auto_init_hp_out alc882_auto_init_hp_out
11289#define alc268_auto_init_analog_input alc882_auto_init_analog_input
11290
11291/* init callback for auto-configuration model -- overriding the default init */
11292static void alc268_auto_init(struct hda_codec *codec)
11293{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010011294 struct alc_spec *spec = codec->spec;
Kailang Yanga361d842007-06-05 12:30:55 +020011295 alc268_auto_init_multi_out(codec);
11296 alc268_auto_init_hp_out(codec);
11297 alc268_auto_init_mono_speaker_out(codec);
11298 alc268_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010011299 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020011300 alc_inithook(codec);
Kailang Yanga361d842007-06-05 12:30:55 +020011301}
11302
11303/*
11304 * configuration and preset
11305 */
11306static const char *alc268_models[ALC268_MODEL_LAST] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020011307 [ALC267_QUANTA_IL1] = "quanta-il1",
Kailang Yanga361d842007-06-05 12:30:55 +020011308 [ALC268_3ST] = "3stack",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020011309 [ALC268_TOSHIBA] = "toshiba",
Takashi Iwaid2738092007-08-16 14:59:45 +020011310 [ALC268_ACER] = "acer",
Kailang Yang8ef355d2008-08-26 13:10:22 +020011311 [ALC268_ACER_ASPIRE_ONE] = "acer-aspire",
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011312 [ALC268_DELL] = "dell",
Mirco Tischlerf12462c2008-02-04 12:33:59 +010011313 [ALC268_ZEPTO] = "zepto",
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010011314#ifdef CONFIG_SND_DEBUG
11315 [ALC268_TEST] = "test",
11316#endif
Kailang Yanga361d842007-06-05 12:30:55 +020011317 [ALC268_AUTO] = "auto",
11318};
11319
11320static struct snd_pci_quirk alc268_cfg_tbl[] = {
Takashi Iwaia0b8f7d2008-04-22 19:39:49 +020011321 SND_PCI_QUIRK(0x1025, 0x011e, "Acer Aspire 5720z", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011322 SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER),
Andy Shevchenkodafc8352008-01-25 11:53:50 +010011323 SND_PCI_QUIRK(0x1025, 0x012e, "Acer Aspire 5310", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011324 SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER),
Andy Shevchenko29a52c22008-01-24 17:29:00 +010011325 SND_PCI_QUIRK(0x1025, 0x0136, "Acer Aspire 5315", ALC268_ACER),
Kailang Yang8ef355d2008-08-26 13:10:22 +020011326 SND_PCI_QUIRK(0x1025, 0x015b, "Acer Aspire One",
11327 ALC268_ACER_ASPIRE_ONE),
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011328 SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011329 SND_PCI_QUIRK(0x103c, 0x30cc, "TOSHIBA", ALC268_TOSHIBA),
Kailang Yanga361d842007-06-05 12:30:55 +020011330 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST),
Kailang Yangd1a991a2007-08-15 16:21:59 +020011331 SND_PCI_QUIRK(0x1179, 0xff10, "TOSHIBA A205", ALC268_TOSHIBA),
Takashi Iwai8e7f00f2007-09-07 10:58:58 +020011332 SND_PCI_QUIRK(0x1179, 0xff50, "TOSHIBA A305", ALC268_TOSHIBA),
Travis Place2346d0c2008-09-01 08:24:00 +020011333 SND_PCI_QUIRK(0x1179, 0xff64, "TOSHIBA L305", ALC268_TOSHIBA),
Tony Vroon378bd6a2008-06-04 12:08:30 +020011334 SND_PCI_QUIRK(0x14c0, 0x0025, "COMPAL IFL90/JFL-92", ALC268_TOSHIBA),
Takashi Iwaib875bf32007-09-06 15:00:27 +020011335 SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER),
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020011336 SND_PCI_QUIRK(0x152d, 0x0771, "Quanta IL1", ALC267_QUANTA_IL1),
Mirco Tischlerf12462c2008-02-04 12:33:59 +010011337 SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO),
Kailang Yanga361d842007-06-05 12:30:55 +020011338 {}
11339};
11340
11341static struct alc_config_preset alc268_presets[] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020011342 [ALC267_QUANTA_IL1] = {
11343 .mixers = { alc267_quanta_il1_mixer },
11344 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
11345 alc267_quanta_il1_verbs },
11346 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11347 .dac_nids = alc268_dac_nids,
11348 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
11349 .adc_nids = alc268_adc_nids_alt,
11350 .hp_nid = 0x03,
11351 .num_channel_mode = ARRAY_SIZE(alc268_modes),
11352 .channel_mode = alc268_modes,
11353 .input_mux = &alc268_capture_source,
11354 .unsol_event = alc267_quanta_il1_unsol_event,
11355 .init_hook = alc267_quanta_il1_automute,
11356 },
Kailang Yanga361d842007-06-05 12:30:55 +020011357 [ALC268_3ST] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011358 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
11359 alc268_beep_mixer },
Kailang Yanga361d842007-06-05 12:30:55 +020011360 .init_verbs = { alc268_base_init_verbs },
11361 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11362 .dac_nids = alc268_dac_nids,
11363 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
11364 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010011365 .capsrc_nids = alc268_capsrc_nids,
Kailang Yanga361d842007-06-05 12:30:55 +020011366 .hp_nid = 0x03,
11367 .dig_out_nid = ALC268_DIGOUT_NID,
11368 .num_channel_mode = ARRAY_SIZE(alc268_modes),
11369 .channel_mode = alc268_modes,
11370 .input_mux = &alc268_capture_source,
11371 },
Kailang Yangd1a991a2007-08-15 16:21:59 +020011372 [ALC268_TOSHIBA] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011373 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
11374 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020011375 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
11376 alc268_toshiba_verbs },
Kailang Yangd1a991a2007-08-15 16:21:59 +020011377 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11378 .dac_nids = alc268_dac_nids,
11379 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
11380 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010011381 .capsrc_nids = alc268_capsrc_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020011382 .hp_nid = 0x03,
11383 .num_channel_mode = ARRAY_SIZE(alc268_modes),
11384 .channel_mode = alc268_modes,
11385 .input_mux = &alc268_capture_source,
Takashi Iwaid2738092007-08-16 14:59:45 +020011386 .unsol_event = alc268_toshiba_unsol_event,
11387 .init_hook = alc268_toshiba_automute,
11388 },
11389 [ALC268_ACER] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011390 .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer,
11391 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020011392 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
11393 alc268_acer_verbs },
11394 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11395 .dac_nids = alc268_dac_nids,
11396 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
11397 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010011398 .capsrc_nids = alc268_capsrc_nids,
Takashi Iwaid2738092007-08-16 14:59:45 +020011399 .hp_nid = 0x02,
11400 .num_channel_mode = ARRAY_SIZE(alc268_modes),
11401 .channel_mode = alc268_modes,
Takashi Iwai0ccb5412008-03-06 16:58:35 +010011402 .input_mux = &alc268_acer_capture_source,
Takashi Iwaid2738092007-08-16 14:59:45 +020011403 .unsol_event = alc268_acer_unsol_event,
Takashi Iwai889c4392007-08-23 18:56:52 +020011404 .init_hook = alc268_acer_init_hook,
Kailang Yangd1a991a2007-08-15 16:21:59 +020011405 },
Kailang Yang8ef355d2008-08-26 13:10:22 +020011406 [ALC268_ACER_ASPIRE_ONE] = {
11407 .mixers = { alc268_acer_aspire_one_mixer,
11408 alc268_capture_alt_mixer },
11409 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
11410 alc268_acer_aspire_one_verbs },
11411 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11412 .dac_nids = alc268_dac_nids,
11413 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
11414 .adc_nids = alc268_adc_nids_alt,
11415 .capsrc_nids = alc268_capsrc_nids,
11416 .hp_nid = 0x03,
11417 .num_channel_mode = ARRAY_SIZE(alc268_modes),
11418 .channel_mode = alc268_modes,
11419 .input_mux = &alc268_acer_lc_capture_source,
11420 .unsol_event = alc268_acer_lc_unsol_event,
11421 .init_hook = alc268_acer_lc_init_hook,
11422 },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011423 [ALC268_DELL] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011424 .mixers = { alc268_dell_mixer, alc268_beep_mixer },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011425 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
11426 alc268_dell_verbs },
11427 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11428 .dac_nids = alc268_dac_nids,
11429 .hp_nid = 0x02,
11430 .num_channel_mode = ARRAY_SIZE(alc268_modes),
11431 .channel_mode = alc268_modes,
11432 .unsol_event = alc268_dell_unsol_event,
11433 .init_hook = alc268_dell_init_hook,
11434 .input_mux = &alc268_capture_source,
11435 },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010011436 [ALC268_ZEPTO] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011437 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
11438 alc268_beep_mixer },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010011439 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
11440 alc268_toshiba_verbs },
11441 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11442 .dac_nids = alc268_dac_nids,
11443 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
11444 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010011445 .capsrc_nids = alc268_capsrc_nids,
Mirco Tischlerf12462c2008-02-04 12:33:59 +010011446 .hp_nid = 0x03,
11447 .dig_out_nid = ALC268_DIGOUT_NID,
11448 .num_channel_mode = ARRAY_SIZE(alc268_modes),
11449 .channel_mode = alc268_modes,
11450 .input_mux = &alc268_capture_source,
11451 .unsol_event = alc268_toshiba_unsol_event,
11452 .init_hook = alc268_toshiba_automute
11453 },
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010011454#ifdef CONFIG_SND_DEBUG
11455 [ALC268_TEST] = {
11456 .mixers = { alc268_test_mixer, alc268_capture_mixer },
11457 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
11458 alc268_volume_init_verbs },
11459 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11460 .dac_nids = alc268_dac_nids,
11461 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
11462 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010011463 .capsrc_nids = alc268_capsrc_nids,
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010011464 .hp_nid = 0x03,
11465 .dig_out_nid = ALC268_DIGOUT_NID,
11466 .num_channel_mode = ARRAY_SIZE(alc268_modes),
11467 .channel_mode = alc268_modes,
11468 .input_mux = &alc268_capture_source,
11469 },
11470#endif
Kailang Yanga361d842007-06-05 12:30:55 +020011471};
11472
11473static int patch_alc268(struct hda_codec *codec)
11474{
11475 struct alc_spec *spec;
11476 int board_config;
11477 int err;
11478
11479 spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
11480 if (spec == NULL)
11481 return -ENOMEM;
11482
11483 codec->spec = spec;
11484
11485 board_config = snd_hda_check_board_config(codec, ALC268_MODEL_LAST,
11486 alc268_models,
11487 alc268_cfg_tbl);
11488
11489 if (board_config < 0 || board_config >= ALC268_MODEL_LAST) {
11490 printk(KERN_INFO "hda_codec: Unknown model for ALC268, "
11491 "trying auto-probe from BIOS...\n");
11492 board_config = ALC268_AUTO;
11493 }
11494
11495 if (board_config == ALC268_AUTO) {
11496 /* automatic parse from the BIOS config */
11497 err = alc268_parse_auto_config(codec);
11498 if (err < 0) {
11499 alc_free(codec);
11500 return err;
11501 } else if (!err) {
11502 printk(KERN_INFO
11503 "hda_codec: Cannot set up configuration "
11504 "from BIOS. Using base mode...\n");
11505 board_config = ALC268_3ST;
11506 }
11507 }
11508
11509 if (board_config != ALC268_AUTO)
11510 setup_preset(spec, &alc268_presets[board_config]);
11511
Kailang Yang2f893282008-05-27 12:14:47 +020011512 if (codec->vendor_id == 0x10ec0267) {
11513 spec->stream_name_analog = "ALC267 Analog";
11514 spec->stream_name_digital = "ALC267 Digital";
11515 } else {
11516 spec->stream_name_analog = "ALC268 Analog";
11517 spec->stream_name_digital = "ALC268 Digital";
11518 }
11519
Kailang Yanga361d842007-06-05 12:30:55 +020011520 spec->stream_analog_playback = &alc268_pcm_analog_playback;
11521 spec->stream_analog_capture = &alc268_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +010011522 spec->stream_analog_alt_capture = &alc268_pcm_analog_alt_capture;
Kailang Yanga361d842007-06-05 12:30:55 +020011523
Kailang Yanga361d842007-06-05 12:30:55 +020011524 spec->stream_digital_playback = &alc268_pcm_digital_playback;
11525
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011526 if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
11527 /* override the amp caps for beep generator */
11528 snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT,
11529 (0x0c << AC_AMPCAP_OFFSET_SHIFT) |
11530 (0x0c << AC_AMPCAP_NUM_STEPS_SHIFT) |
11531 (0x07 << AC_AMPCAP_STEP_SIZE_SHIFT) |
11532 (0 << AC_AMPCAP_MUTE_SHIFT));
11533
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011534 if (!spec->adc_nids && spec->input_mux) {
11535 /* check whether NID 0x07 is valid */
11536 unsigned int wcap = get_wcaps(codec, 0x07);
Takashi Iwai85860c02008-02-19 15:00:15 +010011537 int i;
Kailang Yanga361d842007-06-05 12:30:55 +020011538
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011539 /* get type */
11540 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Takashi Iwai67ebcb02008-02-19 15:03:57 +010011541 if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011542 spec->adc_nids = alc268_adc_nids_alt;
11543 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt);
Takashi Iwaid88897e2008-10-31 15:01:37 +010011544 add_mixer(spec, alc268_capture_alt_mixer);
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011545 } else {
11546 spec->adc_nids = alc268_adc_nids;
11547 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids);
Takashi Iwaid88897e2008-10-31 15:01:37 +010011548 add_mixer(spec, alc268_capture_mixer);
Kailang Yanga361d842007-06-05 12:30:55 +020011549 }
Takashi Iwaie1406342008-02-11 18:32:32 +010011550 spec->capsrc_nids = alc268_capsrc_nids;
Takashi Iwai85860c02008-02-19 15:00:15 +010011551 /* set default input source */
11552 for (i = 0; i < spec->num_adc_nids; i++)
11553 snd_hda_codec_write_cache(codec, alc268_capsrc_nids[i],
11554 0, AC_VERB_SET_CONNECT_SEL,
11555 spec->input_mux->items[0].index);
Kailang Yanga361d842007-06-05 12:30:55 +020011556 }
Takashi Iwai2134ea42008-01-10 16:53:55 +010011557
11558 spec->vmaster_nid = 0x02;
11559
Kailang Yanga361d842007-06-05 12:30:55 +020011560 codec->patch_ops = alc_patch_ops;
11561 if (board_config == ALC268_AUTO)
11562 spec->init_hook = alc268_auto_init;
Kailang Yangea1fb292008-08-26 12:58:38 +020011563
Kailang Yanga361d842007-06-05 12:30:55 +020011564 return 0;
11565}
11566
11567/*
Kailang Yangf6a92242007-12-13 16:52:54 +010011568 * ALC269 channel source setting (2 channel)
11569 */
11570#define ALC269_DIGOUT_NID ALC880_DIGOUT_NID
11571
11572#define alc269_dac_nids alc260_dac_nids
11573
11574static hda_nid_t alc269_adc_nids[1] = {
11575 /* ADC1 */
Kailang Yangf53281e2008-07-18 12:36:43 +020011576 0x08,
11577};
11578
Takashi Iwaie01bf502008-08-21 16:25:07 +020011579static hda_nid_t alc269_capsrc_nids[1] = {
11580 0x23,
11581};
11582
11583/* NOTE: ADC2 (0x07) is connected from a recording *MIXER* (0x24),
11584 * not a mux!
11585 */
11586
Kailang Yangf53281e2008-07-18 12:36:43 +020011587static struct hda_input_mux alc269_eeepc_dmic_capture_source = {
11588 .num_items = 2,
11589 .items = {
11590 { "i-Mic", 0x5 },
11591 { "e-Mic", 0x0 },
11592 },
11593};
11594
11595static struct hda_input_mux alc269_eeepc_amic_capture_source = {
11596 .num_items = 2,
11597 .items = {
11598 { "i-Mic", 0x1 },
11599 { "e-Mic", 0x0 },
11600 },
Kailang Yangf6a92242007-12-13 16:52:54 +010011601};
11602
11603#define alc269_modes alc260_modes
11604#define alc269_capture_source alc880_lg_lw_capture_source
11605
11606static struct snd_kcontrol_new alc269_base_mixer[] = {
11607 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
11608 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11609 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11610 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11611 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11612 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai2005af22008-08-20 18:38:26 +020011613 HDA_CODEC_VOLUME("Beep Playback Volume", 0x0b, 0x4, HDA_INPUT),
11614 HDA_CODEC_MUTE("Beep Playback Switch", 0x0b, 0x4, HDA_INPUT),
Kailang Yangf6a92242007-12-13 16:52:54 +010011615 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11616 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11617 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11618 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
11619 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11620 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
11621 { } /* end */
11622};
11623
Kailang Yang60db6b52008-08-26 13:13:00 +020011624static struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = {
11625 /* output mixer control */
11626 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
11627 {
11628 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11629 .name = "Master Playback Switch",
11630 .info = snd_hda_mixer_amp_switch_info,
11631 .get = snd_hda_mixer_amp_switch_get,
11632 .put = alc268_acer_master_sw_put,
11633 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
11634 },
11635 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11636 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11637 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11638 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11639 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11640 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
11641 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x04, HDA_INPUT),
11642 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x04, HDA_INPUT),
11643 { }
11644};
11645
Kailang Yangf53281e2008-07-18 12:36:43 +020011646/* bind volumes of both NID 0x0c and 0x0d */
11647static struct hda_bind_ctls alc269_epc_bind_vol = {
11648 .ops = &snd_hda_bind_vol,
11649 .values = {
11650 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
11651 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
11652 0
11653 },
11654};
11655
11656static struct snd_kcontrol_new alc269_eeepc_mixer[] = {
11657 HDA_CODEC_MUTE("iSpeaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11658 HDA_BIND_VOL("LineOut Playback Volume", &alc269_epc_bind_vol),
11659 HDA_CODEC_MUTE("LineOut Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11660 { } /* end */
11661};
11662
Kailang Yangf6a92242007-12-13 16:52:54 +010011663/* capture mixer elements */
Kailang Yangf53281e2008-07-18 12:36:43 +020011664static struct snd_kcontrol_new alc269_epc_capture_mixer[] = {
11665 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
11666 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
Takashi Iwai26f5df22008-11-03 17:39:46 +010011667 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11668 { } /* end */
11669};
11670
11671/* FSC amilo */
11672static struct snd_kcontrol_new alc269_fujitsu_mixer[] = {
11673 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11674 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11675 HDA_BIND_VOL("PCM Playback Volume", &alc269_epc_bind_vol),
Kailang Yangf53281e2008-07-18 12:36:43 +020011676 { } /* end */
11677};
11678
Takashi Iwai2005af22008-08-20 18:38:26 +020011679/* beep control */
11680static struct snd_kcontrol_new alc269_beep_mixer[] = {
11681 HDA_CODEC_VOLUME("Beep Playback Volume", 0x0b, 0x4, HDA_INPUT),
11682 HDA_CODEC_MUTE("Beep Playback Switch", 0x0b, 0x4, HDA_INPUT),
11683 { } /* end */
11684};
11685
Kailang Yang60db6b52008-08-26 13:13:00 +020011686static struct hda_verb alc269_quanta_fl1_verbs[] = {
11687 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
11688 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11689 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11690 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
11691 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
11692 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11693 { }
11694};
11695
11696/* toggle speaker-output according to the hp-jack state */
11697static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec)
11698{
11699 unsigned int present;
11700 unsigned char bits;
11701
11702 present = snd_hda_codec_read(codec, 0x15, 0,
11703 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
11704 bits = present ? AMP_IN_MUTE(0) : 0;
11705 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
11706 AMP_IN_MUTE(0), bits);
11707 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
11708 AMP_IN_MUTE(0), bits);
11709
11710 snd_hda_codec_write(codec, 0x20, 0,
11711 AC_VERB_SET_COEF_INDEX, 0x0c);
11712 snd_hda_codec_write(codec, 0x20, 0,
11713 AC_VERB_SET_PROC_COEF, 0x680);
11714
11715 snd_hda_codec_write(codec, 0x20, 0,
11716 AC_VERB_SET_COEF_INDEX, 0x0c);
11717 snd_hda_codec_write(codec, 0x20, 0,
11718 AC_VERB_SET_PROC_COEF, 0x480);
11719}
11720
11721static void alc269_quanta_fl1_mic_automute(struct hda_codec *codec)
11722{
11723 unsigned int present;
11724
11725 present = snd_hda_codec_read(codec, 0x18, 0,
11726 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
11727 snd_hda_codec_write(codec, 0x23, 0,
11728 AC_VERB_SET_CONNECT_SEL, present ? 0x0 : 0x1);
11729}
11730
11731static void alc269_quanta_fl1_unsol_event(struct hda_codec *codec,
11732 unsigned int res)
11733{
11734 if ((res >> 26) == ALC880_HP_EVENT)
11735 alc269_quanta_fl1_speaker_automute(codec);
11736 if ((res >> 26) == ALC880_MIC_EVENT)
11737 alc269_quanta_fl1_mic_automute(codec);
11738}
11739
11740static void alc269_quanta_fl1_init_hook(struct hda_codec *codec)
11741{
11742 alc269_quanta_fl1_speaker_automute(codec);
11743 alc269_quanta_fl1_mic_automute(codec);
11744}
11745
11746static struct hda_verb alc269_eeepc_dmic_init_verbs[] = {
11747 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
11748 {0x23, AC_VERB_SET_CONNECT_SEL, 0x05},
11749 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
11750 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
11751 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11752 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
11753 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11754 {}
11755};
11756
11757static struct hda_verb alc269_eeepc_amic_init_verbs[] = {
11758 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
11759 {0x23, AC_VERB_SET_CONNECT_SEL, 0x01},
11760 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
11761 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x701b | (0x00 << 8))},
11762 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
11763 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11764 {}
11765};
11766
11767/* toggle speaker-output according to the hp-jack state */
11768static void alc269_speaker_automute(struct hda_codec *codec)
11769{
11770 unsigned int present;
11771 unsigned char bits;
11772
11773 present = snd_hda_codec_read(codec, 0x15, 0,
11774 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
11775 bits = present ? AMP_IN_MUTE(0) : 0;
11776 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
11777 AMP_IN_MUTE(0), bits);
11778 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
11779 AMP_IN_MUTE(0), bits);
11780}
11781
11782static void alc269_eeepc_dmic_automute(struct hda_codec *codec)
11783{
11784 unsigned int present;
11785
11786 present = snd_hda_codec_read(codec, 0x18, 0,
11787 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
11788 snd_hda_codec_write(codec, 0x23, 0,
11789 AC_VERB_SET_CONNECT_SEL, (present ? 0 : 5));
11790}
11791
11792static void alc269_eeepc_amic_automute(struct hda_codec *codec)
11793{
11794 unsigned int present;
11795
11796 present = snd_hda_codec_read(codec, 0x18, 0,
11797 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
11798 snd_hda_codec_write(codec, 0x24, 0, AC_VERB_SET_AMP_GAIN_MUTE,
11799 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
11800 snd_hda_codec_write(codec, 0x24, 0, AC_VERB_SET_AMP_GAIN_MUTE,
11801 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
11802}
11803
11804/* unsolicited event for HP jack sensing */
11805static void alc269_eeepc_dmic_unsol_event(struct hda_codec *codec,
11806 unsigned int res)
11807{
11808 if ((res >> 26) == ALC880_HP_EVENT)
11809 alc269_speaker_automute(codec);
11810
11811 if ((res >> 26) == ALC880_MIC_EVENT)
11812 alc269_eeepc_dmic_automute(codec);
11813}
11814
11815static void alc269_eeepc_dmic_inithook(struct hda_codec *codec)
11816{
11817 alc269_speaker_automute(codec);
11818 alc269_eeepc_dmic_automute(codec);
11819}
11820
11821/* unsolicited event for HP jack sensing */
11822static void alc269_eeepc_amic_unsol_event(struct hda_codec *codec,
11823 unsigned int res)
11824{
11825 if ((res >> 26) == ALC880_HP_EVENT)
11826 alc269_speaker_automute(codec);
11827
11828 if ((res >> 26) == ALC880_MIC_EVENT)
11829 alc269_eeepc_amic_automute(codec);
11830}
11831
11832static void alc269_eeepc_amic_inithook(struct hda_codec *codec)
11833{
11834 alc269_speaker_automute(codec);
11835 alc269_eeepc_amic_automute(codec);
11836}
11837
Kailang Yangf6a92242007-12-13 16:52:54 +010011838/*
11839 * generic initialization of ADC, input mixers and output mixers
11840 */
11841static struct hda_verb alc269_init_verbs[] = {
11842 /*
11843 * Unmute ADC0 and set the default input to mic-in
11844 */
Kailang Yang60db6b52008-08-26 13:13:00 +020011845 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangf6a92242007-12-13 16:52:54 +010011846
11847 /* Mute input amps (PCBeep, Line In, Mic 1 & Mic 2) of the
11848 * analog-loopback mixer widget
11849 * Note: PASD motherboards uses the Line In 2 as the input for
11850 * front panel mic (mic 2)
11851 */
11852 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
11853 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11854 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11855 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
11856 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
11857 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
11858
11859 /*
11860 * Set up output mixers (0x0c - 0x0e)
11861 */
11862 /* set vol=0 to output mixers */
11863 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11864 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11865
11866 /* set up input amps for analog loopback */
11867 /* Amp Indices: DAC = 0, mixer = 1 */
11868 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11869 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11870 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11871 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11872 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11873 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11874
11875 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11876 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11877 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11878 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
11879 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
11880 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11881 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11882
11883 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11884 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11885 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11886 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11887 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11888 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11889 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11890
11891 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
11892 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11893
11894 /* FIXME: use matrix-type input source selection */
11895 /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
11896 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yang60db6b52008-08-26 13:13:00 +020011897 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11898 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangf6a92242007-12-13 16:52:54 +010011899 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
11900 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
11901
11902 /* set EAPD */
11903 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
11904 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
11905 { }
11906};
11907
11908/* add playback controls from the parsed DAC table */
11909static int alc269_auto_create_multi_out_ctls(struct alc_spec *spec,
11910 const struct auto_pin_cfg *cfg)
11911{
11912 hda_nid_t nid;
11913 int err;
11914
11915 spec->multiout.num_dacs = 1; /* only use one dac */
11916 spec->multiout.dac_nids = spec->private_dac_nids;
11917 spec->multiout.dac_nids[0] = 2;
11918
11919 nid = cfg->line_out_pins[0];
11920 if (nid) {
11921 err = add_control(spec, ALC_CTL_WIDGET_VOL,
11922 "Front Playback Volume",
11923 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT));
11924 if (err < 0)
11925 return err;
11926 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
11927 "Front Playback Switch",
11928 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
11929 if (err < 0)
11930 return err;
11931 }
11932
11933 nid = cfg->speaker_pins[0];
11934 if (nid) {
11935 if (!cfg->line_out_pins[0]) {
11936 err = add_control(spec, ALC_CTL_WIDGET_VOL,
11937 "Speaker Playback Volume",
11938 HDA_COMPOSE_AMP_VAL(0x02, 3, 0,
11939 HDA_OUTPUT));
11940 if (err < 0)
11941 return err;
11942 }
11943 if (nid == 0x16) {
11944 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
11945 "Speaker Playback Switch",
11946 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
11947 HDA_OUTPUT));
11948 if (err < 0)
11949 return err;
11950 } else {
11951 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
11952 "Speaker Playback Switch",
11953 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
11954 HDA_OUTPUT));
11955 if (err < 0)
11956 return err;
11957 }
11958 }
11959 nid = cfg->hp_pins[0];
11960 if (nid) {
11961 /* spec->multiout.hp_nid = 2; */
11962 if (!cfg->line_out_pins[0] && !cfg->speaker_pins[0]) {
11963 err = add_control(spec, ALC_CTL_WIDGET_VOL,
11964 "Headphone Playback Volume",
11965 HDA_COMPOSE_AMP_VAL(0x02, 3, 0,
11966 HDA_OUTPUT));
11967 if (err < 0)
11968 return err;
11969 }
11970 if (nid == 0x16) {
11971 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
11972 "Headphone Playback Switch",
11973 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
11974 HDA_OUTPUT));
11975 if (err < 0)
11976 return err;
11977 } else {
11978 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
11979 "Headphone Playback Switch",
11980 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
11981 HDA_OUTPUT));
11982 if (err < 0)
11983 return err;
11984 }
11985 }
11986 return 0;
11987}
11988
Takashi Iwaiee956e02008-10-31 17:16:31 +010011989static int alc269_auto_create_analog_input_ctls(struct alc_spec *spec,
11990 const struct auto_pin_cfg *cfg)
11991{
11992 int err;
11993
11994 err = alc880_auto_create_analog_input_ctls(spec, cfg);
11995 if (err < 0)
11996 return err;
11997 /* digital-mic input pin is excluded in alc880_auto_create..()
11998 * because it's under 0x18
11999 */
12000 if (cfg->input_pins[AUTO_PIN_MIC] == 0x12 ||
12001 cfg->input_pins[AUTO_PIN_FRONT_MIC] == 0x12) {
12002 struct hda_input_mux *imux = &spec->private_imux;
12003 imux->items[imux->num_items].label = "Int Mic";
12004 imux->items[imux->num_items].index = 0x05;
12005 imux->num_items++;
12006 }
12007 return 0;
12008}
Kailang Yangf6a92242007-12-13 16:52:54 +010012009
12010#ifdef CONFIG_SND_HDA_POWER_SAVE
12011#define alc269_loopbacks alc880_loopbacks
12012#endif
12013
12014/* pcm configuration: identiacal with ALC880 */
12015#define alc269_pcm_analog_playback alc880_pcm_analog_playback
12016#define alc269_pcm_analog_capture alc880_pcm_analog_capture
12017#define alc269_pcm_digital_playback alc880_pcm_digital_playback
12018#define alc269_pcm_digital_capture alc880_pcm_digital_capture
12019
12020/*
12021 * BIOS auto configuration
12022 */
12023static int alc269_parse_auto_config(struct hda_codec *codec)
12024{
12025 struct alc_spec *spec = codec->spec;
Takashi Iwai2005af22008-08-20 18:38:26 +020012026 int i, err;
Kailang Yangf6a92242007-12-13 16:52:54 +010012027 static hda_nid_t alc269_ignore[] = { 0x1d, 0 };
12028
12029 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
12030 alc269_ignore);
12031 if (err < 0)
12032 return err;
12033
12034 err = alc269_auto_create_multi_out_ctls(spec, &spec->autocfg);
12035 if (err < 0)
12036 return err;
12037 err = alc269_auto_create_analog_input_ctls(spec, &spec->autocfg);
12038 if (err < 0)
12039 return err;
12040
12041 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
12042
12043 if (spec->autocfg.dig_out_pin)
12044 spec->multiout.dig_out_nid = ALC269_DIGOUT_NID;
12045
Takashi Iwai603c4012008-07-30 15:01:44 +020012046 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010012047 add_mixer(spec, spec->kctls.list);
Kailang Yangf6a92242007-12-13 16:52:54 +010012048
Takashi Iwai2005af22008-08-20 18:38:26 +020012049 /* create a beep mixer control if the pin 0x1d isn't assigned */
12050 for (i = 0; i < ARRAY_SIZE(spec->autocfg.input_pins); i++)
12051 if (spec->autocfg.input_pins[i] == 0x1d)
12052 break;
12053 if (i >= ARRAY_SIZE(spec->autocfg.input_pins))
Takashi Iwaid88897e2008-10-31 15:01:37 +010012054 add_mixer(spec, alc269_beep_mixer);
Takashi Iwai2005af22008-08-20 18:38:26 +020012055
Takashi Iwaid88897e2008-10-31 15:01:37 +010012056 add_verb(spec, alc269_init_verbs);
Kailang Yangf6a92242007-12-13 16:52:54 +010012057 spec->num_mux_defs = 1;
12058 spec->input_mux = &spec->private_imux;
Takashi Iwaie01bf502008-08-21 16:25:07 +020012059 /* set default input source */
12060 snd_hda_codec_write_cache(codec, alc269_capsrc_nids[0],
12061 0, AC_VERB_SET_CONNECT_SEL,
12062 spec->input_mux->items[0].index);
Kailang Yangf6a92242007-12-13 16:52:54 +010012063
12064 err = alc_auto_add_mic_boost(codec);
12065 if (err < 0)
12066 return err;
12067
Takashi Iwaif9e336f2008-10-31 16:37:07 +010012068 if (!spec->cap_mixer)
12069 set_capture_mixer(spec);
Kailang Yangf53281e2008-07-18 12:36:43 +020012070
Takashi Iwaie044c392008-10-27 16:56:24 +010012071 store_pin_configs(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010012072 return 1;
12073}
12074
12075#define alc269_auto_init_multi_out alc882_auto_init_multi_out
12076#define alc269_auto_init_hp_out alc882_auto_init_hp_out
12077#define alc269_auto_init_analog_input alc882_auto_init_analog_input
12078
12079
12080/* init callback for auto-configuration model -- overriding the default init */
12081static void alc269_auto_init(struct hda_codec *codec)
12082{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012083 struct alc_spec *spec = codec->spec;
Kailang Yangf6a92242007-12-13 16:52:54 +010012084 alc269_auto_init_multi_out(codec);
12085 alc269_auto_init_hp_out(codec);
12086 alc269_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012087 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020012088 alc_inithook(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010012089}
12090
12091/*
12092 * configuration and preset
12093 */
12094static const char *alc269_models[ALC269_MODEL_LAST] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020012095 [ALC269_BASIC] = "basic",
Takashi Iwai2922c9a2008-08-27 18:12:42 +020012096 [ALC269_QUANTA_FL1] = "quanta",
12097 [ALC269_ASUS_EEEPC_P703] = "eeepc-p703",
Takashi Iwai26f5df22008-11-03 17:39:46 +010012098 [ALC269_ASUS_EEEPC_P901] = "eeepc-p901",
12099 [ALC269_FUJITSU] = "fujitsu"
Kailang Yangf6a92242007-12-13 16:52:54 +010012100};
12101
12102static struct snd_pci_quirk alc269_cfg_tbl[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020012103 SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_QUANTA_FL1),
Kailang Yangf53281e2008-07-18 12:36:43 +020012104 SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A",
12105 ALC269_ASUS_EEEPC_P703),
12106 SND_PCI_QUIRK(0x1043, 0x831a, "ASUS Eeepc P901",
12107 ALC269_ASUS_EEEPC_P901),
Kailang Yang60db6b52008-08-26 13:13:00 +020012108 SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101",
12109 ALC269_ASUS_EEEPC_P901),
Takashi Iwai26f5df22008-11-03 17:39:46 +010012110 SND_PCI_QUIRK(0x1734, 0x115d, "FSC Amilo", ALC269_FUJITSU),
Kailang Yangf6a92242007-12-13 16:52:54 +010012111 {}
12112};
12113
12114static struct alc_config_preset alc269_presets[] = {
12115 [ALC269_BASIC] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010012116 .mixers = { alc269_base_mixer },
Kailang Yangf6a92242007-12-13 16:52:54 +010012117 .init_verbs = { alc269_init_verbs },
12118 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
12119 .dac_nids = alc269_dac_nids,
12120 .hp_nid = 0x03,
12121 .num_channel_mode = ARRAY_SIZE(alc269_modes),
12122 .channel_mode = alc269_modes,
12123 .input_mux = &alc269_capture_source,
12124 },
Kailang Yang60db6b52008-08-26 13:13:00 +020012125 [ALC269_QUANTA_FL1] = {
12126 .mixers = { alc269_quanta_fl1_mixer },
12127 .init_verbs = { alc269_init_verbs, alc269_quanta_fl1_verbs },
12128 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
12129 .dac_nids = alc269_dac_nids,
12130 .hp_nid = 0x03,
12131 .num_channel_mode = ARRAY_SIZE(alc269_modes),
12132 .channel_mode = alc269_modes,
12133 .input_mux = &alc269_capture_source,
12134 .unsol_event = alc269_quanta_fl1_unsol_event,
12135 .init_hook = alc269_quanta_fl1_init_hook,
12136 },
Kailang Yangf53281e2008-07-18 12:36:43 +020012137 [ALC269_ASUS_EEEPC_P703] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010012138 .mixers = { alc269_eeepc_mixer },
12139 .cap_mixer = alc269_epc_capture_mixer,
Kailang Yangf53281e2008-07-18 12:36:43 +020012140 .init_verbs = { alc269_init_verbs,
12141 alc269_eeepc_amic_init_verbs },
12142 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
12143 .dac_nids = alc269_dac_nids,
12144 .hp_nid = 0x03,
12145 .num_channel_mode = ARRAY_SIZE(alc269_modes),
12146 .channel_mode = alc269_modes,
12147 .input_mux = &alc269_eeepc_amic_capture_source,
12148 .unsol_event = alc269_eeepc_amic_unsol_event,
12149 .init_hook = alc269_eeepc_amic_inithook,
12150 },
12151 [ALC269_ASUS_EEEPC_P901] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010012152 .mixers = { alc269_eeepc_mixer },
12153 .cap_mixer = alc269_epc_capture_mixer,
Kailang Yangf53281e2008-07-18 12:36:43 +020012154 .init_verbs = { alc269_init_verbs,
12155 alc269_eeepc_dmic_init_verbs },
12156 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
12157 .dac_nids = alc269_dac_nids,
12158 .hp_nid = 0x03,
12159 .num_channel_mode = ARRAY_SIZE(alc269_modes),
12160 .channel_mode = alc269_modes,
12161 .input_mux = &alc269_eeepc_dmic_capture_source,
12162 .unsol_event = alc269_eeepc_dmic_unsol_event,
12163 .init_hook = alc269_eeepc_dmic_inithook,
12164 },
Takashi Iwai26f5df22008-11-03 17:39:46 +010012165 [ALC269_FUJITSU] = {
12166 .mixers = { alc269_fujitsu_mixer, alc269_beep_mixer },
12167 .cap_mixer = alc269_epc_capture_mixer,
12168 .init_verbs = { alc269_init_verbs,
12169 alc269_eeepc_dmic_init_verbs },
12170 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
12171 .dac_nids = alc269_dac_nids,
12172 .hp_nid = 0x03,
12173 .num_channel_mode = ARRAY_SIZE(alc269_modes),
12174 .channel_mode = alc269_modes,
12175 .input_mux = &alc269_eeepc_dmic_capture_source,
12176 .unsol_event = alc269_eeepc_dmic_unsol_event,
12177 .init_hook = alc269_eeepc_dmic_inithook,
12178 },
Kailang Yangf6a92242007-12-13 16:52:54 +010012179};
12180
12181static int patch_alc269(struct hda_codec *codec)
12182{
12183 struct alc_spec *spec;
12184 int board_config;
12185 int err;
12186
12187 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
12188 if (spec == NULL)
12189 return -ENOMEM;
12190
12191 codec->spec = spec;
12192
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020012193 alc_fix_pll_init(codec, 0x20, 0x04, 15);
12194
Kailang Yangf6a92242007-12-13 16:52:54 +010012195 board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST,
12196 alc269_models,
12197 alc269_cfg_tbl);
12198
12199 if (board_config < 0) {
12200 printk(KERN_INFO "hda_codec: Unknown model for ALC269, "
12201 "trying auto-probe from BIOS...\n");
12202 board_config = ALC269_AUTO;
12203 }
12204
12205 if (board_config == ALC269_AUTO) {
12206 /* automatic parse from the BIOS config */
12207 err = alc269_parse_auto_config(codec);
12208 if (err < 0) {
12209 alc_free(codec);
12210 return err;
12211 } else if (!err) {
12212 printk(KERN_INFO
12213 "hda_codec: Cannot set up configuration "
12214 "from BIOS. Using base mode...\n");
12215 board_config = ALC269_BASIC;
12216 }
12217 }
12218
12219 if (board_config != ALC269_AUTO)
12220 setup_preset(spec, &alc269_presets[board_config]);
12221
12222 spec->stream_name_analog = "ALC269 Analog";
12223 spec->stream_analog_playback = &alc269_pcm_analog_playback;
12224 spec->stream_analog_capture = &alc269_pcm_analog_capture;
12225
12226 spec->stream_name_digital = "ALC269 Digital";
12227 spec->stream_digital_playback = &alc269_pcm_digital_playback;
12228 spec->stream_digital_capture = &alc269_pcm_digital_capture;
12229
12230 spec->adc_nids = alc269_adc_nids;
12231 spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids);
Takashi Iwaie01bf502008-08-21 16:25:07 +020012232 spec->capsrc_nids = alc269_capsrc_nids;
Takashi Iwaif9e336f2008-10-31 16:37:07 +010012233 if (!spec->cap_mixer)
12234 set_capture_mixer(spec);
Kailang Yangf6a92242007-12-13 16:52:54 +010012235
12236 codec->patch_ops = alc_patch_ops;
12237 if (board_config == ALC269_AUTO)
12238 spec->init_hook = alc269_auto_init;
12239#ifdef CONFIG_SND_HDA_POWER_SAVE
12240 if (!spec->loopback.amplist)
12241 spec->loopback.amplist = alc269_loopbacks;
12242#endif
12243
12244 return 0;
12245}
12246
12247/*
Kailang Yangdf694da2005-12-05 19:42:22 +010012248 * ALC861 channel source setting (2/6 channel selection for 3-stack)
12249 */
12250
12251/*
12252 * set the path ways for 2 channel output
12253 * need to set the codec line out and mic 1 pin widgets to inputs
12254 */
12255static struct hda_verb alc861_threestack_ch2_init[] = {
12256 /* set pin widget 1Ah (line in) for input */
12257 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012258 /* set pin widget 18h (mic1/2) for input, for mic also enable
12259 * the vref
12260 */
Kailang Yangdf694da2005-12-05 19:42:22 +010012261 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12262
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012263 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
12264#if 0
12265 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
12266 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
12267#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010012268 { } /* end */
12269};
12270/*
12271 * 6ch mode
12272 * need to set the codec line out and mic 1 pin widgets to outputs
12273 */
12274static struct hda_verb alc861_threestack_ch6_init[] = {
12275 /* set pin widget 1Ah (line in) for output (Back Surround)*/
12276 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12277 /* set pin widget 18h (mic1) for output (CLFE)*/
12278 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12279
12280 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012281 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010012282
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012283 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
12284#if 0
12285 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
12286 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
12287#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010012288 { } /* end */
12289};
12290
12291static struct hda_channel_mode alc861_threestack_modes[2] = {
12292 { 2, alc861_threestack_ch2_init },
12293 { 6, alc861_threestack_ch6_init },
12294};
Takashi Iwai22309c32006-08-09 16:57:28 +020012295/* Set mic1 as input and unmute the mixer */
12296static struct hda_verb alc861_uniwill_m31_ch2_init[] = {
12297 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12298 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
12299 { } /* end */
12300};
12301/* Set mic1 as output and mute mixer */
12302static struct hda_verb alc861_uniwill_m31_ch4_init[] = {
12303 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12304 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
12305 { } /* end */
12306};
12307
12308static struct hda_channel_mode alc861_uniwill_m31_modes[2] = {
12309 { 2, alc861_uniwill_m31_ch2_init },
12310 { 4, alc861_uniwill_m31_ch4_init },
12311};
Kailang Yangdf694da2005-12-05 19:42:22 +010012312
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012313/* Set mic1 and line-in as input and unmute the mixer */
12314static struct hda_verb alc861_asus_ch2_init[] = {
12315 /* set pin widget 1Ah (line in) for input */
12316 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012317 /* set pin widget 18h (mic1/2) for input, for mic also enable
12318 * the vref
12319 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012320 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12321
12322 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
12323#if 0
12324 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
12325 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
12326#endif
12327 { } /* end */
12328};
12329/* Set mic1 nad line-in as output and mute mixer */
12330static struct hda_verb alc861_asus_ch6_init[] = {
12331 /* set pin widget 1Ah (line in) for output (Back Surround)*/
12332 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12333 /* { 0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
12334 /* set pin widget 18h (mic1) for output (CLFE)*/
12335 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12336 /* { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
12337 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
12338 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
12339
12340 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
12341#if 0
12342 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
12343 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
12344#endif
12345 { } /* end */
12346};
12347
12348static struct hda_channel_mode alc861_asus_modes[2] = {
12349 { 2, alc861_asus_ch2_init },
12350 { 6, alc861_asus_ch6_init },
12351};
12352
Kailang Yangdf694da2005-12-05 19:42:22 +010012353/* patch-ALC861 */
12354
12355static struct snd_kcontrol_new alc861_base_mixer[] = {
12356 /* output mixer control */
12357 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
12358 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
12359 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
12360 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
12361 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
12362
12363 /*Input mixer control */
12364 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
12365 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
12366 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
12367 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
12368 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
12369 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
12370 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
12371 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
12372 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
12373 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012374
Kailang Yangdf694da2005-12-05 19:42:22 +010012375 { } /* end */
12376};
12377
12378static struct snd_kcontrol_new alc861_3ST_mixer[] = {
12379 /* output mixer control */
12380 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
12381 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
12382 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
12383 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
12384 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
12385
12386 /* Input mixer control */
12387 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
12388 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
12389 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
12390 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
12391 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
12392 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
12393 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
12394 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
12395 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
12396 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012397
Kailang Yangdf694da2005-12-05 19:42:22 +010012398 {
12399 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12400 .name = "Channel Mode",
12401 .info = alc_ch_mode_info,
12402 .get = alc_ch_mode_get,
12403 .put = alc_ch_mode_put,
12404 .private_value = ARRAY_SIZE(alc861_threestack_modes),
12405 },
12406 { } /* end */
Tobin Davisa53d1ae2006-10-17 12:00:28 +020012407};
12408
Takashi Iwaid1d985f2006-11-23 19:27:12 +010012409static struct snd_kcontrol_new alc861_toshiba_mixer[] = {
Tobin Davisa53d1ae2006-10-17 12:00:28 +020012410 /* output mixer control */
12411 HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT),
12412 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
12413 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
Kailang Yangea1fb292008-08-26 12:58:38 +020012414
Tobin Davisa53d1ae2006-10-17 12:00:28 +020012415 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012416};
Tobin Davisa53d1ae2006-10-17 12:00:28 +020012417
Takashi Iwai22309c32006-08-09 16:57:28 +020012418static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = {
12419 /* output mixer control */
12420 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
12421 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
12422 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
12423 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
12424 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
12425
12426 /* Input mixer control */
12427 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
12428 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
12429 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
12430 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
12431 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
12432 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
12433 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
12434 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
12435 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
12436 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012437
Takashi Iwai22309c32006-08-09 16:57:28 +020012438 {
12439 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12440 .name = "Channel Mode",
12441 .info = alc_ch_mode_info,
12442 .get = alc_ch_mode_get,
12443 .put = alc_ch_mode_put,
12444 .private_value = ARRAY_SIZE(alc861_uniwill_m31_modes),
12445 },
12446 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012447};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012448
12449static struct snd_kcontrol_new alc861_asus_mixer[] = {
12450 /* output mixer control */
12451 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
12452 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
12453 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
12454 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
12455 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
12456
12457 /* Input mixer control */
12458 HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
12459 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT),
12460 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
12461 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
12462 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
12463 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
12464 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
12465 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
12466 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012467 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_OUTPUT),
12468
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012469 {
12470 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12471 .name = "Channel Mode",
12472 .info = alc_ch_mode_info,
12473 .get = alc_ch_mode_get,
12474 .put = alc_ch_mode_put,
12475 .private_value = ARRAY_SIZE(alc861_asus_modes),
12476 },
12477 { }
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010012478};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012479
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010012480/* additional mixer */
Takashi Iwaid1d985f2006-11-23 19:27:12 +010012481static struct snd_kcontrol_new alc861_asus_laptop_mixer[] = {
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010012482 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
12483 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
12484 HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x23, 0x0, HDA_OUTPUT),
12485 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x23, 0x0, HDA_OUTPUT),
12486 { }
12487};
12488
Kailang Yangdf694da2005-12-05 19:42:22 +010012489/*
12490 * generic initialization of ADC, input mixers and output mixers
12491 */
12492static struct hda_verb alc861_base_init_verbs[] = {
12493 /*
12494 * Unmute ADC0 and set the default input to mic-in
12495 */
12496 /* port-A for surround (rear panel) */
12497 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12498 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x00 },
12499 /* port-B for mic-in (rear panel) with vref */
12500 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12501 /* port-C for line-in (rear panel) */
12502 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
12503 /* port-D for Front */
12504 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12505 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
12506 /* port-E for HP out (front panel) */
12507 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
12508 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010012509 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010012510 /* port-F for mic-in (front panel) with vref */
12511 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12512 /* port-G for CLFE (rear panel) */
12513 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12514 { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x00 },
12515 /* port-H for side (rear panel) */
12516 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12517 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x00 },
12518 /* CD-in */
12519 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
12520 /* route front mic to ADC1*/
12521 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
12522 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020012523
Kailang Yangdf694da2005-12-05 19:42:22 +010012524 /* Unmute DAC0~3 & spdif out*/
12525 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12526 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12527 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12528 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12529 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020012530
Kailang Yangdf694da2005-12-05 19:42:22 +010012531 /* Unmute Mixer 14 (mic) 1c (Line in)*/
12532 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12533 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12534 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12535 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020012536
Kailang Yangdf694da2005-12-05 19:42:22 +010012537 /* Unmute Stereo Mixer 15 */
12538 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12539 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12540 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012541 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010012542
12543 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12544 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12545 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12546 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12547 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12548 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12549 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12550 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012551 /* hp used DAC 3 (Front) */
12552 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010012553 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
12554
12555 { }
12556};
12557
12558static struct hda_verb alc861_threestack_init_verbs[] = {
12559 /*
12560 * Unmute ADC0 and set the default input to mic-in
12561 */
12562 /* port-A for surround (rear panel) */
12563 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
12564 /* port-B for mic-in (rear panel) with vref */
12565 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12566 /* port-C for line-in (rear panel) */
12567 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
12568 /* port-D for Front */
12569 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12570 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
12571 /* port-E for HP out (front panel) */
12572 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
12573 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010012574 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010012575 /* port-F for mic-in (front panel) with vref */
12576 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12577 /* port-G for CLFE (rear panel) */
12578 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
12579 /* port-H for side (rear panel) */
12580 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
12581 /* CD-in */
12582 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
12583 /* route front mic to ADC1*/
12584 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
12585 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12586 /* Unmute DAC0~3 & spdif out*/
12587 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12588 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12589 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12590 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12591 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020012592
Kailang Yangdf694da2005-12-05 19:42:22 +010012593 /* Unmute Mixer 14 (mic) 1c (Line in)*/
12594 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12595 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12596 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12597 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020012598
Kailang Yangdf694da2005-12-05 19:42:22 +010012599 /* Unmute Stereo Mixer 15 */
12600 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12601 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12602 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012603 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010012604
12605 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12606 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12607 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12608 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12609 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12610 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12611 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12612 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012613 /* hp used DAC 3 (Front) */
12614 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010012615 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
12616 { }
12617};
Takashi Iwai22309c32006-08-09 16:57:28 +020012618
12619static struct hda_verb alc861_uniwill_m31_init_verbs[] = {
12620 /*
12621 * Unmute ADC0 and set the default input to mic-in
12622 */
12623 /* port-A for surround (rear panel) */
12624 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
12625 /* port-B for mic-in (rear panel) with vref */
12626 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12627 /* port-C for line-in (rear panel) */
12628 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
12629 /* port-D for Front */
12630 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12631 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
12632 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012633 /* this has to be set to VREF80 */
12634 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Takashi Iwai22309c32006-08-09 16:57:28 +020012635 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010012636 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai22309c32006-08-09 16:57:28 +020012637 /* port-F for mic-in (front panel) with vref */
12638 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12639 /* port-G for CLFE (rear panel) */
12640 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
12641 /* port-H for side (rear panel) */
12642 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
12643 /* CD-in */
12644 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
12645 /* route front mic to ADC1*/
12646 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
12647 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12648 /* Unmute DAC0~3 & spdif out*/
12649 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12650 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12651 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12652 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12653 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020012654
Takashi Iwai22309c32006-08-09 16:57:28 +020012655 /* Unmute Mixer 14 (mic) 1c (Line in)*/
12656 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12657 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12658 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12659 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020012660
Takashi Iwai22309c32006-08-09 16:57:28 +020012661 /* Unmute Stereo Mixer 15 */
12662 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12663 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12664 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012665 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Takashi Iwai22309c32006-08-09 16:57:28 +020012666
12667 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12668 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12669 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12670 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12671 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12672 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12673 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12674 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012675 /* hp used DAC 3 (Front) */
12676 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Takashi Iwai22309c32006-08-09 16:57:28 +020012677 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
12678 { }
12679};
12680
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012681static struct hda_verb alc861_asus_init_verbs[] = {
12682 /*
12683 * Unmute ADC0 and set the default input to mic-in
12684 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012685 /* port-A for surround (rear panel)
12686 * according to codec#0 this is the HP jack
12687 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012688 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* was 0x00 */
12689 /* route front PCM to HP */
12690 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x01 },
12691 /* port-B for mic-in (rear panel) with vref */
12692 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12693 /* port-C for line-in (rear panel) */
12694 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
12695 /* port-D for Front */
12696 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12697 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
12698 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012699 /* this has to be set to VREF80 */
12700 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012701 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010012702 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012703 /* port-F for mic-in (front panel) with vref */
12704 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12705 /* port-G for CLFE (rear panel) */
12706 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12707 /* port-H for side (rear panel) */
12708 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12709 /* CD-in */
12710 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
12711 /* route front mic to ADC1*/
12712 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
12713 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12714 /* Unmute DAC0~3 & spdif out*/
12715 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12716 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12717 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12718 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12719 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12720 /* Unmute Mixer 14 (mic) 1c (Line in)*/
12721 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12722 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12723 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12724 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020012725
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012726 /* Unmute Stereo Mixer 15 */
12727 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12728 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12729 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012730 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012731
12732 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12733 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12734 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12735 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12736 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12737 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12738 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12739 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012740 /* hp used DAC 3 (Front) */
12741 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012742 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
12743 { }
12744};
12745
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010012746/* additional init verbs for ASUS laptops */
12747static struct hda_verb alc861_asus_laptop_init_verbs[] = {
12748 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x45 }, /* HP-out */
12749 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2) }, /* mute line-in */
12750 { }
12751};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012752
Kailang Yangdf694da2005-12-05 19:42:22 +010012753/*
12754 * generic initialization of ADC, input mixers and output mixers
12755 */
12756static struct hda_verb alc861_auto_init_verbs[] = {
12757 /*
12758 * Unmute ADC0 and set the default input to mic-in
12759 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012760 /* {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, */
Kailang Yangdf694da2005-12-05 19:42:22 +010012761 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020012762
Kailang Yangdf694da2005-12-05 19:42:22 +010012763 /* Unmute DAC0~3 & spdif out*/
12764 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12765 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12766 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12767 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12768 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020012769
Kailang Yangdf694da2005-12-05 19:42:22 +010012770 /* Unmute Mixer 14 (mic) 1c (Line in)*/
12771 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12772 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12773 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12774 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020012775
Kailang Yangdf694da2005-12-05 19:42:22 +010012776 /* Unmute Stereo Mixer 15 */
12777 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12778 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12779 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
12780 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c},
12781
12782 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12783 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12784 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12785 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12786 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12787 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12788 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12789 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12790
12791 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12792 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012793 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
12794 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010012795 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12796 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012797 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
12798 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010012799
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012800 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, /* set Mic 1 */
Kailang Yangdf694da2005-12-05 19:42:22 +010012801
12802 { }
12803};
12804
Tobin Davisa53d1ae2006-10-17 12:00:28 +020012805static struct hda_verb alc861_toshiba_init_verbs[] = {
12806 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012807
Tobin Davisa53d1ae2006-10-17 12:00:28 +020012808 { }
12809};
12810
12811/* toggle speaker-output according to the hp-jack state */
12812static void alc861_toshiba_automute(struct hda_codec *codec)
12813{
12814 unsigned int present;
12815
12816 present = snd_hda_codec_read(codec, 0x0f, 0,
12817 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020012818 snd_hda_codec_amp_stereo(codec, 0x16, HDA_INPUT, 0,
12819 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
12820 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_INPUT, 3,
12821 HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE);
Tobin Davisa53d1ae2006-10-17 12:00:28 +020012822}
12823
12824static void alc861_toshiba_unsol_event(struct hda_codec *codec,
12825 unsigned int res)
12826{
Tobin Davisa53d1ae2006-10-17 12:00:28 +020012827 if ((res >> 26) == ALC880_HP_EVENT)
12828 alc861_toshiba_automute(codec);
12829}
12830
Kailang Yangdf694da2005-12-05 19:42:22 +010012831/* pcm configuration: identiacal with ALC880 */
12832#define alc861_pcm_analog_playback alc880_pcm_analog_playback
12833#define alc861_pcm_analog_capture alc880_pcm_analog_capture
12834#define alc861_pcm_digital_playback alc880_pcm_digital_playback
12835#define alc861_pcm_digital_capture alc880_pcm_digital_capture
12836
12837
12838#define ALC861_DIGOUT_NID 0x07
12839
12840static struct hda_channel_mode alc861_8ch_modes[1] = {
12841 { 8, NULL }
12842};
12843
12844static hda_nid_t alc861_dac_nids[4] = {
12845 /* front, surround, clfe, side */
12846 0x03, 0x06, 0x05, 0x04
12847};
12848
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012849static hda_nid_t alc660_dac_nids[3] = {
12850 /* front, clfe, surround */
12851 0x03, 0x05, 0x06
12852};
12853
Kailang Yangdf694da2005-12-05 19:42:22 +010012854static hda_nid_t alc861_adc_nids[1] = {
12855 /* ADC0-2 */
12856 0x08,
12857};
12858
12859static struct hda_input_mux alc861_capture_source = {
12860 .num_items = 5,
12861 .items = {
12862 { "Mic", 0x0 },
12863 { "Front Mic", 0x3 },
12864 { "Line", 0x1 },
12865 { "CD", 0x4 },
12866 { "Mixer", 0x5 },
12867 },
12868};
12869
12870/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012871static int alc861_auto_fill_dac_nids(struct alc_spec *spec,
12872 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010012873{
12874 int i;
12875 hda_nid_t nid;
12876
12877 spec->multiout.dac_nids = spec->private_dac_nids;
12878 for (i = 0; i < cfg->line_outs; i++) {
12879 nid = cfg->line_out_pins[i];
12880 if (nid) {
12881 if (i >= ARRAY_SIZE(alc861_dac_nids))
12882 continue;
12883 spec->multiout.dac_nids[i] = alc861_dac_nids[i];
12884 }
12885 }
12886 spec->multiout.num_dacs = cfg->line_outs;
12887 return 0;
12888}
12889
12890/* add playback controls from the parsed DAC table */
12891static int alc861_auto_create_multi_out_ctls(struct alc_spec *spec,
12892 const struct auto_pin_cfg *cfg)
12893{
12894 char name[32];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012895 static const char *chname[4] = {
12896 "Front", "Surround", NULL /*CLFE*/, "Side"
12897 };
Kailang Yangdf694da2005-12-05 19:42:22 +010012898 hda_nid_t nid;
12899 int i, idx, err;
12900
12901 for (i = 0; i < cfg->line_outs; i++) {
12902 nid = spec->multiout.dac_nids[i];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012903 if (!nid)
Kailang Yangdf694da2005-12-05 19:42:22 +010012904 continue;
12905 if (nid == 0x05) {
12906 /* Center/LFE */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012907 err = add_control(spec, ALC_CTL_BIND_MUTE,
12908 "Center Playback Switch",
12909 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
12910 HDA_OUTPUT));
12911 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010012912 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012913 err = add_control(spec, ALC_CTL_BIND_MUTE,
12914 "LFE Playback Switch",
12915 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
12916 HDA_OUTPUT));
12917 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010012918 return err;
12919 } else {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012920 for (idx = 0; idx < ARRAY_SIZE(alc861_dac_nids) - 1;
12921 idx++)
Kailang Yangdf694da2005-12-05 19:42:22 +010012922 if (nid == alc861_dac_nids[idx])
12923 break;
12924 sprintf(name, "%s Playback Switch", chname[idx]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012925 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
12926 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
12927 HDA_OUTPUT));
12928 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010012929 return err;
12930 }
12931 }
12932 return 0;
12933}
12934
12935static int alc861_auto_create_hp_ctls(struct alc_spec *spec, hda_nid_t pin)
12936{
12937 int err;
12938 hda_nid_t nid;
12939
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012940 if (!pin)
Kailang Yangdf694da2005-12-05 19:42:22 +010012941 return 0;
12942
12943 if ((pin >= 0x0b && pin <= 0x10) || pin == 0x1f || pin == 0x20) {
12944 nid = 0x03;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012945 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
12946 "Headphone Playback Switch",
12947 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
12948 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010012949 return err;
12950 spec->multiout.hp_nid = nid;
12951 }
12952 return 0;
12953}
12954
12955/* create playback/capture controls for input pins */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012956static int alc861_auto_create_analog_input_ctls(struct alc_spec *spec,
12957 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010012958{
Kailang Yangdf694da2005-12-05 19:42:22 +010012959 struct hda_input_mux *imux = &spec->private_imux;
12960 int i, err, idx, idx1;
12961
12962 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012963 switch (cfg->input_pins[i]) {
Kailang Yangdf694da2005-12-05 19:42:22 +010012964 case 0x0c:
12965 idx1 = 1;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012966 idx = 2; /* Line In */
Kailang Yangdf694da2005-12-05 19:42:22 +010012967 break;
12968 case 0x0f:
12969 idx1 = 2;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012970 idx = 2; /* Line In */
Kailang Yangdf694da2005-12-05 19:42:22 +010012971 break;
12972 case 0x0d:
12973 idx1 = 0;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012974 idx = 1; /* Mic In */
Kailang Yangdf694da2005-12-05 19:42:22 +010012975 break;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012976 case 0x10:
Kailang Yangdf694da2005-12-05 19:42:22 +010012977 idx1 = 3;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012978 idx = 1; /* Mic In */
Kailang Yangdf694da2005-12-05 19:42:22 +010012979 break;
12980 case 0x11:
12981 idx1 = 4;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012982 idx = 0; /* CD */
Kailang Yangdf694da2005-12-05 19:42:22 +010012983 break;
12984 default:
12985 continue;
12986 }
12987
Takashi Iwai4a471b72005-12-07 13:56:29 +010012988 err = new_analog_input(spec, cfg->input_pins[i],
12989 auto_pin_cfg_labels[i], idx, 0x15);
Kailang Yangdf694da2005-12-05 19:42:22 +010012990 if (err < 0)
12991 return err;
12992
Takashi Iwai4a471b72005-12-07 13:56:29 +010012993 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
Kailang Yangdf694da2005-12-05 19:42:22 +010012994 imux->items[imux->num_items].index = idx1;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012995 imux->num_items++;
Kailang Yangdf694da2005-12-05 19:42:22 +010012996 }
12997 return 0;
12998}
12999
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013000static void alc861_auto_set_output_and_unmute(struct hda_codec *codec,
13001 hda_nid_t nid,
Kailang Yangdf694da2005-12-05 19:42:22 +010013002 int pin_type, int dac_idx)
13003{
Jacek Luczak564c5be2008-05-03 18:41:23 +020013004 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
13005 pin_type);
13006 snd_hda_codec_write(codec, dac_idx, 0, AC_VERB_SET_AMP_GAIN_MUTE,
13007 AMP_OUT_UNMUTE);
Kailang Yangdf694da2005-12-05 19:42:22 +010013008}
13009
13010static void alc861_auto_init_multi_out(struct hda_codec *codec)
13011{
13012 struct alc_spec *spec = codec->spec;
13013 int i;
13014
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013015 alc_subsystem_id(codec, 0x0e, 0x0f, 0x0b);
Kailang Yangdf694da2005-12-05 19:42:22 +010013016 for (i = 0; i < spec->autocfg.line_outs; i++) {
13017 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020013018 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangdf694da2005-12-05 19:42:22 +010013019 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020013020 alc861_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013021 spec->multiout.dac_nids[i]);
Kailang Yangdf694da2005-12-05 19:42:22 +010013022 }
13023}
13024
13025static void alc861_auto_init_hp_out(struct hda_codec *codec)
13026{
13027 struct alc_spec *spec = codec->spec;
13028 hda_nid_t pin;
13029
Takashi Iwaieb06ed82006-09-20 17:10:27 +020013030 pin = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010013031 if (pin) /* connect to front */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013032 alc861_auto_set_output_and_unmute(codec, pin, PIN_HP,
13033 spec->multiout.dac_nids[0]);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013034 pin = spec->autocfg.speaker_pins[0];
13035 if (pin)
13036 alc861_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Kailang Yangdf694da2005-12-05 19:42:22 +010013037}
13038
13039static void alc861_auto_init_analog_input(struct hda_codec *codec)
13040{
13041 struct alc_spec *spec = codec->spec;
13042 int i;
13043
13044 for (i = 0; i < AUTO_PIN_LAST; i++) {
13045 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013046 if (nid >= 0x0c && nid <= 0x11) {
13047 snd_hda_codec_write(codec, nid, 0,
13048 AC_VERB_SET_PIN_WIDGET_CONTROL,
13049 i <= AUTO_PIN_FRONT_MIC ?
13050 PIN_VREF80 : PIN_IN);
Kailang Yangdf694da2005-12-05 19:42:22 +010013051 }
13052 }
13053}
13054
13055/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013056/* return 1 if successful, 0 if the proper config is not found,
13057 * or a negative error code
13058 */
Kailang Yangdf694da2005-12-05 19:42:22 +010013059static int alc861_parse_auto_config(struct hda_codec *codec)
13060{
13061 struct alc_spec *spec = codec->spec;
13062 int err;
13063 static hda_nid_t alc861_ignore[] = { 0x1d, 0 };
13064
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013065 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
13066 alc861_ignore);
13067 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010013068 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013069 if (!spec->autocfg.line_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +010013070 return 0; /* can't find valid BIOS pin config */
13071
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013072 err = alc861_auto_fill_dac_nids(spec, &spec->autocfg);
13073 if (err < 0)
13074 return err;
13075 err = alc861_auto_create_multi_out_ctls(spec, &spec->autocfg);
13076 if (err < 0)
13077 return err;
13078 err = alc861_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
13079 if (err < 0)
13080 return err;
13081 err = alc861_auto_create_analog_input_ctls(spec, &spec->autocfg);
13082 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010013083 return err;
13084
13085 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
13086
13087 if (spec->autocfg.dig_out_pin)
13088 spec->multiout.dig_out_nid = ALC861_DIGOUT_NID;
13089
Takashi Iwai603c4012008-07-30 15:01:44 +020013090 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010013091 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +010013092
Takashi Iwaid88897e2008-10-31 15:01:37 +010013093 add_verb(spec, alc861_auto_init_verbs);
Kailang Yangdf694da2005-12-05 19:42:22 +010013094
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020013095 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +010013096 spec->input_mux = &spec->private_imux;
13097
13098 spec->adc_nids = alc861_adc_nids;
13099 spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids);
Takashi Iwaif9e336f2008-10-31 16:37:07 +010013100 set_capture_mixer(spec);
Kailang Yangdf694da2005-12-05 19:42:22 +010013101
Takashi Iwaie044c392008-10-27 16:56:24 +010013102 store_pin_configs(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010013103 return 1;
13104}
13105
Takashi Iwaiae6b8132006-03-03 16:47:17 +010013106/* additional initialization for auto-configuration model */
13107static void alc861_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010013108{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013109 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010013110 alc861_auto_init_multi_out(codec);
13111 alc861_auto_init_hp_out(codec);
13112 alc861_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013113 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020013114 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010013115}
13116
Takashi Iwaicb53c622007-08-10 17:21:45 +020013117#ifdef CONFIG_SND_HDA_POWER_SAVE
13118static struct hda_amp_list alc861_loopbacks[] = {
13119 { 0x15, HDA_INPUT, 0 },
13120 { 0x15, HDA_INPUT, 1 },
13121 { 0x15, HDA_INPUT, 2 },
13122 { 0x15, HDA_INPUT, 3 },
13123 { } /* end */
13124};
13125#endif
13126
Kailang Yangdf694da2005-12-05 19:42:22 +010013127
13128/*
13129 * configuration and preset
13130 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010013131static const char *alc861_models[ALC861_MODEL_LAST] = {
13132 [ALC861_3ST] = "3stack",
13133 [ALC660_3ST] = "3stack-660",
13134 [ALC861_3ST_DIG] = "3stack-dig",
13135 [ALC861_6ST_DIG] = "6stack-dig",
13136 [ALC861_UNIWILL_M31] = "uniwill-m31",
13137 [ALC861_TOSHIBA] = "toshiba",
13138 [ALC861_ASUS] = "asus",
13139 [ALC861_ASUS_LAPTOP] = "asus-laptop",
13140 [ALC861_AUTO] = "auto",
13141};
13142
13143static struct snd_pci_quirk alc861_cfg_tbl[] = {
Takashi Iwai687a47b2007-01-10 11:25:58 +010013144 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010013145 SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP),
13146 SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP),
13147 SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013148 SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP),
Kailang Yang83c34212007-07-05 11:43:05 +020013149 SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS P1-AH2", ALC861_3ST_DIG),
Tobin Davisad5e7732007-01-08 10:57:32 +010013150 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA),
Takashi Iwai341d4eb2007-07-09 17:53:18 +020013151 /* FIXME: the entry below breaks Toshiba A100 (model=auto works!)
13152 * Any other models that need this preset?
13153 */
13154 /* SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), */
Claudio Matsuokaef64adb2007-07-14 00:26:16 +020013155 SND_PCI_QUIRK(0x1462, 0x7254, "HP dx2200 (MSI MS-7254)", ALC861_3ST),
13156 SND_PCI_QUIRK(0x1462, 0x7297, "HP dx2250 (MSI MS-7297)", ALC861_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013157 SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31),
13158 SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31),
13159 SND_PCI_QUIRK(0x1584, 0x9075, "Airis Praxis N1212", ALC861_ASUS_LAPTOP),
13160 /* FIXME: the below seems conflict */
13161 /* SND_PCI_QUIRK(0x1584, 0x9075, "Uniwill", ALC861_UNIWILL_M31), */
13162 SND_PCI_QUIRK(0x1849, 0x0660, "Asrock 939SLI32", ALC660_3ST),
13163 SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST),
Kailang Yangdf694da2005-12-05 19:42:22 +010013164 {}
13165};
13166
13167static struct alc_config_preset alc861_presets[] = {
13168 [ALC861_3ST] = {
13169 .mixers = { alc861_3ST_mixer },
13170 .init_verbs = { alc861_threestack_init_verbs },
13171 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
13172 .dac_nids = alc861_dac_nids,
13173 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
13174 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020013175 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010013176 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13177 .adc_nids = alc861_adc_nids,
13178 .input_mux = &alc861_capture_source,
13179 },
13180 [ALC861_3ST_DIG] = {
13181 .mixers = { alc861_base_mixer },
13182 .init_verbs = { alc861_threestack_init_verbs },
13183 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
13184 .dac_nids = alc861_dac_nids,
13185 .dig_out_nid = ALC861_DIGOUT_NID,
13186 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
13187 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020013188 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010013189 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13190 .adc_nids = alc861_adc_nids,
13191 .input_mux = &alc861_capture_source,
13192 },
13193 [ALC861_6ST_DIG] = {
13194 .mixers = { alc861_base_mixer },
13195 .init_verbs = { alc861_base_init_verbs },
13196 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
13197 .dac_nids = alc861_dac_nids,
13198 .dig_out_nid = ALC861_DIGOUT_NID,
13199 .num_channel_mode = ARRAY_SIZE(alc861_8ch_modes),
13200 .channel_mode = alc861_8ch_modes,
13201 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13202 .adc_nids = alc861_adc_nids,
13203 .input_mux = &alc861_capture_source,
13204 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013205 [ALC660_3ST] = {
13206 .mixers = { alc861_3ST_mixer },
13207 .init_verbs = { alc861_threestack_init_verbs },
13208 .num_dacs = ARRAY_SIZE(alc660_dac_nids),
13209 .dac_nids = alc660_dac_nids,
13210 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
13211 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020013212 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013213 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13214 .adc_nids = alc861_adc_nids,
13215 .input_mux = &alc861_capture_source,
13216 },
Takashi Iwai22309c32006-08-09 16:57:28 +020013217 [ALC861_UNIWILL_M31] = {
13218 .mixers = { alc861_uniwill_m31_mixer },
13219 .init_verbs = { alc861_uniwill_m31_init_verbs },
13220 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
13221 .dac_nids = alc861_dac_nids,
13222 .dig_out_nid = ALC861_DIGOUT_NID,
13223 .num_channel_mode = ARRAY_SIZE(alc861_uniwill_m31_modes),
13224 .channel_mode = alc861_uniwill_m31_modes,
13225 .need_dac_fix = 1,
13226 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13227 .adc_nids = alc861_adc_nids,
13228 .input_mux = &alc861_capture_source,
13229 },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013230 [ALC861_TOSHIBA] = {
13231 .mixers = { alc861_toshiba_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013232 .init_verbs = { alc861_base_init_verbs,
13233 alc861_toshiba_init_verbs },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013234 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
13235 .dac_nids = alc861_dac_nids,
13236 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
13237 .channel_mode = alc883_3ST_2ch_modes,
13238 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13239 .adc_nids = alc861_adc_nids,
13240 .input_mux = &alc861_capture_source,
13241 .unsol_event = alc861_toshiba_unsol_event,
13242 .init_hook = alc861_toshiba_automute,
13243 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013244 [ALC861_ASUS] = {
13245 .mixers = { alc861_asus_mixer },
13246 .init_verbs = { alc861_asus_init_verbs },
13247 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
13248 .dac_nids = alc861_dac_nids,
13249 .dig_out_nid = ALC861_DIGOUT_NID,
13250 .num_channel_mode = ARRAY_SIZE(alc861_asus_modes),
13251 .channel_mode = alc861_asus_modes,
13252 .need_dac_fix = 1,
13253 .hp_nid = 0x06,
13254 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13255 .adc_nids = alc861_adc_nids,
13256 .input_mux = &alc861_capture_source,
13257 },
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010013258 [ALC861_ASUS_LAPTOP] = {
13259 .mixers = { alc861_toshiba_mixer, alc861_asus_laptop_mixer },
13260 .init_verbs = { alc861_asus_init_verbs,
13261 alc861_asus_laptop_init_verbs },
13262 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
13263 .dac_nids = alc861_dac_nids,
13264 .dig_out_nid = ALC861_DIGOUT_NID,
13265 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
13266 .channel_mode = alc883_3ST_2ch_modes,
13267 .need_dac_fix = 1,
13268 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13269 .adc_nids = alc861_adc_nids,
13270 .input_mux = &alc861_capture_source,
13271 },
13272};
Kailang Yangdf694da2005-12-05 19:42:22 +010013273
13274
13275static int patch_alc861(struct hda_codec *codec)
13276{
13277 struct alc_spec *spec;
13278 int board_config;
13279 int err;
13280
Robert P. J. Daydc041e02006-12-19 14:44:15 +010013281 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010013282 if (spec == NULL)
13283 return -ENOMEM;
13284
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013285 codec->spec = spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010013286
Takashi Iwaif5fcc132006-11-24 17:07:44 +010013287 board_config = snd_hda_check_board_config(codec, ALC861_MODEL_LAST,
13288 alc861_models,
13289 alc861_cfg_tbl);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013290
Takashi Iwaif5fcc132006-11-24 17:07:44 +010013291 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013292 printk(KERN_INFO "hda_codec: Unknown model for ALC861, "
13293 "trying auto-probe from BIOS...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010013294 board_config = ALC861_AUTO;
13295 }
13296
13297 if (board_config == ALC861_AUTO) {
13298 /* automatic parse from the BIOS config */
13299 err = alc861_parse_auto_config(codec);
13300 if (err < 0) {
13301 alc_free(codec);
13302 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013303 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013304 printk(KERN_INFO
13305 "hda_codec: Cannot set up configuration "
13306 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010013307 board_config = ALC861_3ST_DIG;
13308 }
13309 }
13310
13311 if (board_config != ALC861_AUTO)
13312 setup_preset(spec, &alc861_presets[board_config]);
13313
13314 spec->stream_name_analog = "ALC861 Analog";
13315 spec->stream_analog_playback = &alc861_pcm_analog_playback;
13316 spec->stream_analog_capture = &alc861_pcm_analog_capture;
13317
13318 spec->stream_name_digital = "ALC861 Digital";
13319 spec->stream_digital_playback = &alc861_pcm_digital_playback;
13320 spec->stream_digital_capture = &alc861_pcm_digital_capture;
13321
Takashi Iwai2134ea42008-01-10 16:53:55 +010013322 spec->vmaster_nid = 0x03;
13323
Kailang Yangdf694da2005-12-05 19:42:22 +010013324 codec->patch_ops = alc_patch_ops;
13325 if (board_config == ALC861_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +010013326 spec->init_hook = alc861_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020013327#ifdef CONFIG_SND_HDA_POWER_SAVE
13328 if (!spec->loopback.amplist)
13329 spec->loopback.amplist = alc861_loopbacks;
13330#endif
Kailang Yangea1fb292008-08-26 12:58:38 +020013331
Kailang Yangdf694da2005-12-05 19:42:22 +010013332 return 0;
13333}
13334
13335/*
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013336 * ALC861-VD support
13337 *
13338 * Based on ALC882
13339 *
13340 * In addition, an independent DAC
13341 */
13342#define ALC861VD_DIGOUT_NID 0x06
13343
13344static hda_nid_t alc861vd_dac_nids[4] = {
13345 /* front, surr, clfe, side surr */
13346 0x02, 0x03, 0x04, 0x05
13347};
13348
13349/* dac_nids for ALC660vd are in a different order - according to
13350 * Realtek's driver.
13351 * This should probably tesult in a different mixer for 6stack models
13352 * of ALC660vd codecs, but for now there is only 3stack mixer
13353 * - and it is the same as in 861vd.
13354 * adc_nids in ALC660vd are (is) the same as in 861vd
13355 */
13356static hda_nid_t alc660vd_dac_nids[3] = {
13357 /* front, rear, clfe, rear_surr */
13358 0x02, 0x04, 0x03
13359};
13360
13361static hda_nid_t alc861vd_adc_nids[1] = {
13362 /* ADC0 */
13363 0x09,
13364};
13365
Takashi Iwaie1406342008-02-11 18:32:32 +010013366static hda_nid_t alc861vd_capsrc_nids[1] = { 0x22 };
13367
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013368/* input MUX */
13369/* FIXME: should be a matrix-type input source selection */
13370static struct hda_input_mux alc861vd_capture_source = {
13371 .num_items = 4,
13372 .items = {
13373 { "Mic", 0x0 },
13374 { "Front Mic", 0x1 },
13375 { "Line", 0x2 },
13376 { "CD", 0x4 },
13377 },
13378};
13379
Kailang Yang272a5272007-05-14 11:00:38 +020013380static struct hda_input_mux alc861vd_dallas_capture_source = {
Tobin Davisb419f342008-03-07 11:57:51 +010013381 .num_items = 2,
Kailang Yang272a5272007-05-14 11:00:38 +020013382 .items = {
Tobin Davisb419f342008-03-07 11:57:51 +010013383 { "Ext Mic", 0x0 },
13384 { "Int Mic", 0x1 },
Kailang Yang272a5272007-05-14 11:00:38 +020013385 },
13386};
13387
Kailang Yangd1a991a2007-08-15 16:21:59 +020013388static struct hda_input_mux alc861vd_hp_capture_source = {
13389 .num_items = 2,
13390 .items = {
13391 { "Front Mic", 0x0 },
13392 { "ATAPI Mic", 0x1 },
13393 },
13394};
13395
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013396/*
13397 * 2ch mode
13398 */
13399static struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = {
13400 { 2, NULL }
13401};
13402
13403/*
13404 * 6ch mode
13405 */
13406static struct hda_verb alc861vd_6stack_ch6_init[] = {
13407 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
13408 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
13409 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
13410 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
13411 { } /* end */
13412};
13413
13414/*
13415 * 8ch mode
13416 */
13417static struct hda_verb alc861vd_6stack_ch8_init[] = {
13418 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
13419 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
13420 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
13421 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
13422 { } /* end */
13423};
13424
13425static struct hda_channel_mode alc861vd_6stack_modes[2] = {
13426 { 6, alc861vd_6stack_ch6_init },
13427 { 8, alc861vd_6stack_ch8_init },
13428};
13429
13430static struct snd_kcontrol_new alc861vd_chmode_mixer[] = {
13431 {
13432 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13433 .name = "Channel Mode",
13434 .info = alc_ch_mode_info,
13435 .get = alc_ch_mode_get,
13436 .put = alc_ch_mode_put,
13437 },
13438 { } /* end */
13439};
13440
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013441/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
13442 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
13443 */
13444static struct snd_kcontrol_new alc861vd_6st_mixer[] = {
13445 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13446 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
13447
13448 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
13449 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
13450
13451 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0,
13452 HDA_OUTPUT),
13453 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0,
13454 HDA_OUTPUT),
13455 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
13456 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
13457
13458 HDA_CODEC_VOLUME("Side Playback Volume", 0x05, 0x0, HDA_OUTPUT),
13459 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
13460
13461 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
13462
13463 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13464 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13465 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13466
13467 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
13468 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
13469 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
13470
13471 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
13472 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
13473
13474 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
13475 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
13476
13477 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
13478 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
13479
13480 { } /* end */
13481};
13482
13483static struct snd_kcontrol_new alc861vd_3st_mixer[] = {
13484 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13485 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
13486
13487 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
13488
13489 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13490 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13491 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13492
13493 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
13494 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
13495 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
13496
13497 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
13498 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
13499
13500 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
13501 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
13502
13503 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
13504 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
13505
13506 { } /* end */
13507};
13508
Kailang Yangbdd148a2007-05-08 15:19:08 +020013509static struct snd_kcontrol_new alc861vd_lenovo_mixer[] = {
13510 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13511 /*HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),*/
13512 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
13513
13514 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
13515
13516 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13517 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13518 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13519
13520 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
13521 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
13522 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
13523
13524 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
13525 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
13526
13527 { } /* end */
13528};
13529
Tobin Davisb419f342008-03-07 11:57:51 +010013530/* Pin assignment: Speaker=0x14, HP = 0x15,
13531 * Ext Mic=0x18, Int Mic = 0x19, CD = 0x1c, PC Beep = 0x1d
Kailang Yang272a5272007-05-14 11:00:38 +020013532 */
13533static struct snd_kcontrol_new alc861vd_dallas_mixer[] = {
Tobin Davisb419f342008-03-07 11:57:51 +010013534 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13535 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020013536 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
13537 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
Tobin Davisb419f342008-03-07 11:57:51 +010013538 HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
13539 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13540 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13541 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
13542 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
13543 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
13544 HDA_CODEC_VOLUME("PC Beep Volume", 0x0b, 0x05, HDA_INPUT),
13545 HDA_CODEC_MUTE("PC Beep Switch", 0x0b, 0x05, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020013546 { } /* end */
13547};
13548
Kailang Yangd1a991a2007-08-15 16:21:59 +020013549/* Pin assignment: Speaker=0x14, Line-out = 0x15,
13550 * Front Mic=0x18, ATAPI Mic = 0x19,
13551 */
13552static struct snd_kcontrol_new alc861vd_hp_mixer[] = {
13553 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13554 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
13555 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
13556 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
13557 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13558 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13559 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
13560 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangea1fb292008-08-26 12:58:38 +020013561
Kailang Yangd1a991a2007-08-15 16:21:59 +020013562 { } /* end */
13563};
13564
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013565/*
13566 * generic initialization of ADC, input mixers and output mixers
13567 */
13568static struct hda_verb alc861vd_volume_init_verbs[] = {
13569 /*
13570 * Unmute ADC0 and set the default input to mic-in
13571 */
13572 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
13573 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13574
13575 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of
13576 * the analog-loopback mixer widget
13577 */
13578 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020013579 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13580 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13581 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
13582 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
13583 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013584
13585 /* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yangbdd148a2007-05-08 15:19:08 +020013586 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13587 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13588 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013589 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013590
13591 /*
13592 * Set up output mixers (0x02 - 0x05)
13593 */
13594 /* set vol=0 to output mixers */
13595 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13596 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13597 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13598 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13599
13600 /* set up input amps for analog loopback */
13601 /* Amp Indices: DAC = 0, mixer = 1 */
13602 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13603 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13604 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13605 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13606 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13607 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13608 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13609 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13610
13611 { }
13612};
13613
13614/*
13615 * 3-stack pin configuration:
13616 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
13617 */
13618static struct hda_verb alc861vd_3stack_init_verbs[] = {
13619 /*
13620 * Set pin mode and muting
13621 */
13622 /* set front pin widgets 0x14 for output */
13623 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13624 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13625 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
13626
13627 /* Mic (rear) pin: input vref at 80% */
13628 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
13629 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13630 /* Front Mic pin: input vref at 80% */
13631 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
13632 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13633 /* Line In pin: input */
13634 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13635 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13636 /* Line-2 In: Headphone output (output 0 - 0x0c) */
13637 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13638 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13639 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
13640 /* CD pin widget for input */
13641 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13642
13643 { }
13644};
13645
13646/*
13647 * 6-stack pin configuration:
13648 */
13649static struct hda_verb alc861vd_6stack_init_verbs[] = {
13650 /*
13651 * Set pin mode and muting
13652 */
13653 /* set front pin widgets 0x14 for output */
13654 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13655 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13656 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
13657
13658 /* Rear Pin: output 1 (0x0d) */
13659 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13660 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13661 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
13662 /* CLFE Pin: output 2 (0x0e) */
13663 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13664 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13665 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
13666 /* Side Pin: output 3 (0x0f) */
13667 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13668 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13669 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
13670
13671 /* Mic (rear) pin: input vref at 80% */
13672 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
13673 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13674 /* Front Mic pin: input vref at 80% */
13675 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
13676 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13677 /* Line In pin: input */
13678 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13679 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13680 /* Line-2 In: Headphone output (output 0 - 0x0c) */
13681 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13682 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13683 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
13684 /* CD pin widget for input */
13685 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13686
13687 { }
13688};
13689
Kailang Yangbdd148a2007-05-08 15:19:08 +020013690static struct hda_verb alc861vd_eapd_verbs[] = {
13691 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
13692 { }
13693};
13694
Kailang Yangf9423e72008-05-27 12:32:25 +020013695static struct hda_verb alc660vd_eapd_verbs[] = {
13696 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
13697 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
13698 { }
13699};
13700
Kailang Yangbdd148a2007-05-08 15:19:08 +020013701static struct hda_verb alc861vd_lenovo_unsol_verbs[] = {
13702 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13703 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13704 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
13705 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Kailang Yangea1fb292008-08-26 12:58:38 +020013706 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
Kailang Yangbdd148a2007-05-08 15:19:08 +020013707 {}
13708};
13709
13710/* toggle speaker-output according to the hp-jack state */
13711static void alc861vd_lenovo_hp_automute(struct hda_codec *codec)
13712{
13713 unsigned int present;
13714 unsigned char bits;
13715
13716 present = snd_hda_codec_read(codec, 0x1b, 0,
13717 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020013718 bits = present ? HDA_AMP_MUTE : 0;
13719 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
13720 HDA_AMP_MUTE, bits);
Kailang Yangbdd148a2007-05-08 15:19:08 +020013721}
13722
13723static void alc861vd_lenovo_mic_automute(struct hda_codec *codec)
13724{
13725 unsigned int present;
13726 unsigned char bits;
13727
13728 present = snd_hda_codec_read(codec, 0x18, 0,
13729 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020013730 bits = present ? HDA_AMP_MUTE : 0;
13731 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
13732 HDA_AMP_MUTE, bits);
Kailang Yangbdd148a2007-05-08 15:19:08 +020013733}
13734
13735static void alc861vd_lenovo_automute(struct hda_codec *codec)
13736{
13737 alc861vd_lenovo_hp_automute(codec);
13738 alc861vd_lenovo_mic_automute(codec);
13739}
13740
13741static void alc861vd_lenovo_unsol_event(struct hda_codec *codec,
13742 unsigned int res)
13743{
13744 switch (res >> 26) {
13745 case ALC880_HP_EVENT:
13746 alc861vd_lenovo_hp_automute(codec);
13747 break;
13748 case ALC880_MIC_EVENT:
13749 alc861vd_lenovo_mic_automute(codec);
13750 break;
13751 }
13752}
13753
Kailang Yang272a5272007-05-14 11:00:38 +020013754static struct hda_verb alc861vd_dallas_verbs[] = {
13755 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13756 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13757 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13758 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13759
13760 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13761 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13762 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13763 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13764 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13765 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13766 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13767 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020013768
Kailang Yang272a5272007-05-14 11:00:38 +020013769 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13770 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13771 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13772 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13773 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13774 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13775 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13776 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13777
13778 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
13779 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13780 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
13781 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13782 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13783 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13784 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13785 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13786
13787 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13788 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
13789 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
13790 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
13791
13792 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020013793 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yang272a5272007-05-14 11:00:38 +020013794 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
13795
13796 { } /* end */
13797};
13798
13799/* toggle speaker-output according to the hp-jack state */
13800static void alc861vd_dallas_automute(struct hda_codec *codec)
13801{
13802 unsigned int present;
13803
13804 present = snd_hda_codec_read(codec, 0x15, 0,
13805 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020013806 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
13807 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +020013808}
13809
13810static void alc861vd_dallas_unsol_event(struct hda_codec *codec, unsigned int res)
13811{
13812 if ((res >> 26) == ALC880_HP_EVENT)
13813 alc861vd_dallas_automute(codec);
13814}
13815
Takashi Iwaicb53c622007-08-10 17:21:45 +020013816#ifdef CONFIG_SND_HDA_POWER_SAVE
13817#define alc861vd_loopbacks alc880_loopbacks
13818#endif
13819
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013820/* pcm configuration: identiacal with ALC880 */
13821#define alc861vd_pcm_analog_playback alc880_pcm_analog_playback
13822#define alc861vd_pcm_analog_capture alc880_pcm_analog_capture
13823#define alc861vd_pcm_digital_playback alc880_pcm_digital_playback
13824#define alc861vd_pcm_digital_capture alc880_pcm_digital_capture
13825
13826/*
13827 * configuration and preset
13828 */
13829static const char *alc861vd_models[ALC861VD_MODEL_LAST] = {
13830 [ALC660VD_3ST] = "3stack-660",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020013831 [ALC660VD_3ST_DIG] = "3stack-660-digout",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013832 [ALC861VD_3ST] = "3stack",
13833 [ALC861VD_3ST_DIG] = "3stack-digout",
13834 [ALC861VD_6ST_DIG] = "6stack-digout",
Kailang Yangbdd148a2007-05-08 15:19:08 +020013835 [ALC861VD_LENOVO] = "lenovo",
Kailang Yang272a5272007-05-14 11:00:38 +020013836 [ALC861VD_DALLAS] = "dallas",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020013837 [ALC861VD_HP] = "hp",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013838 [ALC861VD_AUTO] = "auto",
13839};
13840
13841static struct snd_pci_quirk alc861vd_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013842 SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST),
13843 SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP),
Takashi Iwai07e038b2007-02-15 18:23:41 +010013844 SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013845 SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),
Alexander Holler2522d732008-07-17 23:36:15 +020013846 SND_PCI_QUIRK(0x1043, 0x1633, "Asus V1Sn", ALC861VD_LENOVO),
Mike Crash6963f842007-06-25 12:12:51 +020013847 SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013848 SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013849 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO),
Takashi Iwai38baf5a2007-08-16 17:52:43 +020013850 /*SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS),*/ /*lenovo*/
Kailang Yang272a5272007-05-14 11:00:38 +020013851 SND_PCI_QUIRK(0x1179, 0xff01, "DALLAS", ALC861VD_DALLAS),
Takashi Iwai542d7c62007-08-16 18:57:30 +020013852 SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO),
Tobin Davisb419f342008-03-07 11:57:51 +010013853 SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_DALLAS),
Takashi Iwai39c5d412007-08-15 16:24:17 +020013854 SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013855 SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo", ALC861VD_LENOVO),
13856 SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo 3000 C200", ALC861VD_LENOVO),
Takashi Iwaibe321a892008-07-07 16:04:04 +020013857 SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 N200", ALC861VD_LENOVO),
Tobin Davis625dc0b2007-07-30 21:42:10 +020013858 SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013859 {}
13860};
13861
13862static struct alc_config_preset alc861vd_presets[] = {
13863 [ALC660VD_3ST] = {
13864 .mixers = { alc861vd_3st_mixer },
13865 .init_verbs = { alc861vd_volume_init_verbs,
13866 alc861vd_3stack_init_verbs },
13867 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
13868 .dac_nids = alc660vd_dac_nids,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013869 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
13870 .channel_mode = alc861vd_3stack_2ch_modes,
13871 .input_mux = &alc861vd_capture_source,
13872 },
Mike Crash6963f842007-06-25 12:12:51 +020013873 [ALC660VD_3ST_DIG] = {
13874 .mixers = { alc861vd_3st_mixer },
13875 .init_verbs = { alc861vd_volume_init_verbs,
13876 alc861vd_3stack_init_verbs },
13877 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
13878 .dac_nids = alc660vd_dac_nids,
13879 .dig_out_nid = ALC861VD_DIGOUT_NID,
Mike Crash6963f842007-06-25 12:12:51 +020013880 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
13881 .channel_mode = alc861vd_3stack_2ch_modes,
13882 .input_mux = &alc861vd_capture_source,
13883 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013884 [ALC861VD_3ST] = {
13885 .mixers = { alc861vd_3st_mixer },
13886 .init_verbs = { alc861vd_volume_init_verbs,
13887 alc861vd_3stack_init_verbs },
13888 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
13889 .dac_nids = alc861vd_dac_nids,
13890 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
13891 .channel_mode = alc861vd_3stack_2ch_modes,
13892 .input_mux = &alc861vd_capture_source,
13893 },
13894 [ALC861VD_3ST_DIG] = {
13895 .mixers = { alc861vd_3st_mixer },
13896 .init_verbs = { alc861vd_volume_init_verbs,
13897 alc861vd_3stack_init_verbs },
13898 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
13899 .dac_nids = alc861vd_dac_nids,
13900 .dig_out_nid = ALC861VD_DIGOUT_NID,
13901 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
13902 .channel_mode = alc861vd_3stack_2ch_modes,
13903 .input_mux = &alc861vd_capture_source,
13904 },
13905 [ALC861VD_6ST_DIG] = {
13906 .mixers = { alc861vd_6st_mixer, alc861vd_chmode_mixer },
13907 .init_verbs = { alc861vd_volume_init_verbs,
13908 alc861vd_6stack_init_verbs },
13909 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
13910 .dac_nids = alc861vd_dac_nids,
13911 .dig_out_nid = ALC861VD_DIGOUT_NID,
13912 .num_channel_mode = ARRAY_SIZE(alc861vd_6stack_modes),
13913 .channel_mode = alc861vd_6stack_modes,
13914 .input_mux = &alc861vd_capture_source,
13915 },
Kailang Yangbdd148a2007-05-08 15:19:08 +020013916 [ALC861VD_LENOVO] = {
13917 .mixers = { alc861vd_lenovo_mixer },
13918 .init_verbs = { alc861vd_volume_init_verbs,
13919 alc861vd_3stack_init_verbs,
13920 alc861vd_eapd_verbs,
13921 alc861vd_lenovo_unsol_verbs },
13922 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
13923 .dac_nids = alc660vd_dac_nids,
Kailang Yangbdd148a2007-05-08 15:19:08 +020013924 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
13925 .channel_mode = alc861vd_3stack_2ch_modes,
13926 .input_mux = &alc861vd_capture_source,
13927 .unsol_event = alc861vd_lenovo_unsol_event,
13928 .init_hook = alc861vd_lenovo_automute,
13929 },
Kailang Yang272a5272007-05-14 11:00:38 +020013930 [ALC861VD_DALLAS] = {
13931 .mixers = { alc861vd_dallas_mixer },
13932 .init_verbs = { alc861vd_dallas_verbs },
13933 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
13934 .dac_nids = alc861vd_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +020013935 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
13936 .channel_mode = alc861vd_3stack_2ch_modes,
13937 .input_mux = &alc861vd_dallas_capture_source,
13938 .unsol_event = alc861vd_dallas_unsol_event,
13939 .init_hook = alc861vd_dallas_automute,
Kailang Yangd1a991a2007-08-15 16:21:59 +020013940 },
13941 [ALC861VD_HP] = {
13942 .mixers = { alc861vd_hp_mixer },
13943 .init_verbs = { alc861vd_dallas_verbs, alc861vd_eapd_verbs },
13944 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
13945 .dac_nids = alc861vd_dac_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020013946 .dig_out_nid = ALC861VD_DIGOUT_NID,
Kailang Yangd1a991a2007-08-15 16:21:59 +020013947 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
13948 .channel_mode = alc861vd_3stack_2ch_modes,
13949 .input_mux = &alc861vd_hp_capture_source,
13950 .unsol_event = alc861vd_dallas_unsol_event,
13951 .init_hook = alc861vd_dallas_automute,
Kailang Yangea1fb292008-08-26 12:58:38 +020013952 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013953};
13954
13955/*
13956 * BIOS auto configuration
13957 */
13958static void alc861vd_auto_set_output_and_unmute(struct hda_codec *codec,
13959 hda_nid_t nid, int pin_type, int dac_idx)
13960{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013961 alc_set_pin_output(codec, nid, pin_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013962}
13963
13964static void alc861vd_auto_init_multi_out(struct hda_codec *codec)
13965{
13966 struct alc_spec *spec = codec->spec;
13967 int i;
13968
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013969 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013970 for (i = 0; i <= HDA_SIDE; i++) {
13971 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020013972 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013973 if (nid)
13974 alc861vd_auto_set_output_and_unmute(codec, nid,
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020013975 pin_type, i);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013976 }
13977}
13978
13979
13980static void alc861vd_auto_init_hp_out(struct hda_codec *codec)
13981{
13982 struct alc_spec *spec = codec->spec;
13983 hda_nid_t pin;
13984
13985 pin = spec->autocfg.hp_pins[0];
13986 if (pin) /* connect to front and use dac 0 */
13987 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013988 pin = spec->autocfg.speaker_pins[0];
13989 if (pin)
13990 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013991}
13992
13993#define alc861vd_is_input_pin(nid) alc880_is_input_pin(nid)
13994#define ALC861VD_PIN_CD_NID ALC880_PIN_CD_NID
13995
13996static void alc861vd_auto_init_analog_input(struct hda_codec *codec)
13997{
13998 struct alc_spec *spec = codec->spec;
13999 int i;
14000
14001 for (i = 0; i < AUTO_PIN_LAST; i++) {
14002 hda_nid_t nid = spec->autocfg.input_pins[i];
14003 if (alc861vd_is_input_pin(nid)) {
14004 snd_hda_codec_write(codec, nid, 0,
14005 AC_VERB_SET_PIN_WIDGET_CONTROL,
14006 i <= AUTO_PIN_FRONT_MIC ?
14007 PIN_VREF80 : PIN_IN);
14008 if (nid != ALC861VD_PIN_CD_NID)
14009 snd_hda_codec_write(codec, nid, 0,
14010 AC_VERB_SET_AMP_GAIN_MUTE,
14011 AMP_OUT_MUTE);
14012 }
14013 }
14014}
14015
Takashi Iwaif511b012008-08-15 16:46:42 +020014016#define alc861vd_auto_init_input_src alc882_auto_init_input_src
14017
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014018#define alc861vd_idx_to_mixer_vol(nid) ((nid) + 0x02)
14019#define alc861vd_idx_to_mixer_switch(nid) ((nid) + 0x0c)
14020
14021/* add playback controls from the parsed DAC table */
14022/* Based on ALC880 version. But ALC861VD has separate,
14023 * different NIDs for mute/unmute switch and volume control */
14024static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
14025 const struct auto_pin_cfg *cfg)
14026{
14027 char name[32];
14028 static const char *chname[4] = {"Front", "Surround", "CLFE", "Side"};
14029 hda_nid_t nid_v, nid_s;
14030 int i, err;
14031
14032 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014033 if (!spec->multiout.dac_nids[i])
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014034 continue;
14035 nid_v = alc861vd_idx_to_mixer_vol(
14036 alc880_dac_to_idx(
14037 spec->multiout.dac_nids[i]));
14038 nid_s = alc861vd_idx_to_mixer_switch(
14039 alc880_dac_to_idx(
14040 spec->multiout.dac_nids[i]));
14041
14042 if (i == 2) {
14043 /* Center/LFE */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014044 err = add_control(spec, ALC_CTL_WIDGET_VOL,
14045 "Center Playback Volume",
14046 HDA_COMPOSE_AMP_VAL(nid_v, 1, 0,
14047 HDA_OUTPUT));
14048 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014049 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014050 err = add_control(spec, ALC_CTL_WIDGET_VOL,
14051 "LFE Playback Volume",
14052 HDA_COMPOSE_AMP_VAL(nid_v, 2, 0,
14053 HDA_OUTPUT));
14054 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014055 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014056 err = add_control(spec, ALC_CTL_BIND_MUTE,
14057 "Center Playback Switch",
14058 HDA_COMPOSE_AMP_VAL(nid_s, 1, 2,
14059 HDA_INPUT));
14060 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014061 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014062 err = add_control(spec, ALC_CTL_BIND_MUTE,
14063 "LFE Playback Switch",
14064 HDA_COMPOSE_AMP_VAL(nid_s, 2, 2,
14065 HDA_INPUT));
14066 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014067 return err;
14068 } else {
14069 sprintf(name, "%s Playback Volume", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014070 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
14071 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0,
14072 HDA_OUTPUT));
14073 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014074 return err;
14075 sprintf(name, "%s Playback Switch", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014076 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
Kailang Yangbdd148a2007-05-08 15:19:08 +020014077 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014078 HDA_INPUT));
14079 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014080 return err;
14081 }
14082 }
14083 return 0;
14084}
14085
14086/* add playback controls for speaker and HP outputs */
14087/* Based on ALC880 version. But ALC861VD has separate,
14088 * different NIDs for mute/unmute switch and volume control */
14089static int alc861vd_auto_create_extra_out(struct alc_spec *spec,
14090 hda_nid_t pin, const char *pfx)
14091{
14092 hda_nid_t nid_v, nid_s;
14093 int err;
14094 char name[32];
14095
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014096 if (!pin)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014097 return 0;
14098
14099 if (alc880_is_fixed_pin(pin)) {
14100 nid_v = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
14101 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014102 if (!spec->multiout.hp_nid)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014103 spec->multiout.hp_nid = nid_v;
14104 else
14105 spec->multiout.extra_out_nid[0] = nid_v;
14106 /* control HP volume/switch on the output mixer amp */
14107 nid_v = alc861vd_idx_to_mixer_vol(
14108 alc880_fixed_pin_idx(pin));
14109 nid_s = alc861vd_idx_to_mixer_switch(
14110 alc880_fixed_pin_idx(pin));
14111
14112 sprintf(name, "%s Playback Volume", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014113 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
14114 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0, HDA_OUTPUT));
14115 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014116 return err;
14117 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014118 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
14119 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2, HDA_INPUT));
14120 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014121 return err;
14122 } else if (alc880_is_multi_pin(pin)) {
14123 /* set manual connection */
14124 /* we have only a switch on HP-out PIN */
14125 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014126 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
14127 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
14128 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014129 return err;
14130 }
14131 return 0;
14132}
14133
14134/* parse the BIOS configuration and set up the alc_spec
14135 * return 1 if successful, 0 if the proper config is not found,
14136 * or a negative error code
14137 * Based on ALC880 version - had to change it to override
14138 * alc880_auto_create_extra_out and alc880_auto_create_multi_out_ctls */
14139static int alc861vd_parse_auto_config(struct hda_codec *codec)
14140{
14141 struct alc_spec *spec = codec->spec;
14142 int err;
14143 static hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
14144
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014145 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
14146 alc861vd_ignore);
14147 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014148 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014149 if (!spec->autocfg.line_outs)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014150 return 0; /* can't find valid BIOS pin config */
14151
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014152 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
14153 if (err < 0)
14154 return err;
14155 err = alc861vd_auto_create_multi_out_ctls(spec, &spec->autocfg);
14156 if (err < 0)
14157 return err;
14158 err = alc861vd_auto_create_extra_out(spec,
14159 spec->autocfg.speaker_pins[0],
14160 "Speaker");
14161 if (err < 0)
14162 return err;
14163 err = alc861vd_auto_create_extra_out(spec,
14164 spec->autocfg.hp_pins[0],
14165 "Headphone");
14166 if (err < 0)
14167 return err;
14168 err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg);
14169 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014170 return err;
14171
14172 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
14173
14174 if (spec->autocfg.dig_out_pin)
14175 spec->multiout.dig_out_nid = ALC861VD_DIGOUT_NID;
14176
Takashi Iwai603c4012008-07-30 15:01:44 +020014177 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010014178 add_mixer(spec, spec->kctls.list);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014179
Takashi Iwaid88897e2008-10-31 15:01:37 +010014180 add_verb(spec, alc861vd_volume_init_verbs);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014181
14182 spec->num_mux_defs = 1;
14183 spec->input_mux = &spec->private_imux;
14184
Takashi Iwai776e1842007-08-29 15:07:11 +020014185 err = alc_auto_add_mic_boost(codec);
14186 if (err < 0)
14187 return err;
14188
Takashi Iwaie044c392008-10-27 16:56:24 +010014189 store_pin_configs(codec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014190 return 1;
14191}
14192
14193/* additional initialization for auto-configuration model */
14194static void alc861vd_auto_init(struct hda_codec *codec)
14195{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014196 struct alc_spec *spec = codec->spec;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014197 alc861vd_auto_init_multi_out(codec);
14198 alc861vd_auto_init_hp_out(codec);
14199 alc861vd_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020014200 alc861vd_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014201 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020014202 alc_inithook(codec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014203}
14204
14205static int patch_alc861vd(struct hda_codec *codec)
14206{
14207 struct alc_spec *spec;
14208 int err, board_config;
14209
14210 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
14211 if (spec == NULL)
14212 return -ENOMEM;
14213
14214 codec->spec = spec;
14215
14216 board_config = snd_hda_check_board_config(codec, ALC861VD_MODEL_LAST,
14217 alc861vd_models,
14218 alc861vd_cfg_tbl);
14219
14220 if (board_config < 0 || board_config >= ALC861VD_MODEL_LAST) {
14221 printk(KERN_INFO "hda_codec: Unknown model for ALC660VD/"
14222 "ALC861VD, trying auto-probe from BIOS...\n");
14223 board_config = ALC861VD_AUTO;
14224 }
14225
14226 if (board_config == ALC861VD_AUTO) {
14227 /* automatic parse from the BIOS config */
14228 err = alc861vd_parse_auto_config(codec);
14229 if (err < 0) {
14230 alc_free(codec);
14231 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014232 } else if (!err) {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014233 printk(KERN_INFO
14234 "hda_codec: Cannot set up configuration "
14235 "from BIOS. Using base mode...\n");
14236 board_config = ALC861VD_3ST;
14237 }
14238 }
14239
14240 if (board_config != ALC861VD_AUTO)
14241 setup_preset(spec, &alc861vd_presets[board_config]);
14242
Kailang Yang2f893282008-05-27 12:14:47 +020014243 if (codec->vendor_id == 0x10ec0660) {
14244 spec->stream_name_analog = "ALC660-VD Analog";
14245 spec->stream_name_digital = "ALC660-VD Digital";
Kailang Yangf9423e72008-05-27 12:32:25 +020014246 /* always turn on EAPD */
Takashi Iwaid88897e2008-10-31 15:01:37 +010014247 add_verb(spec, alc660vd_eapd_verbs);
Kailang Yang2f893282008-05-27 12:14:47 +020014248 } else {
14249 spec->stream_name_analog = "ALC861VD Analog";
14250 spec->stream_name_digital = "ALC861VD Digital";
14251 }
14252
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014253 spec->stream_analog_playback = &alc861vd_pcm_analog_playback;
14254 spec->stream_analog_capture = &alc861vd_pcm_analog_capture;
14255
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014256 spec->stream_digital_playback = &alc861vd_pcm_digital_playback;
14257 spec->stream_digital_capture = &alc861vd_pcm_digital_capture;
14258
14259 spec->adc_nids = alc861vd_adc_nids;
14260 spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids);
Takashi Iwaie1406342008-02-11 18:32:32 +010014261 spec->capsrc_nids = alc861vd_capsrc_nids;
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010014262 spec->is_mix_capture = 1;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014263
Takashi Iwaif9e336f2008-10-31 16:37:07 +010014264 set_capture_mixer(spec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014265
Takashi Iwai2134ea42008-01-10 16:53:55 +010014266 spec->vmaster_nid = 0x02;
14267
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014268 codec->patch_ops = alc_patch_ops;
14269
14270 if (board_config == ALC861VD_AUTO)
14271 spec->init_hook = alc861vd_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020014272#ifdef CONFIG_SND_HDA_POWER_SAVE
14273 if (!spec->loopback.amplist)
14274 spec->loopback.amplist = alc861vd_loopbacks;
14275#endif
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014276
14277 return 0;
14278}
14279
14280/*
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014281 * ALC662 support
14282 *
14283 * ALC662 is almost identical with ALC880 but has cleaner and more flexible
14284 * configuration. Each pin widget can choose any input DACs and a mixer.
14285 * Each ADC is connected from a mixer of all inputs. This makes possible
14286 * 6-channel independent captures.
14287 *
14288 * In addition, an independent DAC for the multi-playback (not used in this
14289 * driver yet).
14290 */
14291#define ALC662_DIGOUT_NID 0x06
14292#define ALC662_DIGIN_NID 0x0a
14293
14294static hda_nid_t alc662_dac_nids[4] = {
14295 /* front, rear, clfe, rear_surr */
14296 0x02, 0x03, 0x04
14297};
14298
14299static hda_nid_t alc662_adc_nids[1] = {
14300 /* ADC1-2 */
14301 0x09,
14302};
Takashi Iwaie1406342008-02-11 18:32:32 +010014303
Kailang Yang77a261b2008-02-19 11:38:05 +010014304static hda_nid_t alc662_capsrc_nids[1] = { 0x22 };
Takashi Iwaie1406342008-02-11 18:32:32 +010014305
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014306/* input MUX */
14307/* FIXME: should be a matrix-type input source selection */
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014308static struct hda_input_mux alc662_capture_source = {
14309 .num_items = 4,
14310 .items = {
14311 { "Mic", 0x0 },
14312 { "Front Mic", 0x1 },
14313 { "Line", 0x2 },
14314 { "CD", 0x4 },
14315 },
14316};
14317
14318static struct hda_input_mux alc662_lenovo_101e_capture_source = {
14319 .num_items = 2,
14320 .items = {
14321 { "Mic", 0x1 },
14322 { "Line", 0x2 },
14323 },
14324};
Kailang Yang291702f2007-10-16 14:28:03 +020014325
14326static struct hda_input_mux alc662_eeepc_capture_source = {
14327 .num_items = 2,
14328 .items = {
14329 { "i-Mic", 0x1 },
14330 { "e-Mic", 0x0 },
14331 },
14332};
14333
Kailang Yang6dda9f42008-05-27 12:05:31 +020014334static struct hda_input_mux alc663_capture_source = {
14335 .num_items = 3,
14336 .items = {
14337 { "Mic", 0x0 },
14338 { "Front Mic", 0x1 },
14339 { "Line", 0x2 },
14340 },
14341};
14342
14343static struct hda_input_mux alc663_m51va_capture_source = {
14344 .num_items = 2,
14345 .items = {
14346 { "Ext-Mic", 0x0 },
14347 { "D-Mic", 0x9 },
14348 },
14349};
14350
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014351/*
14352 * 2ch mode
14353 */
14354static struct hda_channel_mode alc662_3ST_2ch_modes[1] = {
14355 { 2, NULL }
14356};
14357
14358/*
14359 * 2ch mode
14360 */
14361static struct hda_verb alc662_3ST_ch2_init[] = {
14362 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
14363 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
14364 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
14365 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
14366 { } /* end */
14367};
14368
14369/*
14370 * 6ch mode
14371 */
14372static struct hda_verb alc662_3ST_ch6_init[] = {
14373 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14374 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
14375 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
14376 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14377 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
14378 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
14379 { } /* end */
14380};
14381
14382static struct hda_channel_mode alc662_3ST_6ch_modes[2] = {
14383 { 2, alc662_3ST_ch2_init },
14384 { 6, alc662_3ST_ch6_init },
14385};
14386
14387/*
14388 * 2ch mode
14389 */
14390static struct hda_verb alc662_sixstack_ch6_init[] = {
14391 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
14392 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
14393 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14394 { } /* end */
14395};
14396
14397/*
14398 * 6ch mode
14399 */
14400static struct hda_verb alc662_sixstack_ch8_init[] = {
14401 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14402 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14403 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14404 { } /* end */
14405};
14406
14407static struct hda_channel_mode alc662_5stack_modes[2] = {
14408 { 2, alc662_sixstack_ch6_init },
14409 { 6, alc662_sixstack_ch8_init },
14410};
14411
14412/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
14413 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
14414 */
14415
14416static struct snd_kcontrol_new alc662_base_mixer[] = {
14417 /* output mixer control */
14418 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010014419 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014420 HDA_CODEC_VOLUME("Surround Playback Volume", 0x3, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010014421 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014422 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
14423 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010014424 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
14425 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014426 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
14427
14428 /*Input mixer control */
14429 HDA_CODEC_VOLUME("CD Playback Volume", 0xb, 0x4, HDA_INPUT),
14430 HDA_CODEC_MUTE("CD Playback Switch", 0xb, 0x4, HDA_INPUT),
14431 HDA_CODEC_VOLUME("Line Playback Volume", 0xb, 0x02, HDA_INPUT),
14432 HDA_CODEC_MUTE("Line Playback Switch", 0xb, 0x02, HDA_INPUT),
14433 HDA_CODEC_VOLUME("Mic Playback Volume", 0xb, 0x0, HDA_INPUT),
14434 HDA_CODEC_MUTE("Mic Playback Switch", 0xb, 0x0, HDA_INPUT),
14435 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0xb, 0x01, HDA_INPUT),
14436 HDA_CODEC_MUTE("Front Mic Playback Switch", 0xb, 0x01, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014437 { } /* end */
14438};
14439
14440static struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = {
14441 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010014442 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014443 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
14444 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
14445 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
14446 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
14447 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
14448 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14449 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14450 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14451 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14452 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
14453 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014454 { } /* end */
14455};
14456
14457static struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = {
14458 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010014459 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014460 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010014461 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014462 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
14463 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010014464 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
14465 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014466 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
14467 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
14468 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
14469 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
14470 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
14471 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14472 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14473 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14474 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14475 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
14476 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014477 { } /* end */
14478};
14479
14480static struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = {
14481 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14482 HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010014483 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x03, 0x0, HDA_OUTPUT),
14484 HDA_BIND_MUTE("Speaker Playback Switch", 0x03, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014485 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
14486 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
14487 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
14488 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14489 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014490 { } /* end */
14491};
14492
Kailang Yang291702f2007-10-16 14:28:03 +020014493static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = {
Takashi Iwai86cd9292008-01-28 18:09:56 +010014494 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang291702f2007-10-16 14:28:03 +020014495
Herton Ronaldo Krzesinskib4818492008-02-23 11:34:12 +010014496 HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14497 HDA_CODEC_MUTE("Line-Out Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yang291702f2007-10-16 14:28:03 +020014498
14499 HDA_CODEC_VOLUME("e-Mic Boost", 0x18, 0, HDA_INPUT),
14500 HDA_CODEC_VOLUME("e-Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14501 HDA_CODEC_MUTE("e-Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14502
14503 HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT),
14504 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14505 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14506 { } /* end */
14507};
14508
Kailang Yang8c427222008-01-10 13:03:59 +010014509static struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = {
Takashi Iwai31bffaa2008-02-27 16:10:44 +010014510 HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14511 HDA_CODEC_MUTE("Line-Out Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010014512 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
14513 HDA_BIND_MUTE("Surround Playback Switch", 0x03, 2, HDA_INPUT),
14514 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
14515 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
14516 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x04, 1, 2, HDA_INPUT),
14517 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x04, 2, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010014518 HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010014519 HDA_BIND_MUTE("MuteCtrl Playback Switch", 0x0c, 2, HDA_INPUT),
14520 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
14521 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
14522 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14523 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14524 { } /* end */
14525};
14526
Kailang Yangf1d4e282008-08-26 14:03:29 +020014527static struct hda_bind_ctls alc663_asus_bind_master_vol = {
14528 .ops = &snd_hda_bind_vol,
14529 .values = {
14530 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
14531 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
14532 0
14533 },
14534};
14535
14536static struct hda_bind_ctls alc663_asus_one_bind_switch = {
14537 .ops = &snd_hda_bind_sw,
14538 .values = {
14539 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
14540 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
14541 0
14542 },
14543};
14544
Kailang Yang6dda9f42008-05-27 12:05:31 +020014545static struct snd_kcontrol_new alc663_m51va_mixer[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020014546 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
14547 HDA_BIND_SW("Master Playback Switch", &alc663_asus_one_bind_switch),
14548 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14549 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14550 { } /* end */
14551};
14552
14553static struct hda_bind_ctls alc663_asus_tree_bind_switch = {
14554 .ops = &snd_hda_bind_sw,
14555 .values = {
14556 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
14557 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
14558 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
14559 0
14560 },
14561};
14562
14563static struct snd_kcontrol_new alc663_two_hp_m1_mixer[] = {
14564 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
14565 HDA_BIND_SW("Master Playback Switch", &alc663_asus_tree_bind_switch),
14566 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14567 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14568 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14569 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14570
14571 { } /* end */
14572};
14573
14574static struct hda_bind_ctls alc663_asus_four_bind_switch = {
14575 .ops = &snd_hda_bind_sw,
14576 .values = {
14577 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
14578 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
14579 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
14580 0
14581 },
14582};
14583
14584static struct snd_kcontrol_new alc663_two_hp_m2_mixer[] = {
14585 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
14586 HDA_BIND_SW("Master Playback Switch", &alc663_asus_four_bind_switch),
14587 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14588 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14589 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14590 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14591 { } /* end */
14592};
14593
14594static struct snd_kcontrol_new alc662_1bjd_mixer[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020014595 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14596 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020014597 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
14598 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14599 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14600 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14601 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14602 { } /* end */
14603};
14604
14605static struct hda_bind_ctls alc663_asus_two_bind_master_vol = {
14606 .ops = &snd_hda_bind_vol,
14607 .values = {
14608 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
14609 HDA_COMPOSE_AMP_VAL(0x04, 3, 0, HDA_OUTPUT),
14610 0
14611 },
14612};
14613
14614static struct hda_bind_ctls alc663_asus_two_bind_switch = {
14615 .ops = &snd_hda_bind_sw,
14616 .values = {
14617 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
14618 HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT),
14619 0
14620 },
14621};
14622
14623static struct snd_kcontrol_new alc663_asus_21jd_clfe_mixer[] = {
14624 HDA_BIND_VOL("Master Playback Volume",
14625 &alc663_asus_two_bind_master_vol),
14626 HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
14627 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020014628 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
14629 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14630 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020014631 { } /* end */
14632};
14633
14634static struct snd_kcontrol_new alc663_asus_15jd_clfe_mixer[] = {
14635 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
14636 HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
14637 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
14638 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
14639 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14640 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020014641 { } /* end */
14642};
14643
14644static struct snd_kcontrol_new alc663_g71v_mixer[] = {
14645 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14646 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
14647 HDA_CODEC_VOLUME("Front Playback Volume", 0x03, 0x0, HDA_OUTPUT),
14648 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
14649 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
14650
14651 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14652 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14653 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14654 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14655 { } /* end */
14656};
14657
14658static struct snd_kcontrol_new alc663_g50v_mixer[] = {
14659 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14660 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
14661 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
14662
14663 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14664 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14665 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14666 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14667 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
14668 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
14669 { } /* end */
14670};
14671
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014672static struct snd_kcontrol_new alc662_chmode_mixer[] = {
14673 {
14674 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
14675 .name = "Channel Mode",
14676 .info = alc_ch_mode_info,
14677 .get = alc_ch_mode_get,
14678 .put = alc_ch_mode_put,
14679 },
14680 { } /* end */
14681};
14682
14683static struct hda_verb alc662_init_verbs[] = {
14684 /* ADC: mute amp left and right */
14685 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14686 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
14687 /* Front mixer: unmute input/output amp left and right (volume = 0) */
14688
Takashi Iwaicb53c622007-08-10 17:21:45 +020014689 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14690 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
14691 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
14692 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
14693 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014694
Kailang Yangb60dd392007-09-20 12:50:29 +020014695 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14696 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14697 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14698 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14699 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14700 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014701
14702 /* Front Pin: output 0 (0x0c) */
14703 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14704 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14705
14706 /* Rear Pin: output 1 (0x0d) */
14707 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14708 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14709
14710 /* CLFE Pin: output 2 (0x0e) */
14711 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14712 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14713
14714 /* Mic (rear) pin: input vref at 80% */
14715 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14716 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14717 /* Front Mic pin: input vref at 80% */
14718 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14719 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14720 /* Line In pin: input */
14721 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14722 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14723 /* Line-2 In: Headphone output (output 0 - 0x0c) */
14724 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14725 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14726 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
14727 /* CD pin widget for input */
14728 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14729
14730 /* FIXME: use matrix-type input source selection */
14731 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
14732 /* Input mixer */
14733 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14734 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14735 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
14736 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Kailang Yang291702f2007-10-16 14:28:03 +020014737
14738 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14739 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14740 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
14741 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Kailang Yang6dda9f42008-05-27 12:05:31 +020014742
14743 /* always trun on EAPD */
14744 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
14745 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
14746
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014747 { }
14748};
14749
14750static struct hda_verb alc662_sue_init_verbs[] = {
14751 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
14752 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
Kailang Yang291702f2007-10-16 14:28:03 +020014753 {}
14754};
14755
14756static struct hda_verb alc662_eeepc_sue_init_verbs[] = {
14757 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14758 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14759 {}
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014760};
14761
Kailang Yang8c427222008-01-10 13:03:59 +010014762/* Set Unsolicited Event*/
14763static struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = {
14764 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14765 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14766 {}
14767};
14768
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014769/*
14770 * generic initialization of ADC, input mixers and output mixers
14771 */
14772static struct hda_verb alc662_auto_init_verbs[] = {
14773 /*
14774 * Unmute ADC and set the default input to mic-in
14775 */
14776 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
14777 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14778
14779 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
14780 * mixer widget
14781 * Note: PASD motherboards uses the Line In 2 as the input for front
14782 * panel mic (mic 2)
14783 */
14784 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020014785 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14786 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
14787 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
14788 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
14789 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014790
14791 /*
14792 * Set up output mixers (0x0c - 0x0f)
14793 */
14794 /* set vol=0 to output mixers */
14795 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14796 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14797 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14798
14799 /* set up input amps for analog loopback */
14800 /* Amp Indices: DAC = 0, mixer = 1 */
Kailang Yangb60dd392007-09-20 12:50:29 +020014801 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14802 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14803 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14804 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14805 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14806 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014807
14808
14809 /* FIXME: use matrix-type input source selection */
14810 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
14811 /* Input mixer */
14812 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangd1a991a2007-08-15 16:21:59 +020014813 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014814 { }
14815};
14816
Takashi Iwai24fb9172008-09-02 14:48:20 +020014817/* additional verbs for ALC663 */
14818static struct hda_verb alc663_auto_init_verbs[] = {
14819 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14820 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14821 { }
14822};
14823
Kailang Yang6dda9f42008-05-27 12:05:31 +020014824static struct hda_verb alc663_m51va_init_verbs[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020014825 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14826 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yang6dda9f42008-05-27 12:05:31 +020014827 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14828 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangf1d4e282008-08-26 14:03:29 +020014829 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
14830 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14831 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
Kailang Yang6dda9f42008-05-27 12:05:31 +020014832 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14833 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14834 {}
14835};
14836
Kailang Yangf1d4e282008-08-26 14:03:29 +020014837static struct hda_verb alc663_21jd_amic_init_verbs[] = {
14838 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14839 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14840 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
14841 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14842 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14843 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14844 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14845 {}
14846};
14847
14848static struct hda_verb alc662_1bjd_amic_init_verbs[] = {
14849 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14850 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14851 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14852 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
14853 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14854 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14855 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14856 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14857 {}
14858};
14859
14860static struct hda_verb alc663_15jd_amic_init_verbs[] = {
14861 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14862 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14863 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
14864 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14865 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14866 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14867 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14868 {}
14869};
14870
14871static struct hda_verb alc663_two_hp_amic_m1_init_verbs[] = {
14872 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14873 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14874 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14875 {0x21, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */
14876 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14877 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14878 {0x15, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */
14879 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14880 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14881 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14882 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14883 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14884 {}
14885};
14886
14887static struct hda_verb alc663_two_hp_amic_m2_init_verbs[] = {
14888 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14889 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14890 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14891 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
14892 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14893 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14894 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
14895 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14896 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14897 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14898 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14899 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14900 {}
14901};
14902
Kailang Yang6dda9f42008-05-27 12:05:31 +020014903static struct hda_verb alc663_g71v_init_verbs[] = {
14904 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14905 /* {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
14906 /* {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, */ /* Headphone */
14907
14908 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14909 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14910 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
14911
14912 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
14913 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_MIC_EVENT},
14914 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
14915 {}
14916};
14917
14918static struct hda_verb alc663_g50v_init_verbs[] = {
14919 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14920 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14921 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
14922
14923 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14924 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14925 {}
14926};
14927
Kailang Yangf1d4e282008-08-26 14:03:29 +020014928static struct hda_verb alc662_ecs_init_verbs[] = {
14929 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
14930 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14931 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14932 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14933 {}
14934};
14935
Kailang Yangf1d4e282008-08-26 14:03:29 +020014936static struct snd_kcontrol_new alc662_auto_capture_mixer[] = {
14937 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
14938 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
14939 { } /* end */
14940};
14941
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014942static void alc662_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
14943{
14944 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014945 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014946
14947 present = snd_hda_codec_read(codec, 0x14, 0,
14948 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020014949 bits = present ? HDA_AMP_MUTE : 0;
14950 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
14951 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014952}
14953
14954static void alc662_lenovo_101e_all_automute(struct hda_codec *codec)
14955{
14956 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014957 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014958
14959 present = snd_hda_codec_read(codec, 0x1b, 0,
14960 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020014961 bits = present ? HDA_AMP_MUTE : 0;
14962 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
14963 HDA_AMP_MUTE, bits);
14964 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
14965 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014966}
14967
14968static void alc662_lenovo_101e_unsol_event(struct hda_codec *codec,
14969 unsigned int res)
14970{
14971 if ((res >> 26) == ALC880_HP_EVENT)
14972 alc662_lenovo_101e_all_automute(codec);
14973 if ((res >> 26) == ALC880_FRONT_EVENT)
14974 alc662_lenovo_101e_ispeaker_automute(codec);
14975}
14976
Kailang Yang291702f2007-10-16 14:28:03 +020014977static void alc662_eeepc_mic_automute(struct hda_codec *codec)
14978{
14979 unsigned int present;
14980
14981 present = snd_hda_codec_read(codec, 0x18, 0,
14982 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
14983 snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
14984 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
14985 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
14986 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
14987 snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
14988 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
14989 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
14990 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
14991}
14992
14993/* unsolicited event for HP jack sensing */
14994static void alc662_eeepc_unsol_event(struct hda_codec *codec,
14995 unsigned int res)
14996{
14997 if ((res >> 26) == ALC880_HP_EVENT)
14998 alc262_hippo1_automute( codec );
14999
15000 if ((res >> 26) == ALC880_MIC_EVENT)
15001 alc662_eeepc_mic_automute(codec);
15002}
15003
15004static void alc662_eeepc_inithook(struct hda_codec *codec)
15005{
15006 alc262_hippo1_automute( codec );
15007 alc662_eeepc_mic_automute(codec);
15008}
15009
Kailang Yang8c427222008-01-10 13:03:59 +010015010static void alc662_eeepc_ep20_automute(struct hda_codec *codec)
15011{
15012 unsigned int mute;
15013 unsigned int present;
15014
15015 snd_hda_codec_read(codec, 0x14, 0, AC_VERB_SET_PIN_SENSE, 0);
15016 present = snd_hda_codec_read(codec, 0x14, 0,
15017 AC_VERB_GET_PIN_SENSE, 0);
15018 present = (present & 0x80000000) != 0;
15019 if (present) {
15020 /* mute internal speaker */
15021 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +020015022 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yang8c427222008-01-10 13:03:59 +010015023 } else {
15024 /* unmute internal speaker if necessary */
15025 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
15026 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +020015027 HDA_AMP_MUTE, mute);
Kailang Yang8c427222008-01-10 13:03:59 +010015028 }
15029}
15030
15031/* unsolicited event for HP jack sensing */
15032static void alc662_eeepc_ep20_unsol_event(struct hda_codec *codec,
15033 unsigned int res)
15034{
15035 if ((res >> 26) == ALC880_HP_EVENT)
15036 alc662_eeepc_ep20_automute(codec);
15037}
15038
15039static void alc662_eeepc_ep20_inithook(struct hda_codec *codec)
15040{
15041 alc662_eeepc_ep20_automute(codec);
15042}
15043
Kailang Yang6dda9f42008-05-27 12:05:31 +020015044static void alc663_m51va_speaker_automute(struct hda_codec *codec)
15045{
15046 unsigned int present;
15047 unsigned char bits;
15048
15049 present = snd_hda_codec_read(codec, 0x21, 0,
Kailang Yangf1d4e282008-08-26 14:03:29 +020015050 AC_VERB_GET_PIN_SENSE, 0)
15051 & AC_PINSENSE_PRESENCE;
Kailang Yang6dda9f42008-05-27 12:05:31 +020015052 bits = present ? HDA_AMP_MUTE : 0;
Kailang Yangf1d4e282008-08-26 14:03:29 +020015053 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
15054 AMP_IN_MUTE(0), bits);
15055 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
15056 AMP_IN_MUTE(0), bits);
15057}
15058
15059static void alc663_21jd_two_speaker_automute(struct hda_codec *codec)
15060{
15061 unsigned int present;
15062 unsigned char bits;
15063
15064 present = snd_hda_codec_read(codec, 0x21, 0,
15065 AC_VERB_GET_PIN_SENSE, 0)
15066 & AC_PINSENSE_PRESENCE;
15067 bits = present ? HDA_AMP_MUTE : 0;
15068 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
15069 AMP_IN_MUTE(0), bits);
15070 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
15071 AMP_IN_MUTE(0), bits);
15072 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0,
15073 AMP_IN_MUTE(0), bits);
15074 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1,
15075 AMP_IN_MUTE(0), bits);
15076}
15077
15078static void alc663_15jd_two_speaker_automute(struct hda_codec *codec)
15079{
15080 unsigned int present;
15081 unsigned char bits;
15082
15083 present = snd_hda_codec_read(codec, 0x15, 0,
15084 AC_VERB_GET_PIN_SENSE, 0)
15085 & AC_PINSENSE_PRESENCE;
15086 bits = present ? HDA_AMP_MUTE : 0;
15087 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
15088 AMP_IN_MUTE(0), bits);
15089 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
15090 AMP_IN_MUTE(0), bits);
15091 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0,
15092 AMP_IN_MUTE(0), bits);
15093 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1,
15094 AMP_IN_MUTE(0), bits);
15095}
15096
15097static void alc662_f5z_speaker_automute(struct hda_codec *codec)
15098{
15099 unsigned int present;
15100 unsigned char bits;
15101
15102 present = snd_hda_codec_read(codec, 0x1b, 0,
15103 AC_VERB_GET_PIN_SENSE, 0)
15104 & AC_PINSENSE_PRESENCE;
15105 bits = present ? 0 : PIN_OUT;
15106 snd_hda_codec_write(codec, 0x14, 0,
15107 AC_VERB_SET_PIN_WIDGET_CONTROL, bits);
15108}
15109
15110static void alc663_two_hp_m1_speaker_automute(struct hda_codec *codec)
15111{
15112 unsigned int present1, present2;
15113
15114 present1 = snd_hda_codec_read(codec, 0x21, 0,
15115 AC_VERB_GET_PIN_SENSE, 0)
15116 & AC_PINSENSE_PRESENCE;
15117 present2 = snd_hda_codec_read(codec, 0x15, 0,
15118 AC_VERB_GET_PIN_SENSE, 0)
15119 & AC_PINSENSE_PRESENCE;
15120
15121 if (present1 || present2) {
15122 snd_hda_codec_write_cache(codec, 0x14, 0,
15123 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
15124 } else {
15125 snd_hda_codec_write_cache(codec, 0x14, 0,
15126 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
15127 }
15128}
15129
15130static void alc663_two_hp_m2_speaker_automute(struct hda_codec *codec)
15131{
15132 unsigned int present1, present2;
15133
15134 present1 = snd_hda_codec_read(codec, 0x1b, 0,
15135 AC_VERB_GET_PIN_SENSE, 0)
15136 & AC_PINSENSE_PRESENCE;
15137 present2 = snd_hda_codec_read(codec, 0x15, 0,
15138 AC_VERB_GET_PIN_SENSE, 0)
15139 & AC_PINSENSE_PRESENCE;
15140
15141 if (present1 || present2) {
15142 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
15143 AMP_IN_MUTE(0), AMP_IN_MUTE(0));
15144 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
15145 AMP_IN_MUTE(0), AMP_IN_MUTE(0));
15146 } else {
15147 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
15148 AMP_IN_MUTE(0), 0);
15149 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
15150 AMP_IN_MUTE(0), 0);
15151 }
Kailang Yang6dda9f42008-05-27 12:05:31 +020015152}
15153
15154static void alc663_m51va_mic_automute(struct hda_codec *codec)
15155{
15156 unsigned int present;
15157
15158 present = snd_hda_codec_read(codec, 0x18, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +020015159 AC_VERB_GET_PIN_SENSE, 0)
15160 & AC_PINSENSE_PRESENCE;
Kailang Yang6dda9f42008-05-27 12:05:31 +020015161 snd_hda_codec_write_cache(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangea1fb292008-08-26 12:58:38 +020015162 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
Kailang Yang6dda9f42008-05-27 12:05:31 +020015163 snd_hda_codec_write_cache(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangea1fb292008-08-26 12:58:38 +020015164 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
Kailang Yang6dda9f42008-05-27 12:05:31 +020015165 snd_hda_codec_write_cache(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangea1fb292008-08-26 12:58:38 +020015166 0x7000 | (0x09 << 8) | (present ? 0x80 : 0));
Kailang Yang6dda9f42008-05-27 12:05:31 +020015167 snd_hda_codec_write_cache(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangea1fb292008-08-26 12:58:38 +020015168 0x7000 | (0x09 << 8) | (present ? 0x80 : 0));
Kailang Yang6dda9f42008-05-27 12:05:31 +020015169}
15170
15171static void alc663_m51va_unsol_event(struct hda_codec *codec,
15172 unsigned int res)
15173{
15174 switch (res >> 26) {
15175 case ALC880_HP_EVENT:
15176 alc663_m51va_speaker_automute(codec);
15177 break;
15178 case ALC880_MIC_EVENT:
15179 alc663_m51va_mic_automute(codec);
15180 break;
15181 }
15182}
15183
15184static void alc663_m51va_inithook(struct hda_codec *codec)
15185{
15186 alc663_m51va_speaker_automute(codec);
15187 alc663_m51va_mic_automute(codec);
15188}
15189
Kailang Yangf1d4e282008-08-26 14:03:29 +020015190/* ***************** Mode1 ******************************/
15191static void alc663_mode1_unsol_event(struct hda_codec *codec,
15192 unsigned int res)
15193{
15194 switch (res >> 26) {
15195 case ALC880_HP_EVENT:
15196 alc663_m51va_speaker_automute(codec);
15197 break;
15198 case ALC880_MIC_EVENT:
15199 alc662_eeepc_mic_automute(codec);
15200 break;
15201 }
15202}
15203
15204static void alc663_mode1_inithook(struct hda_codec *codec)
15205{
15206 alc663_m51va_speaker_automute(codec);
15207 alc662_eeepc_mic_automute(codec);
15208}
15209/* ***************** Mode2 ******************************/
15210static void alc662_mode2_unsol_event(struct hda_codec *codec,
15211 unsigned int res)
15212{
15213 switch (res >> 26) {
15214 case ALC880_HP_EVENT:
15215 alc662_f5z_speaker_automute(codec);
15216 break;
15217 case ALC880_MIC_EVENT:
15218 alc662_eeepc_mic_automute(codec);
15219 break;
15220 }
15221}
15222
15223static void alc662_mode2_inithook(struct hda_codec *codec)
15224{
15225 alc662_f5z_speaker_automute(codec);
15226 alc662_eeepc_mic_automute(codec);
15227}
15228/* ***************** Mode3 ******************************/
15229static void alc663_mode3_unsol_event(struct hda_codec *codec,
15230 unsigned int res)
15231{
15232 switch (res >> 26) {
15233 case ALC880_HP_EVENT:
15234 alc663_two_hp_m1_speaker_automute(codec);
15235 break;
15236 case ALC880_MIC_EVENT:
15237 alc662_eeepc_mic_automute(codec);
15238 break;
15239 }
15240}
15241
15242static void alc663_mode3_inithook(struct hda_codec *codec)
15243{
15244 alc663_two_hp_m1_speaker_automute(codec);
15245 alc662_eeepc_mic_automute(codec);
15246}
15247/* ***************** Mode4 ******************************/
15248static void alc663_mode4_unsol_event(struct hda_codec *codec,
15249 unsigned int res)
15250{
15251 switch (res >> 26) {
15252 case ALC880_HP_EVENT:
15253 alc663_21jd_two_speaker_automute(codec);
15254 break;
15255 case ALC880_MIC_EVENT:
15256 alc662_eeepc_mic_automute(codec);
15257 break;
15258 }
15259}
15260
15261static void alc663_mode4_inithook(struct hda_codec *codec)
15262{
15263 alc663_21jd_two_speaker_automute(codec);
15264 alc662_eeepc_mic_automute(codec);
15265}
15266/* ***************** Mode5 ******************************/
15267static void alc663_mode5_unsol_event(struct hda_codec *codec,
15268 unsigned int res)
15269{
15270 switch (res >> 26) {
15271 case ALC880_HP_EVENT:
15272 alc663_15jd_two_speaker_automute(codec);
15273 break;
15274 case ALC880_MIC_EVENT:
15275 alc662_eeepc_mic_automute(codec);
15276 break;
15277 }
15278}
15279
15280static void alc663_mode5_inithook(struct hda_codec *codec)
15281{
15282 alc663_15jd_two_speaker_automute(codec);
15283 alc662_eeepc_mic_automute(codec);
15284}
15285/* ***************** Mode6 ******************************/
15286static void alc663_mode6_unsol_event(struct hda_codec *codec,
15287 unsigned int res)
15288{
15289 switch (res >> 26) {
15290 case ALC880_HP_EVENT:
15291 alc663_two_hp_m2_speaker_automute(codec);
15292 break;
15293 case ALC880_MIC_EVENT:
15294 alc662_eeepc_mic_automute(codec);
15295 break;
15296 }
15297}
15298
15299static void alc663_mode6_inithook(struct hda_codec *codec)
15300{
15301 alc663_two_hp_m2_speaker_automute(codec);
15302 alc662_eeepc_mic_automute(codec);
15303}
15304
Kailang Yang6dda9f42008-05-27 12:05:31 +020015305static void alc663_g71v_hp_automute(struct hda_codec *codec)
15306{
15307 unsigned int present;
15308 unsigned char bits;
15309
15310 present = snd_hda_codec_read(codec, 0x21, 0,
15311 AC_VERB_GET_PIN_SENSE, 0)
15312 & AC_PINSENSE_PRESENCE;
15313 bits = present ? HDA_AMP_MUTE : 0;
15314 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
15315 HDA_AMP_MUTE, bits);
15316 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
15317 HDA_AMP_MUTE, bits);
15318}
15319
15320static void alc663_g71v_front_automute(struct hda_codec *codec)
15321{
15322 unsigned int present;
15323 unsigned char bits;
15324
15325 present = snd_hda_codec_read(codec, 0x15, 0,
15326 AC_VERB_GET_PIN_SENSE, 0)
15327 & AC_PINSENSE_PRESENCE;
15328 bits = present ? HDA_AMP_MUTE : 0;
15329 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
15330 HDA_AMP_MUTE, bits);
15331}
15332
15333static void alc663_g71v_unsol_event(struct hda_codec *codec,
15334 unsigned int res)
15335{
15336 switch (res >> 26) {
15337 case ALC880_HP_EVENT:
15338 alc663_g71v_hp_automute(codec);
15339 break;
15340 case ALC880_FRONT_EVENT:
15341 alc663_g71v_front_automute(codec);
15342 break;
15343 case ALC880_MIC_EVENT:
15344 alc662_eeepc_mic_automute(codec);
15345 break;
15346 }
15347}
15348
15349static void alc663_g71v_inithook(struct hda_codec *codec)
15350{
15351 alc663_g71v_front_automute(codec);
15352 alc663_g71v_hp_automute(codec);
15353 alc662_eeepc_mic_automute(codec);
15354}
15355
15356static void alc663_g50v_unsol_event(struct hda_codec *codec,
15357 unsigned int res)
15358{
15359 switch (res >> 26) {
15360 case ALC880_HP_EVENT:
15361 alc663_m51va_speaker_automute(codec);
15362 break;
15363 case ALC880_MIC_EVENT:
15364 alc662_eeepc_mic_automute(codec);
15365 break;
15366 }
15367}
15368
15369static void alc663_g50v_inithook(struct hda_codec *codec)
15370{
15371 alc663_m51va_speaker_automute(codec);
15372 alc662_eeepc_mic_automute(codec);
15373}
15374
Kailang Yangf1d4e282008-08-26 14:03:29 +020015375/* bind hp and internal speaker mute (with plug check) */
15376static int alc662_ecs_master_sw_put(struct snd_kcontrol *kcontrol,
15377 struct snd_ctl_elem_value *ucontrol)
15378{
15379 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
15380 long *valp = ucontrol->value.integer.value;
15381 int change;
15382
15383 change = snd_hda_codec_amp_update(codec, 0x1b, 0, HDA_OUTPUT, 0,
15384 HDA_AMP_MUTE,
15385 valp[0] ? 0 : HDA_AMP_MUTE);
15386 change |= snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0,
15387 HDA_AMP_MUTE,
15388 valp[1] ? 0 : HDA_AMP_MUTE);
15389 if (change)
15390 alc262_hippo1_automute(codec);
15391 return change;
15392}
15393
15394static struct snd_kcontrol_new alc662_ecs_mixer[] = {
15395 HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15396 {
15397 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
15398 .name = "Master Playback Switch",
15399 .info = snd_hda_mixer_amp_switch_info,
15400 .get = snd_hda_mixer_amp_switch_get,
15401 .put = alc662_ecs_master_sw_put,
15402 .private_value = HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
15403 },
15404
15405 HDA_CODEC_VOLUME("e-Mic/LineIn Boost", 0x18, 0, HDA_INPUT),
15406 HDA_CODEC_VOLUME("e-Mic/LineIn Playback Volume", 0x0b, 0x0, HDA_INPUT),
15407 HDA_CODEC_MUTE("e-Mic/LineIn Playback Switch", 0x0b, 0x0, HDA_INPUT),
15408
15409 HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT),
15410 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15411 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
15412 { } /* end */
15413};
15414
Takashi Iwaicb53c622007-08-10 17:21:45 +020015415#ifdef CONFIG_SND_HDA_POWER_SAVE
15416#define alc662_loopbacks alc880_loopbacks
15417#endif
15418
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015419
15420/* pcm configuration: identiacal with ALC880 */
15421#define alc662_pcm_analog_playback alc880_pcm_analog_playback
15422#define alc662_pcm_analog_capture alc880_pcm_analog_capture
15423#define alc662_pcm_digital_playback alc880_pcm_digital_playback
15424#define alc662_pcm_digital_capture alc880_pcm_digital_capture
15425
15426/*
15427 * configuration and preset
15428 */
15429static const char *alc662_models[ALC662_MODEL_LAST] = {
15430 [ALC662_3ST_2ch_DIG] = "3stack-dig",
15431 [ALC662_3ST_6ch_DIG] = "3stack-6ch-dig",
15432 [ALC662_3ST_6ch] = "3stack-6ch",
15433 [ALC662_5ST_DIG] = "6stack-dig",
15434 [ALC662_LENOVO_101E] = "lenovo-101e",
Takashi Iwaib995d762007-10-17 10:41:06 +020015435 [ALC662_ASUS_EEEPC_P701] = "eeepc-p701",
Kailang Yang8c427222008-01-10 13:03:59 +010015436 [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20",
Kailang Yangf1d4e282008-08-26 14:03:29 +020015437 [ALC662_ECS] = "ecs",
Kailang Yang6dda9f42008-05-27 12:05:31 +020015438 [ALC663_ASUS_M51VA] = "m51va",
15439 [ALC663_ASUS_G71V] = "g71v",
15440 [ALC663_ASUS_H13] = "h13",
15441 [ALC663_ASUS_G50V] = "g50v",
Kailang Yangf1d4e282008-08-26 14:03:29 +020015442 [ALC663_ASUS_MODE1] = "asus-mode1",
15443 [ALC662_ASUS_MODE2] = "asus-mode2",
15444 [ALC663_ASUS_MODE3] = "asus-mode3",
15445 [ALC663_ASUS_MODE4] = "asus-mode4",
15446 [ALC663_ASUS_MODE5] = "asus-mode5",
15447 [ALC663_ASUS_MODE6] = "asus-mode6",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015448 [ALC662_AUTO] = "auto",
15449};
15450
15451static struct snd_pci_quirk alc662_cfg_tbl[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020015452 SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M51VA", ALC663_ASUS_M51VA),
Kailang Yang80ffe862008-10-15 11:23:27 +020015453 SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS G50V", ALC663_ASUS_G50V),
Herton Ronaldo Krzesinski3da23ca2008-03-14 12:52:59 +010015454 SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG),
Kailang Yang291702f2007-10-16 14:28:03 +020015455 SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701),
Kailang Yang8c427222008-01-10 13:03:59 +010015456 SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20),
Kailang Yangf1d4e282008-08-26 14:03:29 +020015457 SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC663_ASUS_MODE1),
15458 SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M50Vr", ALC663_ASUS_MODE1),
15459 SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC663_ASUS_MODE1),
15460 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC663_ASUS_MODE1),
15461 SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC663_ASUS_MODE1),
15462 SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS NB", ALC663_ASUS_MODE1),
15463 SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC663_ASUS_MODE1),
15464 SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC663_ASUS_MODE1),
15465 SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC663_ASUS_MODE1),
Kailang Yang80ffe862008-10-15 11:23:27 +020015466 SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC663_ASUS_MODE1),
Kailang Yangf1d4e282008-08-26 14:03:29 +020015467 SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_ASUS_MODE2),
15468 SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_ASUS_MODE2),
15469 SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_ASUS_MODE2),
15470 SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_ASUS_MODE2),
15471 SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_ASUS_MODE2),
15472 SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_ASUS_MODE2),
15473 SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_ASUS_MODE2),
15474 SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_ASUS_MODE2),
15475 SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_ASUS_MODE2),
15476 SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_ASUS_MODE2),
15477 SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_ASUS_MODE2),
15478 SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_ASUS_MODE2),
15479 SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC663_ASUS_MODE3),
15480 SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC663_ASUS_MODE3),
15481 SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC663_ASUS_MODE3),
15482 SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC663_ASUS_MODE3),
15483 SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC663_ASUS_MODE3),
15484 SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC663_ASUS_MODE4),
15485 SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC663_ASUS_MODE5),
15486 SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC663_ASUS_MODE6),
15487 SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC663_ASUS_MODE6),
15488 SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC663_ASUS_MODE6),
Herton Ronaldo Krzesinski95fe5f22008-09-26 23:48:45 -030015489 SND_PCI_QUIRK(0x105b, 0x0d47, "Foxconn 45CMX/45GMX/45CMX-K",
15490 ALC662_3ST_6ch_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010015491 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E),
Kailang Yangf1d4e282008-08-26 14:03:29 +020015492 SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_ECS),
15493 SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS),
Herton Ronaldo Krzesinskicb559742008-09-26 23:47:45 -030015494 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L",
15495 ALC662_3ST_6ch_DIG),
Vedran Miletic19c009a2008-09-29 20:29:25 +020015496 SND_PCI_QUIRK(0x1565, 0x820f, "Biostar TA780G M2+", ALC662_3ST_6ch_DIG),
Takashi Iwai238713d2008-10-05 10:57:39 +020015497 SND_PCI_QUIRK(0x1849, 0x3662, "ASROCK K10N78FullHD-hSLI R3.0",
Vedran Miletic19c009a2008-09-29 20:29:25 +020015498 ALC662_3ST_6ch_DIG),
Kailang Yang6dda9f42008-05-27 12:05:31 +020015499 SND_PCI_QUIRK(0x1854, 0x2000, "ASUS H13-2000", ALC663_ASUS_H13),
15500 SND_PCI_QUIRK(0x1854, 0x2001, "ASUS H13-2001", ALC663_ASUS_H13),
15501 SND_PCI_QUIRK(0x1854, 0x2002, "ASUS H13-2002", ALC663_ASUS_H13),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015502 {}
15503};
15504
15505static struct alc_config_preset alc662_presets[] = {
15506 [ALC662_3ST_2ch_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015507 .mixers = { alc662_3ST_2ch_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015508 .init_verbs = { alc662_init_verbs },
15509 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15510 .dac_nids = alc662_dac_nids,
15511 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015512 .dig_in_nid = ALC662_DIGIN_NID,
15513 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15514 .channel_mode = alc662_3ST_2ch_modes,
15515 .input_mux = &alc662_capture_source,
15516 },
15517 [ALC662_3ST_6ch_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015518 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015519 .init_verbs = { alc662_init_verbs },
15520 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15521 .dac_nids = alc662_dac_nids,
15522 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015523 .dig_in_nid = ALC662_DIGIN_NID,
15524 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
15525 .channel_mode = alc662_3ST_6ch_modes,
15526 .need_dac_fix = 1,
15527 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015528 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015529 [ALC662_3ST_6ch] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015530 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015531 .init_verbs = { alc662_init_verbs },
15532 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15533 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015534 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
15535 .channel_mode = alc662_3ST_6ch_modes,
15536 .need_dac_fix = 1,
15537 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015538 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015539 [ALC662_5ST_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015540 .mixers = { alc662_base_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015541 .init_verbs = { alc662_init_verbs },
15542 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15543 .dac_nids = alc662_dac_nids,
15544 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015545 .dig_in_nid = ALC662_DIGIN_NID,
15546 .num_channel_mode = ARRAY_SIZE(alc662_5stack_modes),
15547 .channel_mode = alc662_5stack_modes,
15548 .input_mux = &alc662_capture_source,
15549 },
15550 [ALC662_LENOVO_101E] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015551 .mixers = { alc662_lenovo_101e_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015552 .init_verbs = { alc662_init_verbs, alc662_sue_init_verbs },
15553 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15554 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015555 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15556 .channel_mode = alc662_3ST_2ch_modes,
15557 .input_mux = &alc662_lenovo_101e_capture_source,
15558 .unsol_event = alc662_lenovo_101e_unsol_event,
15559 .init_hook = alc662_lenovo_101e_all_automute,
15560 },
Kailang Yang291702f2007-10-16 14:28:03 +020015561 [ALC662_ASUS_EEEPC_P701] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015562 .mixers = { alc662_eeepc_p701_mixer },
Kailang Yang291702f2007-10-16 14:28:03 +020015563 .init_verbs = { alc662_init_verbs,
15564 alc662_eeepc_sue_init_verbs },
15565 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15566 .dac_nids = alc662_dac_nids,
Kailang Yang291702f2007-10-16 14:28:03 +020015567 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15568 .channel_mode = alc662_3ST_2ch_modes,
15569 .input_mux = &alc662_eeepc_capture_source,
15570 .unsol_event = alc662_eeepc_unsol_event,
15571 .init_hook = alc662_eeepc_inithook,
15572 },
Kailang Yang8c427222008-01-10 13:03:59 +010015573 [ALC662_ASUS_EEEPC_EP20] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015574 .mixers = { alc662_eeepc_ep20_mixer,
Kailang Yang8c427222008-01-10 13:03:59 +010015575 alc662_chmode_mixer },
15576 .init_verbs = { alc662_init_verbs,
15577 alc662_eeepc_ep20_sue_init_verbs },
15578 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15579 .dac_nids = alc662_dac_nids,
Kailang Yang8c427222008-01-10 13:03:59 +010015580 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
15581 .channel_mode = alc662_3ST_6ch_modes,
15582 .input_mux = &alc662_lenovo_101e_capture_source,
15583 .unsol_event = alc662_eeepc_ep20_unsol_event,
15584 .init_hook = alc662_eeepc_ep20_inithook,
15585 },
Kailang Yangf1d4e282008-08-26 14:03:29 +020015586 [ALC662_ECS] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015587 .mixers = { alc662_ecs_mixer },
Kailang Yangf1d4e282008-08-26 14:03:29 +020015588 .init_verbs = { alc662_init_verbs,
15589 alc662_ecs_init_verbs },
15590 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15591 .dac_nids = alc662_dac_nids,
15592 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15593 .channel_mode = alc662_3ST_2ch_modes,
15594 .input_mux = &alc662_eeepc_capture_source,
15595 .unsol_event = alc662_eeepc_unsol_event,
15596 .init_hook = alc662_eeepc_inithook,
15597 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020015598 [ALC663_ASUS_M51VA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015599 .mixers = { alc663_m51va_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020015600 .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
15601 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15602 .dac_nids = alc662_dac_nids,
15603 .dig_out_nid = ALC662_DIGOUT_NID,
15604 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15605 .channel_mode = alc662_3ST_2ch_modes,
15606 .input_mux = &alc663_m51va_capture_source,
15607 .unsol_event = alc663_m51va_unsol_event,
15608 .init_hook = alc663_m51va_inithook,
15609 },
15610 [ALC663_ASUS_G71V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015611 .mixers = { alc663_g71v_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020015612 .init_verbs = { alc662_init_verbs, alc663_g71v_init_verbs },
15613 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15614 .dac_nids = alc662_dac_nids,
15615 .dig_out_nid = ALC662_DIGOUT_NID,
15616 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15617 .channel_mode = alc662_3ST_2ch_modes,
15618 .input_mux = &alc662_eeepc_capture_source,
15619 .unsol_event = alc663_g71v_unsol_event,
15620 .init_hook = alc663_g71v_inithook,
15621 },
15622 [ALC663_ASUS_H13] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015623 .mixers = { alc663_m51va_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020015624 .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
15625 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15626 .dac_nids = alc662_dac_nids,
15627 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15628 .channel_mode = alc662_3ST_2ch_modes,
15629 .input_mux = &alc663_m51va_capture_source,
15630 .unsol_event = alc663_m51va_unsol_event,
15631 .init_hook = alc663_m51va_inithook,
15632 },
15633 [ALC663_ASUS_G50V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015634 .mixers = { alc663_g50v_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020015635 .init_verbs = { alc662_init_verbs, alc663_g50v_init_verbs },
15636 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15637 .dac_nids = alc662_dac_nids,
15638 .dig_out_nid = ALC662_DIGOUT_NID,
15639 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
15640 .channel_mode = alc662_3ST_6ch_modes,
15641 .input_mux = &alc663_capture_source,
15642 .unsol_event = alc663_g50v_unsol_event,
15643 .init_hook = alc663_g50v_inithook,
15644 },
Kailang Yangf1d4e282008-08-26 14:03:29 +020015645 [ALC663_ASUS_MODE1] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015646 .mixers = { alc663_m51va_mixer },
15647 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020015648 .init_verbs = { alc662_init_verbs,
15649 alc663_21jd_amic_init_verbs },
15650 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15651 .hp_nid = 0x03,
15652 .dac_nids = alc662_dac_nids,
15653 .dig_out_nid = ALC662_DIGOUT_NID,
15654 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15655 .channel_mode = alc662_3ST_2ch_modes,
15656 .input_mux = &alc662_eeepc_capture_source,
15657 .unsol_event = alc663_mode1_unsol_event,
15658 .init_hook = alc663_mode1_inithook,
15659 },
15660 [ALC662_ASUS_MODE2] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015661 .mixers = { alc662_1bjd_mixer },
15662 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020015663 .init_verbs = { alc662_init_verbs,
15664 alc662_1bjd_amic_init_verbs },
15665 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15666 .dac_nids = alc662_dac_nids,
15667 .dig_out_nid = ALC662_DIGOUT_NID,
15668 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15669 .channel_mode = alc662_3ST_2ch_modes,
15670 .input_mux = &alc662_eeepc_capture_source,
15671 .unsol_event = alc662_mode2_unsol_event,
15672 .init_hook = alc662_mode2_inithook,
15673 },
15674 [ALC663_ASUS_MODE3] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015675 .mixers = { alc663_two_hp_m1_mixer },
15676 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020015677 .init_verbs = { alc662_init_verbs,
15678 alc663_two_hp_amic_m1_init_verbs },
15679 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15680 .hp_nid = 0x03,
15681 .dac_nids = alc662_dac_nids,
15682 .dig_out_nid = ALC662_DIGOUT_NID,
15683 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15684 .channel_mode = alc662_3ST_2ch_modes,
15685 .input_mux = &alc662_eeepc_capture_source,
15686 .unsol_event = alc663_mode3_unsol_event,
15687 .init_hook = alc663_mode3_inithook,
15688 },
15689 [ALC663_ASUS_MODE4] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015690 .mixers = { alc663_asus_21jd_clfe_mixer },
15691 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020015692 .init_verbs = { alc662_init_verbs,
15693 alc663_21jd_amic_init_verbs},
15694 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15695 .hp_nid = 0x03,
15696 .dac_nids = alc662_dac_nids,
15697 .dig_out_nid = ALC662_DIGOUT_NID,
15698 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15699 .channel_mode = alc662_3ST_2ch_modes,
15700 .input_mux = &alc662_eeepc_capture_source,
15701 .unsol_event = alc663_mode4_unsol_event,
15702 .init_hook = alc663_mode4_inithook,
15703 },
15704 [ALC663_ASUS_MODE5] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015705 .mixers = { alc663_asus_15jd_clfe_mixer },
15706 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020015707 .init_verbs = { alc662_init_verbs,
15708 alc663_15jd_amic_init_verbs },
15709 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15710 .hp_nid = 0x03,
15711 .dac_nids = alc662_dac_nids,
15712 .dig_out_nid = ALC662_DIGOUT_NID,
15713 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15714 .channel_mode = alc662_3ST_2ch_modes,
15715 .input_mux = &alc662_eeepc_capture_source,
15716 .unsol_event = alc663_mode5_unsol_event,
15717 .init_hook = alc663_mode5_inithook,
15718 },
15719 [ALC663_ASUS_MODE6] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015720 .mixers = { alc663_two_hp_m2_mixer },
15721 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020015722 .init_verbs = { alc662_init_verbs,
15723 alc663_two_hp_amic_m2_init_verbs },
15724 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15725 .hp_nid = 0x03,
15726 .dac_nids = alc662_dac_nids,
15727 .dig_out_nid = ALC662_DIGOUT_NID,
15728 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15729 .channel_mode = alc662_3ST_2ch_modes,
15730 .input_mux = &alc662_eeepc_capture_source,
15731 .unsol_event = alc663_mode6_unsol_event,
15732 .init_hook = alc663_mode6_inithook,
15733 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015734};
15735
15736
15737/*
15738 * BIOS auto configuration
15739 */
15740
15741/* add playback controls from the parsed DAC table */
15742static int alc662_auto_create_multi_out_ctls(struct alc_spec *spec,
15743 const struct auto_pin_cfg *cfg)
15744{
15745 char name[32];
15746 static const char *chname[4] = {
15747 "Front", "Surround", NULL /*CLFE*/, "Side"
15748 };
15749 hda_nid_t nid;
15750 int i, err;
15751
15752 for (i = 0; i < cfg->line_outs; i++) {
15753 if (!spec->multiout.dac_nids[i])
15754 continue;
Kailang Yangb60dd392007-09-20 12:50:29 +020015755 nid = alc880_idx_to_dac(i);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015756 if (i == 2) {
15757 /* Center/LFE */
15758 err = add_control(spec, ALC_CTL_WIDGET_VOL,
15759 "Center Playback Volume",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015760 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
15761 HDA_OUTPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015762 if (err < 0)
15763 return err;
15764 err = add_control(spec, ALC_CTL_WIDGET_VOL,
15765 "LFE Playback Volume",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015766 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
15767 HDA_OUTPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015768 if (err < 0)
15769 return err;
Herton Ronaldo Krzesinskib69ce012008-09-18 16:41:49 -030015770 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015771 "Center Playback Switch",
Herton Ronaldo Krzesinskib69ce012008-09-18 16:41:49 -030015772 HDA_COMPOSE_AMP_VAL(0x0e, 1, 0,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015773 HDA_INPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015774 if (err < 0)
15775 return err;
Herton Ronaldo Krzesinskib69ce012008-09-18 16:41:49 -030015776 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015777 "LFE Playback Switch",
Herton Ronaldo Krzesinskib69ce012008-09-18 16:41:49 -030015778 HDA_COMPOSE_AMP_VAL(0x0e, 2, 0,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015779 HDA_INPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015780 if (err < 0)
15781 return err;
15782 } else {
15783 sprintf(name, "%s Playback Volume", chname[i]);
15784 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015785 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
15786 HDA_OUTPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015787 if (err < 0)
15788 return err;
15789 sprintf(name, "%s Playback Switch", chname[i]);
Herton Ronaldo Krzesinskib69ce012008-09-18 16:41:49 -030015790 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
15791 HDA_COMPOSE_AMP_VAL(alc880_idx_to_mixer(i),
15792 3, 0, HDA_INPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015793 if (err < 0)
15794 return err;
15795 }
15796 }
15797 return 0;
15798}
15799
15800/* add playback controls for speaker and HP outputs */
15801static int alc662_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
15802 const char *pfx)
15803{
15804 hda_nid_t nid;
15805 int err;
15806 char name[32];
15807
15808 if (!pin)
15809 return 0;
15810
Takashi Iwai24fb9172008-09-02 14:48:20 +020015811 if (pin == 0x17) {
15812 /* ALC663 has a mono output pin on 0x17 */
15813 sprintf(name, "%s Playback Switch", pfx);
15814 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
15815 HDA_COMPOSE_AMP_VAL(pin, 2, 0, HDA_OUTPUT));
15816 return err;
15817 }
15818
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015819 if (alc880_is_fixed_pin(pin)) {
15820 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
15821 /* printk("DAC nid=%x\n",nid); */
15822 /* specify the DAC as the extra output */
15823 if (!spec->multiout.hp_nid)
15824 spec->multiout.hp_nid = nid;
15825 else
15826 spec->multiout.extra_out_nid[0] = nid;
15827 /* control HP volume/switch on the output mixer amp */
15828 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
15829 sprintf(name, "%s Playback Volume", pfx);
15830 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
15831 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
15832 if (err < 0)
15833 return err;
15834 sprintf(name, "%s Playback Switch", pfx);
15835 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
15836 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
15837 if (err < 0)
15838 return err;
15839 } else if (alc880_is_multi_pin(pin)) {
15840 /* set manual connection */
15841 /* we have only a switch on HP-out PIN */
15842 sprintf(name, "%s Playback Switch", pfx);
15843 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
15844 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
15845 if (err < 0)
15846 return err;
15847 }
15848 return 0;
15849}
15850
15851/* create playback/capture controls for input pins */
15852static int alc662_auto_create_analog_input_ctls(struct alc_spec *spec,
15853 const struct auto_pin_cfg *cfg)
15854{
15855 struct hda_input_mux *imux = &spec->private_imux;
15856 int i, err, idx;
15857
15858 for (i = 0; i < AUTO_PIN_LAST; i++) {
15859 if (alc880_is_input_pin(cfg->input_pins[i])) {
15860 idx = alc880_input_pin_idx(cfg->input_pins[i]);
15861 err = new_analog_input(spec, cfg->input_pins[i],
15862 auto_pin_cfg_labels[i],
15863 idx, 0x0b);
15864 if (err < 0)
15865 return err;
15866 imux->items[imux->num_items].label =
15867 auto_pin_cfg_labels[i];
15868 imux->items[imux->num_items].index =
15869 alc880_input_pin_idx(cfg->input_pins[i]);
15870 imux->num_items++;
15871 }
15872 }
15873 return 0;
15874}
15875
15876static void alc662_auto_set_output_and_unmute(struct hda_codec *codec,
15877 hda_nid_t nid, int pin_type,
15878 int dac_idx)
15879{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010015880 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015881 /* need the manual connection? */
15882 if (alc880_is_multi_pin(nid)) {
15883 struct alc_spec *spec = codec->spec;
15884 int idx = alc880_multi_pin_idx(nid);
15885 snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
15886 AC_VERB_SET_CONNECT_SEL,
15887 alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
15888 }
15889}
15890
15891static void alc662_auto_init_multi_out(struct hda_codec *codec)
15892{
15893 struct alc_spec *spec = codec->spec;
15894 int i;
15895
Kailang Yang8c427222008-01-10 13:03:59 +010015896 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015897 for (i = 0; i <= HDA_SIDE; i++) {
15898 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020015899 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015900 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020015901 alc662_auto_set_output_and_unmute(codec, nid, pin_type,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015902 i);
15903 }
15904}
15905
15906static void alc662_auto_init_hp_out(struct hda_codec *codec)
15907{
15908 struct alc_spec *spec = codec->spec;
15909 hda_nid_t pin;
15910
15911 pin = spec->autocfg.hp_pins[0];
15912 if (pin) /* connect to front */
15913 /* use dac 0 */
15914 alc662_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010015915 pin = spec->autocfg.speaker_pins[0];
15916 if (pin)
15917 alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015918}
15919
15920#define alc662_is_input_pin(nid) alc880_is_input_pin(nid)
15921#define ALC662_PIN_CD_NID ALC880_PIN_CD_NID
15922
15923static void alc662_auto_init_analog_input(struct hda_codec *codec)
15924{
15925 struct alc_spec *spec = codec->spec;
15926 int i;
15927
15928 for (i = 0; i < AUTO_PIN_LAST; i++) {
15929 hda_nid_t nid = spec->autocfg.input_pins[i];
15930 if (alc662_is_input_pin(nid)) {
15931 snd_hda_codec_write(codec, nid, 0,
15932 AC_VERB_SET_PIN_WIDGET_CONTROL,
15933 (i <= AUTO_PIN_FRONT_MIC ?
15934 PIN_VREF80 : PIN_IN));
15935 if (nid != ALC662_PIN_CD_NID)
15936 snd_hda_codec_write(codec, nid, 0,
15937 AC_VERB_SET_AMP_GAIN_MUTE,
15938 AMP_OUT_MUTE);
15939 }
15940 }
15941}
15942
Takashi Iwaif511b012008-08-15 16:46:42 +020015943#define alc662_auto_init_input_src alc882_auto_init_input_src
15944
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015945static int alc662_parse_auto_config(struct hda_codec *codec)
15946{
15947 struct alc_spec *spec = codec->spec;
15948 int err;
15949 static hda_nid_t alc662_ignore[] = { 0x1d, 0 };
15950
15951 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
15952 alc662_ignore);
15953 if (err < 0)
15954 return err;
15955 if (!spec->autocfg.line_outs)
15956 return 0; /* can't find valid BIOS pin config */
15957
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015958 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
15959 if (err < 0)
15960 return err;
15961 err = alc662_auto_create_multi_out_ctls(spec, &spec->autocfg);
15962 if (err < 0)
15963 return err;
15964 err = alc662_auto_create_extra_out(spec,
15965 spec->autocfg.speaker_pins[0],
15966 "Speaker");
15967 if (err < 0)
15968 return err;
15969 err = alc662_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
15970 "Headphone");
15971 if (err < 0)
15972 return err;
15973 err = alc662_auto_create_analog_input_ctls(spec, &spec->autocfg);
15974 if (err < 0)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015975 return err;
15976
15977 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
15978
15979 if (spec->autocfg.dig_out_pin)
15980 spec->multiout.dig_out_nid = ALC880_DIGOUT_NID;
15981
Takashi Iwai603c4012008-07-30 15:01:44 +020015982 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010015983 add_mixer(spec, spec->kctls.list);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015984
15985 spec->num_mux_defs = 1;
15986 spec->input_mux = &spec->private_imux;
Kailang Yangea1fb292008-08-26 12:58:38 +020015987
Takashi Iwaid88897e2008-10-31 15:01:37 +010015988 add_verb(spec, alc662_auto_init_verbs);
Takashi Iwai24fb9172008-09-02 14:48:20 +020015989 if (codec->vendor_id == 0x10ec0663)
Takashi Iwaid88897e2008-10-31 15:01:37 +010015990 add_verb(spec, alc663_auto_init_verbs);
Takashi Iwaiee979a142008-09-02 15:42:20 +020015991
15992 err = alc_auto_add_mic_boost(codec);
15993 if (err < 0)
15994 return err;
15995
Takashi Iwaie044c392008-10-27 16:56:24 +010015996 store_pin_configs(codec);
Takashi Iwai8c87286f2007-06-19 12:11:16 +020015997 return 1;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015998}
15999
16000/* additional initialization for auto-configuration model */
16001static void alc662_auto_init(struct hda_codec *codec)
16002{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016003 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016004 alc662_auto_init_multi_out(codec);
16005 alc662_auto_init_hp_out(codec);
16006 alc662_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020016007 alc662_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016008 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020016009 alc_inithook(codec);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016010}
16011
16012static int patch_alc662(struct hda_codec *codec)
16013{
16014 struct alc_spec *spec;
16015 int err, board_config;
16016
16017 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
16018 if (!spec)
16019 return -ENOMEM;
16020
16021 codec->spec = spec;
16022
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020016023 alc_fix_pll_init(codec, 0x20, 0x04, 15);
16024
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016025 board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST,
16026 alc662_models,
16027 alc662_cfg_tbl);
16028 if (board_config < 0) {
16029 printk(KERN_INFO "hda_codec: Unknown model for ALC662, "
16030 "trying auto-probe from BIOS...\n");
16031 board_config = ALC662_AUTO;
16032 }
16033
16034 if (board_config == ALC662_AUTO) {
16035 /* automatic parse from the BIOS config */
16036 err = alc662_parse_auto_config(codec);
16037 if (err < 0) {
16038 alc_free(codec);
16039 return err;
Takashi Iwai8c87286f2007-06-19 12:11:16 +020016040 } else if (!err) {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016041 printk(KERN_INFO
16042 "hda_codec: Cannot set up configuration "
16043 "from BIOS. Using base mode...\n");
16044 board_config = ALC662_3ST_2ch_DIG;
16045 }
16046 }
16047
16048 if (board_config != ALC662_AUTO)
16049 setup_preset(spec, &alc662_presets[board_config]);
16050
Kailang Yang6dda9f42008-05-27 12:05:31 +020016051 if (codec->vendor_id == 0x10ec0663) {
16052 spec->stream_name_analog = "ALC663 Analog";
16053 spec->stream_name_digital = "ALC663 Digital";
Kailang Yang01afd412008-10-15 11:22:09 +020016054 } else if (codec->vendor_id == 0x10ec0272) {
16055 spec->stream_name_analog = "ALC272 Analog";
16056 spec->stream_name_digital = "ALC272 Digital";
Kailang Yang6dda9f42008-05-27 12:05:31 +020016057 } else {
16058 spec->stream_name_analog = "ALC662 Analog";
16059 spec->stream_name_digital = "ALC662 Digital";
16060 }
16061
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016062 spec->stream_analog_playback = &alc662_pcm_analog_playback;
16063 spec->stream_analog_capture = &alc662_pcm_analog_capture;
16064
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016065 spec->stream_digital_playback = &alc662_pcm_digital_playback;
16066 spec->stream_digital_capture = &alc662_pcm_digital_capture;
16067
Takashi Iwaie1406342008-02-11 18:32:32 +010016068 spec->adc_nids = alc662_adc_nids;
16069 spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids);
16070 spec->capsrc_nids = alc662_capsrc_nids;
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010016071 spec->is_mix_capture = 1;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016072
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016073 if (!spec->cap_mixer)
16074 set_capture_mixer(spec);
16075
Takashi Iwai2134ea42008-01-10 16:53:55 +010016076 spec->vmaster_nid = 0x02;
16077
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016078 codec->patch_ops = alc_patch_ops;
16079 if (board_config == ALC662_AUTO)
16080 spec->init_hook = alc662_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020016081#ifdef CONFIG_SND_HDA_POWER_SAVE
16082 if (!spec->loopback.amplist)
16083 spec->loopback.amplist = alc662_loopbacks;
16084#endif
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016085
16086 return 0;
16087}
16088
16089/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070016090 * patch entries
16091 */
16092struct hda_codec_preset snd_hda_preset_realtek[] = {
16093 { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
Kailang Yangdf694da2005-12-05 19:42:22 +010016094 { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
Kailang Yangf6a92242007-12-13 16:52:54 +010016095 { .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 },
Kailang Yanga361d842007-06-05 12:30:55 +020016096 { .id = 0x10ec0268, .name = "ALC268", .patch = patch_alc268 },
Kailang Yangf6a92242007-12-13 16:52:54 +010016097 { .id = 0x10ec0269, .name = "ALC269", .patch = patch_alc269 },
Kailang Yang01afd412008-10-15 11:22:09 +020016098 { .id = 0x10ec0272, .name = "ALC272", .patch = patch_alc662 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016099 { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016100 .patch = patch_alc861 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016101 { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
16102 { .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 },
16103 { .id = 0x10ec0862, .name = "ALC861-VD", .patch = patch_alc861vd },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016104 { .id = 0x10ec0662, .rev = 0x100002, .name = "ALC662 rev2",
16105 .patch = patch_alc883 },
16106 { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1",
16107 .patch = patch_alc662 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020016108 { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016109 { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070016110 { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020016111 { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc883 },
Clive Messer669faba2008-09-30 15:49:13 +020016112 { .id = 0x10ec0885, .rev = 0x100101, .name = "ALC889A",
16113 .patch = patch_alc882 }, /* should be patch_alc883() in future */
Takashi Iwaicb308f92008-04-16 14:13:29 +020016114 { .id = 0x10ec0885, .rev = 0x100103, .name = "ALC889A",
Takashi Iwai7943a8a2008-04-16 17:29:09 +020016115 .patch = patch_alc882 }, /* should be patch_alc883() in future */
Kailang Yangdf694da2005-12-05 19:42:22 +010016116 { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
Kailang Yanga385a522008-10-15 11:20:21 +020016117 { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc883 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020016118 { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc883 },
Kailang Yang44426082008-10-15 11:18:05 +020016119 { .id = 0x10ec0888, .rev = 0x100101, .name = "ALC1200",
16120 .patch = patch_alc883 },
Kailang Yangf6a92242007-12-13 16:52:54 +010016121 { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc883 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070016122 {} /* terminator */
16123};