blob: e727e48a48e38d4d893bb21e6eeffdbfc79958df [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Universal Interface for Intel High Definition Audio Codec
3 *
4 * HD audio interface patch for ALC 260/880/882 codecs
5 *
Kailang Yangdf694da2005-12-05 19:42:22 +01006 * Copyright (c) 2004 Kailang Yang <kailang@realtek.com.tw>
7 * PeiSen Hou <pshou@realtek.com.tw>
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 * Takashi Iwai <tiwai@suse.de>
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01009 * Jonathan Woithe <jwoithe@physics.adelaide.edu.au>
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 *
11 * This driver is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This driver is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <linux/init.h>
27#include <linux/delay.h>
28#include <linux/slab.h>
29#include <linux/pci.h>
30#include <sound/core.h>
31#include "hda_codec.h"
32#include "hda_local.h"
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 Woithe7cf51e42006-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 Avdoninbab282b2006-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 Woithe7cf51e42006-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 Woithe7cf51e42006-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 Woithe7cf51e42006-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 Iwaic8b6bf9b2005-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 Iwaic8b6bf9b2005-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 Iwaic8b6bf9b2005-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 Iwaic8b6bf9b2005-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 Iwaic8b6bf9b2005-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 Iwaic8b6bf9b2005-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 Iwaic8b6bf9b2005-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 Iwaic8b6bf9b2005-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 Iwaic8b6bf9b2005-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 Iwaic8b6bf9b2005-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 Iwaic8b6bf9b2005-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 Iwaic8b6bf9b2005-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 Iwaic8b6bf9b2005-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 Iwaic8b6bf9b2005-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 Iwaic8b6bf9b2005-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 Iwaic8b6bf9b2005-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 Iwaic8b6bf9b2005-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 Iwaic8b6bf9b2005-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 Iwaic8b6bf9b2005-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 Iwaic8b6bf9b2005-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 Woithe7cf51e42006-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 Woithe7cf51e42006-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 Woithe7cf51e42006-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 Woithe7cf51e42006-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 Woithe7cf51e42006-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 Woithe7cf51e42006-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 Woithe7cf51e42006-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 Woithe7cf51e42006-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 Woithe7cf51e42006-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 Woithe7cf51e42006-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 Woithe7cf51e42006-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 Woithe7cf51e42006-02-09 12:01:26 +01005423#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005424 [ALC260_TEST] = "test",
Jonathan Woithe7cf51e42006-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 Woithe7cf51e42006-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 Woithe7cf51e42006-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 Woithe7cf51e42006-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 Iwai4ef0ef12008-11-03 17:47:49 +01005621 if (!spec->adc_nids && spec->input_mux) {
5622 /* check whether NID 0x04 is valid */
5623 unsigned int wcap = get_wcaps(codec, 0x04);
5624 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
5625 /* get type */
5626 if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
5627 spec->adc_nids = alc260_adc_nids_alt;
5628 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt);
5629 } else {
5630 spec->adc_nids = alc260_adc_nids;
5631 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids);
5632 }
5633 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005634 set_capture_mixer(spec);
5635
Takashi Iwai2134ea42008-01-10 16:53:55 +01005636 spec->vmaster_nid = 0x08;
5637
Linus Torvalds1da177e2005-04-16 15:20:36 -07005638 codec->patch_ops = alc_patch_ops;
Kailang Yangdf694da2005-12-05 19:42:22 +01005639 if (board_config == ALC260_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005640 spec->init_hook = alc260_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02005641#ifdef CONFIG_SND_HDA_POWER_SAVE
5642 if (!spec->loopback.amplist)
5643 spec->loopback.amplist = alc260_loopbacks;
5644#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005645
5646 return 0;
5647}
5648
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005649
Linus Torvalds1da177e2005-04-16 15:20:36 -07005650/*
5651 * ALC882 support
5652 *
5653 * ALC882 is almost identical with ALC880 but has cleaner and more flexible
5654 * configuration. Each pin widget can choose any input DACs and a mixer.
5655 * Each ADC is connected from a mixer of all inputs. This makes possible
5656 * 6-channel independent captures.
5657 *
5658 * In addition, an independent DAC for the multi-playback (not used in this
5659 * driver yet).
5660 */
Kailang Yangdf694da2005-12-05 19:42:22 +01005661#define ALC882_DIGOUT_NID 0x06
5662#define ALC882_DIGIN_NID 0x0a
Linus Torvalds1da177e2005-04-16 15:20:36 -07005663
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01005664static struct hda_channel_mode alc882_ch_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005665 { 8, NULL }
5666};
5667
5668static hda_nid_t alc882_dac_nids[4] = {
5669 /* front, rear, clfe, rear_surr */
5670 0x02, 0x03, 0x04, 0x05
5671};
5672
Kailang Yangdf694da2005-12-05 19:42:22 +01005673/* identical with ALC880 */
5674#define alc882_adc_nids alc880_adc_nids
5675#define alc882_adc_nids_alt alc880_adc_nids_alt
Linus Torvalds1da177e2005-04-16 15:20:36 -07005676
Takashi Iwaie1406342008-02-11 18:32:32 +01005677static hda_nid_t alc882_capsrc_nids[3] = { 0x24, 0x23, 0x22 };
5678static hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 };
5679
Linus Torvalds1da177e2005-04-16 15:20:36 -07005680/* input MUX */
5681/* FIXME: should be a matrix-type input source selection */
5682
5683static struct hda_input_mux alc882_capture_source = {
5684 .num_items = 4,
5685 .items = {
5686 { "Mic", 0x0 },
5687 { "Front Mic", 0x1 },
5688 { "Line", 0x2 },
5689 { "CD", 0x4 },
5690 },
5691};
Kailang Yangdf694da2005-12-05 19:42:22 +01005692/*
Kailang Yang272a5272007-05-14 11:00:38 +02005693 * 2ch mode
5694 */
5695static struct hda_verb alc882_3ST_ch2_init[] = {
5696 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
5697 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
5698 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
5699 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
5700 { } /* end */
5701};
5702
5703/*
5704 * 6ch mode
5705 */
5706static struct hda_verb alc882_3ST_ch6_init[] = {
5707 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5708 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
5709 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
5710 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5711 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
5712 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
5713 { } /* end */
5714};
5715
5716static struct hda_channel_mode alc882_3ST_6ch_modes[2] = {
5717 { 2, alc882_3ST_ch2_init },
5718 { 6, alc882_3ST_ch6_init },
5719};
5720
5721/*
Kailang Yangdf694da2005-12-05 19:42:22 +01005722 * 6ch mode
5723 */
5724static struct hda_verb alc882_sixstack_ch6_init[] = {
5725 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
5726 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5727 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5728 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5729 { } /* end */
5730};
5731
5732/*
5733 * 8ch mode
5734 */
5735static struct hda_verb alc882_sixstack_ch8_init[] = {
5736 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5737 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5738 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5739 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5740 { } /* end */
5741};
5742
5743static struct hda_channel_mode alc882_sixstack_modes[2] = {
5744 { 6, alc882_sixstack_ch6_init },
5745 { 8, alc882_sixstack_ch8_init },
5746};
5747
Takashi Iwai87350ad2007-08-16 18:19:38 +02005748/*
5749 * macbook pro ALC885 can switch LineIn to LineOut without loosing Mic
5750 */
5751
5752/*
5753 * 2ch mode
5754 */
5755static struct hda_verb alc885_mbp_ch2_init[] = {
5756 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
5757 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5758 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5759 { } /* end */
5760};
5761
5762/*
5763 * 6ch mode
5764 */
5765static struct hda_verb alc885_mbp_ch6_init[] = {
5766 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5767 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5768 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
5769 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5770 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5771 { } /* end */
5772};
5773
5774static struct hda_channel_mode alc885_mbp_6ch_modes[2] = {
5775 { 2, alc885_mbp_ch2_init },
5776 { 6, alc885_mbp_ch6_init },
5777};
5778
5779
Linus Torvalds1da177e2005-04-16 15:20:36 -07005780/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
5781 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
5782 */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01005783static struct snd_kcontrol_new alc882_base_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02005784 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005785 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02005786 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005787 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02005788 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
5789 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005790 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
5791 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02005792 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005793 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005794 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
5795 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5796 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5797 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5798 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5799 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01005800 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005801 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
5802 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01005803 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005804 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
5805 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
5806 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005807 { } /* end */
5808};
5809
Takashi Iwai87350ad2007-08-16 18:19:38 +02005810static struct snd_kcontrol_new alc885_mbp3_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01005811 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
5812 HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
5813 HDA_CODEC_MUTE ("Speaker Playback Switch", 0x14, 0x00, HDA_OUTPUT),
5814 HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
5815 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5816 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02005817 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
5818 HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01005819 HDA_CODEC_VOLUME("Line Boost", 0x1a, 0x00, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02005820 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT),
5821 { } /* end */
5822};
Kailang Yangbdd148a2007-05-08 15:19:08 +02005823static struct snd_kcontrol_new alc882_w2jc_mixer[] = {
5824 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5825 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
5826 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5827 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5828 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5829 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5830 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5831 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
5832 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
5833 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
5834 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
5835 { } /* end */
5836};
5837
Kailang Yang272a5272007-05-14 11:00:38 +02005838static struct snd_kcontrol_new alc882_targa_mixer[] = {
5839 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5840 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
5841 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
5842 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5843 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5844 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5845 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5846 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5847 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai96fe7cc2007-09-07 10:57:44 +02005848 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02005849 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
5850 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai96fe7cc2007-09-07 10:57:44 +02005851 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02005852 { } /* end */
5853};
5854
5855/* Pin assignment: Front=0x14, HP = 0x15, Front = 0x16, ???
5856 * Front Mic=0x18, Line In = 0x1a, Line In = 0x1b, CD = 0x1c
5857 */
5858static struct snd_kcontrol_new alc882_asus_a7j_mixer[] = {
5859 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5860 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
5861 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
5862 HDA_CODEC_MUTE("Mobile Front Playback Switch", 0x16, 0x0, HDA_OUTPUT),
5863 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5864 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5865 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5866 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5867 HDA_CODEC_VOLUME("Mobile Line Playback Volume", 0x0b, 0x03, HDA_INPUT),
5868 HDA_CODEC_MUTE("Mobile Line Playback Switch", 0x0b, 0x03, HDA_INPUT),
5869 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5870 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai96fe7cc2007-09-07 10:57:44 +02005871 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02005872 { } /* end */
5873};
5874
Takashi Iwai914759b2007-09-06 14:52:04 +02005875static struct snd_kcontrol_new alc882_asus_a7m_mixer[] = {
5876 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5877 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
5878 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
5879 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5880 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5881 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5882 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5883 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5884 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
5885 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
5886 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
5887 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
5888 { } /* end */
5889};
5890
Kailang Yangdf694da2005-12-05 19:42:22 +01005891static struct snd_kcontrol_new alc882_chmode_mixer[] = {
5892 {
5893 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5894 .name = "Channel Mode",
5895 .info = alc_ch_mode_info,
5896 .get = alc_ch_mode_get,
5897 .put = alc_ch_mode_put,
5898 },
5899 { } /* end */
5900};
5901
Linus Torvalds1da177e2005-04-16 15:20:36 -07005902static struct hda_verb alc882_init_verbs[] = {
5903 /* Front mixer: unmute input/output amp left and right (volume = 0) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005904 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5905 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5906 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005907 /* Rear mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02005908 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5909 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5910 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005911 /* CLFE mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02005912 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5913 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5914 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005915 /* Side mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02005916 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5917 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5918 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005919
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005920 /* Front Pin: output 0 (0x0c) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005921 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02005922 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005923 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005924 /* Rear Pin: output 1 (0x0d) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005925 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02005926 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005927 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005928 /* CLFE Pin: output 2 (0x0e) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005929 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02005930 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005931 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005932 /* Side Pin: output 3 (0x0f) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005933 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02005934 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005935 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005936 /* Mic (rear) pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02005937 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005938 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5939 /* Front Mic pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02005940 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005941 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5942 /* Line In pin: input */
Takashi Iwai05acb862005-06-10 19:50:25 +02005943 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005944 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5945 /* Line-2 In: Headphone output (output 0 - 0x0c) */
5946 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5947 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5948 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005949 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02005950 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005951
5952 /* FIXME: use matrix-type input source selection */
5953 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
5954 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
Takashi Iwai05acb862005-06-10 19:50:25 +02005955 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5956 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5957 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5958 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005959 /* Input mixer2 */
Takashi Iwai05acb862005-06-10 19:50:25 +02005960 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5961 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5962 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5963 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005964 /* Input mixer3 */
Takashi Iwai05acb862005-06-10 19:50:25 +02005965 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5966 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5967 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5968 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5969 /* ADC1: mute amp left and right */
5970 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02005971 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02005972 /* ADC2: mute amp left and right */
5973 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02005974 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02005975 /* ADC3: mute amp left and right */
5976 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02005977 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005978
5979 { }
5980};
5981
Takashi Iwai4b146cb2006-07-28 14:42:36 +02005982static struct hda_verb alc882_eapd_verbs[] = {
5983 /* change to EAPD mode */
5984 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01005985 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005986 { }
Takashi Iwai4b146cb2006-07-28 14:42:36 +02005987};
5988
Tobin Davis9102cd12006-12-15 10:02:12 +01005989/* Mac Pro test */
5990static struct snd_kcontrol_new alc882_macpro_mixer[] = {
5991 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5992 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
5993 HDA_CODEC_MUTE("Headphone Playback Switch", 0x18, 0x0, HDA_OUTPUT),
5994 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
5995 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
5996 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x02, HDA_INPUT),
5997 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x02, HDA_INPUT),
5998 { } /* end */
5999};
6000
6001static struct hda_verb alc882_macpro_init_verbs[] = {
6002 /* Front mixer: unmute input/output amp left and right (volume = 0) */
6003 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6004 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6005 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6006 /* Front Pin: output 0 (0x0c) */
6007 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6008 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6009 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
6010 /* Front Mic pin: input vref at 80% */
6011 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
6012 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6013 /* Speaker: output */
6014 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6015 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6016 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x04},
6017 /* Headphone output (output 0 - 0x0c) */
6018 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6019 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6020 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
6021
6022 /* FIXME: use matrix-type input source selection */
6023 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
6024 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
6025 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6026 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6027 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6028 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6029 /* Input mixer2 */
6030 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6031 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6032 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6033 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6034 /* Input mixer3 */
6035 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6036 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6037 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6038 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6039 /* ADC1: mute amp left and right */
6040 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6041 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
6042 /* ADC2: mute amp left and right */
6043 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6044 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
6045 /* ADC3: mute amp left and right */
6046 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6047 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
6048
6049 { }
6050};
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006051
Takashi Iwai87350ad2007-08-16 18:19:38 +02006052/* Macbook Pro rev3 */
6053static struct hda_verb alc885_mbp3_init_verbs[] = {
6054 /* Front mixer: unmute input/output amp left and right (volume = 0) */
6055 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6056 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6057 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6058 /* Rear mixer */
6059 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6060 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6061 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6062 /* Front Pin: output 0 (0x0c) */
6063 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6064 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6065 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
6066 /* HP Pin: output 0 (0x0d) */
6067 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
6068 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6069 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
6070 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
6071 /* Mic (rear) pin: input vref at 80% */
6072 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
6073 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6074 /* Front Mic pin: input vref at 80% */
6075 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
6076 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6077 /* Line In pin: use output 1 when in LineOut mode */
6078 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
6079 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6080 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
6081
6082 /* FIXME: use matrix-type input source selection */
6083 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
6084 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
6085 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6086 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6087 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6088 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6089 /* Input mixer2 */
6090 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6091 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6092 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6093 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6094 /* Input mixer3 */
6095 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6096 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6097 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6098 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6099 /* ADC1: mute amp left and right */
6100 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6101 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
6102 /* ADC2: mute amp left and right */
6103 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6104 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
6105 /* ADC3: mute amp left and right */
6106 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6107 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
6108
6109 { }
6110};
6111
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006112/* iMac 24 mixer. */
6113static struct snd_kcontrol_new alc885_imac24_mixer[] = {
6114 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
6115 HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x00, HDA_INPUT),
6116 { } /* end */
6117};
6118
6119/* iMac 24 init verbs. */
6120static struct hda_verb alc885_imac24_init_verbs[] = {
6121 /* Internal speakers: output 0 (0x0c) */
6122 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6123 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6124 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
6125 /* Internal speakers: output 0 (0x0c) */
6126 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6127 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6128 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
6129 /* Headphone: output 0 (0x0c) */
6130 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6131 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6132 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
6133 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
6134 /* Front Mic: input vref at 80% */
6135 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
6136 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6137 { }
6138};
6139
6140/* Toggle speaker-output according to the hp-jack state */
6141static void alc885_imac24_automute(struct hda_codec *codec)
6142{
6143 unsigned int present;
6144
6145 present = snd_hda_codec_read(codec, 0x14, 0,
6146 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02006147 snd_hda_codec_amp_stereo(codec, 0x18, HDA_OUTPUT, 0,
6148 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
6149 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0,
6150 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006151}
6152
6153/* Processes unsolicited events. */
6154static void alc885_imac24_unsol_event(struct hda_codec *codec,
6155 unsigned int res)
6156{
6157 /* Headphone insertion or removal. */
6158 if ((res >> 26) == ALC880_HP_EVENT)
6159 alc885_imac24_automute(codec);
6160}
6161
Takashi Iwai87350ad2007-08-16 18:19:38 +02006162static void alc885_mbp3_automute(struct hda_codec *codec)
6163{
6164 unsigned int present;
6165
6166 present = snd_hda_codec_read(codec, 0x15, 0,
6167 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
6168 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
6169 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
6170 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
6171 HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE);
6172
6173}
6174static void alc885_mbp3_unsol_event(struct hda_codec *codec,
6175 unsigned int res)
6176{
6177 /* Headphone insertion or removal. */
6178 if ((res >> 26) == ALC880_HP_EVENT)
6179 alc885_mbp3_automute(codec);
6180}
6181
6182
Kailang Yang272a5272007-05-14 11:00:38 +02006183static struct hda_verb alc882_targa_verbs[] = {
6184 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6185 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6186
6187 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6188 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02006189
Kailang Yang272a5272007-05-14 11:00:38 +02006190 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
6191 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
6192 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
6193
6194 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
6195 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
6196 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
6197 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
6198 { } /* end */
6199};
6200
6201/* toggle speaker-output according to the hp-jack state */
6202static void alc882_targa_automute(struct hda_codec *codec)
6203{
6204 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02006205
Kailang Yang272a5272007-05-14 11:00:38 +02006206 present = snd_hda_codec_read(codec, 0x14, 0,
6207 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02006208 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
6209 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02006210 snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
6211 present ? 1 : 3);
Kailang Yang272a5272007-05-14 11:00:38 +02006212}
6213
6214static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res)
6215{
6216 /* Looks like the unsol event is incompatible with the standard
6217 * definition. 4bit tag is placed at 26 bit!
6218 */
6219 if (((res >> 26) == ALC880_HP_EVENT)) {
6220 alc882_targa_automute(codec);
6221 }
6222}
6223
6224static struct hda_verb alc882_asus_a7j_verbs[] = {
6225 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6226 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6227
6228 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6229 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6230 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02006231
Kailang Yang272a5272007-05-14 11:00:38 +02006232 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
6233 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
6234 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
6235
6236 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
6237 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
6238 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
6239 { } /* end */
6240};
6241
Takashi Iwai914759b2007-09-06 14:52:04 +02006242static struct hda_verb alc882_asus_a7m_verbs[] = {
6243 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6244 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6245
6246 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6247 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6248 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02006249
Takashi Iwai914759b2007-09-06 14:52:04 +02006250 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
6251 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
6252 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
6253
6254 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
6255 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
6256 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
6257 { } /* end */
6258};
6259
Tobin Davis9102cd12006-12-15 10:02:12 +01006260static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted)
6261{
6262 unsigned int gpiostate, gpiomask, gpiodir;
6263
6264 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
6265 AC_VERB_GET_GPIO_DATA, 0);
6266
6267 if (!muted)
6268 gpiostate |= (1 << pin);
6269 else
6270 gpiostate &= ~(1 << pin);
6271
6272 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
6273 AC_VERB_GET_GPIO_MASK, 0);
6274 gpiomask |= (1 << pin);
6275
6276 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
6277 AC_VERB_GET_GPIO_DIRECTION, 0);
6278 gpiodir |= (1 << pin);
6279
6280
6281 snd_hda_codec_write(codec, codec->afg, 0,
6282 AC_VERB_SET_GPIO_MASK, gpiomask);
6283 snd_hda_codec_write(codec, codec->afg, 0,
6284 AC_VERB_SET_GPIO_DIRECTION, gpiodir);
6285
6286 msleep(1);
6287
6288 snd_hda_codec_write(codec, codec->afg, 0,
6289 AC_VERB_SET_GPIO_DATA, gpiostate);
6290}
6291
Takashi Iwai7debbe52007-08-16 15:01:03 +02006292/* set up GPIO at initialization */
6293static void alc885_macpro_init_hook(struct hda_codec *codec)
6294{
6295 alc882_gpio_mute(codec, 0, 0);
6296 alc882_gpio_mute(codec, 1, 0);
6297}
6298
6299/* set up GPIO and update auto-muting at initialization */
6300static void alc885_imac24_init_hook(struct hda_codec *codec)
6301{
6302 alc885_macpro_init_hook(codec);
6303 alc885_imac24_automute(codec);
6304}
6305
Kailang Yangdf694da2005-12-05 19:42:22 +01006306/*
6307 * generic initialization of ADC, input mixers and output mixers
6308 */
6309static struct hda_verb alc882_auto_init_verbs[] = {
6310 /*
6311 * Unmute ADC0-2 and set the default input to mic-in
6312 */
6313 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
6314 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6315 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
6316 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6317 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
6318 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6319
Takashi Iwaicb53c622007-08-10 17:21:45 +02006320 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +01006321 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006322 * Note: PASD motherboards uses the Line In 2 as the input for
6323 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01006324 */
6325 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02006326 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6327 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6328 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6329 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6330 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01006331
6332 /*
6333 * Set up output mixers (0x0c - 0x0f)
6334 */
6335 /* set vol=0 to output mixers */
6336 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6337 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6338 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6339 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6340 /* set up input amps for analog loopback */
6341 /* Amp Indices: DAC = 0, mixer = 1 */
6342 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6343 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6344 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6345 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6346 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6347 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6348 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6349 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6350 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6351 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6352
6353 /* FIXME: use matrix-type input source selection */
6354 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
6355 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
6356 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6357 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
6358 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
6359 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
6360 /* Input mixer2 */
6361 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6362 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
6363 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
6364 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
6365 /* Input mixer3 */
6366 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6367 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
6368 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
6369 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
6370
6371 { }
6372};
6373
Takashi Iwaicb53c622007-08-10 17:21:45 +02006374#ifdef CONFIG_SND_HDA_POWER_SAVE
6375#define alc882_loopbacks alc880_loopbacks
6376#endif
6377
Kailang Yangdf694da2005-12-05 19:42:22 +01006378/* pcm configuration: identiacal with ALC880 */
6379#define alc882_pcm_analog_playback alc880_pcm_analog_playback
6380#define alc882_pcm_analog_capture alc880_pcm_analog_capture
6381#define alc882_pcm_digital_playback alc880_pcm_digital_playback
6382#define alc882_pcm_digital_capture alc880_pcm_digital_capture
6383
6384/*
6385 * configuration and preset
6386 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006387static const char *alc882_models[ALC882_MODEL_LAST] = {
6388 [ALC882_3ST_DIG] = "3stack-dig",
6389 [ALC882_6ST_DIG] = "6stack-dig",
6390 [ALC882_ARIMA] = "arima",
Kailang Yangbdd148a2007-05-08 15:19:08 +02006391 [ALC882_W2JC] = "w2jc",
Takashi Iwai0438a002007-09-06 14:54:11 +02006392 [ALC882_TARGA] = "targa",
6393 [ALC882_ASUS_A7J] = "asus-a7j",
6394 [ALC882_ASUS_A7M] = "asus-a7m",
Tobin Davis9102cd12006-12-15 10:02:12 +01006395 [ALC885_MACPRO] = "macpro",
Takashi Iwai87350ad2007-08-16 18:19:38 +02006396 [ALC885_MBP3] = "mbp3",
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006397 [ALC885_IMAC24] = "imac24",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006398 [ALC882_AUTO] = "auto",
6399};
6400
6401static struct snd_pci_quirk alc882_cfg_tbl[] = {
6402 SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG),
Kailang Yang272a5272007-05-14 11:00:38 +02006403 SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J),
Kailang Yangac8842a2007-09-20 12:51:39 +02006404 SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J),
Takashi Iwai914759b2007-09-06 14:52:04 +02006405 SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01006406 SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC),
Claudio Matsuokac5d9f1c2007-07-19 23:18:32 +02006407 SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG),
Tobin Davis7b9470d2006-12-28 13:56:48 +01006408 SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01006409 SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG),
Jiang zhe44447042008-01-28 12:28:24 +01006410 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01006411 SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */
6412 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG),
6413 SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA),
Kailang Yangdf694da2005-12-05 19:42:22 +01006414 {}
6415};
6416
6417static struct alc_config_preset alc882_presets[] = {
6418 [ALC882_3ST_DIG] = {
6419 .mixers = { alc882_base_mixer },
6420 .init_verbs = { alc882_init_verbs },
6421 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6422 .dac_nids = alc882_dac_nids,
6423 .dig_out_nid = ALC882_DIGOUT_NID,
Kailang Yangdf694da2005-12-05 19:42:22 +01006424 .dig_in_nid = ALC882_DIGIN_NID,
6425 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
6426 .channel_mode = alc882_ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02006427 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01006428 .input_mux = &alc882_capture_source,
6429 },
6430 [ALC882_6ST_DIG] = {
6431 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
6432 .init_verbs = { alc882_init_verbs },
6433 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6434 .dac_nids = alc882_dac_nids,
6435 .dig_out_nid = ALC882_DIGOUT_NID,
Kailang Yangdf694da2005-12-05 19:42:22 +01006436 .dig_in_nid = ALC882_DIGIN_NID,
6437 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
6438 .channel_mode = alc882_sixstack_modes,
6439 .input_mux = &alc882_capture_source,
6440 },
Takashi Iwai4b146cb2006-07-28 14:42:36 +02006441 [ALC882_ARIMA] = {
6442 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
6443 .init_verbs = { alc882_init_verbs, alc882_eapd_verbs },
6444 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6445 .dac_nids = alc882_dac_nids,
6446 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
6447 .channel_mode = alc882_sixstack_modes,
6448 .input_mux = &alc882_capture_source,
6449 },
Kailang Yangbdd148a2007-05-08 15:19:08 +02006450 [ALC882_W2JC] = {
6451 .mixers = { alc882_w2jc_mixer, alc882_chmode_mixer },
6452 .init_verbs = { alc882_init_verbs, alc882_eapd_verbs,
6453 alc880_gpio1_init_verbs },
6454 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6455 .dac_nids = alc882_dac_nids,
6456 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
6457 .channel_mode = alc880_threestack_modes,
6458 .need_dac_fix = 1,
6459 .input_mux = &alc882_capture_source,
6460 .dig_out_nid = ALC882_DIGOUT_NID,
6461 },
Takashi Iwai87350ad2007-08-16 18:19:38 +02006462 [ALC885_MBP3] = {
6463 .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer },
6464 .init_verbs = { alc885_mbp3_init_verbs,
6465 alc880_gpio1_init_verbs },
6466 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6467 .dac_nids = alc882_dac_nids,
6468 .channel_mode = alc885_mbp_6ch_modes,
6469 .num_channel_mode = ARRAY_SIZE(alc885_mbp_6ch_modes),
6470 .input_mux = &alc882_capture_source,
6471 .dig_out_nid = ALC882_DIGOUT_NID,
6472 .dig_in_nid = ALC882_DIGIN_NID,
6473 .unsol_event = alc885_mbp3_unsol_event,
6474 .init_hook = alc885_mbp3_automute,
6475 },
Tobin Davis9102cd12006-12-15 10:02:12 +01006476 [ALC885_MACPRO] = {
6477 .mixers = { alc882_macpro_mixer },
6478 .init_verbs = { alc882_macpro_init_verbs },
6479 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6480 .dac_nids = alc882_dac_nids,
6481 .dig_out_nid = ALC882_DIGOUT_NID,
6482 .dig_in_nid = ALC882_DIGIN_NID,
6483 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
6484 .channel_mode = alc882_ch_modes,
6485 .input_mux = &alc882_capture_source,
Takashi Iwai7debbe52007-08-16 15:01:03 +02006486 .init_hook = alc885_macpro_init_hook,
Tobin Davis9102cd12006-12-15 10:02:12 +01006487 },
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006488 [ALC885_IMAC24] = {
6489 .mixers = { alc885_imac24_mixer },
6490 .init_verbs = { alc885_imac24_init_verbs },
6491 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6492 .dac_nids = alc882_dac_nids,
6493 .dig_out_nid = ALC882_DIGOUT_NID,
6494 .dig_in_nid = ALC882_DIGIN_NID,
6495 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
6496 .channel_mode = alc882_ch_modes,
6497 .input_mux = &alc882_capture_source,
6498 .unsol_event = alc885_imac24_unsol_event,
Takashi Iwai7debbe52007-08-16 15:01:03 +02006499 .init_hook = alc885_imac24_init_hook,
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006500 },
Kailang Yang272a5272007-05-14 11:00:38 +02006501 [ALC882_TARGA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006502 .mixers = { alc882_targa_mixer, alc882_chmode_mixer },
Kailang Yang272a5272007-05-14 11:00:38 +02006503 .init_verbs = { alc882_init_verbs, alc882_targa_verbs},
6504 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6505 .dac_nids = alc882_dac_nids,
6506 .dig_out_nid = ALC882_DIGOUT_NID,
6507 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
6508 .adc_nids = alc882_adc_nids,
Takashi Iwaie1406342008-02-11 18:32:32 +01006509 .capsrc_nids = alc882_capsrc_nids,
Kailang Yang272a5272007-05-14 11:00:38 +02006510 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
6511 .channel_mode = alc882_3ST_6ch_modes,
6512 .need_dac_fix = 1,
6513 .input_mux = &alc882_capture_source,
6514 .unsol_event = alc882_targa_unsol_event,
6515 .init_hook = alc882_targa_automute,
6516 },
6517 [ALC882_ASUS_A7J] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006518 .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer },
Kailang Yang272a5272007-05-14 11:00:38 +02006519 .init_verbs = { alc882_init_verbs, alc882_asus_a7j_verbs},
6520 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6521 .dac_nids = alc882_dac_nids,
6522 .dig_out_nid = ALC882_DIGOUT_NID,
6523 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
6524 .adc_nids = alc882_adc_nids,
Takashi Iwaie1406342008-02-11 18:32:32 +01006525 .capsrc_nids = alc882_capsrc_nids,
Kailang Yang272a5272007-05-14 11:00:38 +02006526 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
6527 .channel_mode = alc882_3ST_6ch_modes,
6528 .need_dac_fix = 1,
6529 .input_mux = &alc882_capture_source,
Kailang Yangea1fb292008-08-26 12:58:38 +02006530 },
Takashi Iwai914759b2007-09-06 14:52:04 +02006531 [ALC882_ASUS_A7M] = {
6532 .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer },
6533 .init_verbs = { alc882_init_verbs, alc882_eapd_verbs,
6534 alc880_gpio1_init_verbs,
6535 alc882_asus_a7m_verbs },
6536 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6537 .dac_nids = alc882_dac_nids,
6538 .dig_out_nid = ALC882_DIGOUT_NID,
6539 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
6540 .channel_mode = alc880_threestack_modes,
6541 .need_dac_fix = 1,
6542 .input_mux = &alc882_capture_source,
Kailang Yangea1fb292008-08-26 12:58:38 +02006543 },
Kailang Yangdf694da2005-12-05 19:42:22 +01006544};
6545
6546
6547/*
Takashi Iwaif95474e2007-07-10 00:47:43 +02006548 * Pin config fixes
6549 */
Kailang Yangea1fb292008-08-26 12:58:38 +02006550enum {
Takashi Iwaif95474e2007-07-10 00:47:43 +02006551 PINFIX_ABIT_AW9D_MAX
6552};
6553
6554static struct alc_pincfg alc882_abit_aw9d_pinfix[] = {
6555 { 0x15, 0x01080104 }, /* side */
6556 { 0x16, 0x01011012 }, /* rear */
6557 { 0x17, 0x01016011 }, /* clfe */
6558 { }
6559};
6560
6561static const struct alc_pincfg *alc882_pin_fixes[] = {
6562 [PINFIX_ABIT_AW9D_MAX] = alc882_abit_aw9d_pinfix,
6563};
6564
6565static struct snd_pci_quirk alc882_pinfix_tbl[] = {
6566 SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
6567 {}
6568};
6569
6570/*
Kailang Yangdf694da2005-12-05 19:42:22 +01006571 * BIOS auto configuration
6572 */
6573static void alc882_auto_set_output_and_unmute(struct hda_codec *codec,
6574 hda_nid_t nid, int pin_type,
6575 int dac_idx)
6576{
6577 /* set as output */
6578 struct alc_spec *spec = codec->spec;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006579 int idx;
6580
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006581 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01006582 if (spec->multiout.dac_nids[dac_idx] == 0x25)
6583 idx = 4;
6584 else
6585 idx = spec->multiout.dac_nids[dac_idx] - 2;
Kailang Yangdf694da2005-12-05 19:42:22 +01006586 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
6587
6588}
6589
6590static void alc882_auto_init_multi_out(struct hda_codec *codec)
6591{
6592 struct alc_spec *spec = codec->spec;
6593 int i;
6594
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006595 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Kailang Yangdf694da2005-12-05 19:42:22 +01006596 for (i = 0; i <= HDA_SIDE; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006597 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02006598 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01006599 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02006600 alc882_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006601 i);
Kailang Yangdf694da2005-12-05 19:42:22 +01006602 }
6603}
6604
6605static void alc882_auto_init_hp_out(struct hda_codec *codec)
6606{
6607 struct alc_spec *spec = codec->spec;
6608 hda_nid_t pin;
6609
Takashi Iwaieb06ed82006-09-20 17:10:27 +02006610 pin = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006611 if (pin) /* connect to front */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006612 /* use dac 0 */
6613 alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006614 pin = spec->autocfg.speaker_pins[0];
6615 if (pin)
6616 alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Kailang Yangdf694da2005-12-05 19:42:22 +01006617}
6618
6619#define alc882_is_input_pin(nid) alc880_is_input_pin(nid)
6620#define ALC882_PIN_CD_NID ALC880_PIN_CD_NID
6621
6622static void alc882_auto_init_analog_input(struct hda_codec *codec)
6623{
6624 struct alc_spec *spec = codec->spec;
6625 int i;
6626
6627 for (i = 0; i < AUTO_PIN_LAST; i++) {
6628 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwai7194cae2008-03-06 16:58:17 +01006629 unsigned int vref;
6630 if (!nid)
6631 continue;
6632 vref = PIN_IN;
6633 if (1 /*i <= AUTO_PIN_FRONT_MIC*/) {
Kailang Yang531240f2008-05-27 12:10:25 +02006634 unsigned int pincap;
6635 pincap = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
6636 if ((pincap >> AC_PINCAP_VREF_SHIFT) &
Takashi Iwai7194cae2008-03-06 16:58:17 +01006637 AC_PINCAP_VREF_80)
6638 vref = PIN_VREF80;
Kailang Yangdf694da2005-12-05 19:42:22 +01006639 }
Takashi Iwai7194cae2008-03-06 16:58:17 +01006640 snd_hda_codec_write(codec, nid, 0,
6641 AC_VERB_SET_PIN_WIDGET_CONTROL, vref);
6642 if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
6643 snd_hda_codec_write(codec, nid, 0,
6644 AC_VERB_SET_AMP_GAIN_MUTE,
6645 AMP_OUT_MUTE);
Kailang Yangdf694da2005-12-05 19:42:22 +01006646 }
6647}
6648
Takashi Iwaif511b012008-08-15 16:46:42 +02006649static void alc882_auto_init_input_src(struct hda_codec *codec)
6650{
6651 struct alc_spec *spec = codec->spec;
6652 const struct hda_input_mux *imux = spec->input_mux;
6653 int c;
6654
6655 for (c = 0; c < spec->num_adc_nids; c++) {
6656 hda_nid_t conn_list[HDA_MAX_NUM_INPUTS];
6657 hda_nid_t nid = spec->capsrc_nids[c];
6658 int conns, mute, idx, item;
6659
6660 conns = snd_hda_get_connections(codec, nid, conn_list,
6661 ARRAY_SIZE(conn_list));
6662 if (conns < 0)
6663 continue;
6664 for (idx = 0; idx < conns; idx++) {
6665 /* if the current connection is the selected one,
6666 * unmute it as default - otherwise mute it
6667 */
6668 mute = AMP_IN_MUTE(idx);
6669 for (item = 0; item < imux->num_items; item++) {
6670 if (imux->items[item].index == idx) {
6671 if (spec->cur_mux[c] == item)
6672 mute = AMP_IN_UNMUTE(idx);
6673 break;
6674 }
6675 }
6676 snd_hda_codec_write(codec, nid, 0,
6677 AC_VERB_SET_AMP_GAIN_MUTE, mute);
6678 }
6679 }
6680}
6681
Takashi Iwai776e1842007-08-29 15:07:11 +02006682/* add mic boosts if needed */
6683static int alc_auto_add_mic_boost(struct hda_codec *codec)
6684{
6685 struct alc_spec *spec = codec->spec;
6686 int err;
6687 hda_nid_t nid;
6688
6689 nid = spec->autocfg.input_pins[AUTO_PIN_MIC];
Takashi Iwaice22e032008-01-11 17:38:35 +01006690 if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
Takashi Iwai776e1842007-08-29 15:07:11 +02006691 err = add_control(spec, ALC_CTL_WIDGET_VOL,
6692 "Mic Boost",
6693 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
6694 if (err < 0)
6695 return err;
6696 }
6697 nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC];
Takashi Iwaice22e032008-01-11 17:38:35 +01006698 if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
Takashi Iwai776e1842007-08-29 15:07:11 +02006699 err = add_control(spec, ALC_CTL_WIDGET_VOL,
6700 "Front Mic Boost",
6701 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
6702 if (err < 0)
6703 return err;
6704 }
6705 return 0;
6706}
6707
Kailang Yangdf694da2005-12-05 19:42:22 +01006708/* almost identical with ALC880 parser... */
6709static int alc882_parse_auto_config(struct hda_codec *codec)
6710{
6711 struct alc_spec *spec = codec->spec;
6712 int err = alc880_parse_auto_config(codec);
6713
6714 if (err < 0)
6715 return err;
Takashi Iwai776e1842007-08-29 15:07:11 +02006716 else if (!err)
6717 return 0; /* no config found */
6718
6719 err = alc_auto_add_mic_boost(codec);
6720 if (err < 0)
6721 return err;
6722
6723 /* hack - override the init verbs */
6724 spec->init_verbs[0] = alc882_auto_init_verbs;
6725
6726 return 1; /* config found */
Kailang Yangdf694da2005-12-05 19:42:22 +01006727}
6728
Takashi Iwaiae6b8132006-03-03 16:47:17 +01006729/* additional initialization for auto-configuration model */
6730static void alc882_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01006731{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006732 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01006733 alc882_auto_init_multi_out(codec);
6734 alc882_auto_init_hp_out(codec);
6735 alc882_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +02006736 alc882_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006737 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02006738 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01006739}
6740
Takashi Iwai7943a8a2008-04-16 17:29:09 +02006741static int patch_alc883(struct hda_codec *codec); /* called in patch_alc882() */
6742
Linus Torvalds1da177e2005-04-16 15:20:36 -07006743static int patch_alc882(struct hda_codec *codec)
6744{
6745 struct alc_spec *spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01006746 int err, board_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006747
Takashi Iwaie560d8d2005-09-09 14:21:46 +02006748 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006749 if (spec == NULL)
6750 return -ENOMEM;
6751
Linus Torvalds1da177e2005-04-16 15:20:36 -07006752 codec->spec = spec;
6753
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006754 board_config = snd_hda_check_board_config(codec, ALC882_MODEL_LAST,
6755 alc882_models,
6756 alc882_cfg_tbl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006757
Kailang Yangdf694da2005-12-05 19:42:22 +01006758 if (board_config < 0 || board_config >= ALC882_MODEL_LAST) {
Tobin Davis081d17c2007-02-15 17:46:18 +01006759 /* Pick up systems that don't supply PCI SSID */
6760 switch (codec->subsystem_id) {
6761 case 0x106b0c00: /* Mac Pro */
6762 board_config = ALC885_MACPRO;
6763 break;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006764 case 0x106b1000: /* iMac 24 */
Peter Korsgaardf3911c52008-09-27 09:13:45 +02006765 case 0x106b2800: /* AppleTV */
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006766 board_config = ALC885_IMAC24;
6767 break;
Takashi Iwaic7e07572008-06-26 14:42:51 +02006768 case 0x106b00a1: /* Macbook (might be wrong - PCI SSID?) */
David Woodhouse9c95c432008-09-18 13:37:13 -07006769 case 0x106b00a4: /* MacbookPro4,1 */
Takashi Iwai87350ad2007-08-16 18:19:38 +02006770 case 0x106b2c00: /* Macbook Pro rev3 */
Takashi Iwaic7e07572008-06-26 14:42:51 +02006771 case 0x106b3600: /* Macbook 3.1 */
Takashi Iwai87350ad2007-08-16 18:19:38 +02006772 board_config = ALC885_MBP3;
6773 break;
Tobin Davis081d17c2007-02-15 17:46:18 +01006774 default:
Takashi Iwai7943a8a2008-04-16 17:29:09 +02006775 /* ALC889A is handled better as ALC888-compatible */
Clive Messer669faba2008-09-30 15:49:13 +02006776 if (codec->revision_id == 0x100101 ||
6777 codec->revision_id == 0x100103) {
Takashi Iwai7943a8a2008-04-16 17:29:09 +02006778 alc_free(codec);
6779 return patch_alc883(codec);
6780 }
Tobin Davis081d17c2007-02-15 17:46:18 +01006781 printk(KERN_INFO "hda_codec: Unknown model for ALC882, "
6782 "trying auto-probe from BIOS...\n");
6783 board_config = ALC882_AUTO;
6784 }
Kailang Yangdf694da2005-12-05 19:42:22 +01006785 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006786
Takashi Iwaif95474e2007-07-10 00:47:43 +02006787 alc_fix_pincfg(codec, alc882_pinfix_tbl, alc882_pin_fixes);
6788
Kailang Yangdf694da2005-12-05 19:42:22 +01006789 if (board_config == ALC882_AUTO) {
6790 /* automatic parse from the BIOS config */
6791 err = alc882_parse_auto_config(codec);
6792 if (err < 0) {
6793 alc_free(codec);
6794 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006795 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006796 printk(KERN_INFO
6797 "hda_codec: Cannot set up configuration "
6798 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01006799 board_config = ALC882_3ST_DIG;
6800 }
6801 }
6802
6803 if (board_config != ALC882_AUTO)
6804 setup_preset(spec, &alc882_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006805
Kailang Yang2f893282008-05-27 12:14:47 +02006806 if (codec->vendor_id == 0x10ec0885) {
6807 spec->stream_name_analog = "ALC885 Analog";
6808 spec->stream_name_digital = "ALC885 Digital";
6809 } else {
6810 spec->stream_name_analog = "ALC882 Analog";
6811 spec->stream_name_digital = "ALC882 Digital";
6812 }
6813
Kailang Yangdf694da2005-12-05 19:42:22 +01006814 spec->stream_analog_playback = &alc882_pcm_analog_playback;
6815 spec->stream_analog_capture = &alc882_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01006816 /* FIXME: setup DAC5 */
6817 /*spec->stream_analog_alt_playback = &alc880_pcm_analog_alt_playback;*/
6818 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006819
Kailang Yangdf694da2005-12-05 19:42:22 +01006820 spec->stream_digital_playback = &alc882_pcm_digital_playback;
6821 spec->stream_digital_capture = &alc882_pcm_digital_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006822
Takashi Iwai54cbc9a2008-10-31 15:24:04 +01006823 spec->is_mix_capture = 1; /* matrix-style capture */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006824 if (!spec->adc_nids && spec->input_mux) {
Kailang Yangdf694da2005-12-05 19:42:22 +01006825 /* check whether NID 0x07 is valid */
Takashi Iwai4a471b72005-12-07 13:56:29 +01006826 unsigned int wcap = get_wcaps(codec, 0x07);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006827 /* get type */
6828 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Kailang Yangdf694da2005-12-05 19:42:22 +01006829 if (wcap != AC_WID_AUD_IN) {
6830 spec->adc_nids = alc882_adc_nids_alt;
6831 spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids_alt);
Takashi Iwaie1406342008-02-11 18:32:32 +01006832 spec->capsrc_nids = alc882_capsrc_nids_alt;
Kailang Yangdf694da2005-12-05 19:42:22 +01006833 } else {
6834 spec->adc_nids = alc882_adc_nids;
6835 spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids);
Takashi Iwaie1406342008-02-11 18:32:32 +01006836 spec->capsrc_nids = alc882_capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +01006837 }
6838 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006839 set_capture_mixer(spec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006840
Takashi Iwai2134ea42008-01-10 16:53:55 +01006841 spec->vmaster_nid = 0x0c;
6842
Linus Torvalds1da177e2005-04-16 15:20:36 -07006843 codec->patch_ops = alc_patch_ops;
Kailang Yangdf694da2005-12-05 19:42:22 +01006844 if (board_config == ALC882_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01006845 spec->init_hook = alc882_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02006846#ifdef CONFIG_SND_HDA_POWER_SAVE
6847 if (!spec->loopback.amplist)
6848 spec->loopback.amplist = alc882_loopbacks;
6849#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006850
6851 return 0;
6852}
6853
6854/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006855 * ALC883 support
6856 *
6857 * ALC883 is almost identical with ALC880 but has cleaner and more flexible
6858 * configuration. Each pin widget can choose any input DACs and a mixer.
6859 * Each ADC is connected from a mixer of all inputs. This makes possible
6860 * 6-channel independent captures.
6861 *
6862 * In addition, an independent DAC for the multi-playback (not used in this
6863 * driver yet).
6864 */
6865#define ALC883_DIGOUT_NID 0x06
6866#define ALC883_DIGIN_NID 0x0a
6867
6868static hda_nid_t alc883_dac_nids[4] = {
6869 /* front, rear, clfe, rear_surr */
Herton Ronaldo Krzesinskif32a19e2008-03-18 09:27:08 +01006870 0x02, 0x03, 0x04, 0x05
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006871};
6872
6873static hda_nid_t alc883_adc_nids[2] = {
6874 /* ADC1-2 */
6875 0x08, 0x09,
6876};
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006877
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006878static hda_nid_t alc883_adc_nids_alt[1] = {
6879 /* ADC1 */
6880 0x08,
6881};
6882
Takashi Iwaie1406342008-02-11 18:32:32 +01006883static hda_nid_t alc883_capsrc_nids[2] = { 0x23, 0x22 };
6884
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006885/* input MUX */
6886/* FIXME: should be a matrix-type input source selection */
6887
6888static struct hda_input_mux alc883_capture_source = {
6889 .num_items = 4,
6890 .items = {
6891 { "Mic", 0x0 },
6892 { "Front Mic", 0x1 },
6893 { "Line", 0x2 },
6894 { "CD", 0x4 },
6895 },
6896};
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006897
Jiang zhe17bba1b2008-06-04 12:11:07 +02006898static struct hda_input_mux alc883_3stack_6ch_intel = {
6899 .num_items = 4,
6900 .items = {
6901 { "Mic", 0x1 },
6902 { "Front Mic", 0x0 },
6903 { "Line", 0x2 },
6904 { "CD", 0x4 },
6905 },
6906};
6907
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006908static struct hda_input_mux alc883_lenovo_101e_capture_source = {
6909 .num_items = 2,
6910 .items = {
6911 { "Mic", 0x1 },
6912 { "Line", 0x2 },
6913 },
6914};
6915
Kailang Yang272a5272007-05-14 11:00:38 +02006916static struct hda_input_mux alc883_lenovo_nb0763_capture_source = {
6917 .num_items = 4,
6918 .items = {
6919 { "Mic", 0x0 },
6920 { "iMic", 0x1 },
6921 { "Line", 0x2 },
6922 { "CD", 0x4 },
6923 },
6924};
6925
Jiang zhefb97dc62008-03-06 11:07:11 +01006926static struct hda_input_mux alc883_fujitsu_pi2515_capture_source = {
6927 .num_items = 2,
6928 .items = {
6929 { "Mic", 0x0 },
6930 { "Int Mic", 0x1 },
6931 },
6932};
6933
Kailang Yange2757d52008-08-26 13:17:46 +02006934static struct hda_input_mux alc883_lenovo_sky_capture_source = {
6935 .num_items = 3,
6936 .items = {
6937 { "Mic", 0x0 },
6938 { "Front Mic", 0x1 },
6939 { "Line", 0x4 },
6940 },
6941};
6942
6943static struct hda_input_mux alc883_asus_eee1601_capture_source = {
6944 .num_items = 2,
6945 .items = {
6946 { "Mic", 0x0 },
6947 { "Line", 0x2 },
6948 },
6949};
6950
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006951/*
6952 * 2ch mode
6953 */
6954static struct hda_channel_mode alc883_3ST_2ch_modes[1] = {
6955 { 2, NULL }
6956};
6957
6958/*
6959 * 2ch mode
6960 */
6961static struct hda_verb alc883_3ST_ch2_init[] = {
6962 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
6963 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6964 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
6965 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6966 { } /* end */
6967};
6968
6969/*
Tobin Davisb2011312007-09-17 12:45:11 +02006970 * 4ch mode
6971 */
6972static struct hda_verb alc883_3ST_ch4_init[] = {
6973 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
6974 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
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
6981/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006982 * 6ch mode
6983 */
6984static struct hda_verb alc883_3ST_ch6_init[] = {
6985 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6986 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6987 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
6988 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6989 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6990 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6991 { } /* end */
6992};
6993
Tobin Davisb2011312007-09-17 12:45:11 +02006994static struct hda_channel_mode alc883_3ST_6ch_modes[3] = {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006995 { 2, alc883_3ST_ch2_init },
Tobin Davisb2011312007-09-17 12:45:11 +02006996 { 4, alc883_3ST_ch4_init },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006997 { 6, alc883_3ST_ch6_init },
6998};
6999
7000/*
Jiang zhe17bba1b2008-06-04 12:11:07 +02007001 * 2ch mode
7002 */
7003static struct hda_verb alc883_3ST_ch2_intel_init[] = {
7004 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7005 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7006 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7007 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7008 { } /* end */
7009};
7010
7011/*
7012 * 4ch mode
7013 */
7014static struct hda_verb alc883_3ST_ch4_intel_init[] = {
7015 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7016 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
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
7023/*
7024 * 6ch mode
7025 */
7026static struct hda_verb alc883_3ST_ch6_intel_init[] = {
7027 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7028 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7029 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x02 },
7030 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7031 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7032 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7033 { } /* end */
7034};
7035
7036static struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = {
7037 { 2, alc883_3ST_ch2_intel_init },
7038 { 4, alc883_3ST_ch4_intel_init },
7039 { 6, alc883_3ST_ch6_intel_init },
7040};
7041
7042/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007043 * 6ch mode
7044 */
7045static struct hda_verb alc883_sixstack_ch6_init[] = {
7046 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
7047 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7048 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7049 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7050 { } /* end */
7051};
7052
7053/*
7054 * 8ch mode
7055 */
7056static struct hda_verb alc883_sixstack_ch8_init[] = {
7057 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7058 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7059 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7060 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7061 { } /* end */
7062};
7063
7064static struct hda_channel_mode alc883_sixstack_modes[2] = {
7065 { 6, alc883_sixstack_ch6_init },
7066 { 8, alc883_sixstack_ch8_init },
7067};
7068
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01007069static struct hda_verb alc883_medion_eapd_verbs[] = {
7070 /* eanable EAPD on medion laptop */
7071 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
7072 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
7073 { }
7074};
7075
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007076/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
7077 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
7078 */
7079
7080static struct snd_kcontrol_new alc883_base_mixer[] = {
7081 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7082 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7083 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7084 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
7085 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7086 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
7087 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7088 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
7089 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
7090 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
7091 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7092 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7093 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7094 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7095 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7096 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007097 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007098 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7099 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007100 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007101 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
7102 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
7103 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007104 { } /* end */
7105};
7106
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01007107static struct snd_kcontrol_new alc883_mitac_mixer[] = {
7108 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7109 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7110 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7111 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
7112 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7113 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
7114 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
7115 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7116 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7117 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7118 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7119 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
7120 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01007121 { } /* end */
7122};
7123
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007124static struct snd_kcontrol_new alc883_clevo_m720_mixer[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01007125 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7126 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
7127 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7128 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
7129 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7130 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7131 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7132 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7133 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
7134 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Jiang zhe368c7a92008-03-04 11:20:33 +01007135 { } /* end */
7136};
7137
Jiang zhefb97dc62008-03-06 11:07:11 +01007138static struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = {
7139 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7140 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
7141 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7142 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
7143 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7144 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7145 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7146 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7147 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
7148 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Jiang zhefb97dc62008-03-06 11:07:11 +01007149 { } /* end */
7150};
7151
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007152static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = {
7153 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7154 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7155 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7156 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7157 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7158 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7159 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7160 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007161 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007162 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7163 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007164 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007165 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
7166 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
7167 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007168 { } /* end */
7169};
7170
7171static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
7172 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7173 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7174 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7175 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
7176 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7177 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
7178 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7179 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
7180 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7181 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7182 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7183 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7184 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7185 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007186 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007187 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7188 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007189 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007190 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
7191 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
7192 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007193 { } /* end */
7194};
7195
Jiang zhe17bba1b2008-06-04 12:11:07 +02007196static struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = {
7197 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7198 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7199 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7200 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
7201 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
7202 HDA_OUTPUT),
7203 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
7204 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7205 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
7206 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
7207 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7208 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7209 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7210 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7211 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7212 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
7213 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
7214 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7215 HDA_CODEC_VOLUME("Front Mic Boost", 0x18, 0, HDA_INPUT),
7216 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7217 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
7218 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Jiang zhe17bba1b2008-06-04 12:11:07 +02007219 { } /* end */
7220};
7221
Takashi Iwaid1d985f2006-11-23 19:27:12 +01007222static struct snd_kcontrol_new alc883_fivestack_mixer[] = {
Tobin Davisc07584c2006-10-13 12:32:16 +02007223 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02007224 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007225 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02007226 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007227 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7228 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02007229 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7230 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007231 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7232 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7233 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7234 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7235 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7236 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007237 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007238 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7239 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007240 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007241 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
7242 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
7243 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007244 { } /* end */
7245};
7246
Kailang Yangccc656c2006-10-17 12:32:26 +02007247static struct snd_kcontrol_new alc883_tagra_mixer[] = {
7248 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7249 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7250 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7251 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7252 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
7253 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7254 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
7255 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7256 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
7257 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7258 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7259 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7260 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7261 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007262 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02007263 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02007264 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007265};
Kailang Yangccc656c2006-10-17 12:32:26 +02007266
7267static struct snd_kcontrol_new alc883_tagra_2ch_mixer[] = {
7268 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7269 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7270 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7271 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7272 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7273 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007274 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02007275 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Jiang zhe4383fae2008-04-14 12:58:57 +02007276 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7277 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
7278 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02007279 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007280};
Kailang Yangccc656c2006-10-17 12:32:26 +02007281
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007282static struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = {
7283 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7284 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01007285 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7286 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007287 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7288 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7289 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7290 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007291 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007292};
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007293
Kailang Yang272a5272007-05-14 11:00:38 +02007294static struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = {
7295 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7296 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
7297 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 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("iMic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7303 HDA_CODEC_MUTE("iMic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02007304 { } /* end */
7305};
7306
7307static struct snd_kcontrol_new alc883_medion_md2_mixer[] = {
7308 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7309 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7310 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
7311 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7312 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7313 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7314 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7315 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7316 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02007317 { } /* end */
Kailang Yangea1fb292008-08-26 12:58:38 +02007318};
Kailang Yang272a5272007-05-14 11:00:38 +02007319
Tobin Davis2880a862007-08-07 11:50:26 +02007320static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = {
Kailang Yangd1a991a2007-08-15 16:21:59 +02007321 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7322 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02007323 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02007324 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7325 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Kailang Yangd1a991a2007-08-15 16:21:59 +02007326 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7327 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7328 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02007329 { } /* end */
Kailang Yangd1a991a2007-08-15 16:21:59 +02007330};
Tobin Davis2880a862007-08-07 11:50:26 +02007331
Kailang Yange2757d52008-08-26 13:17:46 +02007332static struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = {
7333 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7334 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7335 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
7336 HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
7337 HDA_CODEC_VOLUME_MONO("Center Playback Volume",
7338 0x0d, 1, 0x0, HDA_OUTPUT),
7339 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
7340 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
7341 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
7342 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
7343 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
7344 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7345 HDA_CODEC_MUTE("iSpeaker Playback Switch", 0x1a, 0x0, HDA_OUTPUT),
7346 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7347 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7348 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7349 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7350 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7351 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7352 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7353 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7354 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
7355 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02007356 { } /* end */
7357};
7358
7359static struct hda_bind_ctls alc883_bind_cap_vol = {
7360 .ops = &snd_hda_bind_vol,
7361 .values = {
7362 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
7363 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
7364 0
7365 },
7366};
7367
7368static struct hda_bind_ctls alc883_bind_cap_switch = {
7369 .ops = &snd_hda_bind_sw,
7370 .values = {
7371 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
7372 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
7373 0
7374 },
7375};
7376
7377static struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = {
7378 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7379 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7380 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7381 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7382 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7383 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7384 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7385 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007386 { } /* end */
7387};
7388
7389static struct snd_kcontrol_new alc883_asus_eee1601_cap_mixer[] = {
Kailang Yange2757d52008-08-26 13:17:46 +02007390 HDA_BIND_VOL("Capture Volume", &alc883_bind_cap_vol),
7391 HDA_BIND_SW("Capture Switch", &alc883_bind_cap_switch),
7392 {
7393 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7394 /* .name = "Capture Source", */
7395 .name = "Input Source",
7396 .count = 1,
Takashi Iwai54cbc9a2008-10-31 15:24:04 +01007397 .info = alc_mux_enum_info,
7398 .get = alc_mux_enum_get,
7399 .put = alc_mux_enum_put,
Kailang Yange2757d52008-08-26 13:17:46 +02007400 },
7401 { } /* end */
7402};
7403
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007404static struct snd_kcontrol_new alc883_chmode_mixer[] = {
7405 {
7406 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7407 .name = "Channel Mode",
7408 .info = alc_ch_mode_info,
7409 .get = alc_ch_mode_get,
7410 .put = alc_ch_mode_put,
7411 },
7412 { } /* end */
7413};
7414
7415static struct hda_verb alc883_init_verbs[] = {
7416 /* ADC1: mute amp left and right */
Kailang Yange2757d52008-08-26 13:17:46 +02007417 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007418 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
7419 /* ADC2: mute amp left and right */
7420 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7421 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
7422 /* Front mixer: unmute input/output amp left and right (volume = 0) */
7423 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7424 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7425 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7426 /* Rear mixer */
7427 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7428 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7429 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7430 /* CLFE mixer */
7431 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7432 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7433 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7434 /* Side mixer */
7435 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7436 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7437 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7438
Takashi Iwaicb53c622007-08-10 17:21:45 +02007439 /* mute analog input loopbacks */
7440 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7441 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7442 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7443 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7444 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007445
7446 /* Front Pin: output 0 (0x0c) */
7447 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7448 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7449 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
7450 /* Rear Pin: output 1 (0x0d) */
7451 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7452 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7453 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
7454 /* CLFE Pin: output 2 (0x0e) */
7455 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7456 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7457 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
7458 /* Side Pin: output 3 (0x0f) */
7459 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7460 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7461 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
7462 /* Mic (rear) pin: input vref at 80% */
7463 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7464 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7465 /* Front Mic pin: input vref at 80% */
7466 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7467 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7468 /* Line In pin: input */
7469 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
7470 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7471 /* Line-2 In: Headphone output (output 0 - 0x0c) */
7472 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7473 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7474 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
7475 /* CD pin widget for input */
7476 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
7477
7478 /* FIXME: use matrix-type input source selection */
7479 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
7480 /* Input mixer2 */
7481 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yange2757d52008-08-26 13:17:46 +02007482 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7483 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7484 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007485 /* Input mixer3 */
7486 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yange2757d52008-08-26 13:17:46 +02007487 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7488 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7489 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007490 { }
7491};
7492
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01007493/* toggle speaker-output according to the hp-jack state */
7494static void alc883_mitac_hp_automute(struct hda_codec *codec)
7495{
7496 unsigned int present;
7497
7498 present = snd_hda_codec_read(codec, 0x15, 0,
7499 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7500 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7501 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7502 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
7503 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7504}
7505
7506/* auto-toggle front mic */
7507/*
7508static void alc883_mitac_mic_automute(struct hda_codec *codec)
7509{
7510 unsigned int present;
7511 unsigned char bits;
7512
7513 present = snd_hda_codec_read(codec, 0x18, 0,
7514 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7515 bits = present ? HDA_AMP_MUTE : 0;
7516 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
7517}
7518*/
7519
7520static void alc883_mitac_automute(struct hda_codec *codec)
7521{
7522 alc883_mitac_hp_automute(codec);
7523 /* alc883_mitac_mic_automute(codec); */
7524}
7525
7526static void alc883_mitac_unsol_event(struct hda_codec *codec,
7527 unsigned int res)
7528{
7529 switch (res >> 26) {
7530 case ALC880_HP_EVENT:
7531 alc883_mitac_hp_automute(codec);
7532 break;
7533 case ALC880_MIC_EVENT:
7534 /* alc883_mitac_mic_automute(codec); */
7535 break;
7536 }
7537}
7538
7539static struct hda_verb alc883_mitac_verbs[] = {
7540 /* HP */
7541 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7542 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7543 /* Subwoofer */
7544 {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
7545 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7546
7547 /* enable unsolicited event */
7548 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7549 /* {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, */
7550
7551 { } /* end */
7552};
7553
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007554static struct hda_verb alc883_clevo_m720_verbs[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01007555 /* HP */
7556 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7557 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7558 /* Int speaker */
7559 {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
7560 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7561
7562 /* enable unsolicited event */
7563 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007564 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Jiang zhe368c7a92008-03-04 11:20:33 +01007565
7566 { } /* end */
7567};
7568
Jiang zhefb97dc62008-03-06 11:07:11 +01007569static struct hda_verb alc883_2ch_fujitsu_pi2515_verbs[] = {
7570 /* HP */
7571 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
7572 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7573 /* Subwoofer */
7574 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
7575 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7576
7577 /* enable unsolicited event */
7578 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7579
7580 { } /* end */
7581};
7582
Kailang Yangccc656c2006-10-17 12:32:26 +02007583static struct hda_verb alc883_tagra_verbs[] = {
7584 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7585 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7586
7587 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7588 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02007589
Kailang Yangccc656c2006-10-17 12:32:26 +02007590 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
7591 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
7592 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
7593
7594 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007595 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
7596 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
7597 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
Kailang Yangccc656c2006-10-17 12:32:26 +02007598
7599 { } /* end */
7600};
7601
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007602static struct hda_verb alc883_lenovo_101e_verbs[] = {
7603 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7604 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT|AC_USRSP_EN},
7605 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT|AC_USRSP_EN},
7606 { } /* end */
7607};
7608
Kailang Yang272a5272007-05-14 11:00:38 +02007609static struct hda_verb alc883_lenovo_nb0763_verbs[] = {
7610 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7611 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7612 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7613 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7614 { } /* end */
7615};
7616
7617static struct hda_verb alc888_lenovo_ms7195_verbs[] = {
7618 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7619 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7620 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7621 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT | AC_USRSP_EN},
7622 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7623 { } /* end */
7624};
7625
Kailang Yang189609a2007-08-20 11:31:23 +02007626static struct hda_verb alc883_haier_w66_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
7630 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7631
7632 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
7633 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7634 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7635 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7636 { } /* end */
7637};
7638
Kailang Yange2757d52008-08-26 13:17:46 +02007639static struct hda_verb alc888_lenovo_sky_verbs[] = {
7640 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7641 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7642 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7643 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7644 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7645 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7646 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
7647 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7648 { } /* end */
7649};
7650
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007651static struct hda_verb alc888_3st_hp_verbs[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007652 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */
Herton Ronaldo Krzesinskif32a19e2008-03-18 09:27:08 +01007653 {0x16, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Rear : output 1 (0x0d) */
7654 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* CLFE : output 2 (0x0e) */
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007655 { }
7656};
7657
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007658static struct hda_verb alc888_6st_dell_verbs[] = {
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007659 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7660 { }
7661};
7662
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007663static struct hda_verb alc888_3st_hp_2ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007664 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7665 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7666 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7667 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7668 { }
7669};
7670
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007671static struct hda_verb alc888_3st_hp_6ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007672 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7673 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7674 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7675 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7676 { }
7677};
7678
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007679static struct hda_channel_mode alc888_3st_hp_modes[2] = {
7680 { 2, alc888_3st_hp_2ch_init },
7681 { 6, alc888_3st_hp_6ch_init },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007682};
7683
Kailang Yang272a5272007-05-14 11:00:38 +02007684/* toggle front-jack and RCA according to the hp-jack state */
7685static void alc888_lenovo_ms7195_front_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, 0x1b, 0,
7690 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007691 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7692 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7693 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7694 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02007695}
7696
7697/* toggle RCA according to the front-jack state */
7698static void alc888_lenovo_ms7195_rca_automute(struct hda_codec *codec)
7699{
7700 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02007701
Kailang Yang272a5272007-05-14 11:00:38 +02007702 present = snd_hda_codec_read(codec, 0x14, 0,
7703 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007704 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7705 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02007706}
Takashi Iwai47fd8302007-08-10 17:11:07 +02007707
Kailang Yang272a5272007-05-14 11:00:38 +02007708static void alc883_lenovo_ms7195_unsol_event(struct hda_codec *codec,
7709 unsigned int res)
7710{
7711 if ((res >> 26) == ALC880_HP_EVENT)
7712 alc888_lenovo_ms7195_front_automute(codec);
7713 if ((res >> 26) == ALC880_FRONT_EVENT)
7714 alc888_lenovo_ms7195_rca_automute(codec);
7715}
7716
7717static struct hda_verb alc883_medion_md2_verbs[] = {
7718 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7719 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7720
7721 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7722
7723 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7724 { } /* end */
7725};
7726
7727/* toggle speaker-output according to the hp-jack state */
7728static void alc883_medion_md2_automute(struct hda_codec *codec)
7729{
7730 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02007731
Kailang Yang272a5272007-05-14 11:00:38 +02007732 present = snd_hda_codec_read(codec, 0x14, 0,
7733 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007734 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7735 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02007736}
7737
7738static void alc883_medion_md2_unsol_event(struct hda_codec *codec,
7739 unsigned int res)
7740{
7741 if ((res >> 26) == ALC880_HP_EVENT)
7742 alc883_medion_md2_automute(codec);
7743}
7744
Kailang Yangccc656c2006-10-17 12:32:26 +02007745/* toggle speaker-output according to the hp-jack state */
7746static void alc883_tagra_automute(struct hda_codec *codec)
7747{
7748 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007749 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02007750
7751 present = snd_hda_codec_read(codec, 0x14, 0,
7752 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007753 bits = present ? HDA_AMP_MUTE : 0;
7754 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
7755 HDA_AMP_MUTE, bits);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02007756 snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
7757 present ? 1 : 3);
Kailang Yangccc656c2006-10-17 12:32:26 +02007758}
7759
7760static void alc883_tagra_unsol_event(struct hda_codec *codec, unsigned int res)
7761{
7762 if ((res >> 26) == ALC880_HP_EVENT)
7763 alc883_tagra_automute(codec);
7764}
7765
Jiang zhe368c7a92008-03-04 11:20:33 +01007766/* toggle speaker-output according to the hp-jack state */
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007767static void alc883_clevo_m720_hp_automute(struct hda_codec *codec)
Jiang zhe368c7a92008-03-04 11:20:33 +01007768{
7769 unsigned int present;
7770 unsigned char bits;
7771
7772 present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0)
7773 & AC_PINSENSE_PRESENCE;
7774 bits = present ? HDA_AMP_MUTE : 0;
7775 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7776 HDA_AMP_MUTE, bits);
7777}
7778
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007779static void alc883_clevo_m720_mic_automute(struct hda_codec *codec)
7780{
7781 unsigned int present;
7782
7783 present = snd_hda_codec_read(codec, 0x18, 0,
7784 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7785 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
7786 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7787}
7788
7789static void alc883_clevo_m720_automute(struct hda_codec *codec)
7790{
7791 alc883_clevo_m720_hp_automute(codec);
7792 alc883_clevo_m720_mic_automute(codec);
7793}
7794
7795static void alc883_clevo_m720_unsol_event(struct hda_codec *codec,
Jiang zhe368c7a92008-03-04 11:20:33 +01007796 unsigned int res)
7797{
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007798 switch (res >> 26) {
7799 case ALC880_HP_EVENT:
7800 alc883_clevo_m720_hp_automute(codec);
7801 break;
7802 case ALC880_MIC_EVENT:
7803 alc883_clevo_m720_mic_automute(codec);
7804 break;
7805 }
Jiang zhe368c7a92008-03-04 11:20:33 +01007806}
7807
Jiang zhefb97dc62008-03-06 11:07:11 +01007808/* toggle speaker-output according to the hp-jack state */
7809static void alc883_2ch_fujitsu_pi2515_automute(struct hda_codec *codec)
7810{
7811 unsigned int present;
7812 unsigned char bits;
7813
7814 present = snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0)
7815 & AC_PINSENSE_PRESENCE;
7816 bits = present ? HDA_AMP_MUTE : 0;
7817 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7818 HDA_AMP_MUTE, bits);
7819}
7820
7821static void alc883_2ch_fujitsu_pi2515_unsol_event(struct hda_codec *codec,
7822 unsigned int res)
7823{
7824 if ((res >> 26) == ALC880_HP_EVENT)
7825 alc883_2ch_fujitsu_pi2515_automute(codec);
7826}
7827
Kailang Yang189609a2007-08-20 11:31:23 +02007828static void alc883_haier_w66_automute(struct hda_codec *codec)
7829{
7830 unsigned int present;
7831 unsigned char bits;
7832
7833 present = snd_hda_codec_read(codec, 0x1b, 0,
7834 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7835 bits = present ? 0x80 : 0;
7836 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7837 0x80, bits);
7838}
7839
7840static void alc883_haier_w66_unsol_event(struct hda_codec *codec,
7841 unsigned int res)
7842{
7843 if ((res >> 26) == ALC880_HP_EVENT)
7844 alc883_haier_w66_automute(codec);
7845}
7846
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007847static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
7848{
7849 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007850 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007851
7852 present = snd_hda_codec_read(codec, 0x14, 0,
7853 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007854 bits = present ? HDA_AMP_MUTE : 0;
7855 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7856 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007857}
7858
7859static void alc883_lenovo_101e_all_automute(struct hda_codec *codec)
7860{
7861 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007862 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007863
7864 present = snd_hda_codec_read(codec, 0x1b, 0,
7865 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007866 bits = present ? HDA_AMP_MUTE : 0;
7867 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7868 HDA_AMP_MUTE, bits);
7869 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7870 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007871}
7872
7873static void alc883_lenovo_101e_unsol_event(struct hda_codec *codec,
7874 unsigned int res)
7875{
7876 if ((res >> 26) == ALC880_HP_EVENT)
7877 alc883_lenovo_101e_all_automute(codec);
7878 if ((res >> 26) == ALC880_FRONT_EVENT)
7879 alc883_lenovo_101e_ispeaker_automute(codec);
7880}
7881
Takashi Iwai676a9b52007-08-16 15:23:35 +02007882/* toggle speaker-output according to the hp-jack state */
7883static void alc883_acer_aspire_automute(struct hda_codec *codec)
7884{
7885 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02007886
Takashi Iwai676a9b52007-08-16 15:23:35 +02007887 present = snd_hda_codec_read(codec, 0x14, 0,
7888 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7889 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7890 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7891 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
7892 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7893}
7894
7895static void alc883_acer_aspire_unsol_event(struct hda_codec *codec,
7896 unsigned int res)
7897{
7898 if ((res >> 26) == ALC880_HP_EVENT)
7899 alc883_acer_aspire_automute(codec);
7900}
7901
Kailang Yangd1a991a2007-08-15 16:21:59 +02007902static struct hda_verb alc883_acer_eapd_verbs[] = {
7903 /* HP Pin: output 0 (0x0c) */
7904 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7905 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7906 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
7907 /* Front Pin: output 0 (0x0c) */
Takashi Iwai676a9b52007-08-16 15:23:35 +02007908 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7909 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangd1a991a2007-08-15 16:21:59 +02007910 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangd1a991a2007-08-15 16:21:59 +02007911 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
7912 /* eanable EAPD on medion laptop */
7913 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
7914 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
Takashi Iwai676a9b52007-08-16 15:23:35 +02007915 /* enable unsolicited event */
7916 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yangd1a991a2007-08-15 16:21:59 +02007917 { }
7918};
7919
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007920static void alc888_6st_dell_front_automute(struct hda_codec *codec)
7921{
7922 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02007923
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007924 present = snd_hda_codec_read(codec, 0x1b, 0,
7925 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7926 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7927 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7928 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7929 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7930 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
7931 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7932 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
7933 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7934}
7935
7936static void alc888_6st_dell_unsol_event(struct hda_codec *codec,
7937 unsigned int res)
7938{
7939 switch (res >> 26) {
7940 case ALC880_HP_EVENT:
7941 printk("hp_event\n");
7942 alc888_6st_dell_front_automute(codec);
7943 break;
7944 }
7945}
7946
Kailang Yange2757d52008-08-26 13:17:46 +02007947static void alc888_lenovo_sky_front_automute(struct hda_codec *codec)
7948{
7949 unsigned int mute;
7950 unsigned int present;
7951
7952 snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
7953 present = snd_hda_codec_read(codec, 0x1b, 0,
7954 AC_VERB_GET_PIN_SENSE, 0);
7955 present = (present & 0x80000000) != 0;
7956 if (present) {
7957 /* mute internal speaker */
7958 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7959 HDA_AMP_MUTE, HDA_AMP_MUTE);
7960 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7961 HDA_AMP_MUTE, HDA_AMP_MUTE);
7962 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
7963 HDA_AMP_MUTE, HDA_AMP_MUTE);
7964 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
7965 HDA_AMP_MUTE, HDA_AMP_MUTE);
7966 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0,
7967 HDA_AMP_MUTE, HDA_AMP_MUTE);
7968 } else {
7969 /* unmute internal speaker if necessary */
7970 mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
7971 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7972 HDA_AMP_MUTE, mute);
7973 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7974 HDA_AMP_MUTE, mute);
7975 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
7976 HDA_AMP_MUTE, mute);
7977 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
7978 HDA_AMP_MUTE, mute);
7979 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0,
7980 HDA_AMP_MUTE, mute);
7981 }
7982}
7983
7984static void alc883_lenovo_sky_unsol_event(struct hda_codec *codec,
7985 unsigned int res)
7986{
7987 if ((res >> 26) == ALC880_HP_EVENT)
7988 alc888_lenovo_sky_front_automute(codec);
7989}
7990
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007991/*
7992 * generic initialization of ADC, input mixers and output mixers
7993 */
7994static struct hda_verb alc883_auto_init_verbs[] = {
7995 /*
7996 * Unmute ADC0-2 and set the default input to mic-in
7997 */
7998 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
7999 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8000 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8001 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8002
Takashi Iwaicb53c622007-08-10 17:21:45 +02008003 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008004 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008005 * Note: PASD motherboards uses the Line In 2 as the input for
8006 * front panel mic (mic 2)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008007 */
8008 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02008009 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8010 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8011 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8012 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8013 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008014
8015 /*
8016 * Set up output mixers (0x0c - 0x0f)
8017 */
8018 /* set vol=0 to output mixers */
8019 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8020 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8021 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8022 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8023 /* set up input amps for analog loopback */
8024 /* Amp Indices: DAC = 0, mixer = 1 */
8025 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8026 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8027 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8028 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8029 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8030 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8031 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8032 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8033 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8034 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8035
8036 /* FIXME: use matrix-type input source selection */
8037 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
8038 /* Input mixer1 */
8039 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8040 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8041 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008042 /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, */
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008043 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
8044 /* Input mixer2 */
8045 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8046 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8047 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008048 /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, */
Andy Shevchenkoe3cde642007-12-03 16:50:58 +01008049 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008050
8051 { }
8052};
8053
Kailang Yange2757d52008-08-26 13:17:46 +02008054static struct hda_verb alc888_asus_m90v_verbs[] = {
8055 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8056 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8057 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8058 /* enable unsolicited event */
8059 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8060 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
8061 { } /* end */
8062};
8063
8064static void alc883_nb_mic_automute(struct hda_codec *codec)
8065{
8066 unsigned int present;
8067
8068 present = snd_hda_codec_read(codec, 0x18, 0,
8069 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
8070 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
8071 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
8072 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
8073 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
8074}
8075
8076static void alc883_M90V_speaker_automute(struct hda_codec *codec)
8077{
8078 unsigned int present;
8079 unsigned char bits;
8080
8081 present = snd_hda_codec_read(codec, 0x1b, 0,
8082 AC_VERB_GET_PIN_SENSE, 0)
8083 & AC_PINSENSE_PRESENCE;
8084 bits = present ? 0 : PIN_OUT;
8085 snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
8086 bits);
8087 snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
8088 bits);
8089 snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
8090 bits);
8091}
8092
8093static void alc883_mode2_unsol_event(struct hda_codec *codec,
8094 unsigned int res)
8095{
8096 switch (res >> 26) {
8097 case ALC880_HP_EVENT:
8098 alc883_M90V_speaker_automute(codec);
8099 break;
8100 case ALC880_MIC_EVENT:
8101 alc883_nb_mic_automute(codec);
8102 break;
8103 }
8104}
8105
8106static void alc883_mode2_inithook(struct hda_codec *codec)
8107{
8108 alc883_M90V_speaker_automute(codec);
8109 alc883_nb_mic_automute(codec);
8110}
8111
8112static struct hda_verb alc888_asus_eee1601_verbs[] = {
8113 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8114 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8115 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8116 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8117 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8118 {0x20, AC_VERB_SET_COEF_INDEX, 0x0b},
8119 {0x20, AC_VERB_SET_PROC_COEF, 0x0838},
8120 /* enable unsolicited event */
8121 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8122 { } /* end */
8123};
8124
8125static void alc883_eee1601_speaker_automute(struct hda_codec *codec)
8126{
8127 unsigned int present;
8128 unsigned char bits;
8129
8130 present = snd_hda_codec_read(codec, 0x14, 0,
8131 AC_VERB_GET_PIN_SENSE, 0)
8132 & AC_PINSENSE_PRESENCE;
8133 bits = present ? 0 : PIN_OUT;
8134 snd_hda_codec_write(codec, 0x1b, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
8135 bits);
8136}
8137
8138static void alc883_eee1601_unsol_event(struct hda_codec *codec,
8139 unsigned int res)
8140{
8141 switch (res >> 26) {
8142 case ALC880_HP_EVENT:
8143 alc883_eee1601_speaker_automute(codec);
8144 break;
8145 }
8146}
8147
8148static void alc883_eee1601_inithook(struct hda_codec *codec)
8149{
8150 alc883_eee1601_speaker_automute(codec);
8151}
8152
Takashi Iwaicb53c622007-08-10 17:21:45 +02008153#ifdef CONFIG_SND_HDA_POWER_SAVE
8154#define alc883_loopbacks alc880_loopbacks
8155#endif
8156
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008157/* pcm configuration: identiacal with ALC880 */
8158#define alc883_pcm_analog_playback alc880_pcm_analog_playback
8159#define alc883_pcm_analog_capture alc880_pcm_analog_capture
Takashi Iwai63300792008-01-24 15:31:36 +01008160#define alc883_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008161#define alc883_pcm_digital_playback alc880_pcm_digital_playback
8162#define alc883_pcm_digital_capture alc880_pcm_digital_capture
8163
8164/*
8165 * configuration and preset
8166 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008167static const char *alc883_models[ALC883_MODEL_LAST] = {
8168 [ALC883_3ST_2ch_DIG] = "3stack-dig",
8169 [ALC883_3ST_6ch_DIG] = "3stack-6ch-dig",
8170 [ALC883_3ST_6ch] = "3stack-6ch",
8171 [ALC883_6ST_DIG] = "6stack-dig",
8172 [ALC883_TARGA_DIG] = "targa-dig",
8173 [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008174 [ALC883_ACER] = "acer",
Tobin Davis2880a862007-08-07 11:50:26 +02008175 [ALC883_ACER_ASPIRE] = "acer-aspire",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008176 [ALC883_MEDION] = "medion",
Kailang Yang272a5272007-05-14 11:00:38 +02008177 [ALC883_MEDION_MD2] = "medion-md2",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008178 [ALC883_LAPTOP_EAPD] = "laptop-eapd",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008179 [ALC883_LENOVO_101E_2ch] = "lenovo-101e",
Kailang Yang272a5272007-05-14 11:00:38 +02008180 [ALC883_LENOVO_NB0763] = "lenovo-nb0763",
8181 [ALC888_LENOVO_MS7195_DIG] = "lenovo-ms7195-dig",
Kailang Yange2757d52008-08-26 13:17:46 +02008182 [ALC888_LENOVO_SKY] = "lenovo-sky",
Kailang Yang189609a2007-08-20 11:31:23 +02008183 [ALC883_HAIER_W66] = "haier-w66",
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008184 [ALC888_3ST_HP] = "3stack-hp",
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008185 [ALC888_6ST_DELL] = "6stack-dell",
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008186 [ALC883_MITAC] = "mitac",
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008187 [ALC883_CLEVO_M720] = "clevo-m720",
Jiang zhefb97dc62008-03-06 11:07:11 +01008188 [ALC883_FUJITSU_PI2515] = "fujitsu-pi2515",
Jiang zhe17bba1b2008-06-04 12:11:07 +02008189 [ALC883_3ST_6ch_INTEL] = "3stack-6ch-intel",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008190 [ALC883_AUTO] = "auto",
8191};
8192
8193static struct snd_pci_quirk alc883_cfg_tbl[] = {
8194 SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC883_3ST_6ch_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008195 SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE),
8196 SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE),
8197 SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE),
Jaroslav Kysela0b18cb12008-07-28 17:07:07 +02008198 SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_ACER_ASPIRE),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008199 SND_PCI_QUIRK(0x1025, 0, "Acer laptop", ALC883_ACER), /* default Acer */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008200 SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL),
Tobin Davisfebe3372007-06-12 11:27:46 +02008201 SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008202 SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP),
8203 SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP),
Herton Ronaldo Krzesinski5d85f8d2008-03-20 12:13:46 +01008204 SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG),
Kailang Yanga01c30c2008-10-15 11:14:58 +02008205 SND_PCI_QUIRK(0x1043, 0x1873, "Asus M90V", ALC888_ASUS_M90V),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008206 SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG),
Kailang Yange2757d52008-08-26 13:17:46 +02008207 SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_ASUS_EEE1601),
Travis Place97ec7102008-05-23 18:31:46 +02008208 SND_PCI_QUIRK(0x105b, 0x0ce8, "Foxconn P35AX-S", ALC883_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008209 SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008210 SND_PCI_QUIRK(0x1071, 0x8253, "Mitac 8252d", ALC883_MITAC),
8211 SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD),
Kailang Yange2757d52008-08-26 13:17:46 +02008212 SND_PCI_QUIRK(0x10f1, 0x2350, "TYAN-S2350", ALC888_6ST_DELL),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008213 SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch),
Tobin Davis57b14f22007-04-18 23:05:36 +02008214 SND_PCI_QUIRK(0x1458, 0xa002, "MSI", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008215 SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG),
8216 SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG),
8217 SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG),
Jiang zhe4383fae2008-04-14 12:58:57 +02008218 SND_PCI_QUIRK(0x1462, 0x2fb3, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008219 SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG),
Pascal Terjan82808232008-03-04 11:33:28 +01008220 SND_PCI_QUIRK(0x1462, 0x3783, "NEC S970", ALC883_TARGA_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008221 SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG),
8222 SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG),
8223 SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG),
8224 SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG),
8225 SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG),
8226 SND_PCI_QUIRK(0x1462, 0x3fdf, "MSI", ALC883_TARGA_DIG),
8227 SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG),
8228 SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG),
8229 SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008230 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG),
8231 SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG),
Tobin Davis799f88a2007-05-29 14:29:08 +02008232 SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG),
Herton Ronaldo Krzesinski86d34b72008-03-18 09:27:59 +01008233 SND_PCI_QUIRK(0x1462, 0x7267, "MSI", ALC883_3ST_6ch_DIG),
Leonard Norrgard2a296cb2007-01-08 11:28:22 +01008234 SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG),
Tobin Davis2dcd5222007-07-10 17:04:57 +02008235 SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008236 SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008237 SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG),
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008238 SND_PCI_QUIRK(0x1558, 0x0721, "Clevo laptop M720R", ALC883_CLEVO_M720),
8239 SND_PCI_QUIRK(0x1558, 0x0722, "Clevo laptop M720SR", ALC883_CLEVO_M720),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008240 SND_PCI_QUIRK(0x1558, 0, "Clevo laptop", ALC883_LAPTOP_EAPD),
Daniel T Chene60623b2007-05-29 03:41:55 -04008241 SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008242 SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION),
Jiang zhefb97dc62008-03-06 11:07:11 +01008243 SND_PCI_QUIRK(0x1734, 0x1108, "Fujitsu AMILO Pi2515", ALC883_FUJITSU_PI2515),
Kailang Yang272a5272007-05-14 11:00:38 +02008244 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch),
Kailang Yang272a5272007-05-14 11:00:38 +02008245 SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008246 SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763),
8247 SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Kailang Yange2757d52008-08-26 13:17:46 +02008248 SND_PCI_QUIRK(0x17aa, 0x101d, "Lenovo Sky", ALC888_LENOVO_SKY),
Kailang Yang272a5272007-05-14 11:00:38 +02008249 SND_PCI_QUIRK(0x17c0, 0x4071, "MEDION MD2", ALC883_MEDION_MD2),
Andrew Paprocki0b167bf2008-02-03 10:15:44 +01008250 SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG),
Kailang Yang189609a2007-08-20 11:31:23 +02008251 SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66),
Jiang zhe17bba1b2008-06-04 12:11:07 +02008252 SND_PCI_QUIRK(0x8086, 0x0001, "DG33BUC", ALC883_3ST_6ch_INTEL),
8253 SND_PCI_QUIRK(0x8086, 0x0002, "DG33FBC", ALC883_3ST_6ch_INTEL),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008254 SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008255 {}
8256};
8257
8258static struct alc_config_preset alc883_presets[] = {
8259 [ALC883_3ST_2ch_DIG] = {
8260 .mixers = { alc883_3ST_2ch_mixer },
8261 .init_verbs = { alc883_init_verbs },
8262 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8263 .dac_nids = alc883_dac_nids,
8264 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008265 .dig_in_nid = ALC883_DIGIN_NID,
8266 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8267 .channel_mode = alc883_3ST_2ch_modes,
8268 .input_mux = &alc883_capture_source,
8269 },
8270 [ALC883_3ST_6ch_DIG] = {
8271 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
8272 .init_verbs = { alc883_init_verbs },
8273 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8274 .dac_nids = alc883_dac_nids,
8275 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008276 .dig_in_nid = ALC883_DIGIN_NID,
8277 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
8278 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02008279 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008280 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008281 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008282 [ALC883_3ST_6ch] = {
8283 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
8284 .init_verbs = { alc883_init_verbs },
8285 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8286 .dac_nids = alc883_dac_nids,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008287 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
8288 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02008289 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008290 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008291 },
Jiang zhe17bba1b2008-06-04 12:11:07 +02008292 [ALC883_3ST_6ch_INTEL] = {
8293 .mixers = { alc883_3ST_6ch_intel_mixer, alc883_chmode_mixer },
8294 .init_verbs = { alc883_init_verbs },
8295 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8296 .dac_nids = alc883_dac_nids,
8297 .dig_out_nid = ALC883_DIGOUT_NID,
8298 .dig_in_nid = ALC883_DIGIN_NID,
8299 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_intel_modes),
8300 .channel_mode = alc883_3ST_6ch_intel_modes,
8301 .need_dac_fix = 1,
8302 .input_mux = &alc883_3stack_6ch_intel,
8303 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008304 [ALC883_6ST_DIG] = {
8305 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
8306 .init_verbs = { alc883_init_verbs },
8307 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8308 .dac_nids = alc883_dac_nids,
8309 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008310 .dig_in_nid = ALC883_DIGIN_NID,
8311 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
8312 .channel_mode = alc883_sixstack_modes,
8313 .input_mux = &alc883_capture_source,
8314 },
Kailang Yangccc656c2006-10-17 12:32:26 +02008315 [ALC883_TARGA_DIG] = {
8316 .mixers = { alc883_tagra_mixer, alc883_chmode_mixer },
8317 .init_verbs = { alc883_init_verbs, alc883_tagra_verbs},
8318 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8319 .dac_nids = alc883_dac_nids,
8320 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +02008321 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
8322 .channel_mode = alc883_3ST_6ch_modes,
8323 .need_dac_fix = 1,
8324 .input_mux = &alc883_capture_source,
8325 .unsol_event = alc883_tagra_unsol_event,
8326 .init_hook = alc883_tagra_automute,
8327 },
8328 [ALC883_TARGA_2ch_DIG] = {
8329 .mixers = { alc883_tagra_2ch_mixer},
8330 .init_verbs = { alc883_init_verbs, alc883_tagra_verbs},
8331 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8332 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01008333 .adc_nids = alc883_adc_nids_alt,
8334 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Kailang Yangccc656c2006-10-17 12:32:26 +02008335 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +02008336 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8337 .channel_mode = alc883_3ST_2ch_modes,
8338 .input_mux = &alc883_capture_source,
8339 .unsol_event = alc883_tagra_unsol_event,
8340 .init_hook = alc883_tagra_automute,
8341 },
Vladimir Avdoninbab282b2006-08-22 13:31:58 +02008342 [ALC883_ACER] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02008343 .mixers = { alc883_base_mixer },
Vladimir Avdoninbab282b2006-08-22 13:31:58 +02008344 /* On TravelMate laptops, GPIO 0 enables the internal speaker
8345 * and the headphone jack. Turn this on and rely on the
8346 * standard mute methods whenever the user wants to turn
8347 * these outputs off.
8348 */
8349 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs },
8350 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8351 .dac_nids = alc883_dac_nids,
Vladimir Avdoninbab282b2006-08-22 13:31:58 +02008352 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8353 .channel_mode = alc883_3ST_2ch_modes,
8354 .input_mux = &alc883_capture_source,
8355 },
Tobin Davis2880a862007-08-07 11:50:26 +02008356 [ALC883_ACER_ASPIRE] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02008357 .mixers = { alc883_acer_aspire_mixer },
Kailang Yangd1a991a2007-08-15 16:21:59 +02008358 .init_verbs = { alc883_init_verbs, alc883_acer_eapd_verbs },
Tobin Davis2880a862007-08-07 11:50:26 +02008359 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8360 .dac_nids = alc883_dac_nids,
8361 .dig_out_nid = ALC883_DIGOUT_NID,
Tobin Davis2880a862007-08-07 11:50:26 +02008362 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8363 .channel_mode = alc883_3ST_2ch_modes,
8364 .input_mux = &alc883_capture_source,
Takashi Iwai676a9b52007-08-16 15:23:35 +02008365 .unsol_event = alc883_acer_aspire_unsol_event,
8366 .init_hook = alc883_acer_aspire_automute,
Kailang Yangd1a991a2007-08-15 16:21:59 +02008367 },
Tobin Davisc07584c2006-10-13 12:32:16 +02008368 [ALC883_MEDION] = {
8369 .mixers = { alc883_fivestack_mixer,
8370 alc883_chmode_mixer },
8371 .init_verbs = { alc883_init_verbs,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008372 alc883_medion_eapd_verbs },
Tobin Davisc07584c2006-10-13 12:32:16 +02008373 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8374 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01008375 .adc_nids = alc883_adc_nids_alt,
8376 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Tobin Davisc07584c2006-10-13 12:32:16 +02008377 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
8378 .channel_mode = alc883_sixstack_modes,
8379 .input_mux = &alc883_capture_source,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008380 },
Kailang Yang272a5272007-05-14 11:00:38 +02008381 [ALC883_MEDION_MD2] = {
8382 .mixers = { alc883_medion_md2_mixer},
8383 .init_verbs = { alc883_init_verbs, alc883_medion_md2_verbs},
8384 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8385 .dac_nids = alc883_dac_nids,
8386 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang272a5272007-05-14 11:00:38 +02008387 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8388 .channel_mode = alc883_3ST_2ch_modes,
8389 .input_mux = &alc883_capture_source,
8390 .unsol_event = alc883_medion_md2_unsol_event,
8391 .init_hook = alc883_medion_md2_automute,
Kailang Yangea1fb292008-08-26 12:58:38 +02008392 },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008393 [ALC883_LAPTOP_EAPD] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02008394 .mixers = { alc883_base_mixer },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008395 .init_verbs = { alc883_init_verbs, alc882_eapd_verbs },
8396 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8397 .dac_nids = alc883_dac_nids,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008398 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8399 .channel_mode = alc883_3ST_2ch_modes,
8400 .input_mux = &alc883_capture_source,
8401 },
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008402 [ALC883_CLEVO_M720] = {
8403 .mixers = { alc883_clevo_m720_mixer },
8404 .init_verbs = { alc883_init_verbs, alc883_clevo_m720_verbs },
Jiang zhe368c7a92008-03-04 11:20:33 +01008405 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8406 .dac_nids = alc883_dac_nids,
8407 .dig_out_nid = ALC883_DIGOUT_NID,
8408 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8409 .channel_mode = alc883_3ST_2ch_modes,
8410 .input_mux = &alc883_capture_source,
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008411 .unsol_event = alc883_clevo_m720_unsol_event,
8412 .init_hook = alc883_clevo_m720_automute,
Jiang zhe368c7a92008-03-04 11:20:33 +01008413 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008414 [ALC883_LENOVO_101E_2ch] = {
8415 .mixers = { alc883_lenovo_101e_2ch_mixer},
8416 .init_verbs = { alc883_init_verbs, alc883_lenovo_101e_verbs},
8417 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8418 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01008419 .adc_nids = alc883_adc_nids_alt,
8420 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008421 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8422 .channel_mode = alc883_3ST_2ch_modes,
8423 .input_mux = &alc883_lenovo_101e_capture_source,
8424 .unsol_event = alc883_lenovo_101e_unsol_event,
8425 .init_hook = alc883_lenovo_101e_all_automute,
8426 },
Kailang Yang272a5272007-05-14 11:00:38 +02008427 [ALC883_LENOVO_NB0763] = {
8428 .mixers = { alc883_lenovo_nb0763_mixer },
8429 .init_verbs = { alc883_init_verbs, alc883_lenovo_nb0763_verbs},
8430 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8431 .dac_nids = alc883_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +02008432 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8433 .channel_mode = alc883_3ST_2ch_modes,
8434 .need_dac_fix = 1,
8435 .input_mux = &alc883_lenovo_nb0763_capture_source,
8436 .unsol_event = alc883_medion_md2_unsol_event,
8437 .init_hook = alc883_medion_md2_automute,
8438 },
8439 [ALC888_LENOVO_MS7195_DIG] = {
8440 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
8441 .init_verbs = { alc883_init_verbs, alc888_lenovo_ms7195_verbs},
8442 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8443 .dac_nids = alc883_dac_nids,
8444 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang272a5272007-05-14 11:00:38 +02008445 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
8446 .channel_mode = alc883_3ST_6ch_modes,
8447 .need_dac_fix = 1,
8448 .input_mux = &alc883_capture_source,
8449 .unsol_event = alc883_lenovo_ms7195_unsol_event,
8450 .init_hook = alc888_lenovo_ms7195_front_automute,
Kailang Yang189609a2007-08-20 11:31:23 +02008451 },
8452 [ALC883_HAIER_W66] = {
8453 .mixers = { alc883_tagra_2ch_mixer},
8454 .init_verbs = { alc883_init_verbs, alc883_haier_w66_verbs},
8455 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8456 .dac_nids = alc883_dac_nids,
8457 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang189609a2007-08-20 11:31:23 +02008458 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8459 .channel_mode = alc883_3ST_2ch_modes,
8460 .input_mux = &alc883_capture_source,
8461 .unsol_event = alc883_haier_w66_unsol_event,
8462 .init_hook = alc883_haier_w66_automute,
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +01008463 },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008464 [ALC888_3ST_HP] = {
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +01008465 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008466 .init_verbs = { alc883_init_verbs, alc888_3st_hp_verbs },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008467 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8468 .dac_nids = alc883_dac_nids,
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008469 .num_channel_mode = ARRAY_SIZE(alc888_3st_hp_modes),
8470 .channel_mode = alc888_3st_hp_modes,
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008471 .need_dac_fix = 1,
8472 .input_mux = &alc883_capture_source,
8473 },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008474 [ALC888_6ST_DELL] = {
Herton Ronaldo Krzesinskif24dbdc2008-03-20 12:14:28 +01008475 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008476 .init_verbs = { alc883_init_verbs, alc888_6st_dell_verbs },
8477 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8478 .dac_nids = alc883_dac_nids,
8479 .dig_out_nid = ALC883_DIGOUT_NID,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008480 .dig_in_nid = ALC883_DIGIN_NID,
8481 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
8482 .channel_mode = alc883_sixstack_modes,
8483 .input_mux = &alc883_capture_source,
8484 .unsol_event = alc888_6st_dell_unsol_event,
8485 .init_hook = alc888_6st_dell_front_automute,
8486 },
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008487 [ALC883_MITAC] = {
8488 .mixers = { alc883_mitac_mixer },
8489 .init_verbs = { alc883_init_verbs, alc883_mitac_verbs },
8490 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8491 .dac_nids = alc883_dac_nids,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008492 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8493 .channel_mode = alc883_3ST_2ch_modes,
8494 .input_mux = &alc883_capture_source,
8495 .unsol_event = alc883_mitac_unsol_event,
8496 .init_hook = alc883_mitac_automute,
8497 },
Jiang zhefb97dc62008-03-06 11:07:11 +01008498 [ALC883_FUJITSU_PI2515] = {
8499 .mixers = { alc883_2ch_fujitsu_pi2515_mixer },
8500 .init_verbs = { alc883_init_verbs,
8501 alc883_2ch_fujitsu_pi2515_verbs},
8502 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8503 .dac_nids = alc883_dac_nids,
8504 .dig_out_nid = ALC883_DIGOUT_NID,
8505 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8506 .channel_mode = alc883_3ST_2ch_modes,
8507 .input_mux = &alc883_fujitsu_pi2515_capture_source,
8508 .unsol_event = alc883_2ch_fujitsu_pi2515_unsol_event,
8509 .init_hook = alc883_2ch_fujitsu_pi2515_automute,
8510 },
Kailang Yange2757d52008-08-26 13:17:46 +02008511 [ALC888_LENOVO_SKY] = {
8512 .mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer },
8513 .init_verbs = { alc883_init_verbs, alc888_lenovo_sky_verbs},
8514 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8515 .dac_nids = alc883_dac_nids,
8516 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yange2757d52008-08-26 13:17:46 +02008517 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
8518 .channel_mode = alc883_sixstack_modes,
8519 .need_dac_fix = 1,
8520 .input_mux = &alc883_lenovo_sky_capture_source,
8521 .unsol_event = alc883_lenovo_sky_unsol_event,
8522 .init_hook = alc888_lenovo_sky_front_automute,
8523 },
8524 [ALC888_ASUS_M90V] = {
8525 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
8526 .init_verbs = { alc883_init_verbs, alc888_asus_m90v_verbs },
8527 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8528 .dac_nids = alc883_dac_nids,
8529 .dig_out_nid = ALC883_DIGOUT_NID,
8530 .dig_in_nid = ALC883_DIGIN_NID,
8531 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
8532 .channel_mode = alc883_3ST_6ch_modes,
8533 .need_dac_fix = 1,
8534 .input_mux = &alc883_fujitsu_pi2515_capture_source,
8535 .unsol_event = alc883_mode2_unsol_event,
8536 .init_hook = alc883_mode2_inithook,
8537 },
8538 [ALC888_ASUS_EEE1601] = {
8539 .mixers = { alc883_asus_eee1601_mixer },
Takashi Iwaif9e336f2008-10-31 16:37:07 +01008540 .cap_mixer = alc883_asus_eee1601_cap_mixer,
Kailang Yange2757d52008-08-26 13:17:46 +02008541 .init_verbs = { alc883_init_verbs, alc888_asus_eee1601_verbs },
8542 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8543 .dac_nids = alc883_dac_nids,
8544 .dig_out_nid = ALC883_DIGOUT_NID,
8545 .dig_in_nid = ALC883_DIGIN_NID,
8546 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8547 .channel_mode = alc883_3ST_2ch_modes,
8548 .need_dac_fix = 1,
8549 .input_mux = &alc883_asus_eee1601_capture_source,
8550 .unsol_event = alc883_eee1601_unsol_event,
8551 .init_hook = alc883_eee1601_inithook,
8552 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008553};
8554
8555
8556/*
8557 * BIOS auto configuration
8558 */
8559static void alc883_auto_set_output_and_unmute(struct hda_codec *codec,
8560 hda_nid_t nid, int pin_type,
8561 int dac_idx)
8562{
8563 /* set as output */
8564 struct alc_spec *spec = codec->spec;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008565 int idx;
8566
Takashi Iwaif6c7e542008-02-12 18:32:23 +01008567 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008568 if (spec->multiout.dac_nids[dac_idx] == 0x25)
8569 idx = 4;
8570 else
8571 idx = spec->multiout.dac_nids[dac_idx] - 2;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008572 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
8573
8574}
8575
8576static void alc883_auto_init_multi_out(struct hda_codec *codec)
8577{
8578 struct alc_spec *spec = codec->spec;
8579 int i;
8580
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008581 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008582 for (i = 0; i <= HDA_SIDE; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008583 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02008584 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008585 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02008586 alc883_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008587 i);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008588 }
8589}
8590
8591static void alc883_auto_init_hp_out(struct hda_codec *codec)
8592{
8593 struct alc_spec *spec = codec->spec;
8594 hda_nid_t pin;
8595
Takashi Iwaieb06ed82006-09-20 17:10:27 +02008596 pin = spec->autocfg.hp_pins[0];
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008597 if (pin) /* connect to front */
8598 /* use dac 0 */
8599 alc883_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01008600 pin = spec->autocfg.speaker_pins[0];
8601 if (pin)
8602 alc883_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008603}
8604
8605#define alc883_is_input_pin(nid) alc880_is_input_pin(nid)
8606#define ALC883_PIN_CD_NID ALC880_PIN_CD_NID
8607
8608static void alc883_auto_init_analog_input(struct hda_codec *codec)
8609{
8610 struct alc_spec *spec = codec->spec;
8611 int i;
8612
8613 for (i = 0; i < AUTO_PIN_LAST; i++) {
8614 hda_nid_t nid = spec->autocfg.input_pins[i];
8615 if (alc883_is_input_pin(nid)) {
8616 snd_hda_codec_write(codec, nid, 0,
8617 AC_VERB_SET_PIN_WIDGET_CONTROL,
8618 (i <= AUTO_PIN_FRONT_MIC ?
8619 PIN_VREF80 : PIN_IN));
8620 if (nid != ALC883_PIN_CD_NID)
8621 snd_hda_codec_write(codec, nid, 0,
8622 AC_VERB_SET_AMP_GAIN_MUTE,
8623 AMP_OUT_MUTE);
8624 }
8625 }
8626}
8627
Takashi Iwaif511b012008-08-15 16:46:42 +02008628#define alc883_auto_init_input_src alc882_auto_init_input_src
8629
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008630/* almost identical with ALC880 parser... */
8631static int alc883_parse_auto_config(struct hda_codec *codec)
8632{
8633 struct alc_spec *spec = codec->spec;
8634 int err = alc880_parse_auto_config(codec);
8635
8636 if (err < 0)
8637 return err;
Takashi Iwai776e1842007-08-29 15:07:11 +02008638 else if (!err)
8639 return 0; /* no config found */
8640
8641 err = alc_auto_add_mic_boost(codec);
8642 if (err < 0)
8643 return err;
8644
8645 /* hack - override the init verbs */
8646 spec->init_verbs[0] = alc883_auto_init_verbs;
Takashi Iwai776e1842007-08-29 15:07:11 +02008647
8648 return 1; /* config found */
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008649}
8650
8651/* additional initialization for auto-configuration model */
8652static void alc883_auto_init(struct hda_codec *codec)
8653{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01008654 struct alc_spec *spec = codec->spec;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008655 alc883_auto_init_multi_out(codec);
8656 alc883_auto_init_hp_out(codec);
8657 alc883_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +02008658 alc883_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01008659 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02008660 alc_inithook(codec);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008661}
8662
8663static int patch_alc883(struct hda_codec *codec)
8664{
8665 struct alc_spec *spec;
8666 int err, board_config;
8667
8668 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
8669 if (spec == NULL)
8670 return -ENOMEM;
8671
8672 codec->spec = spec;
8673
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02008674 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
8675
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008676 board_config = snd_hda_check_board_config(codec, ALC883_MODEL_LAST,
8677 alc883_models,
8678 alc883_cfg_tbl);
8679 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008680 printk(KERN_INFO "hda_codec: Unknown model for ALC883, "
8681 "trying auto-probe from BIOS...\n");
8682 board_config = ALC883_AUTO;
8683 }
8684
8685 if (board_config == ALC883_AUTO) {
8686 /* automatic parse from the BIOS config */
8687 err = alc883_parse_auto_config(codec);
8688 if (err < 0) {
8689 alc_free(codec);
8690 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008691 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008692 printk(KERN_INFO
8693 "hda_codec: Cannot set up configuration "
8694 "from BIOS. Using base mode...\n");
8695 board_config = ALC883_3ST_2ch_DIG;
8696 }
8697 }
8698
8699 if (board_config != ALC883_AUTO)
8700 setup_preset(spec, &alc883_presets[board_config]);
8701
Kailang Yang2f893282008-05-27 12:14:47 +02008702 switch (codec->vendor_id) {
8703 case 0x10ec0888:
Kailang Yang44426082008-10-15 11:18:05 +02008704 if (codec->revision_id == 0x100101) {
8705 spec->stream_name_analog = "ALC1200 Analog";
8706 spec->stream_name_digital = "ALC1200 Digital";
8707 } else {
8708 spec->stream_name_analog = "ALC888 Analog";
8709 spec->stream_name_digital = "ALC888 Digital";
8710 }
Kailang Yang2f893282008-05-27 12:14:47 +02008711 break;
8712 case 0x10ec0889:
8713 spec->stream_name_analog = "ALC889 Analog";
8714 spec->stream_name_digital = "ALC889 Digital";
8715 break;
8716 default:
8717 spec->stream_name_analog = "ALC883 Analog";
8718 spec->stream_name_digital = "ALC883 Digital";
8719 break;
8720 }
8721
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008722 spec->stream_analog_playback = &alc883_pcm_analog_playback;
8723 spec->stream_analog_capture = &alc883_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01008724 spec->stream_analog_alt_capture = &alc883_pcm_analog_alt_capture;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008725
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008726 spec->stream_digital_playback = &alc883_pcm_digital_playback;
8727 spec->stream_digital_capture = &alc883_pcm_digital_capture;
8728
Takashi Iwaif9e336f2008-10-31 16:37:07 +01008729 if (!spec->num_adc_nids) {
8730 spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids);
8731 spec->adc_nids = alc883_adc_nids;
8732 }
8733 if (!spec->capsrc_nids)
8734 spec->capsrc_nids = alc883_capsrc_nids;
Takashi Iwai54cbc9a2008-10-31 15:24:04 +01008735 spec->is_mix_capture = 1; /* matrix-style capture */
Takashi Iwaif9e336f2008-10-31 16:37:07 +01008736 if (!spec->cap_mixer)
8737 set_capture_mixer(spec);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008738
Takashi Iwai2134ea42008-01-10 16:53:55 +01008739 spec->vmaster_nid = 0x0c;
8740
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008741 codec->patch_ops = alc_patch_ops;
8742 if (board_config == ALC883_AUTO)
8743 spec->init_hook = alc883_auto_init;
Kailang Yangf9423e72008-05-27 12:32:25 +02008744
Takashi Iwaicb53c622007-08-10 17:21:45 +02008745#ifdef CONFIG_SND_HDA_POWER_SAVE
8746 if (!spec->loopback.amplist)
8747 spec->loopback.amplist = alc883_loopbacks;
8748#endif
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008749
8750 return 0;
8751}
8752
8753/*
Kailang Yangdf694da2005-12-05 19:42:22 +01008754 * ALC262 support
8755 */
8756
8757#define ALC262_DIGOUT_NID ALC880_DIGOUT_NID
8758#define ALC262_DIGIN_NID ALC880_DIGIN_NID
8759
8760#define alc262_dac_nids alc260_dac_nids
8761#define alc262_adc_nids alc882_adc_nids
8762#define alc262_adc_nids_alt alc882_adc_nids_alt
Takashi Iwai88c71a92008-02-14 17:27:17 +01008763#define alc262_capsrc_nids alc882_capsrc_nids
8764#define alc262_capsrc_nids_alt alc882_capsrc_nids_alt
Kailang Yangdf694da2005-12-05 19:42:22 +01008765
8766#define alc262_modes alc260_modes
Takashi Iwaic5f2ea02005-12-06 18:54:31 +01008767#define alc262_capture_source alc882_capture_source
Kailang Yangdf694da2005-12-05 19:42:22 +01008768
Kailang Yang4e555fe2008-08-26 13:05:55 +02008769static hda_nid_t alc262_dmic_adc_nids[1] = {
8770 /* ADC0 */
8771 0x09
8772};
8773
8774static hda_nid_t alc262_dmic_capsrc_nids[1] = { 0x22 };
8775
Kailang Yangdf694da2005-12-05 19:42:22 +01008776static struct snd_kcontrol_new alc262_base_mixer[] = {
8777 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8778 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8779 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8780 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8781 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8782 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8783 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8784 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008785 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01008786 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
8787 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008788 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01008789 /* HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01008790 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT), */
Kailang Yangdf694da2005-12-05 19:42:22 +01008791 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),
8792 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8793 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8794 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01008795 { } /* end */
Takashi Iwai834be882006-03-01 14:16:17 +01008796};
8797
Kailang Yangccc656c2006-10-17 12:32:26 +02008798static struct snd_kcontrol_new alc262_hippo1_mixer[] = {
8799 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8800 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8801 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8802 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8803 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8804 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8805 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8806 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008807 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008808 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
8809 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008810 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008811 /* HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01008812 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT), */
Kailang Yangccc656c2006-10-17 12:32:26 +02008813 /*HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),*/
8814 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8815 { } /* end */
8816};
8817
Takashi Iwaice875f02008-01-28 18:17:43 +01008818/* update HP, line and mono-out pins according to the master switch */
8819static void alc262_hp_master_update(struct hda_codec *codec)
8820{
8821 struct alc_spec *spec = codec->spec;
8822 int val = spec->master_sw;
8823
8824 /* HP & line-out */
8825 snd_hda_codec_write_cache(codec, 0x1b, 0,
8826 AC_VERB_SET_PIN_WIDGET_CONTROL,
8827 val ? PIN_HP : 0);
8828 snd_hda_codec_write_cache(codec, 0x15, 0,
8829 AC_VERB_SET_PIN_WIDGET_CONTROL,
8830 val ? PIN_HP : 0);
8831 /* mono (speaker) depending on the HP jack sense */
8832 val = val && !spec->jack_present;
8833 snd_hda_codec_write_cache(codec, 0x16, 0,
8834 AC_VERB_SET_PIN_WIDGET_CONTROL,
8835 val ? PIN_OUT : 0);
8836}
8837
8838static void alc262_hp_bpc_automute(struct hda_codec *codec)
8839{
8840 struct alc_spec *spec = codec->spec;
8841 unsigned int presence;
8842 presence = snd_hda_codec_read(codec, 0x1b, 0,
8843 AC_VERB_GET_PIN_SENSE, 0);
8844 spec->jack_present = !!(presence & AC_PINSENSE_PRESENCE);
8845 alc262_hp_master_update(codec);
8846}
8847
8848static void alc262_hp_bpc_unsol_event(struct hda_codec *codec, unsigned int res)
8849{
8850 if ((res >> 26) != ALC880_HP_EVENT)
8851 return;
8852 alc262_hp_bpc_automute(codec);
8853}
8854
8855static void alc262_hp_wildwest_automute(struct hda_codec *codec)
8856{
8857 struct alc_spec *spec = codec->spec;
8858 unsigned int presence;
8859 presence = snd_hda_codec_read(codec, 0x15, 0,
8860 AC_VERB_GET_PIN_SENSE, 0);
8861 spec->jack_present = !!(presence & AC_PINSENSE_PRESENCE);
8862 alc262_hp_master_update(codec);
8863}
8864
8865static void alc262_hp_wildwest_unsol_event(struct hda_codec *codec,
8866 unsigned int res)
8867{
8868 if ((res >> 26) != ALC880_HP_EVENT)
8869 return;
8870 alc262_hp_wildwest_automute(codec);
8871}
8872
8873static int alc262_hp_master_sw_get(struct snd_kcontrol *kcontrol,
8874 struct snd_ctl_elem_value *ucontrol)
8875{
8876 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
8877 struct alc_spec *spec = codec->spec;
8878 *ucontrol->value.integer.value = spec->master_sw;
8879 return 0;
8880}
8881
8882static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol,
8883 struct snd_ctl_elem_value *ucontrol)
8884{
8885 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
8886 struct alc_spec *spec = codec->spec;
8887 int val = !!*ucontrol->value.integer.value;
8888
8889 if (val == spec->master_sw)
8890 return 0;
8891 spec->master_sw = val;
8892 alc262_hp_master_update(codec);
8893 return 1;
8894}
8895
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008896static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
Takashi Iwaice875f02008-01-28 18:17:43 +01008897 {
8898 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8899 .name = "Master Playback Switch",
8900 .info = snd_ctl_boolean_mono_info,
8901 .get = alc262_hp_master_sw_get,
8902 .put = alc262_hp_master_sw_put,
8903 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008904 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8905 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8906 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +01008907 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
8908 HDA_OUTPUT),
8909 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
8910 HDA_OUTPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008911 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8912 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008913 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008914 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
8915 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008916 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008917 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8918 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8919 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8920 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8921 HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
8922 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT),
8923 HDA_CODEC_VOLUME("AUX IN Playback Volume", 0x0b, 0x06, HDA_INPUT),
8924 HDA_CODEC_MUTE("AUX IN Playback Switch", 0x0b, 0x06, HDA_INPUT),
8925 { } /* end */
8926};
8927
Kailang Yangcd7509a2007-01-26 18:33:17 +01008928static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = {
Takashi Iwaice875f02008-01-28 18:17:43 +01008929 {
8930 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8931 .name = "Master Playback Switch",
8932 .info = snd_ctl_boolean_mono_info,
8933 .get = alc262_hp_master_sw_get,
8934 .put = alc262_hp_master_sw_put,
8935 },
Kailang Yangcd7509a2007-01-26 18:33:17 +01008936 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8937 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8938 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8939 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +01008940 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
8941 HDA_OUTPUT),
8942 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
8943 HDA_OUTPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +01008944 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT),
8945 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008946 HDA_CODEC_VOLUME("Front Mic Boost", 0x1a, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +01008947 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
8948 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
8949 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8950 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8951 HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
8952 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT),
8953 { } /* end */
8954};
8955
8956static struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = {
8957 HDA_CODEC_VOLUME("Rear Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8958 HDA_CODEC_MUTE("Rear Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008959 HDA_CODEC_VOLUME("Rear Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +01008960 { } /* end */
8961};
8962
Kailang Yang66d2a9d2007-11-14 12:06:21 +01008963/* mute/unmute internal speaker according to the hp jack and mute state */
8964static void alc262_hp_t5735_automute(struct hda_codec *codec, int force)
8965{
8966 struct alc_spec *spec = codec->spec;
Kailang Yang66d2a9d2007-11-14 12:06:21 +01008967
8968 if (force || !spec->sense_updated) {
8969 unsigned int present;
8970 present = snd_hda_codec_read(codec, 0x15, 0,
8971 AC_VERB_GET_PIN_SENSE, 0);
Takashi Iwai4bb26132008-01-28 18:12:42 +01008972 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
Kailang Yang66d2a9d2007-11-14 12:06:21 +01008973 spec->sense_updated = 1;
8974 }
Takashi Iwai4bb26132008-01-28 18:12:42 +01008975 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0, HDA_AMP_MUTE,
8976 spec->jack_present ? HDA_AMP_MUTE : 0);
Kailang Yang66d2a9d2007-11-14 12:06:21 +01008977}
8978
8979static void alc262_hp_t5735_unsol_event(struct hda_codec *codec,
8980 unsigned int res)
8981{
8982 if ((res >> 26) != ALC880_HP_EVENT)
8983 return;
8984 alc262_hp_t5735_automute(codec, 1);
8985}
8986
8987static void alc262_hp_t5735_init_hook(struct hda_codec *codec)
8988{
8989 alc262_hp_t5735_automute(codec, 1);
8990}
8991
8992static struct snd_kcontrol_new alc262_hp_t5735_mixer[] = {
Takashi Iwai86cd9292008-01-28 18:09:56 +01008993 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8994 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang66d2a9d2007-11-14 12:06:21 +01008995 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8996 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8997 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8998 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8999 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9000 { } /* end */
9001};
9002
9003static struct hda_verb alc262_hp_t5735_verbs[] = {
9004 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9005 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9006
9007 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9008 { }
9009};
9010
Kailang Yang8c427222008-01-10 13:03:59 +01009011static struct snd_kcontrol_new alc262_hp_rp5700_mixer[] = {
Takashi Iwaif2f48e12008-01-28 18:14:43 +01009012 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9013 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01009014 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
9015 HDA_CODEC_MUTE("Speaker Playback Switch", 0x16, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +01009016 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
9017 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
9018 { } /* end */
9019};
9020
9021static struct hda_verb alc262_hp_rp5700_verbs[] = {
9022 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9023 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9024 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9025 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9026 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
9027 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
9028 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
9029 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
9030 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
9031 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
9032 {}
9033};
9034
9035static struct hda_input_mux alc262_hp_rp5700_capture_source = {
9036 .num_items = 1,
9037 .items = {
9038 { "Line", 0x1 },
9039 },
9040};
9041
Takashi Iwai0724ea22007-08-23 00:31:43 +02009042/* bind hp and internal speaker mute (with plug check) */
9043static int alc262_sony_master_sw_put(struct snd_kcontrol *kcontrol,
9044 struct snd_ctl_elem_value *ucontrol)
9045{
9046 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
9047 long *valp = ucontrol->value.integer.value;
9048 int change;
9049
9050 /* change hp mute */
9051 change = snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0,
9052 HDA_AMP_MUTE,
9053 valp[0] ? 0 : HDA_AMP_MUTE);
9054 change |= snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0,
9055 HDA_AMP_MUTE,
9056 valp[1] ? 0 : HDA_AMP_MUTE);
9057 if (change) {
9058 /* change speaker according to HP jack state */
9059 struct alc_spec *spec = codec->spec;
9060 unsigned int mute;
9061 if (spec->jack_present)
9062 mute = HDA_AMP_MUTE;
9063 else
9064 mute = snd_hda_codec_amp_read(codec, 0x15, 0,
9065 HDA_OUTPUT, 0);
9066 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9067 HDA_AMP_MUTE, mute);
9068 }
9069 return change;
9070}
Takashi Iwai5b319542007-07-26 11:49:22 +02009071
Kailang Yang272a5272007-05-14 11:00:38 +02009072static struct snd_kcontrol_new alc262_sony_mixer[] = {
Takashi Iwai0724ea22007-08-23 00:31:43 +02009073 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9074 {
9075 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9076 .name = "Master Playback Switch",
9077 .info = snd_hda_mixer_amp_switch_info,
9078 .get = snd_hda_mixer_amp_switch_get,
9079 .put = alc262_sony_master_sw_put,
9080 .private_value = HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
9081 },
Kailang Yang272a5272007-05-14 11:00:38 +02009082 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9083 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9084 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
9085 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
9086 { } /* end */
9087};
9088
Kailang Yang83c34212007-07-05 11:43:05 +02009089static struct snd_kcontrol_new alc262_benq_t31_mixer[] = {
9090 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9091 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9092 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9093 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9094 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9095 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
9096 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
9097 { } /* end */
9098};
Kailang Yang272a5272007-05-14 11:00:38 +02009099
Kailang Yangdf694da2005-12-05 19:42:22 +01009100#define alc262_capture_mixer alc882_capture_mixer
9101#define alc262_capture_alt_mixer alc882_capture_alt_mixer
9102
9103/*
9104 * generic initialization of ADC, input mixers and output mixers
9105 */
9106static struct hda_verb alc262_init_verbs[] = {
9107 /*
9108 * Unmute ADC0-2 and set the default input to mic-in
9109 */
9110 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
9111 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9112 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
9113 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9114 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
9115 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9116
Takashi Iwaicb53c622007-08-10 17:21:45 +02009117 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +01009118 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009119 * Note: PASD motherboards uses the Line In 2 as the input for
9120 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01009121 */
9122 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02009123 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9124 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
9125 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
9126 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
9127 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01009128
9129 /*
9130 * Set up output mixers (0x0c - 0x0e)
9131 */
9132 /* set vol=0 to output mixers */
9133 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9134 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9135 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9136 /* set up input amps for analog loopback */
9137 /* Amp Indices: DAC = 0, mixer = 1 */
9138 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9139 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9140 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9141 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9142 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9143 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9144
9145 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
9146 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
9147 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
9148 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9149 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9150 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9151
9152 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
9153 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
9154 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
9155 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
9156 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Kailang Yangea1fb292008-08-26 12:58:38 +02009157
Kailang Yangdf694da2005-12-05 19:42:22 +01009158 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
9159 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Kailang Yangea1fb292008-08-26 12:58:38 +02009160
Kailang Yangdf694da2005-12-05 19:42:22 +01009161 /* FIXME: use matrix-type input source selection */
9162 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
9163 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
9164 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9165 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
9166 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
9167 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
9168 /* Input mixer2 */
9169 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9170 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
9171 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
9172 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
9173 /* Input mixer3 */
9174 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9175 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
9176 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009177 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
Kailang Yangdf694da2005-12-05 19:42:22 +01009178
9179 { }
9180};
9181
Kailang Yang4e555fe2008-08-26 13:05:55 +02009182static struct hda_verb alc262_eapd_verbs[] = {
9183 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
9184 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
9185 { }
9186};
9187
Kailang Yangccc656c2006-10-17 12:32:26 +02009188static struct hda_verb alc262_hippo_unsol_verbs[] = {
9189 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
9190 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9191 {}
9192};
9193
9194static struct hda_verb alc262_hippo1_unsol_verbs[] = {
9195 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
9196 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
9197 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
9198
9199 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
9200 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9201 {}
9202};
9203
Kailang Yang272a5272007-05-14 11:00:38 +02009204static struct hda_verb alc262_sony_unsol_verbs[] = {
9205 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
9206 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9207 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, // Front Mic
9208
9209 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
9210 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Akio Idehara7b1e8792008-06-09 22:46:07 +09009211 {}
Kailang Yang272a5272007-05-14 11:00:38 +02009212};
9213
Kailang Yang4e555fe2008-08-26 13:05:55 +02009214static struct hda_input_mux alc262_dmic_capture_source = {
9215 .num_items = 2,
9216 .items = {
9217 { "Int DMic", 0x9 },
9218 { "Mic", 0x0 },
9219 },
9220};
9221
9222static struct snd_kcontrol_new alc262_toshiba_s06_mixer[] = {
9223 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9224 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9225 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9226 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9227 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang4e555fe2008-08-26 13:05:55 +02009228 { } /* end */
9229};
9230
9231static struct hda_verb alc262_toshiba_s06_verbs[] = {
9232 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
9233 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9234 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9235 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9236 {0x22, AC_VERB_SET_CONNECT_SEL, 0x09},
9237 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9238 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
9239 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
9240 {}
9241};
9242
9243static void alc262_dmic_automute(struct hda_codec *codec)
9244{
9245 unsigned int present;
9246
9247 present = snd_hda_codec_read(codec, 0x18, 0,
9248 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
9249 snd_hda_codec_write(codec, 0x22, 0,
9250 AC_VERB_SET_CONNECT_SEL, present ? 0x0 : 0x09);
9251}
9252
9253/* toggle speaker-output according to the hp-jack state */
9254static void alc262_toshiba_s06_speaker_automute(struct hda_codec *codec)
9255{
9256 unsigned int present;
9257 unsigned char bits;
9258
9259 present = snd_hda_codec_read(codec, 0x15, 0,
9260 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
9261 bits = present ? 0 : PIN_OUT;
9262 snd_hda_codec_write(codec, 0x14, 0,
9263 AC_VERB_SET_PIN_WIDGET_CONTROL, bits);
9264}
9265
9266
9267
9268/* unsolicited event for HP jack sensing */
9269static void alc262_toshiba_s06_unsol_event(struct hda_codec *codec,
9270 unsigned int res)
9271{
9272 if ((res >> 26) == ALC880_HP_EVENT)
9273 alc262_toshiba_s06_speaker_automute(codec);
9274 if ((res >> 26) == ALC880_MIC_EVENT)
9275 alc262_dmic_automute(codec);
9276
9277}
9278
9279static void alc262_toshiba_s06_init_hook(struct hda_codec *codec)
9280{
9281 alc262_toshiba_s06_speaker_automute(codec);
9282 alc262_dmic_automute(codec);
9283}
9284
Kailang Yangccc656c2006-10-17 12:32:26 +02009285/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwai5b319542007-07-26 11:49:22 +02009286static void alc262_hippo_automute(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02009287{
9288 struct alc_spec *spec = codec->spec;
9289 unsigned int mute;
Takashi Iwai5b319542007-07-26 11:49:22 +02009290 unsigned int present;
Kailang Yangccc656c2006-10-17 12:32:26 +02009291
Takashi Iwai5b319542007-07-26 11:49:22 +02009292 /* need to execute and sync at first */
9293 snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0);
9294 present = snd_hda_codec_read(codec, 0x15, 0,
9295 AC_VERB_GET_PIN_SENSE, 0);
9296 spec->jack_present = (present & 0x80000000) != 0;
Kailang Yangccc656c2006-10-17 12:32:26 +02009297 if (spec->jack_present) {
9298 /* mute internal speaker */
Takashi Iwai47fd8302007-08-10 17:11:07 +02009299 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9300 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yangccc656c2006-10-17 12:32:26 +02009301 } else {
9302 /* unmute internal speaker if necessary */
9303 mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0);
Takashi Iwai47fd8302007-08-10 17:11:07 +02009304 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9305 HDA_AMP_MUTE, mute);
Kailang Yangccc656c2006-10-17 12:32:26 +02009306 }
9307}
9308
9309/* unsolicited event for HP jack sensing */
9310static void alc262_hippo_unsol_event(struct hda_codec *codec,
9311 unsigned int res)
9312{
9313 if ((res >> 26) != ALC880_HP_EVENT)
9314 return;
Takashi Iwai5b319542007-07-26 11:49:22 +02009315 alc262_hippo_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02009316}
9317
Takashi Iwai5b319542007-07-26 11:49:22 +02009318static void alc262_hippo1_automute(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02009319{
Kailang Yangccc656c2006-10-17 12:32:26 +02009320 unsigned int mute;
Takashi Iwai5b319542007-07-26 11:49:22 +02009321 unsigned int present;
Kailang Yangccc656c2006-10-17 12:32:26 +02009322
Takashi Iwai5b319542007-07-26 11:49:22 +02009323 snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
9324 present = snd_hda_codec_read(codec, 0x1b, 0,
9325 AC_VERB_GET_PIN_SENSE, 0);
9326 present = (present & 0x80000000) != 0;
9327 if (present) {
Kailang Yangccc656c2006-10-17 12:32:26 +02009328 /* mute internal speaker */
Takashi Iwai47fd8302007-08-10 17:11:07 +02009329 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9330 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yangccc656c2006-10-17 12:32:26 +02009331 } else {
9332 /* unmute internal speaker if necessary */
9333 mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
Takashi Iwai47fd8302007-08-10 17:11:07 +02009334 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9335 HDA_AMP_MUTE, mute);
Kailang Yangccc656c2006-10-17 12:32:26 +02009336 }
9337}
9338
9339/* unsolicited event for HP jack sensing */
9340static void alc262_hippo1_unsol_event(struct hda_codec *codec,
9341 unsigned int res)
9342{
9343 if ((res >> 26) != ALC880_HP_EVENT)
9344 return;
Takashi Iwai5b319542007-07-26 11:49:22 +02009345 alc262_hippo1_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02009346}
9347
Takashi Iwai834be882006-03-01 14:16:17 +01009348/*
Pascal Terjane8f9ae22008-08-04 14:36:05 +02009349 * nec model
9350 * 0x15 = headphone
9351 * 0x16 = internal speaker
9352 * 0x18 = external mic
9353 */
9354
9355static struct snd_kcontrol_new alc262_nec_mixer[] = {
9356 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
9357 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 0, 0x0, HDA_OUTPUT),
9358
9359 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9360 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9361 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9362
9363 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
9364 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9365 { } /* end */
9366};
9367
9368static struct hda_verb alc262_nec_verbs[] = {
9369 /* Unmute Speaker */
9370 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9371
9372 /* Headphone */
9373 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
9374 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9375
9376 /* External mic to headphone */
9377 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9378 /* External mic to speaker */
9379 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9380 {}
9381};
9382
9383/*
Takashi Iwai834be882006-03-01 14:16:17 +01009384 * fujitsu model
Tony Vroon5d9fab22008-03-14 17:09:18 +01009385 * 0x14 = headphone/spdif-out, 0x15 = internal speaker,
9386 * 0x1b = port replicator headphone out
Takashi Iwai834be882006-03-01 14:16:17 +01009387 */
9388
9389#define ALC_HP_EVENT 0x37
9390
9391static struct hda_verb alc262_fujitsu_unsol_verbs[] = {
9392 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
9393 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Tony Vroon5d9fab22008-03-14 17:09:18 +01009394 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
9395 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai834be882006-03-01 14:16:17 +01009396 {}
9397};
9398
Jiang zhe0e31daf2008-03-20 12:12:39 +01009399static struct hda_verb alc262_lenovo_3000_unsol_verbs[] = {
9400 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
9401 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9402 {}
9403};
9404
Takashi Iwai834be882006-03-01 14:16:17 +01009405static struct hda_input_mux alc262_fujitsu_capture_source = {
Takashi Iwai39d3ed32007-10-12 15:03:48 +02009406 .num_items = 3,
Takashi Iwai834be882006-03-01 14:16:17 +01009407 .items = {
9408 { "Mic", 0x0 },
Takashi Iwai39d3ed32007-10-12 15:03:48 +02009409 { "Int Mic", 0x1 },
Takashi Iwai834be882006-03-01 14:16:17 +01009410 { "CD", 0x4 },
9411 },
9412};
9413
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009414static struct hda_input_mux alc262_HP_capture_source = {
9415 .num_items = 5,
9416 .items = {
9417 { "Mic", 0x0 },
zhejiangaccbe492007-08-31 12:36:05 +02009418 { "Front Mic", 0x1 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009419 { "Line", 0x2 },
9420 { "CD", 0x4 },
9421 { "AUX IN", 0x6 },
9422 },
9423};
9424
zhejiangaccbe492007-08-31 12:36:05 +02009425static struct hda_input_mux alc262_HP_D7000_capture_source = {
9426 .num_items = 4,
9427 .items = {
9428 { "Mic", 0x0 },
9429 { "Front Mic", 0x2 },
9430 { "Line", 0x1 },
9431 { "CD", 0x4 },
9432 },
9433};
9434
Takashi Iwaiebc7a402008-05-20 09:23:05 +02009435/* mute/unmute internal speaker according to the hp jacks and mute state */
Takashi Iwai834be882006-03-01 14:16:17 +01009436static void alc262_fujitsu_automute(struct hda_codec *codec, int force)
9437{
9438 struct alc_spec *spec = codec->spec;
9439 unsigned int mute;
9440
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009441 if (force || !spec->sense_updated) {
Takashi Iwaiebc7a402008-05-20 09:23:05 +02009442 unsigned int present;
Takashi Iwai834be882006-03-01 14:16:17 +01009443 /* need to execute and sync at first */
9444 snd_hda_codec_read(codec, 0x14, 0, AC_VERB_SET_PIN_SENSE, 0);
Takashi Iwaiebc7a402008-05-20 09:23:05 +02009445 /* check laptop HP jack */
9446 present = snd_hda_codec_read(codec, 0x14, 0,
9447 AC_VERB_GET_PIN_SENSE, 0);
9448 /* need to execute and sync at first */
9449 snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
9450 /* check docking HP jack */
9451 present |= snd_hda_codec_read(codec, 0x1b, 0,
9452 AC_VERB_GET_PIN_SENSE, 0);
9453 if (present & AC_PINSENSE_PRESENCE)
9454 spec->jack_present = 1;
9455 else
9456 spec->jack_present = 0;
Takashi Iwai834be882006-03-01 14:16:17 +01009457 spec->sense_updated = 1;
9458 }
Takashi Iwaiebc7a402008-05-20 09:23:05 +02009459 /* unmute internal speaker only if both HPs are unplugged and
9460 * master switch is on
9461 */
9462 if (spec->jack_present)
9463 mute = HDA_AMP_MUTE;
9464 else
Takashi Iwai834be882006-03-01 14:16:17 +01009465 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
Takashi Iwaiebc7a402008-05-20 09:23:05 +02009466 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9467 HDA_AMP_MUTE, mute);
Takashi Iwai834be882006-03-01 14:16:17 +01009468}
9469
9470/* unsolicited event for HP jack sensing */
9471static void alc262_fujitsu_unsol_event(struct hda_codec *codec,
9472 unsigned int res)
9473{
9474 if ((res >> 26) != ALC_HP_EVENT)
9475 return;
9476 alc262_fujitsu_automute(codec, 1);
9477}
9478
Takashi Iwaiebc7a402008-05-20 09:23:05 +02009479static void alc262_fujitsu_init_hook(struct hda_codec *codec)
9480{
9481 alc262_fujitsu_automute(codec, 1);
9482}
9483
Takashi Iwai834be882006-03-01 14:16:17 +01009484/* bind volumes of both NID 0x0c and 0x0d */
Takashi Iwaicca3b372007-08-10 17:12:15 +02009485static struct hda_bind_ctls alc262_fujitsu_bind_master_vol = {
9486 .ops = &snd_hda_bind_vol,
9487 .values = {
9488 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT),
9489 HDA_COMPOSE_AMP_VAL(0x0d, 3, 0, HDA_OUTPUT),
9490 0
9491 },
9492};
Takashi Iwai834be882006-03-01 14:16:17 +01009493
Jiang zhe0e31daf2008-03-20 12:12:39 +01009494/* mute/unmute internal speaker according to the hp jack and mute state */
9495static void alc262_lenovo_3000_automute(struct hda_codec *codec, int force)
9496{
9497 struct alc_spec *spec = codec->spec;
9498 unsigned int mute;
9499
9500 if (force || !spec->sense_updated) {
9501 unsigned int present_int_hp;
9502 /* need to execute and sync at first */
9503 snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
9504 present_int_hp = snd_hda_codec_read(codec, 0x1b, 0,
9505 AC_VERB_GET_PIN_SENSE, 0);
9506 spec->jack_present = (present_int_hp & 0x80000000) != 0;
9507 spec->sense_updated = 1;
9508 }
9509 if (spec->jack_present) {
9510 /* mute internal speaker */
9511 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9512 HDA_AMP_MUTE, HDA_AMP_MUTE);
9513 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
9514 HDA_AMP_MUTE, HDA_AMP_MUTE);
9515 } else {
9516 /* unmute internal speaker if necessary */
9517 mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
9518 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9519 HDA_AMP_MUTE, mute);
9520 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
9521 HDA_AMP_MUTE, mute);
9522 }
9523}
9524
9525/* unsolicited event for HP jack sensing */
9526static void alc262_lenovo_3000_unsol_event(struct hda_codec *codec,
9527 unsigned int res)
9528{
9529 if ((res >> 26) != ALC_HP_EVENT)
9530 return;
9531 alc262_lenovo_3000_automute(codec, 1);
9532}
9533
Takashi Iwai834be882006-03-01 14:16:17 +01009534/* bind hp and internal speaker mute (with plug check) */
9535static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol,
9536 struct snd_ctl_elem_value *ucontrol)
9537{
9538 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
9539 long *valp = ucontrol->value.integer.value;
9540 int change;
9541
Tony Vroon5d9fab22008-03-14 17:09:18 +01009542 change = snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9543 HDA_AMP_MUTE,
9544 valp ? 0 : HDA_AMP_MUTE);
9545 change |= snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
9546 HDA_AMP_MUTE,
9547 valp ? 0 : HDA_AMP_MUTE);
9548
Takashi Iwai82beb8f2007-08-10 17:09:26 +02009549 if (change)
9550 alc262_fujitsu_automute(codec, 0);
Takashi Iwai834be882006-03-01 14:16:17 +01009551 return change;
9552}
9553
9554static struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02009555 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
Takashi Iwai834be882006-03-01 14:16:17 +01009556 {
9557 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9558 .name = "Master Playback Switch",
9559 .info = snd_hda_mixer_amp_switch_info,
9560 .get = snd_hda_mixer_amp_switch_get,
9561 .put = alc262_fujitsu_master_sw_put,
9562 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
9563 },
9564 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9565 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Tony Vroon06a9c302008-04-14 13:31:45 +02009566 HDA_CODEC_VOLUME("PC Speaker Volume", 0x0b, 0x05, HDA_INPUT),
9567 HDA_CODEC_MUTE("PC Speaker Switch", 0x0b, 0x05, HDA_INPUT),
Takashi Iwai834be882006-03-01 14:16:17 +01009568 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9569 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9570 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai39d3ed32007-10-12 15:03:48 +02009571 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
9572 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
9573 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai834be882006-03-01 14:16:17 +01009574 { } /* end */
9575};
9576
Jiang zhe0e31daf2008-03-20 12:12:39 +01009577/* bind hp and internal speaker mute (with plug check) */
9578static int alc262_lenovo_3000_master_sw_put(struct snd_kcontrol *kcontrol,
9579 struct snd_ctl_elem_value *ucontrol)
9580{
9581 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
9582 long *valp = ucontrol->value.integer.value;
9583 int change;
9584
9585 change = snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
9586 HDA_AMP_MUTE,
9587 valp ? 0 : HDA_AMP_MUTE);
9588
9589 if (change)
9590 alc262_lenovo_3000_automute(codec, 0);
9591 return change;
9592}
9593
9594static struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = {
9595 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
9596 {
9597 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9598 .name = "Master Playback Switch",
9599 .info = snd_hda_mixer_amp_switch_info,
9600 .get = snd_hda_mixer_amp_switch_get,
9601 .put = alc262_lenovo_3000_master_sw_put,
9602 .private_value = HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
9603 },
9604 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9605 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9606 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9607 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9608 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9609 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
9610 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
9611 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
9612 { } /* end */
9613};
9614
Hiroshi Miura9f99a632008-08-28 16:09:06 +02009615static struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = {
9616 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
9617 {
9618 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9619 .name = "Master Playback Switch",
9620 .info = snd_hda_mixer_amp_switch_info,
9621 .get = snd_hda_mixer_amp_switch_get,
9622 .put = alc262_sony_master_sw_put,
9623 .private_value = HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
9624 },
9625 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9626 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9627 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9628 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
9629 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
9630 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
9631 { } /* end */
9632};
9633
Takashi Iwai304dcaa2006-07-25 14:51:16 +02009634/* additional init verbs for Benq laptops */
9635static struct hda_verb alc262_EAPD_verbs[] = {
9636 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
9637 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
9638 {}
9639};
9640
Kailang Yang83c34212007-07-05 11:43:05 +02009641static struct hda_verb alc262_benq_t31_EAPD_verbs[] = {
9642 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9643 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9644
9645 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
9646 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
9647 {}
9648};
9649
Tobin Davisf651b502007-10-26 12:40:47 +02009650/* Samsung Q1 Ultra Vista model setup */
9651static struct snd_kcontrol_new alc262_ultra_mixer[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01009652 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9653 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +02009654 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
9655 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
9656 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01009657 HDA_CODEC_VOLUME("Headphone Mic Boost", 0x15, 0, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +02009658 { } /* end */
9659};
9660
9661static struct hda_verb alc262_ultra_verbs[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01009662 /* output mixer */
9663 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9664 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
9665 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9666 /* speaker */
9667 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9668 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9669 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9670 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
9671 /* HP */
Tobin Davisf651b502007-10-26 12:40:47 +02009672 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01009673 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9674 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9675 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9676 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
9677 /* internal mic */
9678 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
9679 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
9680 /* ADC, choose mic */
9681 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9682 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9683 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9684 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
9685 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
9686 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
9687 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
9688 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
9689 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
9690 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(8)},
Tobin Davisf651b502007-10-26 12:40:47 +02009691 {}
9692};
9693
Tobin Davisf651b502007-10-26 12:40:47 +02009694/* mute/unmute internal speaker according to the hp jack and mute state */
9695static void alc262_ultra_automute(struct hda_codec *codec)
9696{
9697 struct alc_spec *spec = codec->spec;
9698 unsigned int mute;
Tobin Davisf651b502007-10-26 12:40:47 +02009699
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01009700 mute = 0;
9701 /* auto-mute only when HP is used as HP */
9702 if (!spec->cur_mux[0]) {
9703 unsigned int present;
9704 /* need to execute and sync at first */
9705 snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0);
9706 present = snd_hda_codec_read(codec, 0x15, 0,
9707 AC_VERB_GET_PIN_SENSE, 0);
9708 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
9709 if (spec->jack_present)
9710 mute = HDA_AMP_MUTE;
Tobin Davisf651b502007-10-26 12:40:47 +02009711 }
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01009712 /* mute/unmute internal speaker */
9713 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9714 HDA_AMP_MUTE, mute);
9715 /* mute/unmute HP */
9716 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9717 HDA_AMP_MUTE, mute ? 0 : HDA_AMP_MUTE);
Tobin Davisf651b502007-10-26 12:40:47 +02009718}
9719
9720/* unsolicited event for HP jack sensing */
9721static void alc262_ultra_unsol_event(struct hda_codec *codec,
9722 unsigned int res)
9723{
9724 if ((res >> 26) != ALC880_HP_EVENT)
9725 return;
9726 alc262_ultra_automute(codec);
9727}
9728
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01009729static struct hda_input_mux alc262_ultra_capture_source = {
9730 .num_items = 2,
9731 .items = {
9732 { "Mic", 0x1 },
9733 { "Headphone", 0x7 },
9734 },
9735};
9736
9737static int alc262_ultra_mux_enum_put(struct snd_kcontrol *kcontrol,
9738 struct snd_ctl_elem_value *ucontrol)
9739{
9740 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
9741 struct alc_spec *spec = codec->spec;
9742 int ret;
9743
Takashi Iwai54cbc9a2008-10-31 15:24:04 +01009744 ret = alc_mux_enum_put(kcontrol, ucontrol);
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01009745 if (!ret)
9746 return 0;
9747 /* reprogram the HP pin as mic or HP according to the input source */
9748 snd_hda_codec_write_cache(codec, 0x15, 0,
9749 AC_VERB_SET_PIN_WIDGET_CONTROL,
9750 spec->cur_mux[0] ? PIN_VREF80 : PIN_HP);
9751 alc262_ultra_automute(codec); /* mute/unmute HP */
9752 return ret;
9753}
9754
9755static struct snd_kcontrol_new alc262_ultra_capture_mixer[] = {
9756 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
9757 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
9758 {
9759 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9760 .name = "Capture Source",
Takashi Iwai54cbc9a2008-10-31 15:24:04 +01009761 .info = alc_mux_enum_info,
9762 .get = alc_mux_enum_get,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01009763 .put = alc262_ultra_mux_enum_put,
9764 },
9765 { } /* end */
9766};
9767
Kailang Yangdf694da2005-12-05 19:42:22 +01009768/* add playback controls from the parsed DAC table */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009769static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
9770 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +01009771{
9772 hda_nid_t nid;
9773 int err;
9774
9775 spec->multiout.num_dacs = 1; /* only use one dac */
9776 spec->multiout.dac_nids = spec->private_dac_nids;
9777 spec->multiout.dac_nids[0] = 2;
9778
9779 nid = cfg->line_out_pins[0];
9780 if (nid) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009781 err = add_control(spec, ALC_CTL_WIDGET_VOL,
9782 "Front Playback Volume",
9783 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT));
9784 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009785 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009786 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
9787 "Front Playback Switch",
9788 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
9789 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009790 return err;
9791 }
9792
Takashi Iwai82bc9552006-03-21 11:24:42 +01009793 nid = cfg->speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01009794 if (nid) {
9795 if (nid == 0x16) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009796 err = add_control(spec, ALC_CTL_WIDGET_VOL,
9797 "Speaker Playback Volume",
9798 HDA_COMPOSE_AMP_VAL(0x0e, 2, 0,
9799 HDA_OUTPUT));
9800 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009801 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009802 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
9803 "Speaker Playback Switch",
9804 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
9805 HDA_OUTPUT));
9806 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009807 return err;
9808 } else {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009809 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
9810 "Speaker Playback Switch",
9811 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
9812 HDA_OUTPUT));
9813 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009814 return err;
9815 }
9816 }
Takashi Iwaieb06ed82006-09-20 17:10:27 +02009817 nid = cfg->hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01009818 if (nid) {
9819 /* spec->multiout.hp_nid = 2; */
9820 if (nid == 0x16) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009821 err = add_control(spec, ALC_CTL_WIDGET_VOL,
9822 "Headphone Playback Volume",
9823 HDA_COMPOSE_AMP_VAL(0x0e, 2, 0,
9824 HDA_OUTPUT));
9825 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009826 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009827 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
9828 "Headphone Playback Switch",
9829 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
9830 HDA_OUTPUT));
9831 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009832 return err;
9833 } else {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009834 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
9835 "Headphone Playback Switch",
9836 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
9837 HDA_OUTPUT));
9838 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01009839 return err;
9840 }
9841 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009842 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01009843}
9844
9845/* identical with ALC880 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009846#define alc262_auto_create_analog_input_ctls \
9847 alc880_auto_create_analog_input_ctls
Kailang Yangdf694da2005-12-05 19:42:22 +01009848
9849/*
9850 * generic initialization of ADC, input mixers and output mixers
9851 */
9852static struct hda_verb alc262_volume_init_verbs[] = {
9853 /*
9854 * Unmute ADC0-2 and set the default input to mic-in
9855 */
9856 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
9857 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9858 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
9859 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9860 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
9861 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9862
Takashi Iwaicb53c622007-08-10 17:21:45 +02009863 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +01009864 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009865 * Note: PASD motherboards uses the Line In 2 as the input for
9866 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01009867 */
9868 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02009869 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9870 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
9871 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
9872 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
9873 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01009874
9875 /*
9876 * Set up output mixers (0x0c - 0x0f)
9877 */
9878 /* set vol=0 to output mixers */
9879 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9880 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9881 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yangea1fb292008-08-26 12:58:38 +02009882
Kailang Yangdf694da2005-12-05 19:42:22 +01009883 /* set up input amps for analog loopback */
9884 /* Amp Indices: DAC = 0, mixer = 1 */
9885 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9886 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9887 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9888 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9889 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9890 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9891
9892 /* FIXME: use matrix-type input source selection */
9893 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
9894 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
9895 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9896 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
9897 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
9898 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
9899 /* Input mixer2 */
9900 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9901 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
9902 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
9903 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
9904 /* Input mixer3 */
9905 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9906 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
9907 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
9908 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
9909
9910 { }
9911};
9912
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009913static struct hda_verb alc262_HP_BPC_init_verbs[] = {
9914 /*
9915 * Unmute ADC0-2 and set the default input to mic-in
9916 */
9917 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
9918 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9919 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
9920 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9921 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
9922 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9923
Takashi Iwaicb53c622007-08-10 17:21:45 +02009924 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009925 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009926 * Note: PASD motherboards uses the Line In 2 as the input for
9927 * front panel mic (mic 2)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009928 */
9929 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02009930 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9931 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
9932 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
9933 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
9934 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
9935 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
9936 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
Kailang Yangea1fb292008-08-26 12:58:38 +02009937
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009938 /*
9939 * Set up output mixers (0x0c - 0x0e)
9940 */
9941 /* set vol=0 to output mixers */
9942 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9943 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9944 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9945
9946 /* set up input amps for analog loopback */
9947 /* Amp Indices: DAC = 0, mixer = 1 */
9948 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9949 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9950 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9951 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9952 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9953 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9954
Takashi Iwaice875f02008-01-28 18:17:43 +01009955 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009956 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9957 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9958
9959 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
9960 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
9961
9962 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
9963 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9964
9965 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9966 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9967 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9968 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9969 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9970
9971 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
9972 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
9973 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
9974 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
9975 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
9976 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
9977
9978
9979 /* FIXME: use matrix-type input source selection */
9980 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
9981 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
9982 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9983 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
9984 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
9985 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
9986 /* Input mixer2 */
9987 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9988 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
9989 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
9990 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
9991 /* Input mixer3 */
9992 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9993 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
9994 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
9995 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
9996
Takashi Iwaice875f02008-01-28 18:17:43 +01009997 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9998
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009999 { }
10000};
10001
Kailang Yangcd7509a2007-01-26 18:33:17 +010010002static struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = {
10003 /*
10004 * Unmute ADC0-2 and set the default input to mic-in
10005 */
10006 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
10007 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10008 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
10009 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10010 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
10011 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10012
Takashi Iwaicb53c622007-08-10 17:21:45 +020010013 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangcd7509a2007-01-26 18:33:17 +010010014 * mixer widget
10015 * Note: PASD motherboards uses the Line In 2 as the input for front
10016 * panel mic (mic 2)
10017 */
10018 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020010019 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
10020 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10021 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
10022 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
10023 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
10024 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
10025 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
10026 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Kailang Yangcd7509a2007-01-26 18:33:17 +010010027 /*
10028 * Set up output mixers (0x0c - 0x0e)
10029 */
10030 /* set vol=0 to output mixers */
10031 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10032 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10033 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10034
10035 /* set up input amps for analog loopback */
10036 /* Amp Indices: DAC = 0, mixer = 1 */
10037 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10038 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10039 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10040 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10041 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10042 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10043
10044
10045 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP */
10046 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Mono */
10047 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* rear MIC */
10048 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* Line in */
10049 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
10050 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Line out */
10051 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD in */
10052
10053 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
10054 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
10055
10056 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
10057 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
10058
10059 /* {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, */
10060 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10061 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10062 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
10063 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10064 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10065
10066 /* FIXME: use matrix-type input source selection */
10067 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
10068 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
10069 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, /*rear MIC*/
10070 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, /*Line in*/
10071 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, /*F MIC*/
10072 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, /*Front*/
10073 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, /*CD*/
10074 /* {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
10075 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, /*HP*/
10076 /* Input mixer2 */
10077 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10078 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
10079 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
10080 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
10081 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
10082 /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
10083 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
10084 /* Input mixer3 */
10085 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10086 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
10087 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
10088 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
10089 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
10090 /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
10091 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
10092
Takashi Iwaice875f02008-01-28 18:17:43 +010010093 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
10094
Kailang Yangcd7509a2007-01-26 18:33:17 +010010095 { }
10096};
10097
Hiroshi Miura9f99a632008-08-28 16:09:06 +020010098static struct hda_verb alc262_toshiba_rx1_unsol_verbs[] = {
10099
10100 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Front Speaker */
10101 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
10102 {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
10103
10104 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* MIC jack */
10105 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
10106 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
10107 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
10108
10109 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP jack */
10110 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
10111 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
10112 {}
10113};
10114
10115
Takashi Iwaicb53c622007-08-10 17:21:45 +020010116#ifdef CONFIG_SND_HDA_POWER_SAVE
10117#define alc262_loopbacks alc880_loopbacks
10118#endif
10119
Kailang Yangdf694da2005-12-05 19:42:22 +010010120/* pcm configuration: identiacal with ALC880 */
10121#define alc262_pcm_analog_playback alc880_pcm_analog_playback
10122#define alc262_pcm_analog_capture alc880_pcm_analog_capture
10123#define alc262_pcm_digital_playback alc880_pcm_digital_playback
10124#define alc262_pcm_digital_capture alc880_pcm_digital_capture
10125
10126/*
10127 * BIOS auto configuration
10128 */
10129static int alc262_parse_auto_config(struct hda_codec *codec)
10130{
10131 struct alc_spec *spec = codec->spec;
10132 int err;
10133 static hda_nid_t alc262_ignore[] = { 0x1d, 0 };
10134
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010135 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
10136 alc262_ignore);
10137 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010138 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010139 if (!spec->autocfg.line_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +010010140 return 0; /* can't find valid BIOS pin config */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010141 err = alc262_auto_create_multi_out_ctls(spec, &spec->autocfg);
10142 if (err < 0)
10143 return err;
10144 err = alc262_auto_create_analog_input_ctls(spec, &spec->autocfg);
10145 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010146 return err;
10147
10148 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
10149
10150 if (spec->autocfg.dig_out_pin)
10151 spec->multiout.dig_out_nid = ALC262_DIGOUT_NID;
10152 if (spec->autocfg.dig_in_pin)
10153 spec->dig_in_nid = ALC262_DIGIN_NID;
10154
Takashi Iwai603c4012008-07-30 15:01:44 +020010155 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010010156 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +010010157
Takashi Iwaid88897e2008-10-31 15:01:37 +010010158 add_verb(spec, alc262_volume_init_verbs);
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020010159 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +010010160 spec->input_mux = &spec->private_imux;
10161
Takashi Iwai776e1842007-08-29 15:07:11 +020010162 err = alc_auto_add_mic_boost(codec);
10163 if (err < 0)
10164 return err;
10165
Takashi Iwaie044c392008-10-27 16:56:24 +010010166 store_pin_configs(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010010167 return 1;
10168}
10169
10170#define alc262_auto_init_multi_out alc882_auto_init_multi_out
10171#define alc262_auto_init_hp_out alc882_auto_init_hp_out
10172#define alc262_auto_init_analog_input alc882_auto_init_analog_input
Takashi Iwaif511b012008-08-15 16:46:42 +020010173#define alc262_auto_init_input_src alc882_auto_init_input_src
Kailang Yangdf694da2005-12-05 19:42:22 +010010174
10175
10176/* init callback for auto-configuration model -- overriding the default init */
Takashi Iwaiae6b8132006-03-03 16:47:17 +010010177static void alc262_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010010178{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010179 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010010180 alc262_auto_init_multi_out(codec);
10181 alc262_auto_init_hp_out(codec);
10182 alc262_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020010183 alc262_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010184 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020010185 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010010186}
10187
10188/*
10189 * configuration and preset
10190 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010191static const char *alc262_models[ALC262_MODEL_LAST] = {
10192 [ALC262_BASIC] = "basic",
10193 [ALC262_HIPPO] = "hippo",
10194 [ALC262_HIPPO_1] = "hippo_1",
10195 [ALC262_FUJITSU] = "fujitsu",
10196 [ALC262_HP_BPC] = "hp-bpc",
Kailang Yangcd7509a2007-01-26 18:33:17 +010010197 [ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000",
Takashi Iwai61dc35d2007-11-14 12:26:44 +010010198 [ALC262_HP_TC_T5735] = "hp-tc-t5735",
Kailang Yang8c427222008-01-10 13:03:59 +010010199 [ALC262_HP_RP5700] = "hp-rp5700",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010200 [ALC262_BENQ_ED8] = "benq",
Takashi Iwai0f405022007-07-06 12:24:11 +020010201 [ALC262_BENQ_T31] = "benq-t31",
10202 [ALC262_SONY_ASSAMD] = "sony-assamd",
Takashi Iwai2922c9a2008-08-27 18:12:42 +020010203 [ALC262_TOSHIBA_S06] = "toshiba-s06",
Hiroshi Miura9f99a632008-08-28 16:09:06 +020010204 [ALC262_TOSHIBA_RX1] = "toshiba-rx1",
Tobin Davisf651b502007-10-26 12:40:47 +020010205 [ALC262_ULTRA] = "ultra",
Jiang zhe0e31daf2008-03-20 12:12:39 +010010206 [ALC262_LENOVO_3000] = "lenovo-3000",
Pascal Terjane8f9ae22008-08-04 14:36:05 +020010207 [ALC262_NEC] = "nec",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010208 [ALC262_AUTO] = "auto",
10209};
10210
10211static struct snd_pci_quirk alc262_cfg_tbl[] = {
10212 SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO),
Pascal Terjane8f9ae22008-08-04 14:36:05 +020010213 SND_PCI_QUIRK(0x1033, 0x8895, "NEC Versa S9100", ALC262_NEC),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010214 SND_PCI_QUIRK(0x103c, 0x12fe, "HP xw9400", ALC262_HP_BPC),
Kailang Yang7d87de22007-06-05 12:17:21 +020010215 SND_PCI_QUIRK(0x103c, 0x12ff, "HP xw4550", ALC262_HP_BPC),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010216 SND_PCI_QUIRK(0x103c, 0x1306, "HP xw8600", ALC262_HP_BPC),
10217 SND_PCI_QUIRK(0x103c, 0x1307, "HP xw6600", ALC262_HP_BPC),
Kailang Yang7d87de22007-06-05 12:17:21 +020010218 SND_PCI_QUIRK(0x103c, 0x1308, "HP xw4600", ALC262_HP_BPC),
Takashi Iwaib98f9332007-11-07 14:18:01 +010010219 SND_PCI_QUIRK(0x103c, 0x1309, "HP xw4*00", ALC262_HP_BPC),
Takashi Iwaib98f9332007-11-07 14:18:01 +010010220 SND_PCI_QUIRK(0x103c, 0x130a, "HP xw6*00", ALC262_HP_BPC),
Takashi Iwaib98f9332007-11-07 14:18:01 +010010221 SND_PCI_QUIRK(0x103c, 0x130b, "HP xw8*00", ALC262_HP_BPC),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010222 SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010223 SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010224 SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010225 SND_PCI_QUIRK(0x103c, 0x2803, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010226 SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010227 SND_PCI_QUIRK(0x103c, 0x2805, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010228 SND_PCI_QUIRK(0x103c, 0x2806, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010229 SND_PCI_QUIRK(0x103c, 0x2807, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010230 SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC),
10231 SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC),
10232 SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC),
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010233 SND_PCI_QUIRK(0x103c, 0x302f, "HP Thin Client T5735",
10234 ALC262_HP_TC_T5735),
Kailang Yang8c427222008-01-10 13:03:59 +010010235 SND_PCI_QUIRK(0x103c, 0x2817, "HP RP5700", ALC262_HP_RP5700),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010236 SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010237 SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010238 SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD),
10239 SND_PCI_QUIRK(0x104d, 0x900e, "Sony ASSAMD", ALC262_SONY_ASSAMD),
10240 SND_PCI_QUIRK(0x104d, 0x9015, "Sony 0x9015", ALC262_SONY_ASSAMD),
Akio Idehara36ca6e12008-06-09 22:57:40 +090010241 SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1",
Hiroshi Miura9f99a632008-08-28 16:09:06 +020010242 ALC262_TOSHIBA_RX1),
Kailang Yang80ffe862008-10-15 11:23:27 +020010243 SND_PCI_QUIRK(0x1179, 0xff7b, "Toshiba S06", ALC262_TOSHIBA_S06),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010244 SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU),
Tony Vroon3f1eeae2008-02-25 16:44:13 +010010245 SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010246 SND_PCI_QUIRK(0x144d, 0xc032, "Samsung Q1 Ultra", ALC262_ULTRA),
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010247 SND_PCI_QUIRK(0x144d, 0xc039, "Samsung Q1U EL", ALC262_ULTRA),
Jiang zhe0e31daf2008-03-20 12:12:39 +010010248 SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 y410", ALC262_LENOVO_3000),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010249 SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8),
Kailang Yang83c34212007-07-05 11:43:05 +020010250 SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010251 SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1),
Kailang Yangdf694da2005-12-05 19:42:22 +010010252 {}
10253};
10254
10255static struct alc_config_preset alc262_presets[] = {
10256 [ALC262_BASIC] = {
10257 .mixers = { alc262_base_mixer },
10258 .init_verbs = { alc262_init_verbs },
10259 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10260 .dac_nids = alc262_dac_nids,
10261 .hp_nid = 0x03,
10262 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10263 .channel_mode = alc262_modes,
Takashi Iwaia3bcba32005-12-06 19:05:29 +010010264 .input_mux = &alc262_capture_source,
Kailang Yangdf694da2005-12-05 19:42:22 +010010265 },
Kailang Yangccc656c2006-10-17 12:32:26 +020010266 [ALC262_HIPPO] = {
10267 .mixers = { alc262_base_mixer },
10268 .init_verbs = { alc262_init_verbs, alc262_hippo_unsol_verbs},
10269 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10270 .dac_nids = alc262_dac_nids,
10271 .hp_nid = 0x03,
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_hippo_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +020010277 .init_hook = alc262_hippo_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020010278 },
10279 [ALC262_HIPPO_1] = {
10280 .mixers = { alc262_hippo1_mixer },
10281 .init_verbs = { alc262_init_verbs, alc262_hippo1_unsol_verbs},
10282 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10283 .dac_nids = alc262_dac_nids,
10284 .hp_nid = 0x02,
10285 .dig_out_nid = ALC262_DIGOUT_NID,
10286 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10287 .channel_mode = alc262_modes,
10288 .input_mux = &alc262_capture_source,
10289 .unsol_event = alc262_hippo1_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +020010290 .init_hook = alc262_hippo1_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020010291 },
Takashi Iwai834be882006-03-01 14:16:17 +010010292 [ALC262_FUJITSU] = {
10293 .mixers = { alc262_fujitsu_mixer },
Takashi Iwai39d3ed32007-10-12 15:03:48 +020010294 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
10295 alc262_fujitsu_unsol_verbs },
Takashi Iwai834be882006-03-01 14:16:17 +010010296 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10297 .dac_nids = alc262_dac_nids,
10298 .hp_nid = 0x03,
10299 .dig_out_nid = ALC262_DIGOUT_NID,
10300 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10301 .channel_mode = alc262_modes,
10302 .input_mux = &alc262_fujitsu_capture_source,
Takashi Iwaiae6b8132006-03-03 16:47:17 +010010303 .unsol_event = alc262_fujitsu_unsol_event,
Takashi Iwaiebc7a402008-05-20 09:23:05 +020010304 .init_hook = alc262_fujitsu_init_hook,
Takashi Iwai834be882006-03-01 14:16:17 +010010305 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010306 [ALC262_HP_BPC] = {
10307 .mixers = { alc262_HP_BPC_mixer },
10308 .init_verbs = { alc262_HP_BPC_init_verbs },
10309 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10310 .dac_nids = alc262_dac_nids,
10311 .hp_nid = 0x03,
10312 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10313 .channel_mode = alc262_modes,
10314 .input_mux = &alc262_HP_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010010315 .unsol_event = alc262_hp_bpc_unsol_event,
10316 .init_hook = alc262_hp_bpc_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010317 },
Kailang Yangcd7509a2007-01-26 18:33:17 +010010318 [ALC262_HP_BPC_D7000_WF] = {
10319 .mixers = { alc262_HP_BPC_WildWest_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 Yangcd7509a2007-01-26 18:33:17 +010010330 [ALC262_HP_BPC_D7000_WL] = {
10331 .mixers = { alc262_HP_BPC_WildWest_mixer,
10332 alc262_HP_BPC_WildWest_option_mixer },
10333 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
10334 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10335 .dac_nids = alc262_dac_nids,
10336 .hp_nid = 0x03,
10337 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10338 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +020010339 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010010340 .unsol_event = alc262_hp_wildwest_unsol_event,
10341 .init_hook = alc262_hp_wildwest_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010342 },
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010343 [ALC262_HP_TC_T5735] = {
10344 .mixers = { alc262_hp_t5735_mixer },
10345 .init_verbs = { alc262_init_verbs, alc262_hp_t5735_verbs },
10346 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10347 .dac_nids = alc262_dac_nids,
10348 .hp_nid = 0x03,
10349 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10350 .channel_mode = alc262_modes,
10351 .input_mux = &alc262_capture_source,
10352 .unsol_event = alc262_hp_t5735_unsol_event,
10353 .init_hook = alc262_hp_t5735_init_hook,
Kailang Yang8c427222008-01-10 13:03:59 +010010354 },
10355 [ALC262_HP_RP5700] = {
10356 .mixers = { alc262_hp_rp5700_mixer },
10357 .init_verbs = { alc262_init_verbs, alc262_hp_rp5700_verbs },
10358 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10359 .dac_nids = alc262_dac_nids,
10360 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10361 .channel_mode = alc262_modes,
10362 .input_mux = &alc262_hp_rp5700_capture_source,
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010363 },
Takashi Iwai304dcaa2006-07-25 14:51:16 +020010364 [ALC262_BENQ_ED8] = {
10365 .mixers = { alc262_base_mixer },
10366 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs },
10367 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10368 .dac_nids = alc262_dac_nids,
10369 .hp_nid = 0x03,
10370 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10371 .channel_mode = alc262_modes,
10372 .input_mux = &alc262_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010373 },
Kailang Yang272a5272007-05-14 11:00:38 +020010374 [ALC262_SONY_ASSAMD] = {
10375 .mixers = { alc262_sony_mixer },
10376 .init_verbs = { alc262_init_verbs, alc262_sony_unsol_verbs},
10377 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10378 .dac_nids = alc262_dac_nids,
10379 .hp_nid = 0x02,
10380 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10381 .channel_mode = alc262_modes,
10382 .input_mux = &alc262_capture_source,
10383 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +020010384 .init_hook = alc262_hippo_automute,
Kailang Yang83c34212007-07-05 11:43:05 +020010385 },
10386 [ALC262_BENQ_T31] = {
10387 .mixers = { alc262_benq_t31_mixer },
10388 .init_verbs = { alc262_init_verbs, alc262_benq_t31_EAPD_verbs, alc262_hippo_unsol_verbs },
10389 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10390 .dac_nids = alc262_dac_nids,
10391 .hp_nid = 0x03,
10392 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10393 .channel_mode = alc262_modes,
10394 .input_mux = &alc262_capture_source,
10395 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +020010396 .init_hook = alc262_hippo_automute,
Kailang Yangea1fb292008-08-26 12:58:38 +020010397 },
Tobin Davisf651b502007-10-26 12:40:47 +020010398 [ALC262_ULTRA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010399 .mixers = { alc262_ultra_mixer },
10400 .cap_mixer = alc262_ultra_capture_mixer,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010401 .init_verbs = { alc262_ultra_verbs },
Tobin Davisf651b502007-10-26 12:40:47 +020010402 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10403 .dac_nids = alc262_dac_nids,
Tobin Davisf651b502007-10-26 12:40:47 +020010404 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10405 .channel_mode = alc262_modes,
10406 .input_mux = &alc262_ultra_capture_source,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010407 .adc_nids = alc262_adc_nids, /* ADC0 */
10408 .capsrc_nids = alc262_capsrc_nids,
10409 .num_adc_nids = 1, /* single ADC */
Tobin Davisf651b502007-10-26 12:40:47 +020010410 .unsol_event = alc262_ultra_unsol_event,
10411 .init_hook = alc262_ultra_automute,
10412 },
Jiang zhe0e31daf2008-03-20 12:12:39 +010010413 [ALC262_LENOVO_3000] = {
10414 .mixers = { alc262_lenovo_3000_mixer },
10415 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
10416 alc262_lenovo_3000_unsol_verbs },
10417 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10418 .dac_nids = alc262_dac_nids,
10419 .hp_nid = 0x03,
10420 .dig_out_nid = ALC262_DIGOUT_NID,
10421 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10422 .channel_mode = alc262_modes,
10423 .input_mux = &alc262_fujitsu_capture_source,
10424 .unsol_event = alc262_lenovo_3000_unsol_event,
10425 },
Pascal Terjane8f9ae22008-08-04 14:36:05 +020010426 [ALC262_NEC] = {
10427 .mixers = { alc262_nec_mixer },
10428 .init_verbs = { alc262_nec_verbs },
10429 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10430 .dac_nids = alc262_dac_nids,
10431 .hp_nid = 0x03,
10432 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10433 .channel_mode = alc262_modes,
10434 .input_mux = &alc262_capture_source,
10435 },
Kailang Yang4e555fe2008-08-26 13:05:55 +020010436 [ALC262_TOSHIBA_S06] = {
10437 .mixers = { alc262_toshiba_s06_mixer },
10438 .init_verbs = { alc262_init_verbs, alc262_toshiba_s06_verbs,
10439 alc262_eapd_verbs },
10440 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10441 .capsrc_nids = alc262_dmic_capsrc_nids,
10442 .dac_nids = alc262_dac_nids,
10443 .adc_nids = alc262_dmic_adc_nids, /* ADC0 */
10444 .dig_out_nid = ALC262_DIGOUT_NID,
10445 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10446 .channel_mode = alc262_modes,
10447 .input_mux = &alc262_dmic_capture_source,
10448 .unsol_event = alc262_toshiba_s06_unsol_event,
10449 .init_hook = alc262_toshiba_s06_init_hook,
10450 },
Hiroshi Miura9f99a632008-08-28 16:09:06 +020010451 [ALC262_TOSHIBA_RX1] = {
10452 .mixers = { alc262_toshiba_rx1_mixer },
10453 .init_verbs = { alc262_init_verbs, alc262_toshiba_rx1_unsol_verbs },
10454 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10455 .dac_nids = alc262_dac_nids,
10456 .hp_nid = 0x03,
10457 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10458 .channel_mode = alc262_modes,
10459 .input_mux = &alc262_capture_source,
10460 .unsol_event = alc262_hippo_unsol_event,
10461 .init_hook = alc262_hippo_automute,
10462 },
Kailang Yangdf694da2005-12-05 19:42:22 +010010463};
10464
10465static int patch_alc262(struct hda_codec *codec)
10466{
10467 struct alc_spec *spec;
10468 int board_config;
10469 int err;
10470
Robert P. J. Daydc041e02006-12-19 14:44:15 +010010471 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010010472 if (spec == NULL)
10473 return -ENOMEM;
10474
10475 codec->spec = spec;
10476#if 0
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010477 /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is
10478 * under-run
10479 */
Kailang Yangdf694da2005-12-05 19:42:22 +010010480 {
10481 int tmp;
10482 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
10483 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
10484 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
10485 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80);
10486 }
10487#endif
10488
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020010489 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
10490
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010491 board_config = snd_hda_check_board_config(codec, ALC262_MODEL_LAST,
10492 alc262_models,
10493 alc262_cfg_tbl);
Kailang Yangcd7509a2007-01-26 18:33:17 +010010494
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010495 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010496 printk(KERN_INFO "hda_codec: Unknown model for ALC262, "
10497 "trying auto-probe from BIOS...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010010498 board_config = ALC262_AUTO;
10499 }
10500
10501 if (board_config == ALC262_AUTO) {
10502 /* automatic parse from the BIOS config */
10503 err = alc262_parse_auto_config(codec);
10504 if (err < 0) {
10505 alc_free(codec);
10506 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010507 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010508 printk(KERN_INFO
10509 "hda_codec: Cannot set up configuration "
10510 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010010511 board_config = ALC262_BASIC;
10512 }
10513 }
10514
10515 if (board_config != ALC262_AUTO)
10516 setup_preset(spec, &alc262_presets[board_config]);
10517
10518 spec->stream_name_analog = "ALC262 Analog";
10519 spec->stream_analog_playback = &alc262_pcm_analog_playback;
10520 spec->stream_analog_capture = &alc262_pcm_analog_capture;
Kailang Yangea1fb292008-08-26 12:58:38 +020010521
Kailang Yangdf694da2005-12-05 19:42:22 +010010522 spec->stream_name_digital = "ALC262 Digital";
10523 spec->stream_digital_playback = &alc262_pcm_digital_playback;
10524 spec->stream_digital_capture = &alc262_pcm_digital_capture;
10525
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010010526 spec->is_mix_capture = 1;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010527 if (!spec->adc_nids && spec->input_mux) {
Kailang Yangdf694da2005-12-05 19:42:22 +010010528 /* check whether NID 0x07 is valid */
Takashi Iwai4a471b72005-12-07 13:56:29 +010010529 unsigned int wcap = get_wcaps(codec, 0x07);
10530
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010531 /* get type */
10532 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Kailang Yangdf694da2005-12-05 19:42:22 +010010533 if (wcap != AC_WID_AUD_IN) {
10534 spec->adc_nids = alc262_adc_nids_alt;
10535 spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids_alt);
Takashi Iwai88c71a92008-02-14 17:27:17 +010010536 spec->capsrc_nids = alc262_capsrc_nids_alt;
Kailang Yangdf694da2005-12-05 19:42:22 +010010537 } else {
10538 spec->adc_nids = alc262_adc_nids;
10539 spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids);
Takashi Iwai88c71a92008-02-14 17:27:17 +010010540 spec->capsrc_nids = alc262_capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +010010541 }
10542 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010543 if (!spec->cap_mixer)
10544 set_capture_mixer(spec);
Kailang Yangdf694da2005-12-05 19:42:22 +010010545
Takashi Iwai2134ea42008-01-10 16:53:55 +010010546 spec->vmaster_nid = 0x0c;
10547
Kailang Yangdf694da2005-12-05 19:42:22 +010010548 codec->patch_ops = alc_patch_ops;
10549 if (board_config == ALC262_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +010010550 spec->init_hook = alc262_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020010551#ifdef CONFIG_SND_HDA_POWER_SAVE
10552 if (!spec->loopback.amplist)
10553 spec->loopback.amplist = alc262_loopbacks;
10554#endif
Kailang Yangea1fb292008-08-26 12:58:38 +020010555
Kailang Yangdf694da2005-12-05 19:42:22 +010010556 return 0;
10557}
10558
Kailang Yangdf694da2005-12-05 19:42:22 +010010559/*
Kailang Yanga361d842007-06-05 12:30:55 +020010560 * ALC268 channel source setting (2 channel)
10561 */
10562#define ALC268_DIGOUT_NID ALC880_DIGOUT_NID
10563#define alc268_modes alc260_modes
Kailang Yangea1fb292008-08-26 12:58:38 +020010564
Kailang Yanga361d842007-06-05 12:30:55 +020010565static hda_nid_t alc268_dac_nids[2] = {
10566 /* front, hp */
10567 0x02, 0x03
10568};
10569
10570static hda_nid_t alc268_adc_nids[2] = {
10571 /* ADC0-1 */
10572 0x08, 0x07
10573};
10574
10575static hda_nid_t alc268_adc_nids_alt[1] = {
10576 /* ADC0 */
10577 0x08
10578};
10579
Takashi Iwaie1406342008-02-11 18:32:32 +010010580static hda_nid_t alc268_capsrc_nids[2] = { 0x23, 0x24 };
10581
Kailang Yanga361d842007-06-05 12:30:55 +020010582static struct snd_kcontrol_new alc268_base_mixer[] = {
10583 /* output mixer control */
10584 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
10585 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
10586 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
10587 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai33bf17a2007-08-21 11:51:42 +020010588 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10589 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
10590 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
Kailang Yanga361d842007-06-05 12:30:55 +020010591 { }
10592};
10593
Takashi Iwaiaef9d312008-02-19 13:16:41 +010010594/* bind Beep switches of both NID 0x0f and 0x10 */
10595static struct hda_bind_ctls alc268_bind_beep_sw = {
10596 .ops = &snd_hda_bind_sw,
10597 .values = {
10598 HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT),
10599 HDA_COMPOSE_AMP_VAL(0x10, 3, 1, HDA_INPUT),
10600 0
10601 },
10602};
10603
10604static struct snd_kcontrol_new alc268_beep_mixer[] = {
10605 HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT),
10606 HDA_BIND_SW("Beep Playback Switch", &alc268_bind_beep_sw),
10607 { }
10608};
10609
Kailang Yangd1a991a2007-08-15 16:21:59 +020010610static struct hda_verb alc268_eapd_verbs[] = {
10611 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
10612 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
10613 { }
10614};
10615
Takashi Iwaid2738092007-08-16 14:59:45 +020010616/* Toshiba specific */
10617#define alc268_toshiba_automute alc262_hippo_automute
10618
10619static struct hda_verb alc268_toshiba_verbs[] = {
10620 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
10621 { } /* end */
10622};
10623
Kailang Yang8ef355d2008-08-26 13:10:22 +020010624static struct hda_input_mux alc268_acer_lc_capture_source = {
10625 .num_items = 2,
10626 .items = {
10627 { "i-Mic", 0x6 },
10628 { "E-Mic", 0x0 },
10629 },
10630};
10631
Takashi Iwaid2738092007-08-16 14:59:45 +020010632/* Acer specific */
Takashi Iwai889c4392007-08-23 18:56:52 +020010633/* bind volumes of both NID 0x02 and 0x03 */
Takashi Iwai6bc96852007-08-17 09:02:12 +020010634static struct hda_bind_ctls alc268_acer_bind_master_vol = {
10635 .ops = &snd_hda_bind_vol,
10636 .values = {
10637 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
10638 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
10639 0
10640 },
10641};
10642
Takashi Iwai889c4392007-08-23 18:56:52 +020010643/* mute/unmute internal speaker according to the hp jack and mute state */
10644static void alc268_acer_automute(struct hda_codec *codec, int force)
10645{
10646 struct alc_spec *spec = codec->spec;
10647 unsigned int mute;
10648
10649 if (force || !spec->sense_updated) {
10650 unsigned int present;
10651 present = snd_hda_codec_read(codec, 0x14, 0,
10652 AC_VERB_GET_PIN_SENSE, 0);
10653 spec->jack_present = (present & 0x80000000) != 0;
10654 spec->sense_updated = 1;
10655 }
10656 if (spec->jack_present)
10657 mute = HDA_AMP_MUTE; /* mute internal speaker */
10658 else /* unmute internal speaker if necessary */
10659 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
10660 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
10661 HDA_AMP_MUTE, mute);
10662}
10663
10664
10665/* bind hp and internal speaker mute (with plug check) */
10666static int alc268_acer_master_sw_put(struct snd_kcontrol *kcontrol,
10667 struct snd_ctl_elem_value *ucontrol)
10668{
10669 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
10670 long *valp = ucontrol->value.integer.value;
10671 int change;
10672
10673 change = snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0,
10674 HDA_AMP_MUTE,
10675 valp[0] ? 0 : HDA_AMP_MUTE);
10676 change |= snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0,
10677 HDA_AMP_MUTE,
10678 valp[1] ? 0 : HDA_AMP_MUTE);
10679 if (change)
10680 alc268_acer_automute(codec, 0);
10681 return change;
10682}
Takashi Iwaid2738092007-08-16 14:59:45 +020010683
Kailang Yang8ef355d2008-08-26 13:10:22 +020010684static struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = {
10685 /* output mixer control */
10686 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
10687 {
10688 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10689 .name = "Master Playback Switch",
10690 .info = snd_hda_mixer_amp_switch_info,
10691 .get = snd_hda_mixer_amp_switch_get,
10692 .put = alc268_acer_master_sw_put,
10693 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
10694 },
10695 HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x18, 0, HDA_INPUT),
10696 { }
10697};
10698
Takashi Iwaid2738092007-08-16 14:59:45 +020010699static struct snd_kcontrol_new alc268_acer_mixer[] = {
10700 /* output mixer control */
10701 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
10702 {
10703 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10704 .name = "Master Playback Switch",
10705 .info = snd_hda_mixer_amp_switch_info,
10706 .get = snd_hda_mixer_amp_switch_get,
10707 .put = alc268_acer_master_sw_put,
10708 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
10709 },
Takashi Iwai33bf17a2007-08-21 11:51:42 +020010710 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10711 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
10712 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
Takashi Iwaid2738092007-08-16 14:59:45 +020010713 { }
10714};
10715
Kailang Yang8ef355d2008-08-26 13:10:22 +020010716static struct hda_verb alc268_acer_aspire_one_verbs[] = {
10717 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
10718 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
10719 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
10720 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
10721 {0x23, AC_VERB_SET_CONNECT_SEL, 0x06},
10722 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, 0xa017},
10723 { }
10724};
10725
Takashi Iwaid2738092007-08-16 14:59:45 +020010726static struct hda_verb alc268_acer_verbs[] = {
Takashi Iwai0ccb5412008-03-06 16:58:35 +010010727 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* internal dmic? */
10728 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaid2738092007-08-16 14:59:45 +020010729 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
10730 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai0ccb5412008-03-06 16:58:35 +010010731 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
10732 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaid2738092007-08-16 14:59:45 +020010733 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
10734 { }
10735};
10736
10737/* unsolicited event for HP jack sensing */
10738static void alc268_toshiba_unsol_event(struct hda_codec *codec,
10739 unsigned int res)
10740{
Takashi Iwai889c4392007-08-23 18:56:52 +020010741 if ((res >> 26) != ALC880_HP_EVENT)
Takashi Iwaid2738092007-08-16 14:59:45 +020010742 return;
10743 alc268_toshiba_automute(codec);
10744}
10745
10746static void alc268_acer_unsol_event(struct hda_codec *codec,
10747 unsigned int res)
10748{
Takashi Iwai889c4392007-08-23 18:56:52 +020010749 if ((res >> 26) != ALC880_HP_EVENT)
Takashi Iwaid2738092007-08-16 14:59:45 +020010750 return;
10751 alc268_acer_automute(codec, 1);
10752}
10753
Takashi Iwai889c4392007-08-23 18:56:52 +020010754static void alc268_acer_init_hook(struct hda_codec *codec)
10755{
10756 alc268_acer_automute(codec, 1);
10757}
10758
Kailang Yang8ef355d2008-08-26 13:10:22 +020010759/* toggle speaker-output according to the hp-jack state */
10760static void alc268_aspire_one_speaker_automute(struct hda_codec *codec)
10761{
10762 unsigned int present;
10763 unsigned char bits;
10764
10765 present = snd_hda_codec_read(codec, 0x15, 0,
10766 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
10767 bits = present ? AMP_IN_MUTE(0) : 0;
10768 snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 0,
10769 AMP_IN_MUTE(0), bits);
10770 snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 1,
10771 AMP_IN_MUTE(0), bits);
10772}
10773
10774
10775static void alc268_acer_mic_automute(struct hda_codec *codec)
10776{
10777 unsigned int present;
10778
10779 present = snd_hda_codec_read(codec, 0x18, 0,
10780 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
10781 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_CONNECT_SEL,
10782 present ? 0x0 : 0x6);
10783}
10784
10785static void alc268_acer_lc_unsol_event(struct hda_codec *codec,
10786 unsigned int res)
10787{
10788 if ((res >> 26) == ALC880_HP_EVENT)
10789 alc268_aspire_one_speaker_automute(codec);
10790 if ((res >> 26) == ALC880_MIC_EVENT)
10791 alc268_acer_mic_automute(codec);
10792}
10793
10794static void alc268_acer_lc_init_hook(struct hda_codec *codec)
10795{
10796 alc268_aspire_one_speaker_automute(codec);
10797 alc268_acer_mic_automute(codec);
10798}
10799
Takashi Iwai3866f0b2008-01-15 12:37:42 +010010800static struct snd_kcontrol_new alc268_dell_mixer[] = {
10801 /* output mixer control */
10802 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
10803 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
10804 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
10805 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
10806 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10807 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
10808 { }
10809};
10810
10811static struct hda_verb alc268_dell_verbs[] = {
10812 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
10813 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
10814 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
10815 { }
10816};
10817
10818/* mute/unmute internal speaker according to the hp jack and mute state */
10819static void alc268_dell_automute(struct hda_codec *codec)
10820{
10821 unsigned int present;
10822 unsigned int mute;
10823
10824 present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0);
10825 if (present & 0x80000000)
10826 mute = HDA_AMP_MUTE;
10827 else
10828 mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0);
10829 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
10830 HDA_AMP_MUTE, mute);
10831}
10832
10833static void alc268_dell_unsol_event(struct hda_codec *codec,
10834 unsigned int res)
10835{
10836 if ((res >> 26) != ALC880_HP_EVENT)
10837 return;
10838 alc268_dell_automute(codec);
10839}
10840
10841#define alc268_dell_init_hook alc268_dell_automute
10842
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020010843static struct snd_kcontrol_new alc267_quanta_il1_mixer[] = {
10844 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x2, 0x0, HDA_OUTPUT),
10845 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
10846 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
10847 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
10848 HDA_CODEC_VOLUME("Mic Capture Volume", 0x23, 0x0, HDA_OUTPUT),
10849 HDA_BIND_MUTE("Mic Capture Switch", 0x23, 2, HDA_OUTPUT),
10850 HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
10851 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
10852 { }
10853};
10854
10855static struct hda_verb alc267_quanta_il1_verbs[] = {
10856 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
10857 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
10858 { }
10859};
10860
10861static void alc267_quanta_il1_hp_automute(struct hda_codec *codec)
10862{
10863 unsigned int present;
10864
10865 present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0)
10866 & AC_PINSENSE_PRESENCE;
10867 snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
10868 present ? 0 : PIN_OUT);
10869}
10870
10871static void alc267_quanta_il1_mic_automute(struct hda_codec *codec)
10872{
10873 unsigned int present;
10874
10875 present = snd_hda_codec_read(codec, 0x18, 0,
10876 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
10877 snd_hda_codec_write(codec, 0x23, 0,
10878 AC_VERB_SET_CONNECT_SEL,
10879 present ? 0x00 : 0x01);
10880}
10881
10882static void alc267_quanta_il1_automute(struct hda_codec *codec)
10883{
10884 alc267_quanta_il1_hp_automute(codec);
10885 alc267_quanta_il1_mic_automute(codec);
10886}
10887
10888static void alc267_quanta_il1_unsol_event(struct hda_codec *codec,
10889 unsigned int res)
10890{
10891 switch (res >> 26) {
10892 case ALC880_HP_EVENT:
10893 alc267_quanta_il1_hp_automute(codec);
10894 break;
10895 case ALC880_MIC_EVENT:
10896 alc267_quanta_il1_mic_automute(codec);
10897 break;
10898 }
10899}
10900
Kailang Yanga361d842007-06-05 12:30:55 +020010901/*
10902 * generic initialization of ADC, input mixers and output mixers
10903 */
10904static struct hda_verb alc268_base_init_verbs[] = {
10905 /* Unmute DAC0-1 and set vol = 0 */
10906 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10907 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10908 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10909 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10910 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10911 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10912
10913 /*
10914 * Set up output mixers (0x0c - 0x0e)
10915 */
10916 /* set vol=0 to output mixers */
10917 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10918 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10919 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10920 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
10921
10922 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10923 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10924
10925 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
10926 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
10927 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
10928 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
10929 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
10930 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10931 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10932 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10933
10934 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10935 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10936 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10937 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10938 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10939 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10940 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwaiaef9d312008-02-19 13:16:41 +010010941
10942 /* set PCBEEP vol = 0, mute connections */
10943 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10944 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10945 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020010946
Jiang Zhea9b3aa82007-12-20 13:13:13 +010010947 /* Unmute Selector 23h,24h and set the default input to mic-in */
Kailang Yangea1fb292008-08-26 12:58:38 +020010948
Jiang Zhea9b3aa82007-12-20 13:13:13 +010010949 {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
10950 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10951 {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
10952 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020010953
Kailang Yanga361d842007-06-05 12:30:55 +020010954 { }
10955};
10956
10957/*
10958 * generic initialization of ADC, input mixers and output mixers
10959 */
10960static struct hda_verb alc268_volume_init_verbs[] = {
10961 /* set output DAC */
10962 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10963 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10964 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10965 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10966
10967 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
10968 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
10969 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10970 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10971 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10972
10973 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10974 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10975 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10976 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10977 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10978
10979 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10980 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10981 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10982 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10983
Takashi Iwaiaef9d312008-02-19 13:16:41 +010010984 /* set PCBEEP vol = 0, mute connections */
10985 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10986 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10987 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020010988
10989 { }
10990};
10991
Kailang Yanga361d842007-06-05 12:30:55 +020010992static struct snd_kcontrol_new alc268_capture_alt_mixer[] = {
10993 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
10994 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
10995 {
10996 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10997 /* The multiple "Capture Source" controls confuse alsamixer
10998 * So call somewhat different..
Kailang Yanga361d842007-06-05 12:30:55 +020010999 */
11000 /* .name = "Capture Source", */
11001 .name = "Input Source",
11002 .count = 1,
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010011003 .info = alc_mux_enum_info,
11004 .get = alc_mux_enum_get,
11005 .put = alc_mux_enum_put,
Kailang Yanga361d842007-06-05 12:30:55 +020011006 },
11007 { } /* end */
11008};
11009
11010static struct snd_kcontrol_new alc268_capture_mixer[] = {
11011 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
11012 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
11013 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x24, 0x0, HDA_OUTPUT),
11014 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x24, 0x0, HDA_OUTPUT),
11015 {
11016 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11017 /* The multiple "Capture Source" controls confuse alsamixer
11018 * So call somewhat different..
Kailang Yanga361d842007-06-05 12:30:55 +020011019 */
11020 /* .name = "Capture Source", */
11021 .name = "Input Source",
11022 .count = 2,
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010011023 .info = alc_mux_enum_info,
11024 .get = alc_mux_enum_get,
11025 .put = alc_mux_enum_put,
Kailang Yanga361d842007-06-05 12:30:55 +020011026 },
11027 { } /* end */
11028};
11029
11030static struct hda_input_mux alc268_capture_source = {
11031 .num_items = 4,
11032 .items = {
11033 { "Mic", 0x0 },
11034 { "Front Mic", 0x1 },
11035 { "Line", 0x2 },
11036 { "CD", 0x3 },
11037 },
11038};
11039
Takashi Iwai0ccb5412008-03-06 16:58:35 +010011040static struct hda_input_mux alc268_acer_capture_source = {
11041 .num_items = 3,
11042 .items = {
11043 { "Mic", 0x0 },
11044 { "Internal Mic", 0x6 },
11045 { "Line", 0x2 },
11046 },
11047};
11048
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010011049#ifdef CONFIG_SND_DEBUG
11050static struct snd_kcontrol_new alc268_test_mixer[] = {
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010011051 /* Volume widgets */
11052 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x02, 0x0, HDA_OUTPUT),
11053 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x03, 0x0, HDA_OUTPUT),
11054 HDA_BIND_MUTE_MONO("Mono sum Playback Switch", 0x0e, 1, 2, HDA_INPUT),
11055 HDA_BIND_MUTE("LINE-OUT sum Playback Switch", 0x0f, 2, HDA_INPUT),
11056 HDA_BIND_MUTE("HP-OUT sum Playback Switch", 0x10, 2, HDA_INPUT),
11057 HDA_BIND_MUTE("LINE-OUT Playback Switch", 0x14, 2, HDA_OUTPUT),
11058 HDA_BIND_MUTE("HP-OUT Playback Switch", 0x15, 2, HDA_OUTPUT),
11059 HDA_BIND_MUTE("Mono Playback Switch", 0x16, 2, HDA_OUTPUT),
11060 HDA_CODEC_VOLUME("MIC1 Capture Volume", 0x18, 0x0, HDA_INPUT),
11061 HDA_BIND_MUTE("MIC1 Capture Switch", 0x18, 2, HDA_OUTPUT),
11062 HDA_CODEC_VOLUME("MIC2 Capture Volume", 0x19, 0x0, HDA_INPUT),
11063 HDA_CODEC_VOLUME("LINE1 Capture Volume", 0x1a, 0x0, HDA_INPUT),
11064 HDA_BIND_MUTE("LINE1 Capture Switch", 0x1a, 2, HDA_OUTPUT),
Takashi Iwaif0747ee2008-01-15 11:41:41 +010011065 /* The below appears problematic on some hardwares */
11066 /*HDA_CODEC_VOLUME("PCBEEP Playback Volume", 0x1d, 0x0, HDA_INPUT),*/
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010011067 HDA_CODEC_VOLUME("PCM-IN1 Capture Volume", 0x23, 0x0, HDA_OUTPUT),
11068 HDA_BIND_MUTE("PCM-IN1 Capture Switch", 0x23, 2, HDA_OUTPUT),
11069 HDA_CODEC_VOLUME("PCM-IN2 Capture Volume", 0x24, 0x0, HDA_OUTPUT),
11070 HDA_BIND_MUTE("PCM-IN2 Capture Switch", 0x24, 2, HDA_OUTPUT),
11071
11072 /* Modes for retasking pin widgets */
11073 ALC_PIN_MODE("LINE-OUT pin mode", 0x14, ALC_PIN_DIR_INOUT),
11074 ALC_PIN_MODE("HP-OUT pin mode", 0x15, ALC_PIN_DIR_INOUT),
11075 ALC_PIN_MODE("MIC1 pin mode", 0x18, ALC_PIN_DIR_INOUT),
11076 ALC_PIN_MODE("LINE1 pin mode", 0x1a, ALC_PIN_DIR_INOUT),
11077
11078 /* Controls for GPIO pins, assuming they are configured as outputs */
11079 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
11080 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
11081 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
11082 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
11083
11084 /* Switches to allow the digital SPDIF output pin to be enabled.
11085 * The ALC268 does not have an SPDIF input.
11086 */
11087 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x06, 0x01),
11088
11089 /* A switch allowing EAPD to be enabled. Some laptops seem to use
11090 * this output to turn on an external amplifier.
11091 */
11092 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
11093 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
11094
11095 { } /* end */
11096};
11097#endif
11098
Kailang Yanga361d842007-06-05 12:30:55 +020011099/* create input playback/capture controls for the given pin */
11100static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
11101 const char *ctlname, int idx)
11102{
11103 char name[32];
11104 int err;
11105
11106 sprintf(name, "%s Playback Volume", ctlname);
11107 if (nid == 0x14) {
11108 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
11109 HDA_COMPOSE_AMP_VAL(0x02, 3, idx,
11110 HDA_OUTPUT));
11111 if (err < 0)
11112 return err;
11113 } else if (nid == 0x15) {
11114 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
11115 HDA_COMPOSE_AMP_VAL(0x03, 3, idx,
11116 HDA_OUTPUT));
11117 if (err < 0)
11118 return err;
11119 } else
11120 return -1;
11121 sprintf(name, "%s Playback Switch", ctlname);
11122 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
11123 HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
11124 if (err < 0)
11125 return err;
11126 return 0;
11127}
11128
11129/* add playback controls from the parsed DAC table */
11130static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
11131 const struct auto_pin_cfg *cfg)
11132{
11133 hda_nid_t nid;
11134 int err;
11135
11136 spec->multiout.num_dacs = 2; /* only use one dac */
11137 spec->multiout.dac_nids = spec->private_dac_nids;
11138 spec->multiout.dac_nids[0] = 2;
11139 spec->multiout.dac_nids[1] = 3;
11140
11141 nid = cfg->line_out_pins[0];
11142 if (nid)
Kailang Yangea1fb292008-08-26 12:58:38 +020011143 alc268_new_analog_output(spec, nid, "Front", 0);
Kailang Yanga361d842007-06-05 12:30:55 +020011144
11145 nid = cfg->speaker_pins[0];
11146 if (nid == 0x1d) {
11147 err = add_control(spec, ALC_CTL_WIDGET_VOL,
11148 "Speaker Playback Volume",
11149 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
11150 if (err < 0)
11151 return err;
11152 }
11153 nid = cfg->hp_pins[0];
11154 if (nid)
11155 alc268_new_analog_output(spec, nid, "Headphone", 0);
11156
11157 nid = cfg->line_out_pins[1] | cfg->line_out_pins[2];
11158 if (nid == 0x16) {
11159 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
11160 "Mono Playback Switch",
11161 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_INPUT));
11162 if (err < 0)
11163 return err;
11164 }
Kailang Yangea1fb292008-08-26 12:58:38 +020011165 return 0;
Kailang Yanga361d842007-06-05 12:30:55 +020011166}
11167
11168/* create playback/capture controls for input pins */
11169static int alc268_auto_create_analog_input_ctls(struct alc_spec *spec,
11170 const struct auto_pin_cfg *cfg)
11171{
11172 struct hda_input_mux *imux = &spec->private_imux;
11173 int i, idx1;
11174
11175 for (i = 0; i < AUTO_PIN_LAST; i++) {
11176 switch(cfg->input_pins[i]) {
11177 case 0x18:
11178 idx1 = 0; /* Mic 1 */
11179 break;
11180 case 0x19:
11181 idx1 = 1; /* Mic 2 */
11182 break;
11183 case 0x1a:
11184 idx1 = 2; /* Line In */
11185 break;
Kailang Yangea1fb292008-08-26 12:58:38 +020011186 case 0x1c:
Kailang Yanga361d842007-06-05 12:30:55 +020011187 idx1 = 3; /* CD */
11188 break;
Takashi Iwai7194cae2008-03-06 16:58:17 +010011189 case 0x12:
11190 case 0x13:
11191 idx1 = 6; /* digital mics */
11192 break;
Kailang Yanga361d842007-06-05 12:30:55 +020011193 default:
11194 continue;
11195 }
11196 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
11197 imux->items[imux->num_items].index = idx1;
Kailang Yangea1fb292008-08-26 12:58:38 +020011198 imux->num_items++;
Kailang Yanga361d842007-06-05 12:30:55 +020011199 }
11200 return 0;
11201}
11202
11203static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec)
11204{
11205 struct alc_spec *spec = codec->spec;
11206 hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
11207 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
11208 hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
11209 unsigned int dac_vol1, dac_vol2;
11210
11211 if (speaker_nid) {
11212 snd_hda_codec_write(codec, speaker_nid, 0,
11213 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
11214 snd_hda_codec_write(codec, 0x0f, 0,
11215 AC_VERB_SET_AMP_GAIN_MUTE,
11216 AMP_IN_UNMUTE(1));
11217 snd_hda_codec_write(codec, 0x10, 0,
11218 AC_VERB_SET_AMP_GAIN_MUTE,
11219 AMP_IN_UNMUTE(1));
11220 } else {
11221 snd_hda_codec_write(codec, 0x0f, 0,
11222 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
11223 snd_hda_codec_write(codec, 0x10, 0,
11224 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
11225 }
11226
11227 dac_vol1 = dac_vol2 = 0xb000 | 0x40; /* set max volume */
Kailang Yangea1fb292008-08-26 12:58:38 +020011228 if (line_nid == 0x14)
Kailang Yanga361d842007-06-05 12:30:55 +020011229 dac_vol2 = AMP_OUT_ZERO;
11230 else if (line_nid == 0x15)
11231 dac_vol1 = AMP_OUT_ZERO;
Kailang Yangea1fb292008-08-26 12:58:38 +020011232 if (hp_nid == 0x14)
Kailang Yanga361d842007-06-05 12:30:55 +020011233 dac_vol2 = AMP_OUT_ZERO;
11234 else if (hp_nid == 0x15)
11235 dac_vol1 = AMP_OUT_ZERO;
11236 if (line_nid != 0x16 || hp_nid != 0x16 ||
11237 spec->autocfg.line_out_pins[1] != 0x16 ||
11238 spec->autocfg.line_out_pins[2] != 0x16)
11239 dac_vol1 = dac_vol2 = AMP_OUT_ZERO;
11240
11241 snd_hda_codec_write(codec, 0x02, 0,
11242 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol1);
11243 snd_hda_codec_write(codec, 0x03, 0,
11244 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol2);
11245}
11246
11247/* pcm configuration: identiacal with ALC880 */
11248#define alc268_pcm_analog_playback alc880_pcm_analog_playback
11249#define alc268_pcm_analog_capture alc880_pcm_analog_capture
Takashi Iwai63300792008-01-24 15:31:36 +010011250#define alc268_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
Kailang Yanga361d842007-06-05 12:30:55 +020011251#define alc268_pcm_digital_playback alc880_pcm_digital_playback
11252
11253/*
11254 * BIOS auto configuration
11255 */
11256static int alc268_parse_auto_config(struct hda_codec *codec)
11257{
11258 struct alc_spec *spec = codec->spec;
11259 int err;
11260 static hda_nid_t alc268_ignore[] = { 0 };
11261
11262 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
11263 alc268_ignore);
11264 if (err < 0)
11265 return err;
11266 if (!spec->autocfg.line_outs)
11267 return 0; /* can't find valid BIOS pin config */
11268
11269 err = alc268_auto_create_multi_out_ctls(spec, &spec->autocfg);
11270 if (err < 0)
11271 return err;
11272 err = alc268_auto_create_analog_input_ctls(spec, &spec->autocfg);
11273 if (err < 0)
11274 return err;
11275
11276 spec->multiout.max_channels = 2;
11277
11278 /* digital only support output */
11279 if (spec->autocfg.dig_out_pin)
11280 spec->multiout.dig_out_nid = ALC268_DIGOUT_NID;
11281
Takashi Iwai603c4012008-07-30 15:01:44 +020011282 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010011283 add_mixer(spec, spec->kctls.list);
Kailang Yanga361d842007-06-05 12:30:55 +020011284
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011285 if (spec->autocfg.speaker_pins[0] != 0x1d)
Takashi Iwaid88897e2008-10-31 15:01:37 +010011286 add_mixer(spec, alc268_beep_mixer);
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011287
Takashi Iwaid88897e2008-10-31 15:01:37 +010011288 add_verb(spec, alc268_volume_init_verbs);
Kailang Yanga361d842007-06-05 12:30:55 +020011289 spec->num_mux_defs = 1;
11290 spec->input_mux = &spec->private_imux;
11291
Takashi Iwai776e1842007-08-29 15:07:11 +020011292 err = alc_auto_add_mic_boost(codec);
11293 if (err < 0)
11294 return err;
11295
Takashi Iwaie044c392008-10-27 16:56:24 +010011296 store_pin_configs(codec);
Kailang Yanga361d842007-06-05 12:30:55 +020011297 return 1;
11298}
11299
11300#define alc268_auto_init_multi_out alc882_auto_init_multi_out
11301#define alc268_auto_init_hp_out alc882_auto_init_hp_out
11302#define alc268_auto_init_analog_input alc882_auto_init_analog_input
11303
11304/* init callback for auto-configuration model -- overriding the default init */
11305static void alc268_auto_init(struct hda_codec *codec)
11306{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010011307 struct alc_spec *spec = codec->spec;
Kailang Yanga361d842007-06-05 12:30:55 +020011308 alc268_auto_init_multi_out(codec);
11309 alc268_auto_init_hp_out(codec);
11310 alc268_auto_init_mono_speaker_out(codec);
11311 alc268_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010011312 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020011313 alc_inithook(codec);
Kailang Yanga361d842007-06-05 12:30:55 +020011314}
11315
11316/*
11317 * configuration and preset
11318 */
11319static const char *alc268_models[ALC268_MODEL_LAST] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020011320 [ALC267_QUANTA_IL1] = "quanta-il1",
Kailang Yanga361d842007-06-05 12:30:55 +020011321 [ALC268_3ST] = "3stack",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020011322 [ALC268_TOSHIBA] = "toshiba",
Takashi Iwaid2738092007-08-16 14:59:45 +020011323 [ALC268_ACER] = "acer",
Kailang Yang8ef355d2008-08-26 13:10:22 +020011324 [ALC268_ACER_ASPIRE_ONE] = "acer-aspire",
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011325 [ALC268_DELL] = "dell",
Mirco Tischlerf12462c2008-02-04 12:33:59 +010011326 [ALC268_ZEPTO] = "zepto",
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010011327#ifdef CONFIG_SND_DEBUG
11328 [ALC268_TEST] = "test",
11329#endif
Kailang Yanga361d842007-06-05 12:30:55 +020011330 [ALC268_AUTO] = "auto",
11331};
11332
11333static struct snd_pci_quirk alc268_cfg_tbl[] = {
Takashi Iwaia0b8f7d2008-04-22 19:39:49 +020011334 SND_PCI_QUIRK(0x1025, 0x011e, "Acer Aspire 5720z", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011335 SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER),
Andy Shevchenkodafc8352008-01-25 11:53:50 +010011336 SND_PCI_QUIRK(0x1025, 0x012e, "Acer Aspire 5310", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011337 SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER),
Andy Shevchenko29a52c22008-01-24 17:29:00 +010011338 SND_PCI_QUIRK(0x1025, 0x0136, "Acer Aspire 5315", ALC268_ACER),
Kailang Yang8ef355d2008-08-26 13:10:22 +020011339 SND_PCI_QUIRK(0x1025, 0x015b, "Acer Aspire One",
11340 ALC268_ACER_ASPIRE_ONE),
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011341 SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011342 SND_PCI_QUIRK(0x103c, 0x30cc, "TOSHIBA", ALC268_TOSHIBA),
Kailang Yanga361d842007-06-05 12:30:55 +020011343 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST),
Kailang Yangd1a991a2007-08-15 16:21:59 +020011344 SND_PCI_QUIRK(0x1179, 0xff10, "TOSHIBA A205", ALC268_TOSHIBA),
Takashi Iwai8e7f00f2007-09-07 10:58:58 +020011345 SND_PCI_QUIRK(0x1179, 0xff50, "TOSHIBA A305", ALC268_TOSHIBA),
Travis Place2346d0c2008-09-01 08:24:00 +020011346 SND_PCI_QUIRK(0x1179, 0xff64, "TOSHIBA L305", ALC268_TOSHIBA),
Tony Vroon378bd6a2008-06-04 12:08:30 +020011347 SND_PCI_QUIRK(0x14c0, 0x0025, "COMPAL IFL90/JFL-92", ALC268_TOSHIBA),
Takashi Iwaib875bf32007-09-06 15:00:27 +020011348 SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER),
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020011349 SND_PCI_QUIRK(0x152d, 0x0771, "Quanta IL1", ALC267_QUANTA_IL1),
Mirco Tischlerf12462c2008-02-04 12:33:59 +010011350 SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO),
Kailang Yanga361d842007-06-05 12:30:55 +020011351 {}
11352};
11353
11354static struct alc_config_preset alc268_presets[] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020011355 [ALC267_QUANTA_IL1] = {
11356 .mixers = { alc267_quanta_il1_mixer },
11357 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
11358 alc267_quanta_il1_verbs },
11359 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11360 .dac_nids = alc268_dac_nids,
11361 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
11362 .adc_nids = alc268_adc_nids_alt,
11363 .hp_nid = 0x03,
11364 .num_channel_mode = ARRAY_SIZE(alc268_modes),
11365 .channel_mode = alc268_modes,
11366 .input_mux = &alc268_capture_source,
11367 .unsol_event = alc267_quanta_il1_unsol_event,
11368 .init_hook = alc267_quanta_il1_automute,
11369 },
Kailang Yanga361d842007-06-05 12:30:55 +020011370 [ALC268_3ST] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011371 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
11372 alc268_beep_mixer },
Kailang Yanga361d842007-06-05 12:30:55 +020011373 .init_verbs = { alc268_base_init_verbs },
11374 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11375 .dac_nids = alc268_dac_nids,
11376 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
11377 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010011378 .capsrc_nids = alc268_capsrc_nids,
Kailang Yanga361d842007-06-05 12:30:55 +020011379 .hp_nid = 0x03,
11380 .dig_out_nid = ALC268_DIGOUT_NID,
11381 .num_channel_mode = ARRAY_SIZE(alc268_modes),
11382 .channel_mode = alc268_modes,
11383 .input_mux = &alc268_capture_source,
11384 },
Kailang Yangd1a991a2007-08-15 16:21:59 +020011385 [ALC268_TOSHIBA] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011386 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
11387 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020011388 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
11389 alc268_toshiba_verbs },
Kailang Yangd1a991a2007-08-15 16:21:59 +020011390 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11391 .dac_nids = alc268_dac_nids,
11392 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
11393 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010011394 .capsrc_nids = alc268_capsrc_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020011395 .hp_nid = 0x03,
11396 .num_channel_mode = ARRAY_SIZE(alc268_modes),
11397 .channel_mode = alc268_modes,
11398 .input_mux = &alc268_capture_source,
Takashi Iwaid2738092007-08-16 14:59:45 +020011399 .unsol_event = alc268_toshiba_unsol_event,
11400 .init_hook = alc268_toshiba_automute,
11401 },
11402 [ALC268_ACER] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011403 .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer,
11404 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020011405 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
11406 alc268_acer_verbs },
11407 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11408 .dac_nids = alc268_dac_nids,
11409 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
11410 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010011411 .capsrc_nids = alc268_capsrc_nids,
Takashi Iwaid2738092007-08-16 14:59:45 +020011412 .hp_nid = 0x02,
11413 .num_channel_mode = ARRAY_SIZE(alc268_modes),
11414 .channel_mode = alc268_modes,
Takashi Iwai0ccb5412008-03-06 16:58:35 +010011415 .input_mux = &alc268_acer_capture_source,
Takashi Iwaid2738092007-08-16 14:59:45 +020011416 .unsol_event = alc268_acer_unsol_event,
Takashi Iwai889c4392007-08-23 18:56:52 +020011417 .init_hook = alc268_acer_init_hook,
Kailang Yangd1a991a2007-08-15 16:21:59 +020011418 },
Kailang Yang8ef355d2008-08-26 13:10:22 +020011419 [ALC268_ACER_ASPIRE_ONE] = {
11420 .mixers = { alc268_acer_aspire_one_mixer,
11421 alc268_capture_alt_mixer },
11422 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
11423 alc268_acer_aspire_one_verbs },
11424 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11425 .dac_nids = alc268_dac_nids,
11426 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
11427 .adc_nids = alc268_adc_nids_alt,
11428 .capsrc_nids = alc268_capsrc_nids,
11429 .hp_nid = 0x03,
11430 .num_channel_mode = ARRAY_SIZE(alc268_modes),
11431 .channel_mode = alc268_modes,
11432 .input_mux = &alc268_acer_lc_capture_source,
11433 .unsol_event = alc268_acer_lc_unsol_event,
11434 .init_hook = alc268_acer_lc_init_hook,
11435 },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011436 [ALC268_DELL] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011437 .mixers = { alc268_dell_mixer, alc268_beep_mixer },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011438 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
11439 alc268_dell_verbs },
11440 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11441 .dac_nids = alc268_dac_nids,
11442 .hp_nid = 0x02,
11443 .num_channel_mode = ARRAY_SIZE(alc268_modes),
11444 .channel_mode = alc268_modes,
11445 .unsol_event = alc268_dell_unsol_event,
11446 .init_hook = alc268_dell_init_hook,
11447 .input_mux = &alc268_capture_source,
11448 },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010011449 [ALC268_ZEPTO] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011450 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
11451 alc268_beep_mixer },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010011452 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
11453 alc268_toshiba_verbs },
11454 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11455 .dac_nids = alc268_dac_nids,
11456 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
11457 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010011458 .capsrc_nids = alc268_capsrc_nids,
Mirco Tischlerf12462c2008-02-04 12:33:59 +010011459 .hp_nid = 0x03,
11460 .dig_out_nid = ALC268_DIGOUT_NID,
11461 .num_channel_mode = ARRAY_SIZE(alc268_modes),
11462 .channel_mode = alc268_modes,
11463 .input_mux = &alc268_capture_source,
11464 .unsol_event = alc268_toshiba_unsol_event,
11465 .init_hook = alc268_toshiba_automute
11466 },
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010011467#ifdef CONFIG_SND_DEBUG
11468 [ALC268_TEST] = {
11469 .mixers = { alc268_test_mixer, alc268_capture_mixer },
11470 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
11471 alc268_volume_init_verbs },
11472 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11473 .dac_nids = alc268_dac_nids,
11474 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
11475 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010011476 .capsrc_nids = alc268_capsrc_nids,
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010011477 .hp_nid = 0x03,
11478 .dig_out_nid = ALC268_DIGOUT_NID,
11479 .num_channel_mode = ARRAY_SIZE(alc268_modes),
11480 .channel_mode = alc268_modes,
11481 .input_mux = &alc268_capture_source,
11482 },
11483#endif
Kailang Yanga361d842007-06-05 12:30:55 +020011484};
11485
11486static int patch_alc268(struct hda_codec *codec)
11487{
11488 struct alc_spec *spec;
11489 int board_config;
11490 int err;
11491
11492 spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
11493 if (spec == NULL)
11494 return -ENOMEM;
11495
11496 codec->spec = spec;
11497
11498 board_config = snd_hda_check_board_config(codec, ALC268_MODEL_LAST,
11499 alc268_models,
11500 alc268_cfg_tbl);
11501
11502 if (board_config < 0 || board_config >= ALC268_MODEL_LAST) {
11503 printk(KERN_INFO "hda_codec: Unknown model for ALC268, "
11504 "trying auto-probe from BIOS...\n");
11505 board_config = ALC268_AUTO;
11506 }
11507
11508 if (board_config == ALC268_AUTO) {
11509 /* automatic parse from the BIOS config */
11510 err = alc268_parse_auto_config(codec);
11511 if (err < 0) {
11512 alc_free(codec);
11513 return err;
11514 } else if (!err) {
11515 printk(KERN_INFO
11516 "hda_codec: Cannot set up configuration "
11517 "from BIOS. Using base mode...\n");
11518 board_config = ALC268_3ST;
11519 }
11520 }
11521
11522 if (board_config != ALC268_AUTO)
11523 setup_preset(spec, &alc268_presets[board_config]);
11524
Kailang Yang2f893282008-05-27 12:14:47 +020011525 if (codec->vendor_id == 0x10ec0267) {
11526 spec->stream_name_analog = "ALC267 Analog";
11527 spec->stream_name_digital = "ALC267 Digital";
11528 } else {
11529 spec->stream_name_analog = "ALC268 Analog";
11530 spec->stream_name_digital = "ALC268 Digital";
11531 }
11532
Kailang Yanga361d842007-06-05 12:30:55 +020011533 spec->stream_analog_playback = &alc268_pcm_analog_playback;
11534 spec->stream_analog_capture = &alc268_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +010011535 spec->stream_analog_alt_capture = &alc268_pcm_analog_alt_capture;
Kailang Yanga361d842007-06-05 12:30:55 +020011536
Kailang Yanga361d842007-06-05 12:30:55 +020011537 spec->stream_digital_playback = &alc268_pcm_digital_playback;
11538
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011539 if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
11540 /* override the amp caps for beep generator */
11541 snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT,
11542 (0x0c << AC_AMPCAP_OFFSET_SHIFT) |
11543 (0x0c << AC_AMPCAP_NUM_STEPS_SHIFT) |
11544 (0x07 << AC_AMPCAP_STEP_SIZE_SHIFT) |
11545 (0 << AC_AMPCAP_MUTE_SHIFT));
11546
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011547 if (!spec->adc_nids && spec->input_mux) {
11548 /* check whether NID 0x07 is valid */
11549 unsigned int wcap = get_wcaps(codec, 0x07);
Takashi Iwai85860c02008-02-19 15:00:15 +010011550 int i;
Kailang Yanga361d842007-06-05 12:30:55 +020011551
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011552 /* get type */
11553 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Takashi Iwai67ebcb02008-02-19 15:03:57 +010011554 if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011555 spec->adc_nids = alc268_adc_nids_alt;
11556 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt);
Takashi Iwaid88897e2008-10-31 15:01:37 +010011557 add_mixer(spec, alc268_capture_alt_mixer);
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011558 } else {
11559 spec->adc_nids = alc268_adc_nids;
11560 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids);
Takashi Iwaid88897e2008-10-31 15:01:37 +010011561 add_mixer(spec, alc268_capture_mixer);
Kailang Yanga361d842007-06-05 12:30:55 +020011562 }
Takashi Iwaie1406342008-02-11 18:32:32 +010011563 spec->capsrc_nids = alc268_capsrc_nids;
Takashi Iwai85860c02008-02-19 15:00:15 +010011564 /* set default input source */
11565 for (i = 0; i < spec->num_adc_nids; i++)
11566 snd_hda_codec_write_cache(codec, alc268_capsrc_nids[i],
11567 0, AC_VERB_SET_CONNECT_SEL,
11568 spec->input_mux->items[0].index);
Kailang Yanga361d842007-06-05 12:30:55 +020011569 }
Takashi Iwai2134ea42008-01-10 16:53:55 +010011570
11571 spec->vmaster_nid = 0x02;
11572
Kailang Yanga361d842007-06-05 12:30:55 +020011573 codec->patch_ops = alc_patch_ops;
11574 if (board_config == ALC268_AUTO)
11575 spec->init_hook = alc268_auto_init;
Kailang Yangea1fb292008-08-26 12:58:38 +020011576
Kailang Yanga361d842007-06-05 12:30:55 +020011577 return 0;
11578}
11579
11580/*
Kailang Yangf6a92242007-12-13 16:52:54 +010011581 * ALC269 channel source setting (2 channel)
11582 */
11583#define ALC269_DIGOUT_NID ALC880_DIGOUT_NID
11584
11585#define alc269_dac_nids alc260_dac_nids
11586
11587static hda_nid_t alc269_adc_nids[1] = {
11588 /* ADC1 */
Kailang Yangf53281e2008-07-18 12:36:43 +020011589 0x08,
11590};
11591
Takashi Iwaie01bf502008-08-21 16:25:07 +020011592static hda_nid_t alc269_capsrc_nids[1] = {
11593 0x23,
11594};
11595
11596/* NOTE: ADC2 (0x07) is connected from a recording *MIXER* (0x24),
11597 * not a mux!
11598 */
11599
Kailang Yangf53281e2008-07-18 12:36:43 +020011600static struct hda_input_mux alc269_eeepc_dmic_capture_source = {
11601 .num_items = 2,
11602 .items = {
11603 { "i-Mic", 0x5 },
11604 { "e-Mic", 0x0 },
11605 },
11606};
11607
11608static struct hda_input_mux alc269_eeepc_amic_capture_source = {
11609 .num_items = 2,
11610 .items = {
11611 { "i-Mic", 0x1 },
11612 { "e-Mic", 0x0 },
11613 },
Kailang Yangf6a92242007-12-13 16:52:54 +010011614};
11615
11616#define alc269_modes alc260_modes
11617#define alc269_capture_source alc880_lg_lw_capture_source
11618
11619static struct snd_kcontrol_new alc269_base_mixer[] = {
11620 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
11621 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11622 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11623 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11624 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11625 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai2005af22008-08-20 18:38:26 +020011626 HDA_CODEC_VOLUME("Beep Playback Volume", 0x0b, 0x4, HDA_INPUT),
11627 HDA_CODEC_MUTE("Beep Playback Switch", 0x0b, 0x4, HDA_INPUT),
Kailang Yangf6a92242007-12-13 16:52:54 +010011628 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11629 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11630 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11631 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
11632 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11633 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
11634 { } /* end */
11635};
11636
Kailang Yang60db6b52008-08-26 13:13:00 +020011637static struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = {
11638 /* output mixer control */
11639 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
11640 {
11641 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11642 .name = "Master Playback Switch",
11643 .info = snd_hda_mixer_amp_switch_info,
11644 .get = snd_hda_mixer_amp_switch_get,
11645 .put = alc268_acer_master_sw_put,
11646 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
11647 },
11648 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11649 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11650 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11651 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11652 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11653 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
11654 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x04, HDA_INPUT),
11655 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x04, HDA_INPUT),
11656 { }
11657};
11658
Kailang Yangf53281e2008-07-18 12:36:43 +020011659/* bind volumes of both NID 0x0c and 0x0d */
11660static struct hda_bind_ctls alc269_epc_bind_vol = {
11661 .ops = &snd_hda_bind_vol,
11662 .values = {
11663 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
11664 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
11665 0
11666 },
11667};
11668
11669static struct snd_kcontrol_new alc269_eeepc_mixer[] = {
11670 HDA_CODEC_MUTE("iSpeaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11671 HDA_BIND_VOL("LineOut Playback Volume", &alc269_epc_bind_vol),
11672 HDA_CODEC_MUTE("LineOut Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11673 { } /* end */
11674};
11675
Kailang Yangf6a92242007-12-13 16:52:54 +010011676/* capture mixer elements */
Kailang Yangf53281e2008-07-18 12:36:43 +020011677static struct snd_kcontrol_new alc269_epc_capture_mixer[] = {
11678 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
11679 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
Takashi Iwai26f5df22008-11-03 17:39:46 +010011680 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11681 { } /* end */
11682};
11683
11684/* FSC amilo */
11685static struct snd_kcontrol_new alc269_fujitsu_mixer[] = {
11686 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11687 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11688 HDA_BIND_VOL("PCM Playback Volume", &alc269_epc_bind_vol),
Kailang Yangf53281e2008-07-18 12:36:43 +020011689 { } /* end */
11690};
11691
Takashi Iwai2005af22008-08-20 18:38:26 +020011692/* beep control */
11693static struct snd_kcontrol_new alc269_beep_mixer[] = {
11694 HDA_CODEC_VOLUME("Beep Playback Volume", 0x0b, 0x4, HDA_INPUT),
11695 HDA_CODEC_MUTE("Beep Playback Switch", 0x0b, 0x4, HDA_INPUT),
11696 { } /* end */
11697};
11698
Kailang Yang60db6b52008-08-26 13:13:00 +020011699static struct hda_verb alc269_quanta_fl1_verbs[] = {
11700 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
11701 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11702 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11703 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
11704 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
11705 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11706 { }
11707};
11708
11709/* toggle speaker-output according to the hp-jack state */
11710static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec)
11711{
11712 unsigned int present;
11713 unsigned char bits;
11714
11715 present = snd_hda_codec_read(codec, 0x15, 0,
11716 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
11717 bits = present ? AMP_IN_MUTE(0) : 0;
11718 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
11719 AMP_IN_MUTE(0), bits);
11720 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
11721 AMP_IN_MUTE(0), bits);
11722
11723 snd_hda_codec_write(codec, 0x20, 0,
11724 AC_VERB_SET_COEF_INDEX, 0x0c);
11725 snd_hda_codec_write(codec, 0x20, 0,
11726 AC_VERB_SET_PROC_COEF, 0x680);
11727
11728 snd_hda_codec_write(codec, 0x20, 0,
11729 AC_VERB_SET_COEF_INDEX, 0x0c);
11730 snd_hda_codec_write(codec, 0x20, 0,
11731 AC_VERB_SET_PROC_COEF, 0x480);
11732}
11733
11734static void alc269_quanta_fl1_mic_automute(struct hda_codec *codec)
11735{
11736 unsigned int present;
11737
11738 present = snd_hda_codec_read(codec, 0x18, 0,
11739 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
11740 snd_hda_codec_write(codec, 0x23, 0,
11741 AC_VERB_SET_CONNECT_SEL, present ? 0x0 : 0x1);
11742}
11743
11744static void alc269_quanta_fl1_unsol_event(struct hda_codec *codec,
11745 unsigned int res)
11746{
11747 if ((res >> 26) == ALC880_HP_EVENT)
11748 alc269_quanta_fl1_speaker_automute(codec);
11749 if ((res >> 26) == ALC880_MIC_EVENT)
11750 alc269_quanta_fl1_mic_automute(codec);
11751}
11752
11753static void alc269_quanta_fl1_init_hook(struct hda_codec *codec)
11754{
11755 alc269_quanta_fl1_speaker_automute(codec);
11756 alc269_quanta_fl1_mic_automute(codec);
11757}
11758
11759static struct hda_verb alc269_eeepc_dmic_init_verbs[] = {
11760 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
11761 {0x23, AC_VERB_SET_CONNECT_SEL, 0x05},
11762 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
11763 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
11764 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11765 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
11766 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11767 {}
11768};
11769
11770static struct hda_verb alc269_eeepc_amic_init_verbs[] = {
11771 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
11772 {0x23, AC_VERB_SET_CONNECT_SEL, 0x01},
11773 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
11774 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x701b | (0x00 << 8))},
11775 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
11776 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11777 {}
11778};
11779
11780/* toggle speaker-output according to the hp-jack state */
11781static void alc269_speaker_automute(struct hda_codec *codec)
11782{
11783 unsigned int present;
11784 unsigned char bits;
11785
11786 present = snd_hda_codec_read(codec, 0x15, 0,
11787 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
11788 bits = present ? AMP_IN_MUTE(0) : 0;
11789 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
11790 AMP_IN_MUTE(0), bits);
11791 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
11792 AMP_IN_MUTE(0), bits);
11793}
11794
11795static void alc269_eeepc_dmic_automute(struct hda_codec *codec)
11796{
11797 unsigned int present;
11798
11799 present = snd_hda_codec_read(codec, 0x18, 0,
11800 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
11801 snd_hda_codec_write(codec, 0x23, 0,
11802 AC_VERB_SET_CONNECT_SEL, (present ? 0 : 5));
11803}
11804
11805static void alc269_eeepc_amic_automute(struct hda_codec *codec)
11806{
11807 unsigned int present;
11808
11809 present = snd_hda_codec_read(codec, 0x18, 0,
11810 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
11811 snd_hda_codec_write(codec, 0x24, 0, AC_VERB_SET_AMP_GAIN_MUTE,
11812 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
11813 snd_hda_codec_write(codec, 0x24, 0, AC_VERB_SET_AMP_GAIN_MUTE,
11814 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
11815}
11816
11817/* unsolicited event for HP jack sensing */
11818static void alc269_eeepc_dmic_unsol_event(struct hda_codec *codec,
11819 unsigned int res)
11820{
11821 if ((res >> 26) == ALC880_HP_EVENT)
11822 alc269_speaker_automute(codec);
11823
11824 if ((res >> 26) == ALC880_MIC_EVENT)
11825 alc269_eeepc_dmic_automute(codec);
11826}
11827
11828static void alc269_eeepc_dmic_inithook(struct hda_codec *codec)
11829{
11830 alc269_speaker_automute(codec);
11831 alc269_eeepc_dmic_automute(codec);
11832}
11833
11834/* unsolicited event for HP jack sensing */
11835static void alc269_eeepc_amic_unsol_event(struct hda_codec *codec,
11836 unsigned int res)
11837{
11838 if ((res >> 26) == ALC880_HP_EVENT)
11839 alc269_speaker_automute(codec);
11840
11841 if ((res >> 26) == ALC880_MIC_EVENT)
11842 alc269_eeepc_amic_automute(codec);
11843}
11844
11845static void alc269_eeepc_amic_inithook(struct hda_codec *codec)
11846{
11847 alc269_speaker_automute(codec);
11848 alc269_eeepc_amic_automute(codec);
11849}
11850
Kailang Yangf6a92242007-12-13 16:52:54 +010011851/*
11852 * generic initialization of ADC, input mixers and output mixers
11853 */
11854static struct hda_verb alc269_init_verbs[] = {
11855 /*
11856 * Unmute ADC0 and set the default input to mic-in
11857 */
Kailang Yang60db6b52008-08-26 13:13:00 +020011858 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangf6a92242007-12-13 16:52:54 +010011859
11860 /* Mute input amps (PCBeep, Line In, Mic 1 & Mic 2) of the
11861 * analog-loopback mixer widget
11862 * Note: PASD motherboards uses the Line In 2 as the input for
11863 * front panel mic (mic 2)
11864 */
11865 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
11866 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11867 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11868 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
11869 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
11870 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
11871
11872 /*
11873 * Set up output mixers (0x0c - 0x0e)
11874 */
11875 /* set vol=0 to output mixers */
11876 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11877 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11878
11879 /* set up input amps for analog loopback */
11880 /* Amp Indices: DAC = 0, mixer = 1 */
11881 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11882 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11883 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11884 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11885 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11886 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11887
11888 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11889 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11890 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11891 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
11892 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
11893 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11894 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11895
11896 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11897 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11898 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11899 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11900 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11901 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11902 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11903
11904 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
11905 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11906
11907 /* FIXME: use matrix-type input source selection */
11908 /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
11909 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yang60db6b52008-08-26 13:13:00 +020011910 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11911 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangf6a92242007-12-13 16:52:54 +010011912 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
11913 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
11914
11915 /* set EAPD */
11916 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
11917 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
11918 { }
11919};
11920
11921/* add playback controls from the parsed DAC table */
11922static int alc269_auto_create_multi_out_ctls(struct alc_spec *spec,
11923 const struct auto_pin_cfg *cfg)
11924{
11925 hda_nid_t nid;
11926 int err;
11927
11928 spec->multiout.num_dacs = 1; /* only use one dac */
11929 spec->multiout.dac_nids = spec->private_dac_nids;
11930 spec->multiout.dac_nids[0] = 2;
11931
11932 nid = cfg->line_out_pins[0];
11933 if (nid) {
11934 err = add_control(spec, ALC_CTL_WIDGET_VOL,
11935 "Front Playback Volume",
11936 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT));
11937 if (err < 0)
11938 return err;
11939 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
11940 "Front Playback Switch",
11941 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
11942 if (err < 0)
11943 return err;
11944 }
11945
11946 nid = cfg->speaker_pins[0];
11947 if (nid) {
11948 if (!cfg->line_out_pins[0]) {
11949 err = add_control(spec, ALC_CTL_WIDGET_VOL,
11950 "Speaker Playback Volume",
11951 HDA_COMPOSE_AMP_VAL(0x02, 3, 0,
11952 HDA_OUTPUT));
11953 if (err < 0)
11954 return err;
11955 }
11956 if (nid == 0x16) {
11957 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
11958 "Speaker Playback Switch",
11959 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
11960 HDA_OUTPUT));
11961 if (err < 0)
11962 return err;
11963 } else {
11964 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
11965 "Speaker Playback Switch",
11966 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
11967 HDA_OUTPUT));
11968 if (err < 0)
11969 return err;
11970 }
11971 }
11972 nid = cfg->hp_pins[0];
11973 if (nid) {
11974 /* spec->multiout.hp_nid = 2; */
11975 if (!cfg->line_out_pins[0] && !cfg->speaker_pins[0]) {
11976 err = add_control(spec, ALC_CTL_WIDGET_VOL,
11977 "Headphone Playback Volume",
11978 HDA_COMPOSE_AMP_VAL(0x02, 3, 0,
11979 HDA_OUTPUT));
11980 if (err < 0)
11981 return err;
11982 }
11983 if (nid == 0x16) {
11984 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
11985 "Headphone Playback Switch",
11986 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
11987 HDA_OUTPUT));
11988 if (err < 0)
11989 return err;
11990 } else {
11991 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
11992 "Headphone Playback Switch",
11993 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
11994 HDA_OUTPUT));
11995 if (err < 0)
11996 return err;
11997 }
11998 }
11999 return 0;
12000}
12001
Takashi Iwaiee956e02008-10-31 17:16:31 +010012002static int alc269_auto_create_analog_input_ctls(struct alc_spec *spec,
12003 const struct auto_pin_cfg *cfg)
12004{
12005 int err;
12006
12007 err = alc880_auto_create_analog_input_ctls(spec, cfg);
12008 if (err < 0)
12009 return err;
12010 /* digital-mic input pin is excluded in alc880_auto_create..()
12011 * because it's under 0x18
12012 */
12013 if (cfg->input_pins[AUTO_PIN_MIC] == 0x12 ||
12014 cfg->input_pins[AUTO_PIN_FRONT_MIC] == 0x12) {
12015 struct hda_input_mux *imux = &spec->private_imux;
12016 imux->items[imux->num_items].label = "Int Mic";
12017 imux->items[imux->num_items].index = 0x05;
12018 imux->num_items++;
12019 }
12020 return 0;
12021}
Kailang Yangf6a92242007-12-13 16:52:54 +010012022
12023#ifdef CONFIG_SND_HDA_POWER_SAVE
12024#define alc269_loopbacks alc880_loopbacks
12025#endif
12026
12027/* pcm configuration: identiacal with ALC880 */
12028#define alc269_pcm_analog_playback alc880_pcm_analog_playback
12029#define alc269_pcm_analog_capture alc880_pcm_analog_capture
12030#define alc269_pcm_digital_playback alc880_pcm_digital_playback
12031#define alc269_pcm_digital_capture alc880_pcm_digital_capture
12032
12033/*
12034 * BIOS auto configuration
12035 */
12036static int alc269_parse_auto_config(struct hda_codec *codec)
12037{
12038 struct alc_spec *spec = codec->spec;
Takashi Iwai2005af22008-08-20 18:38:26 +020012039 int i, err;
Kailang Yangf6a92242007-12-13 16:52:54 +010012040 static hda_nid_t alc269_ignore[] = { 0x1d, 0 };
12041
12042 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
12043 alc269_ignore);
12044 if (err < 0)
12045 return err;
12046
12047 err = alc269_auto_create_multi_out_ctls(spec, &spec->autocfg);
12048 if (err < 0)
12049 return err;
12050 err = alc269_auto_create_analog_input_ctls(spec, &spec->autocfg);
12051 if (err < 0)
12052 return err;
12053
12054 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
12055
12056 if (spec->autocfg.dig_out_pin)
12057 spec->multiout.dig_out_nid = ALC269_DIGOUT_NID;
12058
Takashi Iwai603c4012008-07-30 15:01:44 +020012059 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010012060 add_mixer(spec, spec->kctls.list);
Kailang Yangf6a92242007-12-13 16:52:54 +010012061
Takashi Iwai2005af22008-08-20 18:38:26 +020012062 /* create a beep mixer control if the pin 0x1d isn't assigned */
12063 for (i = 0; i < ARRAY_SIZE(spec->autocfg.input_pins); i++)
12064 if (spec->autocfg.input_pins[i] == 0x1d)
12065 break;
12066 if (i >= ARRAY_SIZE(spec->autocfg.input_pins))
Takashi Iwaid88897e2008-10-31 15:01:37 +010012067 add_mixer(spec, alc269_beep_mixer);
Takashi Iwai2005af22008-08-20 18:38:26 +020012068
Takashi Iwaid88897e2008-10-31 15:01:37 +010012069 add_verb(spec, alc269_init_verbs);
Kailang Yangf6a92242007-12-13 16:52:54 +010012070 spec->num_mux_defs = 1;
12071 spec->input_mux = &spec->private_imux;
Takashi Iwaie01bf502008-08-21 16:25:07 +020012072 /* set default input source */
12073 snd_hda_codec_write_cache(codec, alc269_capsrc_nids[0],
12074 0, AC_VERB_SET_CONNECT_SEL,
12075 spec->input_mux->items[0].index);
Kailang Yangf6a92242007-12-13 16:52:54 +010012076
12077 err = alc_auto_add_mic_boost(codec);
12078 if (err < 0)
12079 return err;
12080
Takashi Iwaif9e336f2008-10-31 16:37:07 +010012081 if (!spec->cap_mixer)
12082 set_capture_mixer(spec);
Kailang Yangf53281e2008-07-18 12:36:43 +020012083
Takashi Iwaie044c392008-10-27 16:56:24 +010012084 store_pin_configs(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010012085 return 1;
12086}
12087
12088#define alc269_auto_init_multi_out alc882_auto_init_multi_out
12089#define alc269_auto_init_hp_out alc882_auto_init_hp_out
12090#define alc269_auto_init_analog_input alc882_auto_init_analog_input
12091
12092
12093/* init callback for auto-configuration model -- overriding the default init */
12094static void alc269_auto_init(struct hda_codec *codec)
12095{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012096 struct alc_spec *spec = codec->spec;
Kailang Yangf6a92242007-12-13 16:52:54 +010012097 alc269_auto_init_multi_out(codec);
12098 alc269_auto_init_hp_out(codec);
12099 alc269_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012100 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020012101 alc_inithook(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010012102}
12103
12104/*
12105 * configuration and preset
12106 */
12107static const char *alc269_models[ALC269_MODEL_LAST] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020012108 [ALC269_BASIC] = "basic",
Takashi Iwai2922c9a2008-08-27 18:12:42 +020012109 [ALC269_QUANTA_FL1] = "quanta",
12110 [ALC269_ASUS_EEEPC_P703] = "eeepc-p703",
Takashi Iwai26f5df22008-11-03 17:39:46 +010012111 [ALC269_ASUS_EEEPC_P901] = "eeepc-p901",
12112 [ALC269_FUJITSU] = "fujitsu"
Kailang Yangf6a92242007-12-13 16:52:54 +010012113};
12114
12115static struct snd_pci_quirk alc269_cfg_tbl[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020012116 SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_QUANTA_FL1),
Kailang Yangf53281e2008-07-18 12:36:43 +020012117 SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A",
12118 ALC269_ASUS_EEEPC_P703),
12119 SND_PCI_QUIRK(0x1043, 0x831a, "ASUS Eeepc P901",
12120 ALC269_ASUS_EEEPC_P901),
Kailang Yang60db6b52008-08-26 13:13:00 +020012121 SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101",
12122 ALC269_ASUS_EEEPC_P901),
Takashi Iwai26f5df22008-11-03 17:39:46 +010012123 SND_PCI_QUIRK(0x1734, 0x115d, "FSC Amilo", ALC269_FUJITSU),
Kailang Yangf6a92242007-12-13 16:52:54 +010012124 {}
12125};
12126
12127static struct alc_config_preset alc269_presets[] = {
12128 [ALC269_BASIC] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010012129 .mixers = { alc269_base_mixer },
Kailang Yangf6a92242007-12-13 16:52:54 +010012130 .init_verbs = { alc269_init_verbs },
12131 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
12132 .dac_nids = alc269_dac_nids,
12133 .hp_nid = 0x03,
12134 .num_channel_mode = ARRAY_SIZE(alc269_modes),
12135 .channel_mode = alc269_modes,
12136 .input_mux = &alc269_capture_source,
12137 },
Kailang Yang60db6b52008-08-26 13:13:00 +020012138 [ALC269_QUANTA_FL1] = {
12139 .mixers = { alc269_quanta_fl1_mixer },
12140 .init_verbs = { alc269_init_verbs, alc269_quanta_fl1_verbs },
12141 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
12142 .dac_nids = alc269_dac_nids,
12143 .hp_nid = 0x03,
12144 .num_channel_mode = ARRAY_SIZE(alc269_modes),
12145 .channel_mode = alc269_modes,
12146 .input_mux = &alc269_capture_source,
12147 .unsol_event = alc269_quanta_fl1_unsol_event,
12148 .init_hook = alc269_quanta_fl1_init_hook,
12149 },
Kailang Yangf53281e2008-07-18 12:36:43 +020012150 [ALC269_ASUS_EEEPC_P703] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010012151 .mixers = { alc269_eeepc_mixer },
12152 .cap_mixer = alc269_epc_capture_mixer,
Kailang Yangf53281e2008-07-18 12:36:43 +020012153 .init_verbs = { alc269_init_verbs,
12154 alc269_eeepc_amic_init_verbs },
12155 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
12156 .dac_nids = alc269_dac_nids,
12157 .hp_nid = 0x03,
12158 .num_channel_mode = ARRAY_SIZE(alc269_modes),
12159 .channel_mode = alc269_modes,
12160 .input_mux = &alc269_eeepc_amic_capture_source,
12161 .unsol_event = alc269_eeepc_amic_unsol_event,
12162 .init_hook = alc269_eeepc_amic_inithook,
12163 },
12164 [ALC269_ASUS_EEEPC_P901] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010012165 .mixers = { alc269_eeepc_mixer },
12166 .cap_mixer = alc269_epc_capture_mixer,
Kailang Yangf53281e2008-07-18 12:36:43 +020012167 .init_verbs = { alc269_init_verbs,
12168 alc269_eeepc_dmic_init_verbs },
12169 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
12170 .dac_nids = alc269_dac_nids,
12171 .hp_nid = 0x03,
12172 .num_channel_mode = ARRAY_SIZE(alc269_modes),
12173 .channel_mode = alc269_modes,
12174 .input_mux = &alc269_eeepc_dmic_capture_source,
12175 .unsol_event = alc269_eeepc_dmic_unsol_event,
12176 .init_hook = alc269_eeepc_dmic_inithook,
12177 },
Takashi Iwai26f5df22008-11-03 17:39:46 +010012178 [ALC269_FUJITSU] = {
12179 .mixers = { alc269_fujitsu_mixer, alc269_beep_mixer },
12180 .cap_mixer = alc269_epc_capture_mixer,
12181 .init_verbs = { alc269_init_verbs,
12182 alc269_eeepc_dmic_init_verbs },
12183 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
12184 .dac_nids = alc269_dac_nids,
12185 .hp_nid = 0x03,
12186 .num_channel_mode = ARRAY_SIZE(alc269_modes),
12187 .channel_mode = alc269_modes,
12188 .input_mux = &alc269_eeepc_dmic_capture_source,
12189 .unsol_event = alc269_eeepc_dmic_unsol_event,
12190 .init_hook = alc269_eeepc_dmic_inithook,
12191 },
Kailang Yangf6a92242007-12-13 16:52:54 +010012192};
12193
12194static int patch_alc269(struct hda_codec *codec)
12195{
12196 struct alc_spec *spec;
12197 int board_config;
12198 int err;
12199
12200 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
12201 if (spec == NULL)
12202 return -ENOMEM;
12203
12204 codec->spec = spec;
12205
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020012206 alc_fix_pll_init(codec, 0x20, 0x04, 15);
12207
Kailang Yangf6a92242007-12-13 16:52:54 +010012208 board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST,
12209 alc269_models,
12210 alc269_cfg_tbl);
12211
12212 if (board_config < 0) {
12213 printk(KERN_INFO "hda_codec: Unknown model for ALC269, "
12214 "trying auto-probe from BIOS...\n");
12215 board_config = ALC269_AUTO;
12216 }
12217
12218 if (board_config == ALC269_AUTO) {
12219 /* automatic parse from the BIOS config */
12220 err = alc269_parse_auto_config(codec);
12221 if (err < 0) {
12222 alc_free(codec);
12223 return err;
12224 } else if (!err) {
12225 printk(KERN_INFO
12226 "hda_codec: Cannot set up configuration "
12227 "from BIOS. Using base mode...\n");
12228 board_config = ALC269_BASIC;
12229 }
12230 }
12231
12232 if (board_config != ALC269_AUTO)
12233 setup_preset(spec, &alc269_presets[board_config]);
12234
12235 spec->stream_name_analog = "ALC269 Analog";
12236 spec->stream_analog_playback = &alc269_pcm_analog_playback;
12237 spec->stream_analog_capture = &alc269_pcm_analog_capture;
12238
12239 spec->stream_name_digital = "ALC269 Digital";
12240 spec->stream_digital_playback = &alc269_pcm_digital_playback;
12241 spec->stream_digital_capture = &alc269_pcm_digital_capture;
12242
12243 spec->adc_nids = alc269_adc_nids;
12244 spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids);
Takashi Iwaie01bf502008-08-21 16:25:07 +020012245 spec->capsrc_nids = alc269_capsrc_nids;
Takashi Iwaif9e336f2008-10-31 16:37:07 +010012246 if (!spec->cap_mixer)
12247 set_capture_mixer(spec);
Kailang Yangf6a92242007-12-13 16:52:54 +010012248
12249 codec->patch_ops = alc_patch_ops;
12250 if (board_config == ALC269_AUTO)
12251 spec->init_hook = alc269_auto_init;
12252#ifdef CONFIG_SND_HDA_POWER_SAVE
12253 if (!spec->loopback.amplist)
12254 spec->loopback.amplist = alc269_loopbacks;
12255#endif
12256
12257 return 0;
12258}
12259
12260/*
Kailang Yangdf694da2005-12-05 19:42:22 +010012261 * ALC861 channel source setting (2/6 channel selection for 3-stack)
12262 */
12263
12264/*
12265 * set the path ways for 2 channel output
12266 * need to set the codec line out and mic 1 pin widgets to inputs
12267 */
12268static struct hda_verb alc861_threestack_ch2_init[] = {
12269 /* set pin widget 1Ah (line in) for input */
12270 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012271 /* set pin widget 18h (mic1/2) for input, for mic also enable
12272 * the vref
12273 */
Kailang Yangdf694da2005-12-05 19:42:22 +010012274 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12275
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012276 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
12277#if 0
12278 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
12279 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
12280#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010012281 { } /* end */
12282};
12283/*
12284 * 6ch mode
12285 * need to set the codec line out and mic 1 pin widgets to outputs
12286 */
12287static struct hda_verb alc861_threestack_ch6_init[] = {
12288 /* set pin widget 1Ah (line in) for output (Back Surround)*/
12289 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12290 /* set pin widget 18h (mic1) for output (CLFE)*/
12291 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12292
12293 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012294 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010012295
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012296 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
12297#if 0
12298 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
12299 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
12300#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010012301 { } /* end */
12302};
12303
12304static struct hda_channel_mode alc861_threestack_modes[2] = {
12305 { 2, alc861_threestack_ch2_init },
12306 { 6, alc861_threestack_ch6_init },
12307};
Takashi Iwai22309c32006-08-09 16:57:28 +020012308/* Set mic1 as input and unmute the mixer */
12309static struct hda_verb alc861_uniwill_m31_ch2_init[] = {
12310 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12311 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
12312 { } /* end */
12313};
12314/* Set mic1 as output and mute mixer */
12315static struct hda_verb alc861_uniwill_m31_ch4_init[] = {
12316 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12317 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
12318 { } /* end */
12319};
12320
12321static struct hda_channel_mode alc861_uniwill_m31_modes[2] = {
12322 { 2, alc861_uniwill_m31_ch2_init },
12323 { 4, alc861_uniwill_m31_ch4_init },
12324};
Kailang Yangdf694da2005-12-05 19:42:22 +010012325
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012326/* Set mic1 and line-in as input and unmute the mixer */
12327static struct hda_verb alc861_asus_ch2_init[] = {
12328 /* set pin widget 1Ah (line in) for input */
12329 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012330 /* set pin widget 18h (mic1/2) for input, for mic also enable
12331 * the vref
12332 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012333 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12334
12335 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
12336#if 0
12337 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
12338 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
12339#endif
12340 { } /* end */
12341};
12342/* Set mic1 nad line-in as output and mute mixer */
12343static struct hda_verb alc861_asus_ch6_init[] = {
12344 /* set pin widget 1Ah (line in) for output (Back Surround)*/
12345 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12346 /* { 0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
12347 /* set pin widget 18h (mic1) for output (CLFE)*/
12348 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12349 /* { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
12350 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
12351 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
12352
12353 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
12354#if 0
12355 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
12356 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
12357#endif
12358 { } /* end */
12359};
12360
12361static struct hda_channel_mode alc861_asus_modes[2] = {
12362 { 2, alc861_asus_ch2_init },
12363 { 6, alc861_asus_ch6_init },
12364};
12365
Kailang Yangdf694da2005-12-05 19:42:22 +010012366/* patch-ALC861 */
12367
12368static struct snd_kcontrol_new alc861_base_mixer[] = {
12369 /* output mixer control */
12370 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
12371 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
12372 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
12373 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
12374 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
12375
12376 /*Input mixer control */
12377 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
12378 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
12379 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
12380 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
12381 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
12382 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
12383 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
12384 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
12385 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
12386 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012387
Kailang Yangdf694da2005-12-05 19:42:22 +010012388 { } /* end */
12389};
12390
12391static struct snd_kcontrol_new alc861_3ST_mixer[] = {
12392 /* output mixer control */
12393 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
12394 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
12395 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
12396 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
12397 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
12398
12399 /* Input mixer control */
12400 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
12401 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
12402 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
12403 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
12404 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
12405 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
12406 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
12407 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
12408 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
12409 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012410
Kailang Yangdf694da2005-12-05 19:42:22 +010012411 {
12412 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12413 .name = "Channel Mode",
12414 .info = alc_ch_mode_info,
12415 .get = alc_ch_mode_get,
12416 .put = alc_ch_mode_put,
12417 .private_value = ARRAY_SIZE(alc861_threestack_modes),
12418 },
12419 { } /* end */
Tobin Davisa53d1ae2006-10-17 12:00:28 +020012420};
12421
Takashi Iwaid1d985f2006-11-23 19:27:12 +010012422static struct snd_kcontrol_new alc861_toshiba_mixer[] = {
Tobin Davisa53d1ae2006-10-17 12:00:28 +020012423 /* output mixer control */
12424 HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT),
12425 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
12426 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
Kailang Yangea1fb292008-08-26 12:58:38 +020012427
Tobin Davisa53d1ae2006-10-17 12:00:28 +020012428 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012429};
Tobin Davisa53d1ae2006-10-17 12:00:28 +020012430
Takashi Iwai22309c32006-08-09 16:57:28 +020012431static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = {
12432 /* output mixer control */
12433 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
12434 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
12435 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
12436 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
12437 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
12438
12439 /* Input mixer control */
12440 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
12441 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
12442 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
12443 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
12444 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
12445 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
12446 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
12447 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
12448 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
12449 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012450
Takashi Iwai22309c32006-08-09 16:57:28 +020012451 {
12452 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12453 .name = "Channel Mode",
12454 .info = alc_ch_mode_info,
12455 .get = alc_ch_mode_get,
12456 .put = alc_ch_mode_put,
12457 .private_value = ARRAY_SIZE(alc861_uniwill_m31_modes),
12458 },
12459 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012460};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012461
12462static struct snd_kcontrol_new alc861_asus_mixer[] = {
12463 /* output mixer control */
12464 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
12465 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
12466 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
12467 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
12468 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
12469
12470 /* Input mixer control */
12471 HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
12472 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT),
12473 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
12474 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
12475 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
12476 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
12477 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
12478 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
12479 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012480 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_OUTPUT),
12481
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012482 {
12483 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12484 .name = "Channel Mode",
12485 .info = alc_ch_mode_info,
12486 .get = alc_ch_mode_get,
12487 .put = alc_ch_mode_put,
12488 .private_value = ARRAY_SIZE(alc861_asus_modes),
12489 },
12490 { }
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010012491};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012492
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010012493/* additional mixer */
Takashi Iwaid1d985f2006-11-23 19:27:12 +010012494static struct snd_kcontrol_new alc861_asus_laptop_mixer[] = {
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010012495 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
12496 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
12497 HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x23, 0x0, HDA_OUTPUT),
12498 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x23, 0x0, HDA_OUTPUT),
12499 { }
12500};
12501
Kailang Yangdf694da2005-12-05 19:42:22 +010012502/*
12503 * generic initialization of ADC, input mixers and output mixers
12504 */
12505static struct hda_verb alc861_base_init_verbs[] = {
12506 /*
12507 * Unmute ADC0 and set the default input to mic-in
12508 */
12509 /* port-A for surround (rear panel) */
12510 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12511 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x00 },
12512 /* port-B for mic-in (rear panel) with vref */
12513 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12514 /* port-C for line-in (rear panel) */
12515 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
12516 /* port-D for Front */
12517 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12518 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
12519 /* port-E for HP out (front panel) */
12520 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
12521 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010012522 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010012523 /* port-F for mic-in (front panel) with vref */
12524 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12525 /* port-G for CLFE (rear panel) */
12526 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12527 { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x00 },
12528 /* port-H for side (rear panel) */
12529 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12530 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x00 },
12531 /* CD-in */
12532 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
12533 /* route front mic to ADC1*/
12534 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
12535 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020012536
Kailang Yangdf694da2005-12-05 19:42:22 +010012537 /* Unmute DAC0~3 & spdif out*/
12538 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12539 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12540 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12541 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12542 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020012543
Kailang Yangdf694da2005-12-05 19:42:22 +010012544 /* Unmute Mixer 14 (mic) 1c (Line in)*/
12545 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12546 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12547 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12548 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020012549
Kailang Yangdf694da2005-12-05 19:42:22 +010012550 /* Unmute Stereo Mixer 15 */
12551 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12552 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12553 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012554 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010012555
12556 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12557 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12558 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12559 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12560 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12561 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12562 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12563 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012564 /* hp used DAC 3 (Front) */
12565 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010012566 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
12567
12568 { }
12569};
12570
12571static struct hda_verb alc861_threestack_init_verbs[] = {
12572 /*
12573 * Unmute ADC0 and set the default input to mic-in
12574 */
12575 /* port-A for surround (rear panel) */
12576 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
12577 /* port-B for mic-in (rear panel) with vref */
12578 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12579 /* port-C for line-in (rear panel) */
12580 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
12581 /* port-D for Front */
12582 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12583 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
12584 /* port-E for HP out (front panel) */
12585 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
12586 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010012587 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010012588 /* port-F for mic-in (front panel) with vref */
12589 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12590 /* port-G for CLFE (rear panel) */
12591 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
12592 /* port-H for side (rear panel) */
12593 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
12594 /* CD-in */
12595 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
12596 /* route front mic to ADC1*/
12597 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
12598 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12599 /* Unmute DAC0~3 & spdif out*/
12600 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12601 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12602 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12603 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12604 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020012605
Kailang Yangdf694da2005-12-05 19:42:22 +010012606 /* Unmute Mixer 14 (mic) 1c (Line in)*/
12607 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12608 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12609 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12610 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020012611
Kailang Yangdf694da2005-12-05 19:42:22 +010012612 /* Unmute Stereo Mixer 15 */
12613 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12614 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12615 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012616 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010012617
12618 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12619 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12620 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12621 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12622 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12623 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12624 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12625 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012626 /* hp used DAC 3 (Front) */
12627 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010012628 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
12629 { }
12630};
Takashi Iwai22309c32006-08-09 16:57:28 +020012631
12632static struct hda_verb alc861_uniwill_m31_init_verbs[] = {
12633 /*
12634 * Unmute ADC0 and set the default input to mic-in
12635 */
12636 /* port-A for surround (rear panel) */
12637 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
12638 /* port-B for mic-in (rear panel) with vref */
12639 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12640 /* port-C for line-in (rear panel) */
12641 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
12642 /* port-D for Front */
12643 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12644 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
12645 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012646 /* this has to be set to VREF80 */
12647 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Takashi Iwai22309c32006-08-09 16:57:28 +020012648 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010012649 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai22309c32006-08-09 16:57:28 +020012650 /* port-F for mic-in (front panel) with vref */
12651 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12652 /* port-G for CLFE (rear panel) */
12653 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
12654 /* port-H for side (rear panel) */
12655 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
12656 /* CD-in */
12657 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
12658 /* route front mic to ADC1*/
12659 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
12660 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12661 /* Unmute DAC0~3 & spdif out*/
12662 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12663 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12664 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12665 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12666 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020012667
Takashi Iwai22309c32006-08-09 16:57:28 +020012668 /* Unmute Mixer 14 (mic) 1c (Line in)*/
12669 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12670 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12671 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12672 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020012673
Takashi Iwai22309c32006-08-09 16:57:28 +020012674 /* Unmute Stereo Mixer 15 */
12675 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12676 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12677 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012678 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Takashi Iwai22309c32006-08-09 16:57:28 +020012679
12680 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12681 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12682 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12683 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12684 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12685 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12686 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12687 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012688 /* hp used DAC 3 (Front) */
12689 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Takashi Iwai22309c32006-08-09 16:57:28 +020012690 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
12691 { }
12692};
12693
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012694static struct hda_verb alc861_asus_init_verbs[] = {
12695 /*
12696 * Unmute ADC0 and set the default input to mic-in
12697 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012698 /* port-A for surround (rear panel)
12699 * according to codec#0 this is the HP jack
12700 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012701 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* was 0x00 */
12702 /* route front PCM to HP */
12703 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x01 },
12704 /* port-B for mic-in (rear panel) with vref */
12705 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12706 /* port-C for line-in (rear panel) */
12707 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
12708 /* port-D for Front */
12709 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12710 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
12711 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012712 /* this has to be set to VREF80 */
12713 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012714 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010012715 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012716 /* port-F for mic-in (front panel) with vref */
12717 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12718 /* port-G for CLFE (rear panel) */
12719 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12720 /* port-H for side (rear panel) */
12721 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12722 /* CD-in */
12723 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
12724 /* route front mic to ADC1*/
12725 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
12726 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12727 /* Unmute DAC0~3 & spdif out*/
12728 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12729 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12730 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12731 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12732 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12733 /* Unmute Mixer 14 (mic) 1c (Line in)*/
12734 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12735 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12736 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12737 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020012738
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012739 /* Unmute Stereo Mixer 15 */
12740 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12741 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12742 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012743 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012744
12745 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12746 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12747 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12748 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12749 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12750 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12751 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12752 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012753 /* hp used DAC 3 (Front) */
12754 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012755 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
12756 { }
12757};
12758
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010012759/* additional init verbs for ASUS laptops */
12760static struct hda_verb alc861_asus_laptop_init_verbs[] = {
12761 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x45 }, /* HP-out */
12762 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2) }, /* mute line-in */
12763 { }
12764};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012765
Kailang Yangdf694da2005-12-05 19:42:22 +010012766/*
12767 * generic initialization of ADC, input mixers and output mixers
12768 */
12769static struct hda_verb alc861_auto_init_verbs[] = {
12770 /*
12771 * Unmute ADC0 and set the default input to mic-in
12772 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012773 /* {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, */
Kailang Yangdf694da2005-12-05 19:42:22 +010012774 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020012775
Kailang Yangdf694da2005-12-05 19:42:22 +010012776 /* Unmute DAC0~3 & spdif out*/
12777 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12778 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12779 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12780 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12781 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020012782
Kailang Yangdf694da2005-12-05 19:42:22 +010012783 /* Unmute Mixer 14 (mic) 1c (Line in)*/
12784 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12785 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12786 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12787 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020012788
Kailang Yangdf694da2005-12-05 19:42:22 +010012789 /* Unmute Stereo Mixer 15 */
12790 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12791 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12792 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
12793 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c},
12794
12795 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12796 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12797 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12798 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12799 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12800 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12801 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12802 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12803
12804 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12805 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012806 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
12807 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010012808 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12809 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012810 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
12811 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010012812
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012813 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, /* set Mic 1 */
Kailang Yangdf694da2005-12-05 19:42:22 +010012814
12815 { }
12816};
12817
Tobin Davisa53d1ae2006-10-17 12:00:28 +020012818static struct hda_verb alc861_toshiba_init_verbs[] = {
12819 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012820
Tobin Davisa53d1ae2006-10-17 12:00:28 +020012821 { }
12822};
12823
12824/* toggle speaker-output according to the hp-jack state */
12825static void alc861_toshiba_automute(struct hda_codec *codec)
12826{
12827 unsigned int present;
12828
12829 present = snd_hda_codec_read(codec, 0x0f, 0,
12830 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020012831 snd_hda_codec_amp_stereo(codec, 0x16, HDA_INPUT, 0,
12832 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
12833 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_INPUT, 3,
12834 HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE);
Tobin Davisa53d1ae2006-10-17 12:00:28 +020012835}
12836
12837static void alc861_toshiba_unsol_event(struct hda_codec *codec,
12838 unsigned int res)
12839{
Tobin Davisa53d1ae2006-10-17 12:00:28 +020012840 if ((res >> 26) == ALC880_HP_EVENT)
12841 alc861_toshiba_automute(codec);
12842}
12843
Kailang Yangdf694da2005-12-05 19:42:22 +010012844/* pcm configuration: identiacal with ALC880 */
12845#define alc861_pcm_analog_playback alc880_pcm_analog_playback
12846#define alc861_pcm_analog_capture alc880_pcm_analog_capture
12847#define alc861_pcm_digital_playback alc880_pcm_digital_playback
12848#define alc861_pcm_digital_capture alc880_pcm_digital_capture
12849
12850
12851#define ALC861_DIGOUT_NID 0x07
12852
12853static struct hda_channel_mode alc861_8ch_modes[1] = {
12854 { 8, NULL }
12855};
12856
12857static hda_nid_t alc861_dac_nids[4] = {
12858 /* front, surround, clfe, side */
12859 0x03, 0x06, 0x05, 0x04
12860};
12861
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012862static hda_nid_t alc660_dac_nids[3] = {
12863 /* front, clfe, surround */
12864 0x03, 0x05, 0x06
12865};
12866
Kailang Yangdf694da2005-12-05 19:42:22 +010012867static hda_nid_t alc861_adc_nids[1] = {
12868 /* ADC0-2 */
12869 0x08,
12870};
12871
12872static struct hda_input_mux alc861_capture_source = {
12873 .num_items = 5,
12874 .items = {
12875 { "Mic", 0x0 },
12876 { "Front Mic", 0x3 },
12877 { "Line", 0x1 },
12878 { "CD", 0x4 },
12879 { "Mixer", 0x5 },
12880 },
12881};
12882
12883/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012884static int alc861_auto_fill_dac_nids(struct alc_spec *spec,
12885 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010012886{
12887 int i;
12888 hda_nid_t nid;
12889
12890 spec->multiout.dac_nids = spec->private_dac_nids;
12891 for (i = 0; i < cfg->line_outs; i++) {
12892 nid = cfg->line_out_pins[i];
12893 if (nid) {
12894 if (i >= ARRAY_SIZE(alc861_dac_nids))
12895 continue;
12896 spec->multiout.dac_nids[i] = alc861_dac_nids[i];
12897 }
12898 }
12899 spec->multiout.num_dacs = cfg->line_outs;
12900 return 0;
12901}
12902
12903/* add playback controls from the parsed DAC table */
12904static int alc861_auto_create_multi_out_ctls(struct alc_spec *spec,
12905 const struct auto_pin_cfg *cfg)
12906{
12907 char name[32];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012908 static const char *chname[4] = {
12909 "Front", "Surround", NULL /*CLFE*/, "Side"
12910 };
Kailang Yangdf694da2005-12-05 19:42:22 +010012911 hda_nid_t nid;
12912 int i, idx, err;
12913
12914 for (i = 0; i < cfg->line_outs; i++) {
12915 nid = spec->multiout.dac_nids[i];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012916 if (!nid)
Kailang Yangdf694da2005-12-05 19:42:22 +010012917 continue;
12918 if (nid == 0x05) {
12919 /* Center/LFE */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012920 err = add_control(spec, ALC_CTL_BIND_MUTE,
12921 "Center Playback Switch",
12922 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
12923 HDA_OUTPUT));
12924 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010012925 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012926 err = add_control(spec, ALC_CTL_BIND_MUTE,
12927 "LFE Playback Switch",
12928 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
12929 HDA_OUTPUT));
12930 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010012931 return err;
12932 } else {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012933 for (idx = 0; idx < ARRAY_SIZE(alc861_dac_nids) - 1;
12934 idx++)
Kailang Yangdf694da2005-12-05 19:42:22 +010012935 if (nid == alc861_dac_nids[idx])
12936 break;
12937 sprintf(name, "%s Playback Switch", chname[idx]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012938 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
12939 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
12940 HDA_OUTPUT));
12941 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010012942 return err;
12943 }
12944 }
12945 return 0;
12946}
12947
12948static int alc861_auto_create_hp_ctls(struct alc_spec *spec, hda_nid_t pin)
12949{
12950 int err;
12951 hda_nid_t nid;
12952
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012953 if (!pin)
Kailang Yangdf694da2005-12-05 19:42:22 +010012954 return 0;
12955
12956 if ((pin >= 0x0b && pin <= 0x10) || pin == 0x1f || pin == 0x20) {
12957 nid = 0x03;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012958 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
12959 "Headphone Playback Switch",
12960 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
12961 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010012962 return err;
12963 spec->multiout.hp_nid = nid;
12964 }
12965 return 0;
12966}
12967
12968/* create playback/capture controls for input pins */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012969static int alc861_auto_create_analog_input_ctls(struct alc_spec *spec,
12970 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010012971{
Kailang Yangdf694da2005-12-05 19:42:22 +010012972 struct hda_input_mux *imux = &spec->private_imux;
12973 int i, err, idx, idx1;
12974
12975 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012976 switch (cfg->input_pins[i]) {
Kailang Yangdf694da2005-12-05 19:42:22 +010012977 case 0x0c:
12978 idx1 = 1;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012979 idx = 2; /* Line In */
Kailang Yangdf694da2005-12-05 19:42:22 +010012980 break;
12981 case 0x0f:
12982 idx1 = 2;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012983 idx = 2; /* Line In */
Kailang Yangdf694da2005-12-05 19:42:22 +010012984 break;
12985 case 0x0d:
12986 idx1 = 0;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012987 idx = 1; /* Mic In */
Kailang Yangdf694da2005-12-05 19:42:22 +010012988 break;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012989 case 0x10:
Kailang Yangdf694da2005-12-05 19:42:22 +010012990 idx1 = 3;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012991 idx = 1; /* Mic In */
Kailang Yangdf694da2005-12-05 19:42:22 +010012992 break;
12993 case 0x11:
12994 idx1 = 4;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012995 idx = 0; /* CD */
Kailang Yangdf694da2005-12-05 19:42:22 +010012996 break;
12997 default:
12998 continue;
12999 }
13000
Takashi Iwai4a471b72005-12-07 13:56:29 +010013001 err = new_analog_input(spec, cfg->input_pins[i],
13002 auto_pin_cfg_labels[i], idx, 0x15);
Kailang Yangdf694da2005-12-05 19:42:22 +010013003 if (err < 0)
13004 return err;
13005
Takashi Iwai4a471b72005-12-07 13:56:29 +010013006 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
Kailang Yangdf694da2005-12-05 19:42:22 +010013007 imux->items[imux->num_items].index = idx1;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013008 imux->num_items++;
Kailang Yangdf694da2005-12-05 19:42:22 +010013009 }
13010 return 0;
13011}
13012
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013013static void alc861_auto_set_output_and_unmute(struct hda_codec *codec,
13014 hda_nid_t nid,
Kailang Yangdf694da2005-12-05 19:42:22 +010013015 int pin_type, int dac_idx)
13016{
Jacek Luczak564c5be2008-05-03 18:41:23 +020013017 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
13018 pin_type);
13019 snd_hda_codec_write(codec, dac_idx, 0, AC_VERB_SET_AMP_GAIN_MUTE,
13020 AMP_OUT_UNMUTE);
Kailang Yangdf694da2005-12-05 19:42:22 +010013021}
13022
13023static void alc861_auto_init_multi_out(struct hda_codec *codec)
13024{
13025 struct alc_spec *spec = codec->spec;
13026 int i;
13027
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013028 alc_subsystem_id(codec, 0x0e, 0x0f, 0x0b);
Kailang Yangdf694da2005-12-05 19:42:22 +010013029 for (i = 0; i < spec->autocfg.line_outs; i++) {
13030 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020013031 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangdf694da2005-12-05 19:42:22 +010013032 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020013033 alc861_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013034 spec->multiout.dac_nids[i]);
Kailang Yangdf694da2005-12-05 19:42:22 +010013035 }
13036}
13037
13038static void alc861_auto_init_hp_out(struct hda_codec *codec)
13039{
13040 struct alc_spec *spec = codec->spec;
13041 hda_nid_t pin;
13042
Takashi Iwaieb06ed82006-09-20 17:10:27 +020013043 pin = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010013044 if (pin) /* connect to front */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013045 alc861_auto_set_output_and_unmute(codec, pin, PIN_HP,
13046 spec->multiout.dac_nids[0]);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013047 pin = spec->autocfg.speaker_pins[0];
13048 if (pin)
13049 alc861_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Kailang Yangdf694da2005-12-05 19:42:22 +010013050}
13051
13052static void alc861_auto_init_analog_input(struct hda_codec *codec)
13053{
13054 struct alc_spec *spec = codec->spec;
13055 int i;
13056
13057 for (i = 0; i < AUTO_PIN_LAST; i++) {
13058 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013059 if (nid >= 0x0c && nid <= 0x11) {
13060 snd_hda_codec_write(codec, nid, 0,
13061 AC_VERB_SET_PIN_WIDGET_CONTROL,
13062 i <= AUTO_PIN_FRONT_MIC ?
13063 PIN_VREF80 : PIN_IN);
Kailang Yangdf694da2005-12-05 19:42:22 +010013064 }
13065 }
13066}
13067
13068/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013069/* return 1 if successful, 0 if the proper config is not found,
13070 * or a negative error code
13071 */
Kailang Yangdf694da2005-12-05 19:42:22 +010013072static int alc861_parse_auto_config(struct hda_codec *codec)
13073{
13074 struct alc_spec *spec = codec->spec;
13075 int err;
13076 static hda_nid_t alc861_ignore[] = { 0x1d, 0 };
13077
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013078 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
13079 alc861_ignore);
13080 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010013081 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013082 if (!spec->autocfg.line_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +010013083 return 0; /* can't find valid BIOS pin config */
13084
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013085 err = alc861_auto_fill_dac_nids(spec, &spec->autocfg);
13086 if (err < 0)
13087 return err;
13088 err = alc861_auto_create_multi_out_ctls(spec, &spec->autocfg);
13089 if (err < 0)
13090 return err;
13091 err = alc861_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
13092 if (err < 0)
13093 return err;
13094 err = alc861_auto_create_analog_input_ctls(spec, &spec->autocfg);
13095 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010013096 return err;
13097
13098 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
13099
13100 if (spec->autocfg.dig_out_pin)
13101 spec->multiout.dig_out_nid = ALC861_DIGOUT_NID;
13102
Takashi Iwai603c4012008-07-30 15:01:44 +020013103 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010013104 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +010013105
Takashi Iwaid88897e2008-10-31 15:01:37 +010013106 add_verb(spec, alc861_auto_init_verbs);
Kailang Yangdf694da2005-12-05 19:42:22 +010013107
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020013108 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +010013109 spec->input_mux = &spec->private_imux;
13110
13111 spec->adc_nids = alc861_adc_nids;
13112 spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids);
Takashi Iwaif9e336f2008-10-31 16:37:07 +010013113 set_capture_mixer(spec);
Kailang Yangdf694da2005-12-05 19:42:22 +010013114
Takashi Iwaie044c392008-10-27 16:56:24 +010013115 store_pin_configs(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010013116 return 1;
13117}
13118
Takashi Iwaiae6b8132006-03-03 16:47:17 +010013119/* additional initialization for auto-configuration model */
13120static void alc861_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010013121{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013122 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010013123 alc861_auto_init_multi_out(codec);
13124 alc861_auto_init_hp_out(codec);
13125 alc861_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013126 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020013127 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010013128}
13129
Takashi Iwaicb53c622007-08-10 17:21:45 +020013130#ifdef CONFIG_SND_HDA_POWER_SAVE
13131static struct hda_amp_list alc861_loopbacks[] = {
13132 { 0x15, HDA_INPUT, 0 },
13133 { 0x15, HDA_INPUT, 1 },
13134 { 0x15, HDA_INPUT, 2 },
13135 { 0x15, HDA_INPUT, 3 },
13136 { } /* end */
13137};
13138#endif
13139
Kailang Yangdf694da2005-12-05 19:42:22 +010013140
13141/*
13142 * configuration and preset
13143 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010013144static const char *alc861_models[ALC861_MODEL_LAST] = {
13145 [ALC861_3ST] = "3stack",
13146 [ALC660_3ST] = "3stack-660",
13147 [ALC861_3ST_DIG] = "3stack-dig",
13148 [ALC861_6ST_DIG] = "6stack-dig",
13149 [ALC861_UNIWILL_M31] = "uniwill-m31",
13150 [ALC861_TOSHIBA] = "toshiba",
13151 [ALC861_ASUS] = "asus",
13152 [ALC861_ASUS_LAPTOP] = "asus-laptop",
13153 [ALC861_AUTO] = "auto",
13154};
13155
13156static struct snd_pci_quirk alc861_cfg_tbl[] = {
Takashi Iwai687a47b2007-01-10 11:25:58 +010013157 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010013158 SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP),
13159 SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP),
13160 SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013161 SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP),
Kailang Yang83c34212007-07-05 11:43:05 +020013162 SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS P1-AH2", ALC861_3ST_DIG),
Tobin Davisad5e7732007-01-08 10:57:32 +010013163 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA),
Takashi Iwai341d4eb2007-07-09 17:53:18 +020013164 /* FIXME: the entry below breaks Toshiba A100 (model=auto works!)
13165 * Any other models that need this preset?
13166 */
13167 /* SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), */
Claudio Matsuokaef64adb2007-07-14 00:26:16 +020013168 SND_PCI_QUIRK(0x1462, 0x7254, "HP dx2200 (MSI MS-7254)", ALC861_3ST),
13169 SND_PCI_QUIRK(0x1462, 0x7297, "HP dx2250 (MSI MS-7297)", ALC861_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013170 SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31),
13171 SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31),
13172 SND_PCI_QUIRK(0x1584, 0x9075, "Airis Praxis N1212", ALC861_ASUS_LAPTOP),
13173 /* FIXME: the below seems conflict */
13174 /* SND_PCI_QUIRK(0x1584, 0x9075, "Uniwill", ALC861_UNIWILL_M31), */
13175 SND_PCI_QUIRK(0x1849, 0x0660, "Asrock 939SLI32", ALC660_3ST),
13176 SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST),
Kailang Yangdf694da2005-12-05 19:42:22 +010013177 {}
13178};
13179
13180static struct alc_config_preset alc861_presets[] = {
13181 [ALC861_3ST] = {
13182 .mixers = { alc861_3ST_mixer },
13183 .init_verbs = { alc861_threestack_init_verbs },
13184 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
13185 .dac_nids = alc861_dac_nids,
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_3ST_DIG] = {
13194 .mixers = { alc861_base_mixer },
13195 .init_verbs = { alc861_threestack_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_threestack_modes),
13200 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020013201 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010013202 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13203 .adc_nids = alc861_adc_nids,
13204 .input_mux = &alc861_capture_source,
13205 },
13206 [ALC861_6ST_DIG] = {
13207 .mixers = { alc861_base_mixer },
13208 .init_verbs = { alc861_base_init_verbs },
13209 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
13210 .dac_nids = alc861_dac_nids,
13211 .dig_out_nid = ALC861_DIGOUT_NID,
13212 .num_channel_mode = ARRAY_SIZE(alc861_8ch_modes),
13213 .channel_mode = alc861_8ch_modes,
13214 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13215 .adc_nids = alc861_adc_nids,
13216 .input_mux = &alc861_capture_source,
13217 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013218 [ALC660_3ST] = {
13219 .mixers = { alc861_3ST_mixer },
13220 .init_verbs = { alc861_threestack_init_verbs },
13221 .num_dacs = ARRAY_SIZE(alc660_dac_nids),
13222 .dac_nids = alc660_dac_nids,
13223 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
13224 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020013225 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013226 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13227 .adc_nids = alc861_adc_nids,
13228 .input_mux = &alc861_capture_source,
13229 },
Takashi Iwai22309c32006-08-09 16:57:28 +020013230 [ALC861_UNIWILL_M31] = {
13231 .mixers = { alc861_uniwill_m31_mixer },
13232 .init_verbs = { alc861_uniwill_m31_init_verbs },
13233 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
13234 .dac_nids = alc861_dac_nids,
13235 .dig_out_nid = ALC861_DIGOUT_NID,
13236 .num_channel_mode = ARRAY_SIZE(alc861_uniwill_m31_modes),
13237 .channel_mode = alc861_uniwill_m31_modes,
13238 .need_dac_fix = 1,
13239 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13240 .adc_nids = alc861_adc_nids,
13241 .input_mux = &alc861_capture_source,
13242 },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013243 [ALC861_TOSHIBA] = {
13244 .mixers = { alc861_toshiba_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013245 .init_verbs = { alc861_base_init_verbs,
13246 alc861_toshiba_init_verbs },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013247 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
13248 .dac_nids = alc861_dac_nids,
13249 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
13250 .channel_mode = alc883_3ST_2ch_modes,
13251 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13252 .adc_nids = alc861_adc_nids,
13253 .input_mux = &alc861_capture_source,
13254 .unsol_event = alc861_toshiba_unsol_event,
13255 .init_hook = alc861_toshiba_automute,
13256 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013257 [ALC861_ASUS] = {
13258 .mixers = { alc861_asus_mixer },
13259 .init_verbs = { alc861_asus_init_verbs },
13260 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
13261 .dac_nids = alc861_dac_nids,
13262 .dig_out_nid = ALC861_DIGOUT_NID,
13263 .num_channel_mode = ARRAY_SIZE(alc861_asus_modes),
13264 .channel_mode = alc861_asus_modes,
13265 .need_dac_fix = 1,
13266 .hp_nid = 0x06,
13267 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13268 .adc_nids = alc861_adc_nids,
13269 .input_mux = &alc861_capture_source,
13270 },
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010013271 [ALC861_ASUS_LAPTOP] = {
13272 .mixers = { alc861_toshiba_mixer, alc861_asus_laptop_mixer },
13273 .init_verbs = { alc861_asus_init_verbs,
13274 alc861_asus_laptop_init_verbs },
13275 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
13276 .dac_nids = alc861_dac_nids,
13277 .dig_out_nid = ALC861_DIGOUT_NID,
13278 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
13279 .channel_mode = alc883_3ST_2ch_modes,
13280 .need_dac_fix = 1,
13281 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13282 .adc_nids = alc861_adc_nids,
13283 .input_mux = &alc861_capture_source,
13284 },
13285};
Kailang Yangdf694da2005-12-05 19:42:22 +010013286
13287
13288static int patch_alc861(struct hda_codec *codec)
13289{
13290 struct alc_spec *spec;
13291 int board_config;
13292 int err;
13293
Robert P. J. Daydc041e02006-12-19 14:44:15 +010013294 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010013295 if (spec == NULL)
13296 return -ENOMEM;
13297
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013298 codec->spec = spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010013299
Takashi Iwaif5fcc132006-11-24 17:07:44 +010013300 board_config = snd_hda_check_board_config(codec, ALC861_MODEL_LAST,
13301 alc861_models,
13302 alc861_cfg_tbl);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013303
Takashi Iwaif5fcc132006-11-24 17:07:44 +010013304 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013305 printk(KERN_INFO "hda_codec: Unknown model for ALC861, "
13306 "trying auto-probe from BIOS...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010013307 board_config = ALC861_AUTO;
13308 }
13309
13310 if (board_config == ALC861_AUTO) {
13311 /* automatic parse from the BIOS config */
13312 err = alc861_parse_auto_config(codec);
13313 if (err < 0) {
13314 alc_free(codec);
13315 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013316 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013317 printk(KERN_INFO
13318 "hda_codec: Cannot set up configuration "
13319 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010013320 board_config = ALC861_3ST_DIG;
13321 }
13322 }
13323
13324 if (board_config != ALC861_AUTO)
13325 setup_preset(spec, &alc861_presets[board_config]);
13326
13327 spec->stream_name_analog = "ALC861 Analog";
13328 spec->stream_analog_playback = &alc861_pcm_analog_playback;
13329 spec->stream_analog_capture = &alc861_pcm_analog_capture;
13330
13331 spec->stream_name_digital = "ALC861 Digital";
13332 spec->stream_digital_playback = &alc861_pcm_digital_playback;
13333 spec->stream_digital_capture = &alc861_pcm_digital_capture;
13334
Takashi Iwai2134ea42008-01-10 16:53:55 +010013335 spec->vmaster_nid = 0x03;
13336
Kailang Yangdf694da2005-12-05 19:42:22 +010013337 codec->patch_ops = alc_patch_ops;
13338 if (board_config == ALC861_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +010013339 spec->init_hook = alc861_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020013340#ifdef CONFIG_SND_HDA_POWER_SAVE
13341 if (!spec->loopback.amplist)
13342 spec->loopback.amplist = alc861_loopbacks;
13343#endif
Kailang Yangea1fb292008-08-26 12:58:38 +020013344
Kailang Yangdf694da2005-12-05 19:42:22 +010013345 return 0;
13346}
13347
13348/*
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013349 * ALC861-VD support
13350 *
13351 * Based on ALC882
13352 *
13353 * In addition, an independent DAC
13354 */
13355#define ALC861VD_DIGOUT_NID 0x06
13356
13357static hda_nid_t alc861vd_dac_nids[4] = {
13358 /* front, surr, clfe, side surr */
13359 0x02, 0x03, 0x04, 0x05
13360};
13361
13362/* dac_nids for ALC660vd are in a different order - according to
13363 * Realtek's driver.
13364 * This should probably tesult in a different mixer for 6stack models
13365 * of ALC660vd codecs, but for now there is only 3stack mixer
13366 * - and it is the same as in 861vd.
13367 * adc_nids in ALC660vd are (is) the same as in 861vd
13368 */
13369static hda_nid_t alc660vd_dac_nids[3] = {
13370 /* front, rear, clfe, rear_surr */
13371 0x02, 0x04, 0x03
13372};
13373
13374static hda_nid_t alc861vd_adc_nids[1] = {
13375 /* ADC0 */
13376 0x09,
13377};
13378
Takashi Iwaie1406342008-02-11 18:32:32 +010013379static hda_nid_t alc861vd_capsrc_nids[1] = { 0x22 };
13380
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013381/* input MUX */
13382/* FIXME: should be a matrix-type input source selection */
13383static struct hda_input_mux alc861vd_capture_source = {
13384 .num_items = 4,
13385 .items = {
13386 { "Mic", 0x0 },
13387 { "Front Mic", 0x1 },
13388 { "Line", 0x2 },
13389 { "CD", 0x4 },
13390 },
13391};
13392
Kailang Yang272a5272007-05-14 11:00:38 +020013393static struct hda_input_mux alc861vd_dallas_capture_source = {
Tobin Davisb419f342008-03-07 11:57:51 +010013394 .num_items = 2,
Kailang Yang272a5272007-05-14 11:00:38 +020013395 .items = {
Tobin Davisb419f342008-03-07 11:57:51 +010013396 { "Ext Mic", 0x0 },
13397 { "Int Mic", 0x1 },
Kailang Yang272a5272007-05-14 11:00:38 +020013398 },
13399};
13400
Kailang Yangd1a991a2007-08-15 16:21:59 +020013401static struct hda_input_mux alc861vd_hp_capture_source = {
13402 .num_items = 2,
13403 .items = {
13404 { "Front Mic", 0x0 },
13405 { "ATAPI Mic", 0x1 },
13406 },
13407};
13408
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013409/*
13410 * 2ch mode
13411 */
13412static struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = {
13413 { 2, NULL }
13414};
13415
13416/*
13417 * 6ch mode
13418 */
13419static struct hda_verb alc861vd_6stack_ch6_init[] = {
13420 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
13421 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
13422 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
13423 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
13424 { } /* end */
13425};
13426
13427/*
13428 * 8ch mode
13429 */
13430static struct hda_verb alc861vd_6stack_ch8_init[] = {
13431 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
13432 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
13433 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
13434 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
13435 { } /* end */
13436};
13437
13438static struct hda_channel_mode alc861vd_6stack_modes[2] = {
13439 { 6, alc861vd_6stack_ch6_init },
13440 { 8, alc861vd_6stack_ch8_init },
13441};
13442
13443static struct snd_kcontrol_new alc861vd_chmode_mixer[] = {
13444 {
13445 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13446 .name = "Channel Mode",
13447 .info = alc_ch_mode_info,
13448 .get = alc_ch_mode_get,
13449 .put = alc_ch_mode_put,
13450 },
13451 { } /* end */
13452};
13453
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013454/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
13455 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
13456 */
13457static struct snd_kcontrol_new alc861vd_6st_mixer[] = {
13458 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13459 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
13460
13461 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
13462 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
13463
13464 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0,
13465 HDA_OUTPUT),
13466 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0,
13467 HDA_OUTPUT),
13468 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
13469 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
13470
13471 HDA_CODEC_VOLUME("Side Playback Volume", 0x05, 0x0, HDA_OUTPUT),
13472 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
13473
13474 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
13475
13476 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13477 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13478 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13479
13480 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
13481 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
13482 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
13483
13484 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
13485 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
13486
13487 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
13488 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
13489
13490 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
13491 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
13492
13493 { } /* end */
13494};
13495
13496static struct snd_kcontrol_new alc861vd_3st_mixer[] = {
13497 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13498 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
13499
13500 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
13501
13502 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13503 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13504 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13505
13506 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
13507 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
13508 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
13509
13510 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
13511 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
13512
13513 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
13514 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
13515
13516 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
13517 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
13518
13519 { } /* end */
13520};
13521
Kailang Yangbdd148a2007-05-08 15:19:08 +020013522static struct snd_kcontrol_new alc861vd_lenovo_mixer[] = {
13523 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13524 /*HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),*/
13525 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
13526
13527 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
13528
13529 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13530 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13531 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13532
13533 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
13534 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
13535 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
13536
13537 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
13538 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
13539
13540 { } /* end */
13541};
13542
Tobin Davisb419f342008-03-07 11:57:51 +010013543/* Pin assignment: Speaker=0x14, HP = 0x15,
13544 * Ext Mic=0x18, Int Mic = 0x19, CD = 0x1c, PC Beep = 0x1d
Kailang Yang272a5272007-05-14 11:00:38 +020013545 */
13546static struct snd_kcontrol_new alc861vd_dallas_mixer[] = {
Tobin Davisb419f342008-03-07 11:57:51 +010013547 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13548 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020013549 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
13550 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
Tobin Davisb419f342008-03-07 11:57:51 +010013551 HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
13552 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13553 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13554 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
13555 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
13556 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
13557 HDA_CODEC_VOLUME("PC Beep Volume", 0x0b, 0x05, HDA_INPUT),
13558 HDA_CODEC_MUTE("PC Beep Switch", 0x0b, 0x05, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020013559 { } /* end */
13560};
13561
Kailang Yangd1a991a2007-08-15 16:21:59 +020013562/* Pin assignment: Speaker=0x14, Line-out = 0x15,
13563 * Front Mic=0x18, ATAPI Mic = 0x19,
13564 */
13565static struct snd_kcontrol_new alc861vd_hp_mixer[] = {
13566 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13567 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
13568 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
13569 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
13570 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13571 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13572 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
13573 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangea1fb292008-08-26 12:58:38 +020013574
Kailang Yangd1a991a2007-08-15 16:21:59 +020013575 { } /* end */
13576};
13577
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013578/*
13579 * generic initialization of ADC, input mixers and output mixers
13580 */
13581static struct hda_verb alc861vd_volume_init_verbs[] = {
13582 /*
13583 * Unmute ADC0 and set the default input to mic-in
13584 */
13585 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
13586 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13587
13588 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of
13589 * the analog-loopback mixer widget
13590 */
13591 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020013592 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13593 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13594 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
13595 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
13596 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013597
13598 /* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yangbdd148a2007-05-08 15:19:08 +020013599 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13600 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13601 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013602 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013603
13604 /*
13605 * Set up output mixers (0x02 - 0x05)
13606 */
13607 /* set vol=0 to output mixers */
13608 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13609 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13610 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13611 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13612
13613 /* set up input amps for analog loopback */
13614 /* Amp Indices: DAC = 0, mixer = 1 */
13615 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13616 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13617 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13618 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13619 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13620 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13621 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13622 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13623
13624 { }
13625};
13626
13627/*
13628 * 3-stack pin configuration:
13629 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
13630 */
13631static struct hda_verb alc861vd_3stack_init_verbs[] = {
13632 /*
13633 * Set pin mode and muting
13634 */
13635 /* set front pin widgets 0x14 for output */
13636 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13637 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13638 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
13639
13640 /* Mic (rear) pin: input vref at 80% */
13641 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
13642 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13643 /* Front Mic pin: input vref at 80% */
13644 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
13645 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13646 /* Line In pin: input */
13647 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13648 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13649 /* Line-2 In: Headphone output (output 0 - 0x0c) */
13650 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13651 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13652 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
13653 /* CD pin widget for input */
13654 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13655
13656 { }
13657};
13658
13659/*
13660 * 6-stack pin configuration:
13661 */
13662static struct hda_verb alc861vd_6stack_init_verbs[] = {
13663 /*
13664 * Set pin mode and muting
13665 */
13666 /* set front pin widgets 0x14 for output */
13667 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13668 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13669 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
13670
13671 /* Rear Pin: output 1 (0x0d) */
13672 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13673 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13674 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
13675 /* CLFE Pin: output 2 (0x0e) */
13676 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13677 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13678 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
13679 /* Side Pin: output 3 (0x0f) */
13680 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13681 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13682 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
13683
13684 /* Mic (rear) pin: input vref at 80% */
13685 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
13686 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13687 /* Front Mic pin: input vref at 80% */
13688 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
13689 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13690 /* Line In pin: input */
13691 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13692 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13693 /* Line-2 In: Headphone output (output 0 - 0x0c) */
13694 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13695 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13696 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
13697 /* CD pin widget for input */
13698 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13699
13700 { }
13701};
13702
Kailang Yangbdd148a2007-05-08 15:19:08 +020013703static struct hda_verb alc861vd_eapd_verbs[] = {
13704 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
13705 { }
13706};
13707
Kailang Yangf9423e72008-05-27 12:32:25 +020013708static struct hda_verb alc660vd_eapd_verbs[] = {
13709 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
13710 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
13711 { }
13712};
13713
Kailang Yangbdd148a2007-05-08 15:19:08 +020013714static struct hda_verb alc861vd_lenovo_unsol_verbs[] = {
13715 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13716 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13717 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
13718 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Kailang Yangea1fb292008-08-26 12:58:38 +020013719 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
Kailang Yangbdd148a2007-05-08 15:19:08 +020013720 {}
13721};
13722
13723/* toggle speaker-output according to the hp-jack state */
13724static void alc861vd_lenovo_hp_automute(struct hda_codec *codec)
13725{
13726 unsigned int present;
13727 unsigned char bits;
13728
13729 present = snd_hda_codec_read(codec, 0x1b, 0,
13730 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020013731 bits = present ? HDA_AMP_MUTE : 0;
13732 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
13733 HDA_AMP_MUTE, bits);
Kailang Yangbdd148a2007-05-08 15:19:08 +020013734}
13735
13736static void alc861vd_lenovo_mic_automute(struct hda_codec *codec)
13737{
13738 unsigned int present;
13739 unsigned char bits;
13740
13741 present = snd_hda_codec_read(codec, 0x18, 0,
13742 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020013743 bits = present ? HDA_AMP_MUTE : 0;
13744 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
13745 HDA_AMP_MUTE, bits);
Kailang Yangbdd148a2007-05-08 15:19:08 +020013746}
13747
13748static void alc861vd_lenovo_automute(struct hda_codec *codec)
13749{
13750 alc861vd_lenovo_hp_automute(codec);
13751 alc861vd_lenovo_mic_automute(codec);
13752}
13753
13754static void alc861vd_lenovo_unsol_event(struct hda_codec *codec,
13755 unsigned int res)
13756{
13757 switch (res >> 26) {
13758 case ALC880_HP_EVENT:
13759 alc861vd_lenovo_hp_automute(codec);
13760 break;
13761 case ALC880_MIC_EVENT:
13762 alc861vd_lenovo_mic_automute(codec);
13763 break;
13764 }
13765}
13766
Kailang Yang272a5272007-05-14 11:00:38 +020013767static struct hda_verb alc861vd_dallas_verbs[] = {
13768 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13769 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13770 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13771 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13772
13773 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13774 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13775 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13776 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13777 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13778 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13779 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13780 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020013781
Kailang Yang272a5272007-05-14 11:00:38 +020013782 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13783 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13784 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13785 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13786 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13787 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13788 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13789 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13790
13791 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
13792 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13793 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
13794 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13795 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13796 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13797 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13798 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13799
13800 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13801 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
13802 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
13803 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
13804
13805 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020013806 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yang272a5272007-05-14 11:00:38 +020013807 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
13808
13809 { } /* end */
13810};
13811
13812/* toggle speaker-output according to the hp-jack state */
13813static void alc861vd_dallas_automute(struct hda_codec *codec)
13814{
13815 unsigned int present;
13816
13817 present = snd_hda_codec_read(codec, 0x15, 0,
13818 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020013819 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
13820 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +020013821}
13822
13823static void alc861vd_dallas_unsol_event(struct hda_codec *codec, unsigned int res)
13824{
13825 if ((res >> 26) == ALC880_HP_EVENT)
13826 alc861vd_dallas_automute(codec);
13827}
13828
Takashi Iwaicb53c622007-08-10 17:21:45 +020013829#ifdef CONFIG_SND_HDA_POWER_SAVE
13830#define alc861vd_loopbacks alc880_loopbacks
13831#endif
13832
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013833/* pcm configuration: identiacal with ALC880 */
13834#define alc861vd_pcm_analog_playback alc880_pcm_analog_playback
13835#define alc861vd_pcm_analog_capture alc880_pcm_analog_capture
13836#define alc861vd_pcm_digital_playback alc880_pcm_digital_playback
13837#define alc861vd_pcm_digital_capture alc880_pcm_digital_capture
13838
13839/*
13840 * configuration and preset
13841 */
13842static const char *alc861vd_models[ALC861VD_MODEL_LAST] = {
13843 [ALC660VD_3ST] = "3stack-660",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020013844 [ALC660VD_3ST_DIG] = "3stack-660-digout",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013845 [ALC861VD_3ST] = "3stack",
13846 [ALC861VD_3ST_DIG] = "3stack-digout",
13847 [ALC861VD_6ST_DIG] = "6stack-digout",
Kailang Yangbdd148a2007-05-08 15:19:08 +020013848 [ALC861VD_LENOVO] = "lenovo",
Kailang Yang272a5272007-05-14 11:00:38 +020013849 [ALC861VD_DALLAS] = "dallas",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020013850 [ALC861VD_HP] = "hp",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013851 [ALC861VD_AUTO] = "auto",
13852};
13853
13854static struct snd_pci_quirk alc861vd_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013855 SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST),
13856 SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP),
Takashi Iwai07e038b2007-02-15 18:23:41 +010013857 SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013858 SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),
Alexander Holler2522d732008-07-17 23:36:15 +020013859 SND_PCI_QUIRK(0x1043, 0x1633, "Asus V1Sn", ALC861VD_LENOVO),
Mike Crash6963f842007-06-25 12:12:51 +020013860 SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013861 SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013862 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO),
Takashi Iwai38baf5a2007-08-16 17:52:43 +020013863 /*SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS),*/ /*lenovo*/
Kailang Yang272a5272007-05-14 11:00:38 +020013864 SND_PCI_QUIRK(0x1179, 0xff01, "DALLAS", ALC861VD_DALLAS),
Takashi Iwai542d7c62007-08-16 18:57:30 +020013865 SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO),
Tobin Davisb419f342008-03-07 11:57:51 +010013866 SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_DALLAS),
Takashi Iwai39c5d412007-08-15 16:24:17 +020013867 SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013868 SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo", ALC861VD_LENOVO),
13869 SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo 3000 C200", ALC861VD_LENOVO),
Takashi Iwaibe321a82008-07-07 16:04:04 +020013870 SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 N200", ALC861VD_LENOVO),
Tobin Davis625dc0b2007-07-30 21:42:10 +020013871 SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013872 {}
13873};
13874
13875static struct alc_config_preset alc861vd_presets[] = {
13876 [ALC660VD_3ST] = {
13877 .mixers = { alc861vd_3st_mixer },
13878 .init_verbs = { alc861vd_volume_init_verbs,
13879 alc861vd_3stack_init_verbs },
13880 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
13881 .dac_nids = alc660vd_dac_nids,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013882 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
13883 .channel_mode = alc861vd_3stack_2ch_modes,
13884 .input_mux = &alc861vd_capture_source,
13885 },
Mike Crash6963f842007-06-25 12:12:51 +020013886 [ALC660VD_3ST_DIG] = {
13887 .mixers = { alc861vd_3st_mixer },
13888 .init_verbs = { alc861vd_volume_init_verbs,
13889 alc861vd_3stack_init_verbs },
13890 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
13891 .dac_nids = alc660vd_dac_nids,
13892 .dig_out_nid = ALC861VD_DIGOUT_NID,
Mike Crash6963f842007-06-25 12:12:51 +020013893 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
13894 .channel_mode = alc861vd_3stack_2ch_modes,
13895 .input_mux = &alc861vd_capture_source,
13896 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013897 [ALC861VD_3ST] = {
13898 .mixers = { alc861vd_3st_mixer },
13899 .init_verbs = { alc861vd_volume_init_verbs,
13900 alc861vd_3stack_init_verbs },
13901 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
13902 .dac_nids = alc861vd_dac_nids,
13903 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
13904 .channel_mode = alc861vd_3stack_2ch_modes,
13905 .input_mux = &alc861vd_capture_source,
13906 },
13907 [ALC861VD_3ST_DIG] = {
13908 .mixers = { alc861vd_3st_mixer },
13909 .init_verbs = { alc861vd_volume_init_verbs,
13910 alc861vd_3stack_init_verbs },
13911 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
13912 .dac_nids = alc861vd_dac_nids,
13913 .dig_out_nid = ALC861VD_DIGOUT_NID,
13914 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
13915 .channel_mode = alc861vd_3stack_2ch_modes,
13916 .input_mux = &alc861vd_capture_source,
13917 },
13918 [ALC861VD_6ST_DIG] = {
13919 .mixers = { alc861vd_6st_mixer, alc861vd_chmode_mixer },
13920 .init_verbs = { alc861vd_volume_init_verbs,
13921 alc861vd_6stack_init_verbs },
13922 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
13923 .dac_nids = alc861vd_dac_nids,
13924 .dig_out_nid = ALC861VD_DIGOUT_NID,
13925 .num_channel_mode = ARRAY_SIZE(alc861vd_6stack_modes),
13926 .channel_mode = alc861vd_6stack_modes,
13927 .input_mux = &alc861vd_capture_source,
13928 },
Kailang Yangbdd148a2007-05-08 15:19:08 +020013929 [ALC861VD_LENOVO] = {
13930 .mixers = { alc861vd_lenovo_mixer },
13931 .init_verbs = { alc861vd_volume_init_verbs,
13932 alc861vd_3stack_init_verbs,
13933 alc861vd_eapd_verbs,
13934 alc861vd_lenovo_unsol_verbs },
13935 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
13936 .dac_nids = alc660vd_dac_nids,
Kailang Yangbdd148a2007-05-08 15:19:08 +020013937 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
13938 .channel_mode = alc861vd_3stack_2ch_modes,
13939 .input_mux = &alc861vd_capture_source,
13940 .unsol_event = alc861vd_lenovo_unsol_event,
13941 .init_hook = alc861vd_lenovo_automute,
13942 },
Kailang Yang272a5272007-05-14 11:00:38 +020013943 [ALC861VD_DALLAS] = {
13944 .mixers = { alc861vd_dallas_mixer },
13945 .init_verbs = { alc861vd_dallas_verbs },
13946 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
13947 .dac_nids = alc861vd_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +020013948 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
13949 .channel_mode = alc861vd_3stack_2ch_modes,
13950 .input_mux = &alc861vd_dallas_capture_source,
13951 .unsol_event = alc861vd_dallas_unsol_event,
13952 .init_hook = alc861vd_dallas_automute,
Kailang Yangd1a991a2007-08-15 16:21:59 +020013953 },
13954 [ALC861VD_HP] = {
13955 .mixers = { alc861vd_hp_mixer },
13956 .init_verbs = { alc861vd_dallas_verbs, alc861vd_eapd_verbs },
13957 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
13958 .dac_nids = alc861vd_dac_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020013959 .dig_out_nid = ALC861VD_DIGOUT_NID,
Kailang Yangd1a991a2007-08-15 16:21:59 +020013960 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
13961 .channel_mode = alc861vd_3stack_2ch_modes,
13962 .input_mux = &alc861vd_hp_capture_source,
13963 .unsol_event = alc861vd_dallas_unsol_event,
13964 .init_hook = alc861vd_dallas_automute,
Kailang Yangea1fb292008-08-26 12:58:38 +020013965 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013966};
13967
13968/*
13969 * BIOS auto configuration
13970 */
13971static void alc861vd_auto_set_output_and_unmute(struct hda_codec *codec,
13972 hda_nid_t nid, int pin_type, int dac_idx)
13973{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013974 alc_set_pin_output(codec, nid, pin_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013975}
13976
13977static void alc861vd_auto_init_multi_out(struct hda_codec *codec)
13978{
13979 struct alc_spec *spec = codec->spec;
13980 int i;
13981
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013982 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013983 for (i = 0; i <= HDA_SIDE; i++) {
13984 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020013985 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013986 if (nid)
13987 alc861vd_auto_set_output_and_unmute(codec, nid,
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020013988 pin_type, i);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013989 }
13990}
13991
13992
13993static void alc861vd_auto_init_hp_out(struct hda_codec *codec)
13994{
13995 struct alc_spec *spec = codec->spec;
13996 hda_nid_t pin;
13997
13998 pin = spec->autocfg.hp_pins[0];
13999 if (pin) /* connect to front and use dac 0 */
14000 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014001 pin = spec->autocfg.speaker_pins[0];
14002 if (pin)
14003 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014004}
14005
14006#define alc861vd_is_input_pin(nid) alc880_is_input_pin(nid)
14007#define ALC861VD_PIN_CD_NID ALC880_PIN_CD_NID
14008
14009static void alc861vd_auto_init_analog_input(struct hda_codec *codec)
14010{
14011 struct alc_spec *spec = codec->spec;
14012 int i;
14013
14014 for (i = 0; i < AUTO_PIN_LAST; i++) {
14015 hda_nid_t nid = spec->autocfg.input_pins[i];
14016 if (alc861vd_is_input_pin(nid)) {
14017 snd_hda_codec_write(codec, nid, 0,
14018 AC_VERB_SET_PIN_WIDGET_CONTROL,
14019 i <= AUTO_PIN_FRONT_MIC ?
14020 PIN_VREF80 : PIN_IN);
14021 if (nid != ALC861VD_PIN_CD_NID)
14022 snd_hda_codec_write(codec, nid, 0,
14023 AC_VERB_SET_AMP_GAIN_MUTE,
14024 AMP_OUT_MUTE);
14025 }
14026 }
14027}
14028
Takashi Iwaif511b012008-08-15 16:46:42 +020014029#define alc861vd_auto_init_input_src alc882_auto_init_input_src
14030
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014031#define alc861vd_idx_to_mixer_vol(nid) ((nid) + 0x02)
14032#define alc861vd_idx_to_mixer_switch(nid) ((nid) + 0x0c)
14033
14034/* add playback controls from the parsed DAC table */
14035/* Based on ALC880 version. But ALC861VD has separate,
14036 * different NIDs for mute/unmute switch and volume control */
14037static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
14038 const struct auto_pin_cfg *cfg)
14039{
14040 char name[32];
14041 static const char *chname[4] = {"Front", "Surround", "CLFE", "Side"};
14042 hda_nid_t nid_v, nid_s;
14043 int i, err;
14044
14045 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014046 if (!spec->multiout.dac_nids[i])
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014047 continue;
14048 nid_v = alc861vd_idx_to_mixer_vol(
14049 alc880_dac_to_idx(
14050 spec->multiout.dac_nids[i]));
14051 nid_s = alc861vd_idx_to_mixer_switch(
14052 alc880_dac_to_idx(
14053 spec->multiout.dac_nids[i]));
14054
14055 if (i == 2) {
14056 /* Center/LFE */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014057 err = add_control(spec, ALC_CTL_WIDGET_VOL,
14058 "Center Playback Volume",
14059 HDA_COMPOSE_AMP_VAL(nid_v, 1, 0,
14060 HDA_OUTPUT));
14061 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014062 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014063 err = add_control(spec, ALC_CTL_WIDGET_VOL,
14064 "LFE Playback Volume",
14065 HDA_COMPOSE_AMP_VAL(nid_v, 2, 0,
14066 HDA_OUTPUT));
14067 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014068 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014069 err = add_control(spec, ALC_CTL_BIND_MUTE,
14070 "Center Playback Switch",
14071 HDA_COMPOSE_AMP_VAL(nid_s, 1, 2,
14072 HDA_INPUT));
14073 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014074 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014075 err = add_control(spec, ALC_CTL_BIND_MUTE,
14076 "LFE Playback Switch",
14077 HDA_COMPOSE_AMP_VAL(nid_s, 2, 2,
14078 HDA_INPUT));
14079 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014080 return err;
14081 } else {
14082 sprintf(name, "%s Playback Volume", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014083 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
14084 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0,
14085 HDA_OUTPUT));
14086 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014087 return err;
14088 sprintf(name, "%s Playback Switch", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014089 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
Kailang Yangbdd148a2007-05-08 15:19:08 +020014090 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014091 HDA_INPUT));
14092 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014093 return err;
14094 }
14095 }
14096 return 0;
14097}
14098
14099/* add playback controls for speaker and HP outputs */
14100/* Based on ALC880 version. But ALC861VD has separate,
14101 * different NIDs for mute/unmute switch and volume control */
14102static int alc861vd_auto_create_extra_out(struct alc_spec *spec,
14103 hda_nid_t pin, const char *pfx)
14104{
14105 hda_nid_t nid_v, nid_s;
14106 int err;
14107 char name[32];
14108
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014109 if (!pin)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014110 return 0;
14111
14112 if (alc880_is_fixed_pin(pin)) {
14113 nid_v = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
14114 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014115 if (!spec->multiout.hp_nid)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014116 spec->multiout.hp_nid = nid_v;
14117 else
14118 spec->multiout.extra_out_nid[0] = nid_v;
14119 /* control HP volume/switch on the output mixer amp */
14120 nid_v = alc861vd_idx_to_mixer_vol(
14121 alc880_fixed_pin_idx(pin));
14122 nid_s = alc861vd_idx_to_mixer_switch(
14123 alc880_fixed_pin_idx(pin));
14124
14125 sprintf(name, "%s Playback Volume", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014126 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
14127 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0, HDA_OUTPUT));
14128 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014129 return err;
14130 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014131 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
14132 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2, HDA_INPUT));
14133 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014134 return err;
14135 } else if (alc880_is_multi_pin(pin)) {
14136 /* set manual connection */
14137 /* we have only a switch on HP-out PIN */
14138 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014139 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
14140 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
14141 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014142 return err;
14143 }
14144 return 0;
14145}
14146
14147/* parse the BIOS configuration and set up the alc_spec
14148 * return 1 if successful, 0 if the proper config is not found,
14149 * or a negative error code
14150 * Based on ALC880 version - had to change it to override
14151 * alc880_auto_create_extra_out and alc880_auto_create_multi_out_ctls */
14152static int alc861vd_parse_auto_config(struct hda_codec *codec)
14153{
14154 struct alc_spec *spec = codec->spec;
14155 int err;
14156 static hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
14157
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014158 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
14159 alc861vd_ignore);
14160 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014161 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014162 if (!spec->autocfg.line_outs)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014163 return 0; /* can't find valid BIOS pin config */
14164
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014165 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
14166 if (err < 0)
14167 return err;
14168 err = alc861vd_auto_create_multi_out_ctls(spec, &spec->autocfg);
14169 if (err < 0)
14170 return err;
14171 err = alc861vd_auto_create_extra_out(spec,
14172 spec->autocfg.speaker_pins[0],
14173 "Speaker");
14174 if (err < 0)
14175 return err;
14176 err = alc861vd_auto_create_extra_out(spec,
14177 spec->autocfg.hp_pins[0],
14178 "Headphone");
14179 if (err < 0)
14180 return err;
14181 err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg);
14182 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014183 return err;
14184
14185 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
14186
14187 if (spec->autocfg.dig_out_pin)
14188 spec->multiout.dig_out_nid = ALC861VD_DIGOUT_NID;
14189
Takashi Iwai603c4012008-07-30 15:01:44 +020014190 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010014191 add_mixer(spec, spec->kctls.list);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014192
Takashi Iwaid88897e2008-10-31 15:01:37 +010014193 add_verb(spec, alc861vd_volume_init_verbs);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014194
14195 spec->num_mux_defs = 1;
14196 spec->input_mux = &spec->private_imux;
14197
Takashi Iwai776e1842007-08-29 15:07:11 +020014198 err = alc_auto_add_mic_boost(codec);
14199 if (err < 0)
14200 return err;
14201
Takashi Iwaie044c392008-10-27 16:56:24 +010014202 store_pin_configs(codec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014203 return 1;
14204}
14205
14206/* additional initialization for auto-configuration model */
14207static void alc861vd_auto_init(struct hda_codec *codec)
14208{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014209 struct alc_spec *spec = codec->spec;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014210 alc861vd_auto_init_multi_out(codec);
14211 alc861vd_auto_init_hp_out(codec);
14212 alc861vd_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020014213 alc861vd_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014214 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020014215 alc_inithook(codec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014216}
14217
14218static int patch_alc861vd(struct hda_codec *codec)
14219{
14220 struct alc_spec *spec;
14221 int err, board_config;
14222
14223 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
14224 if (spec == NULL)
14225 return -ENOMEM;
14226
14227 codec->spec = spec;
14228
14229 board_config = snd_hda_check_board_config(codec, ALC861VD_MODEL_LAST,
14230 alc861vd_models,
14231 alc861vd_cfg_tbl);
14232
14233 if (board_config < 0 || board_config >= ALC861VD_MODEL_LAST) {
14234 printk(KERN_INFO "hda_codec: Unknown model for ALC660VD/"
14235 "ALC861VD, trying auto-probe from BIOS...\n");
14236 board_config = ALC861VD_AUTO;
14237 }
14238
14239 if (board_config == ALC861VD_AUTO) {
14240 /* automatic parse from the BIOS config */
14241 err = alc861vd_parse_auto_config(codec);
14242 if (err < 0) {
14243 alc_free(codec);
14244 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014245 } else if (!err) {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014246 printk(KERN_INFO
14247 "hda_codec: Cannot set up configuration "
14248 "from BIOS. Using base mode...\n");
14249 board_config = ALC861VD_3ST;
14250 }
14251 }
14252
14253 if (board_config != ALC861VD_AUTO)
14254 setup_preset(spec, &alc861vd_presets[board_config]);
14255
Kailang Yang2f893282008-05-27 12:14:47 +020014256 if (codec->vendor_id == 0x10ec0660) {
14257 spec->stream_name_analog = "ALC660-VD Analog";
14258 spec->stream_name_digital = "ALC660-VD Digital";
Kailang Yangf9423e72008-05-27 12:32:25 +020014259 /* always turn on EAPD */
Takashi Iwaid88897e2008-10-31 15:01:37 +010014260 add_verb(spec, alc660vd_eapd_verbs);
Kailang Yang2f893282008-05-27 12:14:47 +020014261 } else {
14262 spec->stream_name_analog = "ALC861VD Analog";
14263 spec->stream_name_digital = "ALC861VD Digital";
14264 }
14265
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014266 spec->stream_analog_playback = &alc861vd_pcm_analog_playback;
14267 spec->stream_analog_capture = &alc861vd_pcm_analog_capture;
14268
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014269 spec->stream_digital_playback = &alc861vd_pcm_digital_playback;
14270 spec->stream_digital_capture = &alc861vd_pcm_digital_capture;
14271
14272 spec->adc_nids = alc861vd_adc_nids;
14273 spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids);
Takashi Iwaie1406342008-02-11 18:32:32 +010014274 spec->capsrc_nids = alc861vd_capsrc_nids;
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010014275 spec->is_mix_capture = 1;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014276
Takashi Iwaif9e336f2008-10-31 16:37:07 +010014277 set_capture_mixer(spec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014278
Takashi Iwai2134ea42008-01-10 16:53:55 +010014279 spec->vmaster_nid = 0x02;
14280
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014281 codec->patch_ops = alc_patch_ops;
14282
14283 if (board_config == ALC861VD_AUTO)
14284 spec->init_hook = alc861vd_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020014285#ifdef CONFIG_SND_HDA_POWER_SAVE
14286 if (!spec->loopback.amplist)
14287 spec->loopback.amplist = alc861vd_loopbacks;
14288#endif
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014289
14290 return 0;
14291}
14292
14293/*
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014294 * ALC662 support
14295 *
14296 * ALC662 is almost identical with ALC880 but has cleaner and more flexible
14297 * configuration. Each pin widget can choose any input DACs and a mixer.
14298 * Each ADC is connected from a mixer of all inputs. This makes possible
14299 * 6-channel independent captures.
14300 *
14301 * In addition, an independent DAC for the multi-playback (not used in this
14302 * driver yet).
14303 */
14304#define ALC662_DIGOUT_NID 0x06
14305#define ALC662_DIGIN_NID 0x0a
14306
14307static hda_nid_t alc662_dac_nids[4] = {
14308 /* front, rear, clfe, rear_surr */
14309 0x02, 0x03, 0x04
14310};
14311
14312static hda_nid_t alc662_adc_nids[1] = {
14313 /* ADC1-2 */
14314 0x09,
14315};
Takashi Iwaie1406342008-02-11 18:32:32 +010014316
Kailang Yang77a261b2008-02-19 11:38:05 +010014317static hda_nid_t alc662_capsrc_nids[1] = { 0x22 };
Takashi Iwaie1406342008-02-11 18:32:32 +010014318
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014319/* input MUX */
14320/* FIXME: should be a matrix-type input source selection */
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014321static struct hda_input_mux alc662_capture_source = {
14322 .num_items = 4,
14323 .items = {
14324 { "Mic", 0x0 },
14325 { "Front Mic", 0x1 },
14326 { "Line", 0x2 },
14327 { "CD", 0x4 },
14328 },
14329};
14330
14331static struct hda_input_mux alc662_lenovo_101e_capture_source = {
14332 .num_items = 2,
14333 .items = {
14334 { "Mic", 0x1 },
14335 { "Line", 0x2 },
14336 },
14337};
Kailang Yang291702f2007-10-16 14:28:03 +020014338
14339static struct hda_input_mux alc662_eeepc_capture_source = {
14340 .num_items = 2,
14341 .items = {
14342 { "i-Mic", 0x1 },
14343 { "e-Mic", 0x0 },
14344 },
14345};
14346
Kailang Yang6dda9f42008-05-27 12:05:31 +020014347static struct hda_input_mux alc663_capture_source = {
14348 .num_items = 3,
14349 .items = {
14350 { "Mic", 0x0 },
14351 { "Front Mic", 0x1 },
14352 { "Line", 0x2 },
14353 },
14354};
14355
14356static struct hda_input_mux alc663_m51va_capture_source = {
14357 .num_items = 2,
14358 .items = {
14359 { "Ext-Mic", 0x0 },
14360 { "D-Mic", 0x9 },
14361 },
14362};
14363
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014364/*
14365 * 2ch mode
14366 */
14367static struct hda_channel_mode alc662_3ST_2ch_modes[1] = {
14368 { 2, NULL }
14369};
14370
14371/*
14372 * 2ch mode
14373 */
14374static struct hda_verb alc662_3ST_ch2_init[] = {
14375 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
14376 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
14377 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
14378 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
14379 { } /* end */
14380};
14381
14382/*
14383 * 6ch mode
14384 */
14385static struct hda_verb alc662_3ST_ch6_init[] = {
14386 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14387 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
14388 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
14389 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14390 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
14391 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
14392 { } /* end */
14393};
14394
14395static struct hda_channel_mode alc662_3ST_6ch_modes[2] = {
14396 { 2, alc662_3ST_ch2_init },
14397 { 6, alc662_3ST_ch6_init },
14398};
14399
14400/*
14401 * 2ch mode
14402 */
14403static struct hda_verb alc662_sixstack_ch6_init[] = {
14404 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
14405 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
14406 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14407 { } /* end */
14408};
14409
14410/*
14411 * 6ch mode
14412 */
14413static struct hda_verb alc662_sixstack_ch8_init[] = {
14414 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14415 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14416 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14417 { } /* end */
14418};
14419
14420static struct hda_channel_mode alc662_5stack_modes[2] = {
14421 { 2, alc662_sixstack_ch6_init },
14422 { 6, alc662_sixstack_ch8_init },
14423};
14424
14425/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
14426 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
14427 */
14428
14429static struct snd_kcontrol_new alc662_base_mixer[] = {
14430 /* output mixer control */
14431 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010014432 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014433 HDA_CODEC_VOLUME("Surround Playback Volume", 0x3, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010014434 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014435 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
14436 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010014437 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
14438 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014439 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
14440
14441 /*Input mixer control */
14442 HDA_CODEC_VOLUME("CD Playback Volume", 0xb, 0x4, HDA_INPUT),
14443 HDA_CODEC_MUTE("CD Playback Switch", 0xb, 0x4, HDA_INPUT),
14444 HDA_CODEC_VOLUME("Line Playback Volume", 0xb, 0x02, HDA_INPUT),
14445 HDA_CODEC_MUTE("Line Playback Switch", 0xb, 0x02, HDA_INPUT),
14446 HDA_CODEC_VOLUME("Mic Playback Volume", 0xb, 0x0, HDA_INPUT),
14447 HDA_CODEC_MUTE("Mic Playback Switch", 0xb, 0x0, HDA_INPUT),
14448 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0xb, 0x01, HDA_INPUT),
14449 HDA_CODEC_MUTE("Front Mic Playback Switch", 0xb, 0x01, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014450 { } /* end */
14451};
14452
14453static struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = {
14454 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010014455 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014456 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
14457 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
14458 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
14459 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
14460 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
14461 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14462 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14463 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14464 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14465 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
14466 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014467 { } /* end */
14468};
14469
14470static struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = {
14471 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010014472 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014473 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010014474 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014475 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
14476 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010014477 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
14478 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014479 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
14480 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
14481 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
14482 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
14483 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
14484 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14485 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14486 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14487 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14488 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
14489 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014490 { } /* end */
14491};
14492
14493static struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = {
14494 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14495 HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010014496 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x03, 0x0, HDA_OUTPUT),
14497 HDA_BIND_MUTE("Speaker Playback Switch", 0x03, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014498 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
14499 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
14500 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
14501 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14502 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014503 { } /* end */
14504};
14505
Kailang Yang291702f2007-10-16 14:28:03 +020014506static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = {
Takashi Iwai86cd9292008-01-28 18:09:56 +010014507 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang291702f2007-10-16 14:28:03 +020014508
Herton Ronaldo Krzesinskib4818492008-02-23 11:34:12 +010014509 HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14510 HDA_CODEC_MUTE("Line-Out Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yang291702f2007-10-16 14:28:03 +020014511
14512 HDA_CODEC_VOLUME("e-Mic Boost", 0x18, 0, HDA_INPUT),
14513 HDA_CODEC_VOLUME("e-Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14514 HDA_CODEC_MUTE("e-Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14515
14516 HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT),
14517 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14518 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14519 { } /* end */
14520};
14521
Kailang Yang8c427222008-01-10 13:03:59 +010014522static struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = {
Takashi Iwai31bffaa2008-02-27 16:10:44 +010014523 HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14524 HDA_CODEC_MUTE("Line-Out Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010014525 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
14526 HDA_BIND_MUTE("Surround Playback Switch", 0x03, 2, HDA_INPUT),
14527 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
14528 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
14529 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x04, 1, 2, HDA_INPUT),
14530 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x04, 2, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010014531 HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010014532 HDA_BIND_MUTE("MuteCtrl Playback Switch", 0x0c, 2, HDA_INPUT),
14533 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
14534 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
14535 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14536 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14537 { } /* end */
14538};
14539
Kailang Yangf1d4e282008-08-26 14:03:29 +020014540static struct hda_bind_ctls alc663_asus_bind_master_vol = {
14541 .ops = &snd_hda_bind_vol,
14542 .values = {
14543 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
14544 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
14545 0
14546 },
14547};
14548
14549static struct hda_bind_ctls alc663_asus_one_bind_switch = {
14550 .ops = &snd_hda_bind_sw,
14551 .values = {
14552 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
14553 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
14554 0
14555 },
14556};
14557
Kailang Yang6dda9f42008-05-27 12:05:31 +020014558static struct snd_kcontrol_new alc663_m51va_mixer[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020014559 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
14560 HDA_BIND_SW("Master Playback Switch", &alc663_asus_one_bind_switch),
14561 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14562 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14563 { } /* end */
14564};
14565
14566static struct hda_bind_ctls alc663_asus_tree_bind_switch = {
14567 .ops = &snd_hda_bind_sw,
14568 .values = {
14569 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
14570 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
14571 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
14572 0
14573 },
14574};
14575
14576static struct snd_kcontrol_new alc663_two_hp_m1_mixer[] = {
14577 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
14578 HDA_BIND_SW("Master Playback Switch", &alc663_asus_tree_bind_switch),
14579 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14580 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14581 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14582 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14583
14584 { } /* end */
14585};
14586
14587static struct hda_bind_ctls alc663_asus_four_bind_switch = {
14588 .ops = &snd_hda_bind_sw,
14589 .values = {
14590 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
14591 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
14592 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
14593 0
14594 },
14595};
14596
14597static struct snd_kcontrol_new alc663_two_hp_m2_mixer[] = {
14598 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
14599 HDA_BIND_SW("Master Playback Switch", &alc663_asus_four_bind_switch),
14600 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14601 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14602 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14603 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14604 { } /* end */
14605};
14606
14607static struct snd_kcontrol_new alc662_1bjd_mixer[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020014608 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14609 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020014610 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
14611 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14612 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14613 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14614 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14615 { } /* end */
14616};
14617
14618static struct hda_bind_ctls alc663_asus_two_bind_master_vol = {
14619 .ops = &snd_hda_bind_vol,
14620 .values = {
14621 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
14622 HDA_COMPOSE_AMP_VAL(0x04, 3, 0, HDA_OUTPUT),
14623 0
14624 },
14625};
14626
14627static struct hda_bind_ctls alc663_asus_two_bind_switch = {
14628 .ops = &snd_hda_bind_sw,
14629 .values = {
14630 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
14631 HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT),
14632 0
14633 },
14634};
14635
14636static struct snd_kcontrol_new alc663_asus_21jd_clfe_mixer[] = {
14637 HDA_BIND_VOL("Master Playback Volume",
14638 &alc663_asus_two_bind_master_vol),
14639 HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
14640 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020014641 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
14642 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14643 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020014644 { } /* end */
14645};
14646
14647static struct snd_kcontrol_new alc663_asus_15jd_clfe_mixer[] = {
14648 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
14649 HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
14650 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
14651 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
14652 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14653 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020014654 { } /* end */
14655};
14656
14657static struct snd_kcontrol_new alc663_g71v_mixer[] = {
14658 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14659 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
14660 HDA_CODEC_VOLUME("Front Playback Volume", 0x03, 0x0, HDA_OUTPUT),
14661 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
14662 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
14663
14664 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14665 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14666 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14667 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14668 { } /* end */
14669};
14670
14671static struct snd_kcontrol_new alc663_g50v_mixer[] = {
14672 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14673 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
14674 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
14675
14676 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14677 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14678 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14679 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14680 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
14681 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
14682 { } /* end */
14683};
14684
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014685static struct snd_kcontrol_new alc662_chmode_mixer[] = {
14686 {
14687 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
14688 .name = "Channel Mode",
14689 .info = alc_ch_mode_info,
14690 .get = alc_ch_mode_get,
14691 .put = alc_ch_mode_put,
14692 },
14693 { } /* end */
14694};
14695
14696static struct hda_verb alc662_init_verbs[] = {
14697 /* ADC: mute amp left and right */
14698 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14699 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
14700 /* Front mixer: unmute input/output amp left and right (volume = 0) */
14701
Takashi Iwaicb53c622007-08-10 17:21:45 +020014702 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14703 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
14704 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
14705 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
14706 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014707
Kailang Yangb60dd392007-09-20 12:50:29 +020014708 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14709 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14710 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14711 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14712 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14713 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014714
14715 /* Front Pin: output 0 (0x0c) */
14716 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14717 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14718
14719 /* Rear Pin: output 1 (0x0d) */
14720 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14721 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14722
14723 /* CLFE Pin: output 2 (0x0e) */
14724 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14725 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14726
14727 /* Mic (rear) pin: input vref at 80% */
14728 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14729 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14730 /* Front Mic pin: input vref at 80% */
14731 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14732 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14733 /* Line In pin: input */
14734 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14735 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14736 /* Line-2 In: Headphone output (output 0 - 0x0c) */
14737 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14738 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14739 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
14740 /* CD pin widget for input */
14741 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14742
14743 /* FIXME: use matrix-type input source selection */
14744 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
14745 /* Input mixer */
14746 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14747 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14748 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
14749 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Kailang Yang291702f2007-10-16 14:28:03 +020014750
14751 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14752 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14753 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
14754 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Kailang Yang6dda9f42008-05-27 12:05:31 +020014755
14756 /* always trun on EAPD */
14757 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
14758 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
14759
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014760 { }
14761};
14762
14763static struct hda_verb alc662_sue_init_verbs[] = {
14764 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
14765 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
Kailang Yang291702f2007-10-16 14:28:03 +020014766 {}
14767};
14768
14769static struct hda_verb alc662_eeepc_sue_init_verbs[] = {
14770 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14771 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14772 {}
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014773};
14774
Kailang Yang8c427222008-01-10 13:03:59 +010014775/* Set Unsolicited Event*/
14776static struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = {
14777 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14778 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14779 {}
14780};
14781
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014782/*
14783 * generic initialization of ADC, input mixers and output mixers
14784 */
14785static struct hda_verb alc662_auto_init_verbs[] = {
14786 /*
14787 * Unmute ADC and set the default input to mic-in
14788 */
14789 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
14790 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14791
14792 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
14793 * mixer widget
14794 * Note: PASD motherboards uses the Line In 2 as the input for front
14795 * panel mic (mic 2)
14796 */
14797 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020014798 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14799 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
14800 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
14801 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
14802 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014803
14804 /*
14805 * Set up output mixers (0x0c - 0x0f)
14806 */
14807 /* set vol=0 to output mixers */
14808 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14809 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14810 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14811
14812 /* set up input amps for analog loopback */
14813 /* Amp Indices: DAC = 0, mixer = 1 */
Kailang Yangb60dd392007-09-20 12:50:29 +020014814 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14815 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14816 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14817 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14818 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14819 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014820
14821
14822 /* FIXME: use matrix-type input source selection */
14823 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
14824 /* Input mixer */
14825 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangd1a991a2007-08-15 16:21:59 +020014826 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014827 { }
14828};
14829
Takashi Iwai24fb9172008-09-02 14:48:20 +020014830/* additional verbs for ALC663 */
14831static struct hda_verb alc663_auto_init_verbs[] = {
14832 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14833 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14834 { }
14835};
14836
Kailang Yang6dda9f42008-05-27 12:05:31 +020014837static struct hda_verb alc663_m51va_init_verbs[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020014838 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14839 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yang6dda9f42008-05-27 12:05:31 +020014840 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14841 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangf1d4e282008-08-26 14:03:29 +020014842 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
14843 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14844 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
Kailang Yang6dda9f42008-05-27 12:05:31 +020014845 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14846 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14847 {}
14848};
14849
Kailang Yangf1d4e282008-08-26 14:03:29 +020014850static struct hda_verb alc663_21jd_amic_init_verbs[] = {
14851 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14852 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14853 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
14854 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14855 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14856 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14857 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14858 {}
14859};
14860
14861static struct hda_verb alc662_1bjd_amic_init_verbs[] = {
14862 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14863 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14864 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14865 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
14866 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14867 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14868 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14869 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14870 {}
14871};
14872
14873static struct hda_verb alc663_15jd_amic_init_verbs[] = {
14874 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14875 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14876 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
14877 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14878 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14879 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14880 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14881 {}
14882};
14883
14884static struct hda_verb alc663_two_hp_amic_m1_init_verbs[] = {
14885 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14886 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14887 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14888 {0x21, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */
14889 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14890 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14891 {0x15, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */
14892 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14893 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14894 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14895 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14896 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14897 {}
14898};
14899
14900static struct hda_verb alc663_two_hp_amic_m2_init_verbs[] = {
14901 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14902 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14903 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14904 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
14905 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14906 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14907 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
14908 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14909 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14910 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14911 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14912 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14913 {}
14914};
14915
Kailang Yang6dda9f42008-05-27 12:05:31 +020014916static struct hda_verb alc663_g71v_init_verbs[] = {
14917 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14918 /* {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
14919 /* {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, */ /* Headphone */
14920
14921 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14922 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14923 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
14924
14925 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
14926 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_MIC_EVENT},
14927 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
14928 {}
14929};
14930
14931static struct hda_verb alc663_g50v_init_verbs[] = {
14932 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14933 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14934 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
14935
14936 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14937 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14938 {}
14939};
14940
Kailang Yangf1d4e282008-08-26 14:03:29 +020014941static struct hda_verb alc662_ecs_init_verbs[] = {
14942 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
14943 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14944 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14945 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14946 {}
14947};
14948
Kailang Yangf1d4e282008-08-26 14:03:29 +020014949static struct snd_kcontrol_new alc662_auto_capture_mixer[] = {
14950 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
14951 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
14952 { } /* end */
14953};
14954
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014955static void alc662_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
14956{
14957 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014958 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014959
14960 present = snd_hda_codec_read(codec, 0x14, 0,
14961 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020014962 bits = present ? HDA_AMP_MUTE : 0;
14963 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
14964 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014965}
14966
14967static void alc662_lenovo_101e_all_automute(struct hda_codec *codec)
14968{
14969 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014970 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014971
14972 present = snd_hda_codec_read(codec, 0x1b, 0,
14973 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020014974 bits = present ? HDA_AMP_MUTE : 0;
14975 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
14976 HDA_AMP_MUTE, bits);
14977 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
14978 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014979}
14980
14981static void alc662_lenovo_101e_unsol_event(struct hda_codec *codec,
14982 unsigned int res)
14983{
14984 if ((res >> 26) == ALC880_HP_EVENT)
14985 alc662_lenovo_101e_all_automute(codec);
14986 if ((res >> 26) == ALC880_FRONT_EVENT)
14987 alc662_lenovo_101e_ispeaker_automute(codec);
14988}
14989
Kailang Yang291702f2007-10-16 14:28:03 +020014990static void alc662_eeepc_mic_automute(struct hda_codec *codec)
14991{
14992 unsigned int present;
14993
14994 present = snd_hda_codec_read(codec, 0x18, 0,
14995 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
14996 snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
14997 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
14998 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
14999 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
15000 snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
15001 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
15002 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
15003 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
15004}
15005
15006/* unsolicited event for HP jack sensing */
15007static void alc662_eeepc_unsol_event(struct hda_codec *codec,
15008 unsigned int res)
15009{
15010 if ((res >> 26) == ALC880_HP_EVENT)
15011 alc262_hippo1_automute( codec );
15012
15013 if ((res >> 26) == ALC880_MIC_EVENT)
15014 alc662_eeepc_mic_automute(codec);
15015}
15016
15017static void alc662_eeepc_inithook(struct hda_codec *codec)
15018{
15019 alc262_hippo1_automute( codec );
15020 alc662_eeepc_mic_automute(codec);
15021}
15022
Kailang Yang8c427222008-01-10 13:03:59 +010015023static void alc662_eeepc_ep20_automute(struct hda_codec *codec)
15024{
15025 unsigned int mute;
15026 unsigned int present;
15027
15028 snd_hda_codec_read(codec, 0x14, 0, AC_VERB_SET_PIN_SENSE, 0);
15029 present = snd_hda_codec_read(codec, 0x14, 0,
15030 AC_VERB_GET_PIN_SENSE, 0);
15031 present = (present & 0x80000000) != 0;
15032 if (present) {
15033 /* mute internal speaker */
15034 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +020015035 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yang8c427222008-01-10 13:03:59 +010015036 } else {
15037 /* unmute internal speaker if necessary */
15038 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
15039 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +020015040 HDA_AMP_MUTE, mute);
Kailang Yang8c427222008-01-10 13:03:59 +010015041 }
15042}
15043
15044/* unsolicited event for HP jack sensing */
15045static void alc662_eeepc_ep20_unsol_event(struct hda_codec *codec,
15046 unsigned int res)
15047{
15048 if ((res >> 26) == ALC880_HP_EVENT)
15049 alc662_eeepc_ep20_automute(codec);
15050}
15051
15052static void alc662_eeepc_ep20_inithook(struct hda_codec *codec)
15053{
15054 alc662_eeepc_ep20_automute(codec);
15055}
15056
Kailang Yang6dda9f42008-05-27 12:05:31 +020015057static void alc663_m51va_speaker_automute(struct hda_codec *codec)
15058{
15059 unsigned int present;
15060 unsigned char bits;
15061
15062 present = snd_hda_codec_read(codec, 0x21, 0,
Kailang Yangf1d4e282008-08-26 14:03:29 +020015063 AC_VERB_GET_PIN_SENSE, 0)
15064 & AC_PINSENSE_PRESENCE;
Kailang Yang6dda9f42008-05-27 12:05:31 +020015065 bits = present ? HDA_AMP_MUTE : 0;
Kailang Yangf1d4e282008-08-26 14:03:29 +020015066 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
15067 AMP_IN_MUTE(0), bits);
15068 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
15069 AMP_IN_MUTE(0), bits);
15070}
15071
15072static void alc663_21jd_two_speaker_automute(struct hda_codec *codec)
15073{
15074 unsigned int present;
15075 unsigned char bits;
15076
15077 present = snd_hda_codec_read(codec, 0x21, 0,
15078 AC_VERB_GET_PIN_SENSE, 0)
15079 & AC_PINSENSE_PRESENCE;
15080 bits = present ? HDA_AMP_MUTE : 0;
15081 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
15082 AMP_IN_MUTE(0), bits);
15083 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
15084 AMP_IN_MUTE(0), bits);
15085 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0,
15086 AMP_IN_MUTE(0), bits);
15087 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1,
15088 AMP_IN_MUTE(0), bits);
15089}
15090
15091static void alc663_15jd_two_speaker_automute(struct hda_codec *codec)
15092{
15093 unsigned int present;
15094 unsigned char bits;
15095
15096 present = snd_hda_codec_read(codec, 0x15, 0,
15097 AC_VERB_GET_PIN_SENSE, 0)
15098 & AC_PINSENSE_PRESENCE;
15099 bits = present ? HDA_AMP_MUTE : 0;
15100 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
15101 AMP_IN_MUTE(0), bits);
15102 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
15103 AMP_IN_MUTE(0), bits);
15104 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0,
15105 AMP_IN_MUTE(0), bits);
15106 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1,
15107 AMP_IN_MUTE(0), bits);
15108}
15109
15110static void alc662_f5z_speaker_automute(struct hda_codec *codec)
15111{
15112 unsigned int present;
15113 unsigned char bits;
15114
15115 present = snd_hda_codec_read(codec, 0x1b, 0,
15116 AC_VERB_GET_PIN_SENSE, 0)
15117 & AC_PINSENSE_PRESENCE;
15118 bits = present ? 0 : PIN_OUT;
15119 snd_hda_codec_write(codec, 0x14, 0,
15120 AC_VERB_SET_PIN_WIDGET_CONTROL, bits);
15121}
15122
15123static void alc663_two_hp_m1_speaker_automute(struct hda_codec *codec)
15124{
15125 unsigned int present1, present2;
15126
15127 present1 = snd_hda_codec_read(codec, 0x21, 0,
15128 AC_VERB_GET_PIN_SENSE, 0)
15129 & AC_PINSENSE_PRESENCE;
15130 present2 = snd_hda_codec_read(codec, 0x15, 0,
15131 AC_VERB_GET_PIN_SENSE, 0)
15132 & AC_PINSENSE_PRESENCE;
15133
15134 if (present1 || present2) {
15135 snd_hda_codec_write_cache(codec, 0x14, 0,
15136 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
15137 } else {
15138 snd_hda_codec_write_cache(codec, 0x14, 0,
15139 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
15140 }
15141}
15142
15143static void alc663_two_hp_m2_speaker_automute(struct hda_codec *codec)
15144{
15145 unsigned int present1, present2;
15146
15147 present1 = snd_hda_codec_read(codec, 0x1b, 0,
15148 AC_VERB_GET_PIN_SENSE, 0)
15149 & AC_PINSENSE_PRESENCE;
15150 present2 = snd_hda_codec_read(codec, 0x15, 0,
15151 AC_VERB_GET_PIN_SENSE, 0)
15152 & AC_PINSENSE_PRESENCE;
15153
15154 if (present1 || present2) {
15155 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
15156 AMP_IN_MUTE(0), AMP_IN_MUTE(0));
15157 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
15158 AMP_IN_MUTE(0), AMP_IN_MUTE(0));
15159 } else {
15160 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
15161 AMP_IN_MUTE(0), 0);
15162 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
15163 AMP_IN_MUTE(0), 0);
15164 }
Kailang Yang6dda9f42008-05-27 12:05:31 +020015165}
15166
15167static void alc663_m51va_mic_automute(struct hda_codec *codec)
15168{
15169 unsigned int present;
15170
15171 present = snd_hda_codec_read(codec, 0x18, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +020015172 AC_VERB_GET_PIN_SENSE, 0)
15173 & AC_PINSENSE_PRESENCE;
Kailang Yang6dda9f42008-05-27 12:05:31 +020015174 snd_hda_codec_write_cache(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangea1fb292008-08-26 12:58:38 +020015175 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
Kailang Yang6dda9f42008-05-27 12:05:31 +020015176 snd_hda_codec_write_cache(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangea1fb292008-08-26 12:58:38 +020015177 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
Kailang Yang6dda9f42008-05-27 12:05:31 +020015178 snd_hda_codec_write_cache(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangea1fb292008-08-26 12:58:38 +020015179 0x7000 | (0x09 << 8) | (present ? 0x80 : 0));
Kailang Yang6dda9f42008-05-27 12:05:31 +020015180 snd_hda_codec_write_cache(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangea1fb292008-08-26 12:58:38 +020015181 0x7000 | (0x09 << 8) | (present ? 0x80 : 0));
Kailang Yang6dda9f42008-05-27 12:05:31 +020015182}
15183
15184static void alc663_m51va_unsol_event(struct hda_codec *codec,
15185 unsigned int res)
15186{
15187 switch (res >> 26) {
15188 case ALC880_HP_EVENT:
15189 alc663_m51va_speaker_automute(codec);
15190 break;
15191 case ALC880_MIC_EVENT:
15192 alc663_m51va_mic_automute(codec);
15193 break;
15194 }
15195}
15196
15197static void alc663_m51va_inithook(struct hda_codec *codec)
15198{
15199 alc663_m51va_speaker_automute(codec);
15200 alc663_m51va_mic_automute(codec);
15201}
15202
Kailang Yangf1d4e282008-08-26 14:03:29 +020015203/* ***************** Mode1 ******************************/
15204static void alc663_mode1_unsol_event(struct hda_codec *codec,
15205 unsigned int res)
15206{
15207 switch (res >> 26) {
15208 case ALC880_HP_EVENT:
15209 alc663_m51va_speaker_automute(codec);
15210 break;
15211 case ALC880_MIC_EVENT:
15212 alc662_eeepc_mic_automute(codec);
15213 break;
15214 }
15215}
15216
15217static void alc663_mode1_inithook(struct hda_codec *codec)
15218{
15219 alc663_m51va_speaker_automute(codec);
15220 alc662_eeepc_mic_automute(codec);
15221}
15222/* ***************** Mode2 ******************************/
15223static void alc662_mode2_unsol_event(struct hda_codec *codec,
15224 unsigned int res)
15225{
15226 switch (res >> 26) {
15227 case ALC880_HP_EVENT:
15228 alc662_f5z_speaker_automute(codec);
15229 break;
15230 case ALC880_MIC_EVENT:
15231 alc662_eeepc_mic_automute(codec);
15232 break;
15233 }
15234}
15235
15236static void alc662_mode2_inithook(struct hda_codec *codec)
15237{
15238 alc662_f5z_speaker_automute(codec);
15239 alc662_eeepc_mic_automute(codec);
15240}
15241/* ***************** Mode3 ******************************/
15242static void alc663_mode3_unsol_event(struct hda_codec *codec,
15243 unsigned int res)
15244{
15245 switch (res >> 26) {
15246 case ALC880_HP_EVENT:
15247 alc663_two_hp_m1_speaker_automute(codec);
15248 break;
15249 case ALC880_MIC_EVENT:
15250 alc662_eeepc_mic_automute(codec);
15251 break;
15252 }
15253}
15254
15255static void alc663_mode3_inithook(struct hda_codec *codec)
15256{
15257 alc663_two_hp_m1_speaker_automute(codec);
15258 alc662_eeepc_mic_automute(codec);
15259}
15260/* ***************** Mode4 ******************************/
15261static void alc663_mode4_unsol_event(struct hda_codec *codec,
15262 unsigned int res)
15263{
15264 switch (res >> 26) {
15265 case ALC880_HP_EVENT:
15266 alc663_21jd_two_speaker_automute(codec);
15267 break;
15268 case ALC880_MIC_EVENT:
15269 alc662_eeepc_mic_automute(codec);
15270 break;
15271 }
15272}
15273
15274static void alc663_mode4_inithook(struct hda_codec *codec)
15275{
15276 alc663_21jd_two_speaker_automute(codec);
15277 alc662_eeepc_mic_automute(codec);
15278}
15279/* ***************** Mode5 ******************************/
15280static void alc663_mode5_unsol_event(struct hda_codec *codec,
15281 unsigned int res)
15282{
15283 switch (res >> 26) {
15284 case ALC880_HP_EVENT:
15285 alc663_15jd_two_speaker_automute(codec);
15286 break;
15287 case ALC880_MIC_EVENT:
15288 alc662_eeepc_mic_automute(codec);
15289 break;
15290 }
15291}
15292
15293static void alc663_mode5_inithook(struct hda_codec *codec)
15294{
15295 alc663_15jd_two_speaker_automute(codec);
15296 alc662_eeepc_mic_automute(codec);
15297}
15298/* ***************** Mode6 ******************************/
15299static void alc663_mode6_unsol_event(struct hda_codec *codec,
15300 unsigned int res)
15301{
15302 switch (res >> 26) {
15303 case ALC880_HP_EVENT:
15304 alc663_two_hp_m2_speaker_automute(codec);
15305 break;
15306 case ALC880_MIC_EVENT:
15307 alc662_eeepc_mic_automute(codec);
15308 break;
15309 }
15310}
15311
15312static void alc663_mode6_inithook(struct hda_codec *codec)
15313{
15314 alc663_two_hp_m2_speaker_automute(codec);
15315 alc662_eeepc_mic_automute(codec);
15316}
15317
Kailang Yang6dda9f42008-05-27 12:05:31 +020015318static void alc663_g71v_hp_automute(struct hda_codec *codec)
15319{
15320 unsigned int present;
15321 unsigned char bits;
15322
15323 present = snd_hda_codec_read(codec, 0x21, 0,
15324 AC_VERB_GET_PIN_SENSE, 0)
15325 & AC_PINSENSE_PRESENCE;
15326 bits = present ? HDA_AMP_MUTE : 0;
15327 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
15328 HDA_AMP_MUTE, bits);
15329 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
15330 HDA_AMP_MUTE, bits);
15331}
15332
15333static void alc663_g71v_front_automute(struct hda_codec *codec)
15334{
15335 unsigned int present;
15336 unsigned char bits;
15337
15338 present = snd_hda_codec_read(codec, 0x15, 0,
15339 AC_VERB_GET_PIN_SENSE, 0)
15340 & AC_PINSENSE_PRESENCE;
15341 bits = present ? HDA_AMP_MUTE : 0;
15342 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
15343 HDA_AMP_MUTE, bits);
15344}
15345
15346static void alc663_g71v_unsol_event(struct hda_codec *codec,
15347 unsigned int res)
15348{
15349 switch (res >> 26) {
15350 case ALC880_HP_EVENT:
15351 alc663_g71v_hp_automute(codec);
15352 break;
15353 case ALC880_FRONT_EVENT:
15354 alc663_g71v_front_automute(codec);
15355 break;
15356 case ALC880_MIC_EVENT:
15357 alc662_eeepc_mic_automute(codec);
15358 break;
15359 }
15360}
15361
15362static void alc663_g71v_inithook(struct hda_codec *codec)
15363{
15364 alc663_g71v_front_automute(codec);
15365 alc663_g71v_hp_automute(codec);
15366 alc662_eeepc_mic_automute(codec);
15367}
15368
15369static void alc663_g50v_unsol_event(struct hda_codec *codec,
15370 unsigned int res)
15371{
15372 switch (res >> 26) {
15373 case ALC880_HP_EVENT:
15374 alc663_m51va_speaker_automute(codec);
15375 break;
15376 case ALC880_MIC_EVENT:
15377 alc662_eeepc_mic_automute(codec);
15378 break;
15379 }
15380}
15381
15382static void alc663_g50v_inithook(struct hda_codec *codec)
15383{
15384 alc663_m51va_speaker_automute(codec);
15385 alc662_eeepc_mic_automute(codec);
15386}
15387
Kailang Yangf1d4e282008-08-26 14:03:29 +020015388/* bind hp and internal speaker mute (with plug check) */
15389static int alc662_ecs_master_sw_put(struct snd_kcontrol *kcontrol,
15390 struct snd_ctl_elem_value *ucontrol)
15391{
15392 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
15393 long *valp = ucontrol->value.integer.value;
15394 int change;
15395
15396 change = snd_hda_codec_amp_update(codec, 0x1b, 0, HDA_OUTPUT, 0,
15397 HDA_AMP_MUTE,
15398 valp[0] ? 0 : HDA_AMP_MUTE);
15399 change |= snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0,
15400 HDA_AMP_MUTE,
15401 valp[1] ? 0 : HDA_AMP_MUTE);
15402 if (change)
15403 alc262_hippo1_automute(codec);
15404 return change;
15405}
15406
15407static struct snd_kcontrol_new alc662_ecs_mixer[] = {
15408 HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15409 {
15410 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
15411 .name = "Master Playback Switch",
15412 .info = snd_hda_mixer_amp_switch_info,
15413 .get = snd_hda_mixer_amp_switch_get,
15414 .put = alc662_ecs_master_sw_put,
15415 .private_value = HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
15416 },
15417
15418 HDA_CODEC_VOLUME("e-Mic/LineIn Boost", 0x18, 0, HDA_INPUT),
15419 HDA_CODEC_VOLUME("e-Mic/LineIn Playback Volume", 0x0b, 0x0, HDA_INPUT),
15420 HDA_CODEC_MUTE("e-Mic/LineIn Playback Switch", 0x0b, 0x0, HDA_INPUT),
15421
15422 HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT),
15423 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15424 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
15425 { } /* end */
15426};
15427
Takashi Iwaicb53c622007-08-10 17:21:45 +020015428#ifdef CONFIG_SND_HDA_POWER_SAVE
15429#define alc662_loopbacks alc880_loopbacks
15430#endif
15431
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015432
15433/* pcm configuration: identiacal with ALC880 */
15434#define alc662_pcm_analog_playback alc880_pcm_analog_playback
15435#define alc662_pcm_analog_capture alc880_pcm_analog_capture
15436#define alc662_pcm_digital_playback alc880_pcm_digital_playback
15437#define alc662_pcm_digital_capture alc880_pcm_digital_capture
15438
15439/*
15440 * configuration and preset
15441 */
15442static const char *alc662_models[ALC662_MODEL_LAST] = {
15443 [ALC662_3ST_2ch_DIG] = "3stack-dig",
15444 [ALC662_3ST_6ch_DIG] = "3stack-6ch-dig",
15445 [ALC662_3ST_6ch] = "3stack-6ch",
15446 [ALC662_5ST_DIG] = "6stack-dig",
15447 [ALC662_LENOVO_101E] = "lenovo-101e",
Takashi Iwaib995d762007-10-17 10:41:06 +020015448 [ALC662_ASUS_EEEPC_P701] = "eeepc-p701",
Kailang Yang8c427222008-01-10 13:03:59 +010015449 [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20",
Kailang Yangf1d4e282008-08-26 14:03:29 +020015450 [ALC662_ECS] = "ecs",
Kailang Yang6dda9f42008-05-27 12:05:31 +020015451 [ALC663_ASUS_M51VA] = "m51va",
15452 [ALC663_ASUS_G71V] = "g71v",
15453 [ALC663_ASUS_H13] = "h13",
15454 [ALC663_ASUS_G50V] = "g50v",
Kailang Yangf1d4e282008-08-26 14:03:29 +020015455 [ALC663_ASUS_MODE1] = "asus-mode1",
15456 [ALC662_ASUS_MODE2] = "asus-mode2",
15457 [ALC663_ASUS_MODE3] = "asus-mode3",
15458 [ALC663_ASUS_MODE4] = "asus-mode4",
15459 [ALC663_ASUS_MODE5] = "asus-mode5",
15460 [ALC663_ASUS_MODE6] = "asus-mode6",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015461 [ALC662_AUTO] = "auto",
15462};
15463
15464static struct snd_pci_quirk alc662_cfg_tbl[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020015465 SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M51VA", ALC663_ASUS_M51VA),
Kailang Yang80ffe862008-10-15 11:23:27 +020015466 SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS G50V", ALC663_ASUS_G50V),
Herton Ronaldo Krzesinski3da23ca2008-03-14 12:52:59 +010015467 SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG),
Kailang Yang291702f2007-10-16 14:28:03 +020015468 SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701),
Kailang Yang8c427222008-01-10 13:03:59 +010015469 SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20),
Kailang Yangf1d4e282008-08-26 14:03:29 +020015470 SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC663_ASUS_MODE1),
15471 SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M50Vr", ALC663_ASUS_MODE1),
15472 SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC663_ASUS_MODE1),
15473 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC663_ASUS_MODE1),
15474 SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC663_ASUS_MODE1),
15475 SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS NB", ALC663_ASUS_MODE1),
15476 SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC663_ASUS_MODE1),
15477 SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC663_ASUS_MODE1),
15478 SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC663_ASUS_MODE1),
Kailang Yang80ffe862008-10-15 11:23:27 +020015479 SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC663_ASUS_MODE1),
Kailang Yangf1d4e282008-08-26 14:03:29 +020015480 SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_ASUS_MODE2),
15481 SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_ASUS_MODE2),
15482 SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_ASUS_MODE2),
15483 SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_ASUS_MODE2),
15484 SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_ASUS_MODE2),
15485 SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_ASUS_MODE2),
15486 SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_ASUS_MODE2),
15487 SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_ASUS_MODE2),
15488 SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_ASUS_MODE2),
15489 SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_ASUS_MODE2),
15490 SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_ASUS_MODE2),
15491 SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_ASUS_MODE2),
15492 SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC663_ASUS_MODE3),
15493 SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC663_ASUS_MODE3),
15494 SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC663_ASUS_MODE3),
15495 SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC663_ASUS_MODE3),
15496 SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC663_ASUS_MODE3),
15497 SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC663_ASUS_MODE4),
15498 SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC663_ASUS_MODE5),
15499 SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC663_ASUS_MODE6),
15500 SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC663_ASUS_MODE6),
15501 SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC663_ASUS_MODE6),
Herton Ronaldo Krzesinski95fe5f22008-09-26 23:48:45 -030015502 SND_PCI_QUIRK(0x105b, 0x0d47, "Foxconn 45CMX/45GMX/45CMX-K",
15503 ALC662_3ST_6ch_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010015504 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E),
Kailang Yangf1d4e282008-08-26 14:03:29 +020015505 SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_ECS),
15506 SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS),
Herton Ronaldo Krzesinskicb559742008-09-26 23:47:45 -030015507 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L",
15508 ALC662_3ST_6ch_DIG),
Vedran Miletic19c009a2008-09-29 20:29:25 +020015509 SND_PCI_QUIRK(0x1565, 0x820f, "Biostar TA780G M2+", ALC662_3ST_6ch_DIG),
Takashi Iwai238713d2008-10-05 10:57:39 +020015510 SND_PCI_QUIRK(0x1849, 0x3662, "ASROCK K10N78FullHD-hSLI R3.0",
Vedran Miletic19c009a2008-09-29 20:29:25 +020015511 ALC662_3ST_6ch_DIG),
Kailang Yang6dda9f42008-05-27 12:05:31 +020015512 SND_PCI_QUIRK(0x1854, 0x2000, "ASUS H13-2000", ALC663_ASUS_H13),
15513 SND_PCI_QUIRK(0x1854, 0x2001, "ASUS H13-2001", ALC663_ASUS_H13),
15514 SND_PCI_QUIRK(0x1854, 0x2002, "ASUS H13-2002", ALC663_ASUS_H13),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015515 {}
15516};
15517
15518static struct alc_config_preset alc662_presets[] = {
15519 [ALC662_3ST_2ch_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015520 .mixers = { alc662_3ST_2ch_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015521 .init_verbs = { alc662_init_verbs },
15522 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15523 .dac_nids = alc662_dac_nids,
15524 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015525 .dig_in_nid = ALC662_DIGIN_NID,
15526 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15527 .channel_mode = alc662_3ST_2ch_modes,
15528 .input_mux = &alc662_capture_source,
15529 },
15530 [ALC662_3ST_6ch_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015531 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015532 .init_verbs = { alc662_init_verbs },
15533 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15534 .dac_nids = alc662_dac_nids,
15535 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015536 .dig_in_nid = ALC662_DIGIN_NID,
15537 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
15538 .channel_mode = alc662_3ST_6ch_modes,
15539 .need_dac_fix = 1,
15540 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015541 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015542 [ALC662_3ST_6ch] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015543 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015544 .init_verbs = { alc662_init_verbs },
15545 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15546 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015547 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
15548 .channel_mode = alc662_3ST_6ch_modes,
15549 .need_dac_fix = 1,
15550 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015551 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015552 [ALC662_5ST_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015553 .mixers = { alc662_base_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015554 .init_verbs = { alc662_init_verbs },
15555 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15556 .dac_nids = alc662_dac_nids,
15557 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015558 .dig_in_nid = ALC662_DIGIN_NID,
15559 .num_channel_mode = ARRAY_SIZE(alc662_5stack_modes),
15560 .channel_mode = alc662_5stack_modes,
15561 .input_mux = &alc662_capture_source,
15562 },
15563 [ALC662_LENOVO_101E] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015564 .mixers = { alc662_lenovo_101e_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015565 .init_verbs = { alc662_init_verbs, alc662_sue_init_verbs },
15566 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15567 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015568 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15569 .channel_mode = alc662_3ST_2ch_modes,
15570 .input_mux = &alc662_lenovo_101e_capture_source,
15571 .unsol_event = alc662_lenovo_101e_unsol_event,
15572 .init_hook = alc662_lenovo_101e_all_automute,
15573 },
Kailang Yang291702f2007-10-16 14:28:03 +020015574 [ALC662_ASUS_EEEPC_P701] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015575 .mixers = { alc662_eeepc_p701_mixer },
Kailang Yang291702f2007-10-16 14:28:03 +020015576 .init_verbs = { alc662_init_verbs,
15577 alc662_eeepc_sue_init_verbs },
15578 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15579 .dac_nids = alc662_dac_nids,
Kailang Yang291702f2007-10-16 14:28:03 +020015580 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15581 .channel_mode = alc662_3ST_2ch_modes,
15582 .input_mux = &alc662_eeepc_capture_source,
15583 .unsol_event = alc662_eeepc_unsol_event,
15584 .init_hook = alc662_eeepc_inithook,
15585 },
Kailang Yang8c427222008-01-10 13:03:59 +010015586 [ALC662_ASUS_EEEPC_EP20] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015587 .mixers = { alc662_eeepc_ep20_mixer,
Kailang Yang8c427222008-01-10 13:03:59 +010015588 alc662_chmode_mixer },
15589 .init_verbs = { alc662_init_verbs,
15590 alc662_eeepc_ep20_sue_init_verbs },
15591 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15592 .dac_nids = alc662_dac_nids,
Kailang Yang8c427222008-01-10 13:03:59 +010015593 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
15594 .channel_mode = alc662_3ST_6ch_modes,
15595 .input_mux = &alc662_lenovo_101e_capture_source,
15596 .unsol_event = alc662_eeepc_ep20_unsol_event,
15597 .init_hook = alc662_eeepc_ep20_inithook,
15598 },
Kailang Yangf1d4e282008-08-26 14:03:29 +020015599 [ALC662_ECS] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015600 .mixers = { alc662_ecs_mixer },
Kailang Yangf1d4e282008-08-26 14:03:29 +020015601 .init_verbs = { alc662_init_verbs,
15602 alc662_ecs_init_verbs },
15603 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15604 .dac_nids = alc662_dac_nids,
15605 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15606 .channel_mode = alc662_3ST_2ch_modes,
15607 .input_mux = &alc662_eeepc_capture_source,
15608 .unsol_event = alc662_eeepc_unsol_event,
15609 .init_hook = alc662_eeepc_inithook,
15610 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020015611 [ALC663_ASUS_M51VA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015612 .mixers = { alc663_m51va_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020015613 .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
15614 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15615 .dac_nids = alc662_dac_nids,
15616 .dig_out_nid = ALC662_DIGOUT_NID,
15617 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15618 .channel_mode = alc662_3ST_2ch_modes,
15619 .input_mux = &alc663_m51va_capture_source,
15620 .unsol_event = alc663_m51va_unsol_event,
15621 .init_hook = alc663_m51va_inithook,
15622 },
15623 [ALC663_ASUS_G71V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015624 .mixers = { alc663_g71v_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020015625 .init_verbs = { alc662_init_verbs, alc663_g71v_init_verbs },
15626 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15627 .dac_nids = alc662_dac_nids,
15628 .dig_out_nid = ALC662_DIGOUT_NID,
15629 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15630 .channel_mode = alc662_3ST_2ch_modes,
15631 .input_mux = &alc662_eeepc_capture_source,
15632 .unsol_event = alc663_g71v_unsol_event,
15633 .init_hook = alc663_g71v_inithook,
15634 },
15635 [ALC663_ASUS_H13] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015636 .mixers = { alc663_m51va_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020015637 .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
15638 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15639 .dac_nids = alc662_dac_nids,
15640 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15641 .channel_mode = alc662_3ST_2ch_modes,
15642 .input_mux = &alc663_m51va_capture_source,
15643 .unsol_event = alc663_m51va_unsol_event,
15644 .init_hook = alc663_m51va_inithook,
15645 },
15646 [ALC663_ASUS_G50V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015647 .mixers = { alc663_g50v_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020015648 .init_verbs = { alc662_init_verbs, alc663_g50v_init_verbs },
15649 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15650 .dac_nids = alc662_dac_nids,
15651 .dig_out_nid = ALC662_DIGOUT_NID,
15652 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
15653 .channel_mode = alc662_3ST_6ch_modes,
15654 .input_mux = &alc663_capture_source,
15655 .unsol_event = alc663_g50v_unsol_event,
15656 .init_hook = alc663_g50v_inithook,
15657 },
Kailang Yangf1d4e282008-08-26 14:03:29 +020015658 [ALC663_ASUS_MODE1] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015659 .mixers = { alc663_m51va_mixer },
15660 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020015661 .init_verbs = { alc662_init_verbs,
15662 alc663_21jd_amic_init_verbs },
15663 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15664 .hp_nid = 0x03,
15665 .dac_nids = alc662_dac_nids,
15666 .dig_out_nid = ALC662_DIGOUT_NID,
15667 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15668 .channel_mode = alc662_3ST_2ch_modes,
15669 .input_mux = &alc662_eeepc_capture_source,
15670 .unsol_event = alc663_mode1_unsol_event,
15671 .init_hook = alc663_mode1_inithook,
15672 },
15673 [ALC662_ASUS_MODE2] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015674 .mixers = { alc662_1bjd_mixer },
15675 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020015676 .init_verbs = { alc662_init_verbs,
15677 alc662_1bjd_amic_init_verbs },
15678 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15679 .dac_nids = alc662_dac_nids,
15680 .dig_out_nid = ALC662_DIGOUT_NID,
15681 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15682 .channel_mode = alc662_3ST_2ch_modes,
15683 .input_mux = &alc662_eeepc_capture_source,
15684 .unsol_event = alc662_mode2_unsol_event,
15685 .init_hook = alc662_mode2_inithook,
15686 },
15687 [ALC663_ASUS_MODE3] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015688 .mixers = { alc663_two_hp_m1_mixer },
15689 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020015690 .init_verbs = { alc662_init_verbs,
15691 alc663_two_hp_amic_m1_init_verbs },
15692 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15693 .hp_nid = 0x03,
15694 .dac_nids = alc662_dac_nids,
15695 .dig_out_nid = ALC662_DIGOUT_NID,
15696 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15697 .channel_mode = alc662_3ST_2ch_modes,
15698 .input_mux = &alc662_eeepc_capture_source,
15699 .unsol_event = alc663_mode3_unsol_event,
15700 .init_hook = alc663_mode3_inithook,
15701 },
15702 [ALC663_ASUS_MODE4] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015703 .mixers = { alc663_asus_21jd_clfe_mixer },
15704 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020015705 .init_verbs = { alc662_init_verbs,
15706 alc663_21jd_amic_init_verbs},
15707 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15708 .hp_nid = 0x03,
15709 .dac_nids = alc662_dac_nids,
15710 .dig_out_nid = ALC662_DIGOUT_NID,
15711 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15712 .channel_mode = alc662_3ST_2ch_modes,
15713 .input_mux = &alc662_eeepc_capture_source,
15714 .unsol_event = alc663_mode4_unsol_event,
15715 .init_hook = alc663_mode4_inithook,
15716 },
15717 [ALC663_ASUS_MODE5] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015718 .mixers = { alc663_asus_15jd_clfe_mixer },
15719 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020015720 .init_verbs = { alc662_init_verbs,
15721 alc663_15jd_amic_init_verbs },
15722 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15723 .hp_nid = 0x03,
15724 .dac_nids = alc662_dac_nids,
15725 .dig_out_nid = ALC662_DIGOUT_NID,
15726 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15727 .channel_mode = alc662_3ST_2ch_modes,
15728 .input_mux = &alc662_eeepc_capture_source,
15729 .unsol_event = alc663_mode5_unsol_event,
15730 .init_hook = alc663_mode5_inithook,
15731 },
15732 [ALC663_ASUS_MODE6] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015733 .mixers = { alc663_two_hp_m2_mixer },
15734 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020015735 .init_verbs = { alc662_init_verbs,
15736 alc663_two_hp_amic_m2_init_verbs },
15737 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15738 .hp_nid = 0x03,
15739 .dac_nids = alc662_dac_nids,
15740 .dig_out_nid = ALC662_DIGOUT_NID,
15741 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15742 .channel_mode = alc662_3ST_2ch_modes,
15743 .input_mux = &alc662_eeepc_capture_source,
15744 .unsol_event = alc663_mode6_unsol_event,
15745 .init_hook = alc663_mode6_inithook,
15746 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015747};
15748
15749
15750/*
15751 * BIOS auto configuration
15752 */
15753
15754/* add playback controls from the parsed DAC table */
15755static int alc662_auto_create_multi_out_ctls(struct alc_spec *spec,
15756 const struct auto_pin_cfg *cfg)
15757{
15758 char name[32];
15759 static const char *chname[4] = {
15760 "Front", "Surround", NULL /*CLFE*/, "Side"
15761 };
15762 hda_nid_t nid;
15763 int i, err;
15764
15765 for (i = 0; i < cfg->line_outs; i++) {
15766 if (!spec->multiout.dac_nids[i])
15767 continue;
Kailang Yangb60dd392007-09-20 12:50:29 +020015768 nid = alc880_idx_to_dac(i);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015769 if (i == 2) {
15770 /* Center/LFE */
15771 err = add_control(spec, ALC_CTL_WIDGET_VOL,
15772 "Center Playback Volume",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015773 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
15774 HDA_OUTPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015775 if (err < 0)
15776 return err;
15777 err = add_control(spec, ALC_CTL_WIDGET_VOL,
15778 "LFE Playback Volume",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015779 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
15780 HDA_OUTPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015781 if (err < 0)
15782 return err;
Herton Ronaldo Krzesinskib69ce012008-09-18 16:41:49 -030015783 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015784 "Center Playback Switch",
Herton Ronaldo Krzesinskib69ce012008-09-18 16:41:49 -030015785 HDA_COMPOSE_AMP_VAL(0x0e, 1, 0,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015786 HDA_INPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015787 if (err < 0)
15788 return err;
Herton Ronaldo Krzesinskib69ce012008-09-18 16:41:49 -030015789 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015790 "LFE Playback Switch",
Herton Ronaldo Krzesinskib69ce012008-09-18 16:41:49 -030015791 HDA_COMPOSE_AMP_VAL(0x0e, 2, 0,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015792 HDA_INPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015793 if (err < 0)
15794 return err;
15795 } else {
15796 sprintf(name, "%s Playback Volume", chname[i]);
15797 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015798 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
15799 HDA_OUTPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015800 if (err < 0)
15801 return err;
15802 sprintf(name, "%s Playback Switch", chname[i]);
Herton Ronaldo Krzesinskib69ce012008-09-18 16:41:49 -030015803 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
15804 HDA_COMPOSE_AMP_VAL(alc880_idx_to_mixer(i),
15805 3, 0, HDA_INPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015806 if (err < 0)
15807 return err;
15808 }
15809 }
15810 return 0;
15811}
15812
15813/* add playback controls for speaker and HP outputs */
15814static int alc662_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
15815 const char *pfx)
15816{
15817 hda_nid_t nid;
15818 int err;
15819 char name[32];
15820
15821 if (!pin)
15822 return 0;
15823
Takashi Iwai24fb9172008-09-02 14:48:20 +020015824 if (pin == 0x17) {
15825 /* ALC663 has a mono output pin on 0x17 */
15826 sprintf(name, "%s Playback Switch", pfx);
15827 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
15828 HDA_COMPOSE_AMP_VAL(pin, 2, 0, HDA_OUTPUT));
15829 return err;
15830 }
15831
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015832 if (alc880_is_fixed_pin(pin)) {
15833 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
15834 /* printk("DAC nid=%x\n",nid); */
15835 /* specify the DAC as the extra output */
15836 if (!spec->multiout.hp_nid)
15837 spec->multiout.hp_nid = nid;
15838 else
15839 spec->multiout.extra_out_nid[0] = nid;
15840 /* control HP volume/switch on the output mixer amp */
15841 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
15842 sprintf(name, "%s Playback Volume", pfx);
15843 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
15844 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
15845 if (err < 0)
15846 return err;
15847 sprintf(name, "%s Playback Switch", pfx);
15848 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
15849 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
15850 if (err < 0)
15851 return err;
15852 } else if (alc880_is_multi_pin(pin)) {
15853 /* set manual connection */
15854 /* we have only a switch on HP-out PIN */
15855 sprintf(name, "%s Playback Switch", pfx);
15856 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
15857 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
15858 if (err < 0)
15859 return err;
15860 }
15861 return 0;
15862}
15863
15864/* create playback/capture controls for input pins */
15865static int alc662_auto_create_analog_input_ctls(struct alc_spec *spec,
15866 const struct auto_pin_cfg *cfg)
15867{
15868 struct hda_input_mux *imux = &spec->private_imux;
15869 int i, err, idx;
15870
15871 for (i = 0; i < AUTO_PIN_LAST; i++) {
15872 if (alc880_is_input_pin(cfg->input_pins[i])) {
15873 idx = alc880_input_pin_idx(cfg->input_pins[i]);
15874 err = new_analog_input(spec, cfg->input_pins[i],
15875 auto_pin_cfg_labels[i],
15876 idx, 0x0b);
15877 if (err < 0)
15878 return err;
15879 imux->items[imux->num_items].label =
15880 auto_pin_cfg_labels[i];
15881 imux->items[imux->num_items].index =
15882 alc880_input_pin_idx(cfg->input_pins[i]);
15883 imux->num_items++;
15884 }
15885 }
15886 return 0;
15887}
15888
15889static void alc662_auto_set_output_and_unmute(struct hda_codec *codec,
15890 hda_nid_t nid, int pin_type,
15891 int dac_idx)
15892{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010015893 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015894 /* need the manual connection? */
15895 if (alc880_is_multi_pin(nid)) {
15896 struct alc_spec *spec = codec->spec;
15897 int idx = alc880_multi_pin_idx(nid);
15898 snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
15899 AC_VERB_SET_CONNECT_SEL,
15900 alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
15901 }
15902}
15903
15904static void alc662_auto_init_multi_out(struct hda_codec *codec)
15905{
15906 struct alc_spec *spec = codec->spec;
15907 int i;
15908
Kailang Yang8c427222008-01-10 13:03:59 +010015909 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015910 for (i = 0; i <= HDA_SIDE; i++) {
15911 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020015912 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015913 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020015914 alc662_auto_set_output_and_unmute(codec, nid, pin_type,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015915 i);
15916 }
15917}
15918
15919static void alc662_auto_init_hp_out(struct hda_codec *codec)
15920{
15921 struct alc_spec *spec = codec->spec;
15922 hda_nid_t pin;
15923
15924 pin = spec->autocfg.hp_pins[0];
15925 if (pin) /* connect to front */
15926 /* use dac 0 */
15927 alc662_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010015928 pin = spec->autocfg.speaker_pins[0];
15929 if (pin)
15930 alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015931}
15932
15933#define alc662_is_input_pin(nid) alc880_is_input_pin(nid)
15934#define ALC662_PIN_CD_NID ALC880_PIN_CD_NID
15935
15936static void alc662_auto_init_analog_input(struct hda_codec *codec)
15937{
15938 struct alc_spec *spec = codec->spec;
15939 int i;
15940
15941 for (i = 0; i < AUTO_PIN_LAST; i++) {
15942 hda_nid_t nid = spec->autocfg.input_pins[i];
15943 if (alc662_is_input_pin(nid)) {
15944 snd_hda_codec_write(codec, nid, 0,
15945 AC_VERB_SET_PIN_WIDGET_CONTROL,
15946 (i <= AUTO_PIN_FRONT_MIC ?
15947 PIN_VREF80 : PIN_IN));
15948 if (nid != ALC662_PIN_CD_NID)
15949 snd_hda_codec_write(codec, nid, 0,
15950 AC_VERB_SET_AMP_GAIN_MUTE,
15951 AMP_OUT_MUTE);
15952 }
15953 }
15954}
15955
Takashi Iwaif511b012008-08-15 16:46:42 +020015956#define alc662_auto_init_input_src alc882_auto_init_input_src
15957
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015958static int alc662_parse_auto_config(struct hda_codec *codec)
15959{
15960 struct alc_spec *spec = codec->spec;
15961 int err;
15962 static hda_nid_t alc662_ignore[] = { 0x1d, 0 };
15963
15964 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
15965 alc662_ignore);
15966 if (err < 0)
15967 return err;
15968 if (!spec->autocfg.line_outs)
15969 return 0; /* can't find valid BIOS pin config */
15970
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015971 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
15972 if (err < 0)
15973 return err;
15974 err = alc662_auto_create_multi_out_ctls(spec, &spec->autocfg);
15975 if (err < 0)
15976 return err;
15977 err = alc662_auto_create_extra_out(spec,
15978 spec->autocfg.speaker_pins[0],
15979 "Speaker");
15980 if (err < 0)
15981 return err;
15982 err = alc662_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
15983 "Headphone");
15984 if (err < 0)
15985 return err;
15986 err = alc662_auto_create_analog_input_ctls(spec, &spec->autocfg);
15987 if (err < 0)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015988 return err;
15989
15990 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
15991
15992 if (spec->autocfg.dig_out_pin)
15993 spec->multiout.dig_out_nid = ALC880_DIGOUT_NID;
15994
Takashi Iwai603c4012008-07-30 15:01:44 +020015995 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010015996 add_mixer(spec, spec->kctls.list);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015997
15998 spec->num_mux_defs = 1;
15999 spec->input_mux = &spec->private_imux;
Kailang Yangea1fb292008-08-26 12:58:38 +020016000
Takashi Iwaid88897e2008-10-31 15:01:37 +010016001 add_verb(spec, alc662_auto_init_verbs);
Takashi Iwai24fb9172008-09-02 14:48:20 +020016002 if (codec->vendor_id == 0x10ec0663)
Takashi Iwaid88897e2008-10-31 15:01:37 +010016003 add_verb(spec, alc663_auto_init_verbs);
Takashi Iwaiee979a142008-09-02 15:42:20 +020016004
16005 err = alc_auto_add_mic_boost(codec);
16006 if (err < 0)
16007 return err;
16008
Takashi Iwaie044c392008-10-27 16:56:24 +010016009 store_pin_configs(codec);
Takashi Iwai8c872862007-06-19 12:11:16 +020016010 return 1;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016011}
16012
16013/* additional initialization for auto-configuration model */
16014static void alc662_auto_init(struct hda_codec *codec)
16015{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016016 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016017 alc662_auto_init_multi_out(codec);
16018 alc662_auto_init_hp_out(codec);
16019 alc662_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020016020 alc662_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016021 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020016022 alc_inithook(codec);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016023}
16024
16025static int patch_alc662(struct hda_codec *codec)
16026{
16027 struct alc_spec *spec;
16028 int err, board_config;
16029
16030 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
16031 if (!spec)
16032 return -ENOMEM;
16033
16034 codec->spec = spec;
16035
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020016036 alc_fix_pll_init(codec, 0x20, 0x04, 15);
16037
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016038 board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST,
16039 alc662_models,
16040 alc662_cfg_tbl);
16041 if (board_config < 0) {
16042 printk(KERN_INFO "hda_codec: Unknown model for ALC662, "
16043 "trying auto-probe from BIOS...\n");
16044 board_config = ALC662_AUTO;
16045 }
16046
16047 if (board_config == ALC662_AUTO) {
16048 /* automatic parse from the BIOS config */
16049 err = alc662_parse_auto_config(codec);
16050 if (err < 0) {
16051 alc_free(codec);
16052 return err;
Takashi Iwai8c872862007-06-19 12:11:16 +020016053 } else if (!err) {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016054 printk(KERN_INFO
16055 "hda_codec: Cannot set up configuration "
16056 "from BIOS. Using base mode...\n");
16057 board_config = ALC662_3ST_2ch_DIG;
16058 }
16059 }
16060
16061 if (board_config != ALC662_AUTO)
16062 setup_preset(spec, &alc662_presets[board_config]);
16063
Kailang Yang6dda9f42008-05-27 12:05:31 +020016064 if (codec->vendor_id == 0x10ec0663) {
16065 spec->stream_name_analog = "ALC663 Analog";
16066 spec->stream_name_digital = "ALC663 Digital";
Kailang Yang01afd412008-10-15 11:22:09 +020016067 } else if (codec->vendor_id == 0x10ec0272) {
16068 spec->stream_name_analog = "ALC272 Analog";
16069 spec->stream_name_digital = "ALC272 Digital";
Kailang Yang6dda9f42008-05-27 12:05:31 +020016070 } else {
16071 spec->stream_name_analog = "ALC662 Analog";
16072 spec->stream_name_digital = "ALC662 Digital";
16073 }
16074
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016075 spec->stream_analog_playback = &alc662_pcm_analog_playback;
16076 spec->stream_analog_capture = &alc662_pcm_analog_capture;
16077
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016078 spec->stream_digital_playback = &alc662_pcm_digital_playback;
16079 spec->stream_digital_capture = &alc662_pcm_digital_capture;
16080
Takashi Iwaie1406342008-02-11 18:32:32 +010016081 spec->adc_nids = alc662_adc_nids;
16082 spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids);
16083 spec->capsrc_nids = alc662_capsrc_nids;
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010016084 spec->is_mix_capture = 1;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016085
Takashi Iwaif9e336f2008-10-31 16:37:07 +010016086 if (!spec->cap_mixer)
16087 set_capture_mixer(spec);
16088
Takashi Iwai2134ea42008-01-10 16:53:55 +010016089 spec->vmaster_nid = 0x02;
16090
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016091 codec->patch_ops = alc_patch_ops;
16092 if (board_config == ALC662_AUTO)
16093 spec->init_hook = alc662_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020016094#ifdef CONFIG_SND_HDA_POWER_SAVE
16095 if (!spec->loopback.amplist)
16096 spec->loopback.amplist = alc662_loopbacks;
16097#endif
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016098
16099 return 0;
16100}
16101
16102/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070016103 * patch entries
16104 */
16105struct hda_codec_preset snd_hda_preset_realtek[] = {
16106 { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
Kailang Yangdf694da2005-12-05 19:42:22 +010016107 { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
Kailang Yangf6a92242007-12-13 16:52:54 +010016108 { .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 },
Kailang Yanga361d842007-06-05 12:30:55 +020016109 { .id = 0x10ec0268, .name = "ALC268", .patch = patch_alc268 },
Kailang Yangf6a92242007-12-13 16:52:54 +010016110 { .id = 0x10ec0269, .name = "ALC269", .patch = patch_alc269 },
Kailang Yang01afd412008-10-15 11:22:09 +020016111 { .id = 0x10ec0272, .name = "ALC272", .patch = patch_alc662 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016112 { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016113 .patch = patch_alc861 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016114 { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
16115 { .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 },
16116 { .id = 0x10ec0862, .name = "ALC861-VD", .patch = patch_alc861vd },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016117 { .id = 0x10ec0662, .rev = 0x100002, .name = "ALC662 rev2",
16118 .patch = patch_alc883 },
16119 { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1",
16120 .patch = patch_alc662 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020016121 { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016122 { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070016123 { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020016124 { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc883 },
Clive Messer669faba2008-09-30 15:49:13 +020016125 { .id = 0x10ec0885, .rev = 0x100101, .name = "ALC889A",
16126 .patch = patch_alc882 }, /* should be patch_alc883() in future */
Takashi Iwaicb308f92008-04-16 14:13:29 +020016127 { .id = 0x10ec0885, .rev = 0x100103, .name = "ALC889A",
Takashi Iwai7943a8a2008-04-16 17:29:09 +020016128 .patch = patch_alc882 }, /* should be patch_alc883() in future */
Kailang Yangdf694da2005-12-05 19:42:22 +010016129 { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
Kailang Yanga385a522008-10-15 11:20:21 +020016130 { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc883 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020016131 { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc883 },
Kailang Yang44426082008-10-15 11:18:05 +020016132 { .id = 0x10ec0888, .rev = 0x100101, .name = "ALC1200",
16133 .patch = patch_alc883 },
Kailang Yangf6a92242007-12-13 16:52:54 +010016134 { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc883 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070016135 {} /* terminator */
16136};