blob: 51479fba960e6a5ffc72663c53ecc313d3601ca1 [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,
Kailang Yangf6a92242007-12-13 16:52:54 +0100133 ALC269_AUTO,
134 ALC269_MODEL_LAST /* last tag */
135};
136
Kailang Yangdf694da2005-12-05 19:42:22 +0100137/* ALC861 models */
138enum {
139 ALC861_3ST,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200140 ALC660_3ST,
Kailang Yangdf694da2005-12-05 19:42:22 +0100141 ALC861_3ST_DIG,
142 ALC861_6ST_DIG,
Takashi Iwai22309c32006-08-09 16:57:28 +0200143 ALC861_UNIWILL_M31,
Tobin Davisa53d1ae2006-10-17 12:00:28 +0200144 ALC861_TOSHIBA,
Mariusz Domanski7cdbff92006-10-23 13:42:56 +0200145 ALC861_ASUS,
Takashi Iwai56bb0ca2006-11-22 11:52:52 +0100146 ALC861_ASUS_LAPTOP,
Kailang Yangdf694da2005-12-05 19:42:22 +0100147 ALC861_AUTO,
148 ALC861_MODEL_LAST,
149};
150
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100151/* ALC861-VD models */
152enum {
153 ALC660VD_3ST,
Mike Crash6963f842007-06-25 12:12:51 +0200154 ALC660VD_3ST_DIG,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100155 ALC861VD_3ST,
156 ALC861VD_3ST_DIG,
157 ALC861VD_6ST_DIG,
Kailang Yangbdd148a2007-05-08 15:19:08 +0200158 ALC861VD_LENOVO,
Kailang Yang272a5272007-05-14 11:00:38 +0200159 ALC861VD_DALLAS,
Kailang Yangd1a991a2007-08-15 16:21:59 +0200160 ALC861VD_HP,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100161 ALC861VD_AUTO,
162 ALC861VD_MODEL_LAST,
163};
164
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200165/* ALC662 models */
166enum {
167 ALC662_3ST_2ch_DIG,
168 ALC662_3ST_6ch_DIG,
169 ALC662_3ST_6ch,
170 ALC662_5ST_DIG,
171 ALC662_LENOVO_101E,
Kailang Yang291702f2007-10-16 14:28:03 +0200172 ALC662_ASUS_EEEPC_P701,
Kailang Yang8c427222008-01-10 13:03:59 +0100173 ALC662_ASUS_EEEPC_EP20,
Kailang Yang6dda9f42008-05-27 12:05:31 +0200174 ALC663_ASUS_M51VA,
175 ALC663_ASUS_G71V,
176 ALC663_ASUS_H13,
177 ALC663_ASUS_G50V,
Kailang Yangf1d4e282008-08-26 14:03:29 +0200178 ALC662_ECS,
179 ALC663_ASUS_MODE1,
180 ALC662_ASUS_MODE2,
181 ALC663_ASUS_MODE3,
182 ALC663_ASUS_MODE4,
183 ALC663_ASUS_MODE5,
184 ALC663_ASUS_MODE6,
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200185 ALC662_AUTO,
186 ALC662_MODEL_LAST,
187};
188
Kailang Yangdf694da2005-12-05 19:42:22 +0100189/* ALC882 models */
190enum {
191 ALC882_3ST_DIG,
192 ALC882_6ST_DIG,
Takashi Iwai4b146cb2006-07-28 14:42:36 +0200193 ALC882_ARIMA,
Kailang Yangbdd148a2007-05-08 15:19:08 +0200194 ALC882_W2JC,
Kailang Yang272a5272007-05-14 11:00:38 +0200195 ALC882_TARGA,
196 ALC882_ASUS_A7J,
Takashi Iwai914759b2007-09-06 14:52:04 +0200197 ALC882_ASUS_A7M,
Tobin Davis9102cd12006-12-15 10:02:12 +0100198 ALC885_MACPRO,
Takashi Iwai87350ad2007-08-16 18:19:38 +0200199 ALC885_MBP3,
Nicola Fagnanic54728d2007-07-19 23:28:52 +0200200 ALC885_IMAC24,
Kailang Yang272a5272007-05-14 11:00:38 +0200201 ALC882_AUTO,
Kailang Yangdf694da2005-12-05 19:42:22 +0100202 ALC882_MODEL_LAST,
203};
204
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200205/* ALC883 models */
206enum {
207 ALC883_3ST_2ch_DIG,
208 ALC883_3ST_6ch_DIG,
209 ALC883_3ST_6ch,
210 ALC883_6ST_DIG,
Kailang Yangccc656c2006-10-17 12:32:26 +0200211 ALC883_TARGA_DIG,
212 ALC883_TARGA_2ch_DIG,
Vladimir Avdoninbab282b2006-08-22 13:31:58 +0200213 ALC883_ACER,
Tobin Davis2880a862007-08-07 11:50:26 +0200214 ALC883_ACER_ASPIRE,
Tobin Davisc07584c2006-10-13 12:32:16 +0200215 ALC883_MEDION,
Kailang Yangea1fb292008-08-26 12:58:38 +0200216 ALC883_MEDION_MD2,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +0100217 ALC883_LAPTOP_EAPD,
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200218 ALC883_LENOVO_101E_2ch,
Kailang Yang272a5272007-05-14 11:00:38 +0200219 ALC883_LENOVO_NB0763,
Kailang Yang189609a2007-08-20 11:31:23 +0200220 ALC888_LENOVO_MS7195_DIG,
Kailang Yange2757d52008-08-26 13:17:46 +0200221 ALC888_LENOVO_SKY,
Kailang Yangea1fb292008-08-26 12:58:38 +0200222 ALC883_HAIER_W66,
Claudio Matsuoka4723c022007-07-13 14:36:19 +0200223 ALC888_3ST_HP,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +0100224 ALC888_6ST_DELL,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +0100225 ALC883_MITAC,
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +0100226 ALC883_CLEVO_M720,
Jiang zhefb97dc62008-03-06 11:07:11 +0100227 ALC883_FUJITSU_PI2515,
Jiang zhe17bba1b2008-06-04 12:11:07 +0200228 ALC883_3ST_6ch_INTEL,
Kailang Yange2757d52008-08-26 13:17:46 +0200229 ALC888_ASUS_M90V,
230 ALC888_ASUS_EEE1601,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200231 ALC883_AUTO,
232 ALC883_MODEL_LAST,
233};
234
Kailang Yangdf694da2005-12-05 19:42:22 +0100235/* for GPIO Poll */
236#define GPIO_MASK 0x03
237
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238struct alc_spec {
239 /* codec parameterization */
Kailang Yangdf694da2005-12-05 19:42:22 +0100240 struct snd_kcontrol_new *mixers[5]; /* mixer arrays */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 unsigned int num_mixers;
242
Kailang Yangdf694da2005-12-05 19:42:22 +0100243 const struct hda_verb *init_verbs[5]; /* initialization verbs
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200244 * don't forget NULL
245 * termination!
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200246 */
247 unsigned int num_init_verbs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248
Takashi Iwai16ded522005-06-10 19:58:24 +0200249 char *stream_name_analog; /* analog PCM stream */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 struct hda_pcm_stream *stream_analog_playback;
251 struct hda_pcm_stream *stream_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +0100252 struct hda_pcm_stream *stream_analog_alt_playback;
253 struct hda_pcm_stream *stream_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200255 char *stream_name_digital; /* digital PCM stream */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 struct hda_pcm_stream *stream_digital_playback;
257 struct hda_pcm_stream *stream_digital_capture;
258
259 /* playback */
Takashi Iwai16ded522005-06-10 19:58:24 +0200260 struct hda_multi_out multiout; /* playback set-up
261 * max_channels, dacs must be set
262 * dig_out_nid and hp_nid are optional
263 */
Takashi Iwai63300792008-01-24 15:31:36 +0100264 hda_nid_t alt_dac_nid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265
266 /* capture */
267 unsigned int num_adc_nids;
268 hda_nid_t *adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100269 hda_nid_t *capsrc_nids;
Takashi Iwai16ded522005-06-10 19:58:24 +0200270 hda_nid_t dig_in_nid; /* digital-in NID; optional */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271
272 /* capture source */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200273 unsigned int num_mux_defs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 const struct hda_input_mux *input_mux;
275 unsigned int cur_mux[3];
276
277 /* channel model */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100278 const struct hda_channel_mode *channel_mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279 int num_channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200280 int need_dac_fix;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281
282 /* PCM information */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100283 struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */
Takashi Iwai41e41f12005-06-08 14:48:49 +0200284
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200285 /* dynamic controls, init_verbs and input_mux */
286 struct auto_pin_cfg autocfg;
Takashi Iwai603c4012008-07-30 15:01:44 +0200287 struct snd_array kctls;
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200288 struct hda_input_mux private_imux;
Takashi Iwai41923e42007-10-22 17:20:10 +0200289 hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
Takashi Iwai834be882006-03-01 14:16:17 +0100290
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100291 /* hooks */
292 void (*init_hook)(struct hda_codec *codec);
293 void (*unsol_event)(struct hda_codec *codec, unsigned int res);
294
Takashi Iwai834be882006-03-01 14:16:17 +0100295 /* for pin sensing */
296 unsigned int sense_updated: 1;
297 unsigned int jack_present: 1;
Takashi Iwaibec15c32008-01-28 18:16:30 +0100298 unsigned int master_sw: 1;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200299
Takashi Iwai2134ea42008-01-10 16:53:55 +0100300 /* for virtual master */
301 hda_nid_t vmaster_nid;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200302#ifdef CONFIG_SND_HDA_POWER_SAVE
303 struct hda_loopback_check loopback;
304#endif
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +0200305
306 /* for PLL fix */
307 hda_nid_t pll_nid;
308 unsigned int pll_coef_idx, pll_coef_bit;
Takashi Iwaie044c392008-10-27 16:56:24 +0100309
310#ifdef SND_HDA_NEEDS_RESUME
311#define ALC_MAX_PINS 16
312 unsigned int num_pins;
313 hda_nid_t pin_nids[ALC_MAX_PINS];
314 unsigned int pin_cfgs[ALC_MAX_PINS];
315#endif
Kailang Yangdf694da2005-12-05 19:42:22 +0100316};
317
318/*
319 * configuration template - to be copied to the spec instance
320 */
321struct alc_config_preset {
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200322 struct snd_kcontrol_new *mixers[5]; /* should be identical size
323 * with spec
324 */
Kailang Yangdf694da2005-12-05 19:42:22 +0100325 const struct hda_verb *init_verbs[5];
326 unsigned int num_dacs;
327 hda_nid_t *dac_nids;
328 hda_nid_t dig_out_nid; /* optional */
329 hda_nid_t hp_nid; /* optional */
330 unsigned int num_adc_nids;
331 hda_nid_t *adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100332 hda_nid_t *capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +0100333 hda_nid_t dig_in_nid;
334 unsigned int num_channel_mode;
335 const struct hda_channel_mode *channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200336 int need_dac_fix;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200337 unsigned int num_mux_defs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100338 const struct hda_input_mux *input_mux;
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100339 void (*unsol_event)(struct hda_codec *, unsigned int);
340 void (*init_hook)(struct hda_codec *);
Takashi Iwaicb53c622007-08-10 17:21:45 +0200341#ifdef CONFIG_SND_HDA_POWER_SAVE
342 struct hda_amp_list *loopbacks;
343#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344};
345
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346
347/*
348 * input MUX handling
349 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200350static int alc_mux_enum_info(struct snd_kcontrol *kcontrol,
351 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352{
353 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
354 struct alc_spec *spec = codec->spec;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200355 unsigned int mux_idx = snd_ctl_get_ioffidx(kcontrol, &uinfo->id);
356 if (mux_idx >= spec->num_mux_defs)
357 mux_idx = 0;
358 return snd_hda_input_mux_info(&spec->input_mux[mux_idx], uinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359}
360
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200361static int alc_mux_enum_get(struct snd_kcontrol *kcontrol,
362 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363{
364 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
365 struct alc_spec *spec = codec->spec;
366 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
367
368 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
369 return 0;
370}
371
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200372static int alc_mux_enum_put(struct snd_kcontrol *kcontrol,
373 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374{
375 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
376 struct alc_spec *spec = codec->spec;
377 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200378 unsigned int mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx;
Takashi Iwaie1406342008-02-11 18:32:32 +0100379 hda_nid_t nid = spec->capsrc_nids ?
380 spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx];
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200381 return snd_hda_input_mux_put(codec, &spec->input_mux[mux_idx], ucontrol,
Takashi Iwaie1406342008-02-11 18:32:32 +0100382 nid, &spec->cur_mux[adc_idx]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383}
384
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200385
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386/*
387 * channel mode setting
388 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200389static int alc_ch_mode_info(struct snd_kcontrol *kcontrol,
390 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391{
392 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
393 struct alc_spec *spec = codec->spec;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100394 return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode,
395 spec->num_channel_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396}
397
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200398static int alc_ch_mode_get(struct snd_kcontrol *kcontrol,
399 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400{
401 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
402 struct alc_spec *spec = codec->spec;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100403 return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200404 spec->num_channel_mode,
405 spec->multiout.max_channels);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406}
407
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200408static int alc_ch_mode_put(struct snd_kcontrol *kcontrol,
409 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410{
411 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
412 struct alc_spec *spec = codec->spec;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200413 int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
414 spec->num_channel_mode,
415 &spec->multiout.max_channels);
Takashi Iwaibd2033f2006-10-10 19:49:31 +0200416 if (err >= 0 && spec->need_dac_fix)
Takashi Iwai4e195a72006-07-28 14:47:34 +0200417 spec->multiout.num_dacs = spec->multiout.max_channels / 2;
418 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419}
420
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421/*
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100422 * Control the mode of pin widget settings via the mixer. "pc" is used
Kailang Yangea1fb292008-08-26 12:58:38 +0200423 * instead of "%" to avoid consequences of accidently treating the % as
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100424 * being part of a format specifier. Maximum allowed length of a value is
425 * 63 characters plus NULL terminator.
Jonathan Woithe7cf51e42006-02-09 12:01:26 +0100426 *
427 * Note: some retasking pin complexes seem to ignore requests for input
428 * states other than HiZ (eg: PIN_VREFxx) and revert to HiZ if any of these
429 * are requested. Therefore order this list so that this behaviour will not
430 * cause problems when mixer clients move through the enum sequentially.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200431 * NIDs 0x0f and 0x10 have been observed to have this behaviour as of
432 * March 2006.
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200433 */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100434static char *alc_pin_mode_names[] = {
Jonathan Woithe7cf51e42006-02-09 12:01:26 +0100435 "Mic 50pc bias", "Mic 80pc bias",
436 "Line in", "Line out", "Headphone out",
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100437};
438static unsigned char alc_pin_mode_values[] = {
Jonathan Woithe7cf51e42006-02-09 12:01:26 +0100439 PIN_VREF50, PIN_VREF80, PIN_IN, PIN_OUT, PIN_HP,
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100440};
441/* The control can present all 5 options, or it can limit the options based
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200442 * in the pin being assumed to be exclusively an input or an output pin. In
443 * addition, "input" pins may or may not process the mic bias option
444 * depending on actual widget capability (NIDs 0x0f and 0x10 don't seem to
445 * accept requests for bias as of chip versions up to March 2006) and/or
446 * wiring in the computer.
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100447 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200448#define ALC_PIN_DIR_IN 0x00
449#define ALC_PIN_DIR_OUT 0x01
450#define ALC_PIN_DIR_INOUT 0x02
451#define ALC_PIN_DIR_IN_NOMICBIAS 0x03
452#define ALC_PIN_DIR_INOUT_NOMICBIAS 0x04
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100453
Kailang Yangea1fb292008-08-26 12:58:38 +0200454/* Info about the pin modes supported by the different pin direction modes.
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100455 * For each direction the minimum and maximum values are given.
456 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200457static signed char alc_pin_mode_dir_info[5][2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100458 { 0, 2 }, /* ALC_PIN_DIR_IN */
459 { 3, 4 }, /* ALC_PIN_DIR_OUT */
460 { 0, 4 }, /* ALC_PIN_DIR_INOUT */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200461 { 2, 2 }, /* ALC_PIN_DIR_IN_NOMICBIAS */
462 { 2, 4 }, /* ALC_PIN_DIR_INOUT_NOMICBIAS */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100463};
464#define alc_pin_mode_min(_dir) (alc_pin_mode_dir_info[_dir][0])
465#define alc_pin_mode_max(_dir) (alc_pin_mode_dir_info[_dir][1])
466#define alc_pin_mode_n_items(_dir) \
467 (alc_pin_mode_max(_dir)-alc_pin_mode_min(_dir)+1)
468
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200469static int alc_pin_mode_info(struct snd_kcontrol *kcontrol,
470 struct snd_ctl_elem_info *uinfo)
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200471{
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100472 unsigned int item_num = uinfo->value.enumerated.item;
473 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
474
475 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200476 uinfo->count = 1;
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100477 uinfo->value.enumerated.items = alc_pin_mode_n_items(dir);
478
479 if (item_num<alc_pin_mode_min(dir) || item_num>alc_pin_mode_max(dir))
480 item_num = alc_pin_mode_min(dir);
481 strcpy(uinfo->value.enumerated.name, alc_pin_mode_names[item_num]);
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200482 return 0;
483}
484
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200485static int alc_pin_mode_get(struct snd_kcontrol *kcontrol,
486 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200487{
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100488 unsigned int i;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200489 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
490 hda_nid_t nid = kcontrol->private_value & 0xffff;
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100491 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200492 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200493 unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
494 AC_VERB_GET_PIN_WIDGET_CONTROL,
495 0x00);
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200496
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100497 /* Find enumerated value for current pinctl setting */
498 i = alc_pin_mode_min(dir);
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200499 while (alc_pin_mode_values[i] != pinctl && i <= alc_pin_mode_max(dir))
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100500 i++;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200501 *valp = i <= alc_pin_mode_max(dir) ? i: alc_pin_mode_min(dir);
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100502 return 0;
503}
504
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200505static int alc_pin_mode_put(struct snd_kcontrol *kcontrol,
506 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100507{
508 signed int change;
509 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
510 hda_nid_t nid = kcontrol->private_value & 0xffff;
511 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
512 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200513 unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
514 AC_VERB_GET_PIN_WIDGET_CONTROL,
515 0x00);
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100516
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200517 if (val < alc_pin_mode_min(dir) || val > alc_pin_mode_max(dir))
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100518 val = alc_pin_mode_min(dir);
519
520 change = pinctl != alc_pin_mode_values[val];
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100521 if (change) {
522 /* Set pin mode to that requested */
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200523 snd_hda_codec_write_cache(codec, nid, 0,
524 AC_VERB_SET_PIN_WIDGET_CONTROL,
525 alc_pin_mode_values[val]);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100526
Kailang Yangea1fb292008-08-26 12:58:38 +0200527 /* Also enable the retasking pin's input/output as required
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100528 * for the requested pin mode. Enum values of 2 or less are
529 * input modes.
530 *
531 * Dynamically switching the input/output buffers probably
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200532 * reduces noise slightly (particularly on input) so we'll
533 * do it. However, having both input and output buffers
534 * enabled simultaneously doesn't seem to be problematic if
535 * this turns out to be necessary in the future.
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100536 */
537 if (val <= 2) {
Takashi Iwai47fd8302007-08-10 17:11:07 +0200538 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
539 HDA_AMP_MUTE, HDA_AMP_MUTE);
540 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
541 HDA_AMP_MUTE, 0);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100542 } else {
Takashi Iwai47fd8302007-08-10 17:11:07 +0200543 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
544 HDA_AMP_MUTE, HDA_AMP_MUTE);
545 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
546 HDA_AMP_MUTE, 0);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100547 }
548 }
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200549 return change;
550}
551
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100552#define ALC_PIN_MODE(xname, nid, dir) \
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200553 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100554 .info = alc_pin_mode_info, \
555 .get = alc_pin_mode_get, \
556 .put = alc_pin_mode_put, \
557 .private_value = nid | (dir<<16) }
Kailang Yangdf694da2005-12-05 19:42:22 +0100558
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100559/* A switch control for ALC260 GPIO pins. Multiple GPIOs can be ganged
560 * together using a mask with more than one bit set. This control is
561 * currently used only by the ALC260 test model. At this stage they are not
562 * needed for any "production" models.
563 */
564#ifdef CONFIG_SND_DEBUG
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200565#define alc_gpio_data_info snd_ctl_boolean_mono_info
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200566
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200567static int alc_gpio_data_get(struct snd_kcontrol *kcontrol,
568 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100569{
570 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
571 hda_nid_t nid = kcontrol->private_value & 0xffff;
572 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
573 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200574 unsigned int val = snd_hda_codec_read(codec, nid, 0,
575 AC_VERB_GET_GPIO_DATA, 0x00);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100576
577 *valp = (val & mask) != 0;
578 return 0;
579}
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200580static int alc_gpio_data_put(struct snd_kcontrol *kcontrol,
581 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100582{
583 signed int change;
584 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
585 hda_nid_t nid = kcontrol->private_value & 0xffff;
586 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
587 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200588 unsigned int gpio_data = snd_hda_codec_read(codec, nid, 0,
589 AC_VERB_GET_GPIO_DATA,
590 0x00);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100591
592 /* Set/unset the masked GPIO bit(s) as needed */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200593 change = (val == 0 ? 0 : mask) != (gpio_data & mask);
594 if (val == 0)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100595 gpio_data &= ~mask;
596 else
597 gpio_data |= mask;
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200598 snd_hda_codec_write_cache(codec, nid, 0,
599 AC_VERB_SET_GPIO_DATA, gpio_data);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100600
601 return change;
602}
603#define ALC_GPIO_DATA_SWITCH(xname, nid, mask) \
604 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
605 .info = alc_gpio_data_info, \
606 .get = alc_gpio_data_get, \
607 .put = alc_gpio_data_put, \
608 .private_value = nid | (mask<<16) }
609#endif /* CONFIG_SND_DEBUG */
610
Jonathan Woithe92621f12006-02-28 11:47:47 +0100611/* A switch control to allow the enabling of the digital IO pins on the
612 * ALC260. This is incredibly simplistic; the intention of this control is
613 * to provide something in the test model allowing digital outputs to be
614 * identified if present. If models are found which can utilise these
615 * outputs a more complete mixer control can be devised for those models if
616 * necessary.
617 */
618#ifdef CONFIG_SND_DEBUG
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200619#define alc_spdif_ctrl_info snd_ctl_boolean_mono_info
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200620
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200621static int alc_spdif_ctrl_get(struct snd_kcontrol *kcontrol,
622 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe92621f12006-02-28 11:47:47 +0100623{
624 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
625 hda_nid_t nid = kcontrol->private_value & 0xffff;
626 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
627 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200628 unsigned int val = snd_hda_codec_read(codec, nid, 0,
Andrew Paprocki3982d172007-12-19 12:13:44 +0100629 AC_VERB_GET_DIGI_CONVERT_1, 0x00);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100630
631 *valp = (val & mask) != 0;
632 return 0;
633}
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200634static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol,
635 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe92621f12006-02-28 11:47:47 +0100636{
637 signed int change;
638 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
639 hda_nid_t nid = kcontrol->private_value & 0xffff;
640 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
641 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200642 unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
Andrew Paprocki3982d172007-12-19 12:13:44 +0100643 AC_VERB_GET_DIGI_CONVERT_1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200644 0x00);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100645
646 /* Set/unset the masked control bit(s) as needed */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200647 change = (val == 0 ? 0 : mask) != (ctrl_data & mask);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100648 if (val==0)
649 ctrl_data &= ~mask;
650 else
651 ctrl_data |= mask;
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200652 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
653 ctrl_data);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100654
655 return change;
656}
657#define ALC_SPDIF_CTRL_SWITCH(xname, nid, mask) \
658 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
659 .info = alc_spdif_ctrl_info, \
660 .get = alc_spdif_ctrl_get, \
661 .put = alc_spdif_ctrl_put, \
662 .private_value = nid | (mask<<16) }
663#endif /* CONFIG_SND_DEBUG */
664
Jonathan Woithef8225f62008-01-08 12:16:54 +0100665/* A switch control to allow the enabling EAPD digital outputs on the ALC26x.
666 * Again, this is only used in the ALC26x test models to help identify when
667 * the EAPD line must be asserted for features to work.
668 */
669#ifdef CONFIG_SND_DEBUG
670#define alc_eapd_ctrl_info snd_ctl_boolean_mono_info
671
672static int alc_eapd_ctrl_get(struct snd_kcontrol *kcontrol,
673 struct snd_ctl_elem_value *ucontrol)
674{
675 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
676 hda_nid_t nid = kcontrol->private_value & 0xffff;
677 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
678 long *valp = ucontrol->value.integer.value;
679 unsigned int val = snd_hda_codec_read(codec, nid, 0,
680 AC_VERB_GET_EAPD_BTLENABLE, 0x00);
681
682 *valp = (val & mask) != 0;
683 return 0;
684}
685
686static int alc_eapd_ctrl_put(struct snd_kcontrol *kcontrol,
687 struct snd_ctl_elem_value *ucontrol)
688{
689 int change;
690 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
691 hda_nid_t nid = kcontrol->private_value & 0xffff;
692 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
693 long val = *ucontrol->value.integer.value;
694 unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
695 AC_VERB_GET_EAPD_BTLENABLE,
696 0x00);
697
698 /* Set/unset the masked control bit(s) as needed */
699 change = (!val ? 0 : mask) != (ctrl_data & mask);
700 if (!val)
701 ctrl_data &= ~mask;
702 else
703 ctrl_data |= mask;
704 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
705 ctrl_data);
706
707 return change;
708}
709
710#define ALC_EAPD_CTRL_SWITCH(xname, nid, mask) \
711 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
712 .info = alc_eapd_ctrl_info, \
713 .get = alc_eapd_ctrl_get, \
714 .put = alc_eapd_ctrl_put, \
715 .private_value = nid | (mask<<16) }
716#endif /* CONFIG_SND_DEBUG */
717
Kailang Yangdf694da2005-12-05 19:42:22 +0100718/*
Takashi Iwaid88897e2008-10-31 15:01:37 +0100719 */
720static void add_mixer(struct alc_spec *spec, struct snd_kcontrol_new *mix)
721{
722 if (snd_BUG_ON(spec->num_mixers >= ARRAY_SIZE(spec->mixers)))
723 return;
724 spec->mixers[spec->num_mixers++] = mix;
725}
726
727static void add_verb(struct alc_spec *spec, const struct hda_verb *verb)
728{
729 if (snd_BUG_ON(spec->num_init_verbs >= ARRAY_SIZE(spec->init_verbs)))
730 return;
731 spec->init_verbs[spec->num_init_verbs++] = verb;
732}
733
734/*
Kailang Yangdf694da2005-12-05 19:42:22 +0100735 * set up from the preset table
736 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200737static void setup_preset(struct alc_spec *spec,
738 const struct alc_config_preset *preset)
Kailang Yangdf694da2005-12-05 19:42:22 +0100739{
740 int i;
741
742 for (i = 0; i < ARRAY_SIZE(preset->mixers) && preset->mixers[i]; i++)
Takashi Iwaid88897e2008-10-31 15:01:37 +0100743 add_mixer(spec, preset->mixers[i]);
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200744 for (i = 0; i < ARRAY_SIZE(preset->init_verbs) && preset->init_verbs[i];
745 i++)
Takashi Iwaid88897e2008-10-31 15:01:37 +0100746 add_verb(spec, preset->init_verbs[i]);
Kailang Yangea1fb292008-08-26 12:58:38 +0200747
Kailang Yangdf694da2005-12-05 19:42:22 +0100748 spec->channel_mode = preset->channel_mode;
749 spec->num_channel_mode = preset->num_channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200750 spec->need_dac_fix = preset->need_dac_fix;
Kailang Yangdf694da2005-12-05 19:42:22 +0100751
752 spec->multiout.max_channels = spec->channel_mode[0].channels;
753
754 spec->multiout.num_dacs = preset->num_dacs;
755 spec->multiout.dac_nids = preset->dac_nids;
756 spec->multiout.dig_out_nid = preset->dig_out_nid;
757 spec->multiout.hp_nid = preset->hp_nid;
Kailang Yangea1fb292008-08-26 12:58:38 +0200758
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200759 spec->num_mux_defs = preset->num_mux_defs;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200760 if (!spec->num_mux_defs)
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200761 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +0100762 spec->input_mux = preset->input_mux;
763
764 spec->num_adc_nids = preset->num_adc_nids;
765 spec->adc_nids = preset->adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100766 spec->capsrc_nids = preset->capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +0100767 spec->dig_in_nid = preset->dig_in_nid;
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100768
769 spec->unsol_event = preset->unsol_event;
770 spec->init_hook = preset->init_hook;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200771#ifdef CONFIG_SND_HDA_POWER_SAVE
772 spec->loopback.amplist = preset->loopbacks;
773#endif
Kailang Yangdf694da2005-12-05 19:42:22 +0100774}
775
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200776/* Enable GPIO mask and set output */
777static struct hda_verb alc_gpio1_init_verbs[] = {
778 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
779 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
780 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
781 { }
782};
783
784static struct hda_verb alc_gpio2_init_verbs[] = {
785 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
786 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
787 {0x01, AC_VERB_SET_GPIO_DATA, 0x02},
788 { }
789};
790
Kailang Yangbdd148a2007-05-08 15:19:08 +0200791static struct hda_verb alc_gpio3_init_verbs[] = {
792 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
793 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
794 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
795 { }
796};
797
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +0200798/*
799 * Fix hardware PLL issue
800 * On some codecs, the analog PLL gating control must be off while
801 * the default value is 1.
802 */
803static void alc_fix_pll(struct hda_codec *codec)
804{
805 struct alc_spec *spec = codec->spec;
806 unsigned int val;
807
808 if (!spec->pll_nid)
809 return;
810 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
811 spec->pll_coef_idx);
812 val = snd_hda_codec_read(codec, spec->pll_nid, 0,
813 AC_VERB_GET_PROC_COEF, 0);
814 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
815 spec->pll_coef_idx);
816 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_PROC_COEF,
817 val & ~(1 << spec->pll_coef_bit));
818}
819
820static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
821 unsigned int coef_idx, unsigned int coef_bit)
822{
823 struct alc_spec *spec = codec->spec;
824 spec->pll_nid = nid;
825 spec->pll_coef_idx = coef_idx;
826 spec->pll_coef_bit = coef_bit;
827 alc_fix_pll(codec);
828}
829
Kailang Yangc9b58002007-10-16 14:30:01 +0200830static void alc_sku_automute(struct hda_codec *codec)
831{
832 struct alc_spec *spec = codec->spec;
Kailang Yangc9b58002007-10-16 14:30:01 +0200833 unsigned int present;
834 unsigned int hp_nid = spec->autocfg.hp_pins[0];
835 unsigned int sp_nid = spec->autocfg.speaker_pins[0];
836
837 /* need to execute and sync at first */
838 snd_hda_codec_read(codec, hp_nid, 0, AC_VERB_SET_PIN_SENSE, 0);
839 present = snd_hda_codec_read(codec, hp_nid, 0,
840 AC_VERB_GET_PIN_SENSE, 0);
841 spec->jack_present = (present & 0x80000000) != 0;
Takashi Iwaif6c7e542008-02-12 18:32:23 +0100842 snd_hda_codec_write(codec, sp_nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
843 spec->jack_present ? 0 : PIN_OUT);
Kailang Yangc9b58002007-10-16 14:30:01 +0200844}
845
Takashi Iwai4605b712008-10-31 14:18:24 +0100846#if 0 /* it's broken in some acses -- temporarily disabled */
Kailang Yang7fb0d782008-10-15 11:12:35 +0200847static void alc_mic_automute(struct hda_codec *codec)
848{
849 struct alc_spec *spec = codec->spec;
850 unsigned int present;
851 unsigned int mic_nid = spec->autocfg.input_pins[AUTO_PIN_MIC];
852 unsigned int fmic_nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC];
853 unsigned int mix_nid = spec->capsrc_nids[0];
854 unsigned int capsrc_idx_mic, capsrc_idx_fmic;
855
856 capsrc_idx_mic = mic_nid - 0x18;
857 capsrc_idx_fmic = fmic_nid - 0x18;
858 present = snd_hda_codec_read(codec, mic_nid, 0,
859 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
860 snd_hda_codec_write(codec, mix_nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
861 0x7000 | (capsrc_idx_mic << 8) | (present ? 0 : 0x80));
862 snd_hda_codec_write(codec, mix_nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
863 0x7000 | (capsrc_idx_fmic << 8) | (present ? 0x80 : 0));
864 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, capsrc_idx_fmic,
865 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
866}
Takashi Iwai4605b712008-10-31 14:18:24 +0100867#else
868#define alc_mic_automute(codec) /* NOP */
869#endif /* disabled */
Kailang Yang7fb0d782008-10-15 11:12:35 +0200870
Kailang Yangc9b58002007-10-16 14:30:01 +0200871/* unsolicited event for HP jack sensing */
872static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res)
873{
874 if (codec->vendor_id == 0x10ec0880)
875 res >>= 28;
876 else
877 res >>= 26;
Kailang Yang7fb0d782008-10-15 11:12:35 +0200878 if (res == ALC880_HP_EVENT)
879 alc_sku_automute(codec);
Kailang Yangc9b58002007-10-16 14:30:01 +0200880
Kailang Yang7fb0d782008-10-15 11:12:35 +0200881 if (res == ALC880_MIC_EVENT)
882 alc_mic_automute(codec);
883}
884
885static void alc_inithook(struct hda_codec *codec)
886{
Kailang Yangc9b58002007-10-16 14:30:01 +0200887 alc_sku_automute(codec);
Kailang Yang7fb0d782008-10-15 11:12:35 +0200888 alc_mic_automute(codec);
Kailang Yangc9b58002007-10-16 14:30:01 +0200889}
890
Kailang Yangf9423e72008-05-27 12:32:25 +0200891/* additional initialization for ALC888 variants */
892static void alc888_coef_init(struct hda_codec *codec)
893{
894 unsigned int tmp;
895
896 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0);
897 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
898 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
899 if ((tmp & 0xf0) == 2)
900 /* alc888S-VC */
901 snd_hda_codec_read(codec, 0x20, 0,
902 AC_VERB_SET_PROC_COEF, 0x830);
903 else
904 /* alc888-VB */
905 snd_hda_codec_read(codec, 0x20, 0,
906 AC_VERB_SET_PROC_COEF, 0x3030);
907}
908
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200909/* 32-bit subsystem ID for BIOS loading in HD Audio codec.
910 * 31 ~ 16 : Manufacture ID
911 * 15 ~ 8 : SKU ID
912 * 7 ~ 0 : Assembly ID
913 * port-A --> pin 39/41, port-E --> pin 14/15, port-D --> pin 35/36
914 */
915static void alc_subsystem_id(struct hda_codec *codec,
916 unsigned int porta, unsigned int porte,
917 unsigned int portd)
918{
Kailang Yangc9b58002007-10-16 14:30:01 +0200919 unsigned int ass, tmp, i;
920 unsigned nid;
921 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200922
Kailang Yangc9b58002007-10-16 14:30:01 +0200923 ass = codec->subsystem_id & 0xffff;
924 if ((ass != codec->bus->pci->subsystem_device) && (ass & 1))
925 goto do_sku;
926
Kailang Yangea1fb292008-08-26 12:58:38 +0200927 /*
Kailang Yangc9b58002007-10-16 14:30:01 +0200928 * 31~30 : port conetcivity
929 * 29~21 : reserve
930 * 20 : PCBEEP input
931 * 19~16 : Check sum (15:1)
932 * 15~1 : Custom
933 * 0 : override
934 */
935 nid = 0x1d;
936 if (codec->vendor_id == 0x10ec0260)
937 nid = 0x17;
938 ass = snd_hda_codec_read(codec, nid, 0,
939 AC_VERB_GET_CONFIG_DEFAULT, 0);
940 if (!(ass & 1) && !(ass & 0x100000))
941 return;
942 if ((ass >> 30) != 1) /* no physical connection */
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200943 return;
944
Kailang Yangc9b58002007-10-16 14:30:01 +0200945 /* check sum */
946 tmp = 0;
947 for (i = 1; i < 16; i++) {
Kailang Yang8c427222008-01-10 13:03:59 +0100948 if ((ass >> i) & 1)
Kailang Yangc9b58002007-10-16 14:30:01 +0200949 tmp++;
950 }
951 if (((ass >> 16) & 0xf) != tmp)
952 return;
953do_sku:
954 /*
955 * 0 : override
956 * 1 : Swap Jack
957 * 2 : 0 --> Desktop, 1 --> Laptop
958 * 3~5 : External Amplifier control
959 * 7~6 : Reserved
960 */
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200961 tmp = (ass & 0x38) >> 3; /* external Amp control */
962 switch (tmp) {
963 case 1:
964 snd_hda_sequence_write(codec, alc_gpio1_init_verbs);
965 break;
966 case 3:
967 snd_hda_sequence_write(codec, alc_gpio2_init_verbs);
968 break;
Kailang Yangbdd148a2007-05-08 15:19:08 +0200969 case 7:
970 snd_hda_sequence_write(codec, alc_gpio3_init_verbs);
971 break;
Kailang Yangc9b58002007-10-16 14:30:01 +0200972 case 5: /* set EAPD output high */
Kailang Yangbdd148a2007-05-08 15:19:08 +0200973 switch (codec->vendor_id) {
Kailang Yangc9b58002007-10-16 14:30:01 +0200974 case 0x10ec0260:
975 snd_hda_codec_write(codec, 0x0f, 0,
976 AC_VERB_SET_EAPD_BTLENABLE, 2);
977 snd_hda_codec_write(codec, 0x10, 0,
978 AC_VERB_SET_EAPD_BTLENABLE, 2);
979 break;
980 case 0x10ec0262:
Kailang Yangbdd148a2007-05-08 15:19:08 +0200981 case 0x10ec0267:
982 case 0x10ec0268:
Kailang Yangc9b58002007-10-16 14:30:01 +0200983 case 0x10ec0269:
Kailang Yangf9423e72008-05-27 12:32:25 +0200984 case 0x10ec0660:
985 case 0x10ec0662:
986 case 0x10ec0663:
Kailang Yangc9b58002007-10-16 14:30:01 +0200987 case 0x10ec0862:
Takashi Iwai20a3a052008-05-23 17:52:53 +0200988 case 0x10ec0889:
Kailang Yangbdd148a2007-05-08 15:19:08 +0200989 snd_hda_codec_write(codec, 0x14, 0,
990 AC_VERB_SET_EAPD_BTLENABLE, 2);
991 snd_hda_codec_write(codec, 0x15, 0,
992 AC_VERB_SET_EAPD_BTLENABLE, 2);
Kailang Yangc9b58002007-10-16 14:30:01 +0200993 break;
Kailang Yangbdd148a2007-05-08 15:19:08 +0200994 }
Kailang Yangc9b58002007-10-16 14:30:01 +0200995 switch (codec->vendor_id) {
996 case 0x10ec0260:
997 snd_hda_codec_write(codec, 0x1a, 0,
998 AC_VERB_SET_COEF_INDEX, 7);
999 tmp = snd_hda_codec_read(codec, 0x1a, 0,
1000 AC_VERB_GET_PROC_COEF, 0);
1001 snd_hda_codec_write(codec, 0x1a, 0,
1002 AC_VERB_SET_COEF_INDEX, 7);
1003 snd_hda_codec_write(codec, 0x1a, 0,
1004 AC_VERB_SET_PROC_COEF,
1005 tmp | 0x2010);
1006 break;
1007 case 0x10ec0262:
1008 case 0x10ec0880:
1009 case 0x10ec0882:
1010 case 0x10ec0883:
1011 case 0x10ec0885:
Takashi Iwai20a3a052008-05-23 17:52:53 +02001012 case 0x10ec0889:
Kailang Yangc9b58002007-10-16 14:30:01 +02001013 snd_hda_codec_write(codec, 0x20, 0,
1014 AC_VERB_SET_COEF_INDEX, 7);
1015 tmp = snd_hda_codec_read(codec, 0x20, 0,
1016 AC_VERB_GET_PROC_COEF, 0);
1017 snd_hda_codec_write(codec, 0x20, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +02001018 AC_VERB_SET_COEF_INDEX, 7);
Kailang Yangc9b58002007-10-16 14:30:01 +02001019 snd_hda_codec_write(codec, 0x20, 0,
1020 AC_VERB_SET_PROC_COEF,
1021 tmp | 0x2010);
1022 break;
Kailang Yangf9423e72008-05-27 12:32:25 +02001023 case 0x10ec0888:
Takashi Iwai1082c742008-08-22 15:24:22 +02001024 /*alc888_coef_init(codec);*/ /* called in alc_init() */
Kailang Yangf9423e72008-05-27 12:32:25 +02001025 break;
Kailang Yangc9b58002007-10-16 14:30:01 +02001026 case 0x10ec0267:
1027 case 0x10ec0268:
1028 snd_hda_codec_write(codec, 0x20, 0,
1029 AC_VERB_SET_COEF_INDEX, 7);
1030 tmp = snd_hda_codec_read(codec, 0x20, 0,
1031 AC_VERB_GET_PROC_COEF, 0);
1032 snd_hda_codec_write(codec, 0x20, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +02001033 AC_VERB_SET_COEF_INDEX, 7);
Kailang Yangc9b58002007-10-16 14:30:01 +02001034 snd_hda_codec_write(codec, 0x20, 0,
1035 AC_VERB_SET_PROC_COEF,
1036 tmp | 0x3000);
1037 break;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001038 }
Kailang Yangc9b58002007-10-16 14:30:01 +02001039 default:
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001040 break;
1041 }
Kailang Yangea1fb292008-08-26 12:58:38 +02001042
Kailang Yang8c427222008-01-10 13:03:59 +01001043 /* is laptop or Desktop and enable the function "Mute internal speaker
Kailang Yangc9b58002007-10-16 14:30:01 +02001044 * when the external headphone out jack is plugged"
1045 */
Kailang Yang8c427222008-01-10 13:03:59 +01001046 if (!(ass & 0x8000))
Kailang Yangc9b58002007-10-16 14:30:01 +02001047 return;
1048 /*
1049 * 10~8 : Jack location
1050 * 12~11: Headphone out -> 00: PortA, 01: PortE, 02: PortD, 03: Resvered
1051 * 14~13: Resvered
1052 * 15 : 1 --> enable the function "Mute internal speaker
1053 * when the external headphone out jack is plugged"
1054 */
1055 if (!spec->autocfg.speaker_pins[0]) {
Kailang Yang8c427222008-01-10 13:03:59 +01001056 if (spec->autocfg.line_out_pins[0])
Kailang Yangc9b58002007-10-16 14:30:01 +02001057 spec->autocfg.speaker_pins[0] =
Kailang Yang8c427222008-01-10 13:03:59 +01001058 spec->autocfg.line_out_pins[0];
Kailang Yangc9b58002007-10-16 14:30:01 +02001059 else
1060 return;
1061 }
1062
1063 if (!spec->autocfg.hp_pins[0]) {
1064 tmp = (ass >> 11) & 0x3; /* HP to chassis */
1065 if (tmp == 0)
1066 spec->autocfg.hp_pins[0] = porta;
1067 else if (tmp == 1)
1068 spec->autocfg.hp_pins[0] = porte;
1069 else if (tmp == 2)
1070 spec->autocfg.hp_pins[0] = portd;
1071 else
1072 return;
1073 }
Kailang Yang7fb0d782008-10-15 11:12:35 +02001074 if (spec->autocfg.hp_pins[0])
1075 snd_hda_codec_write(codec, spec->autocfg.hp_pins[0], 0,
1076 AC_VERB_SET_UNSOLICITED_ENABLE,
1077 AC_USRSP_EN | ALC880_HP_EVENT);
Kailang Yangc9b58002007-10-16 14:30:01 +02001078
Takashi Iwai4605b712008-10-31 14:18:24 +01001079#if 0 /* it's broken in some acses -- temporarily disabled */
Kailang Yang7fb0d782008-10-15 11:12:35 +02001080 if (spec->autocfg.input_pins[AUTO_PIN_MIC] &&
1081 spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC])
1082 snd_hda_codec_write(codec,
1083 spec->autocfg.input_pins[AUTO_PIN_MIC], 0,
1084 AC_VERB_SET_UNSOLICITED_ENABLE,
1085 AC_USRSP_EN | ALC880_MIC_EVENT);
Takashi Iwai4605b712008-10-31 14:18:24 +01001086#endif /* disabled */
Kailang Yangea1fb292008-08-26 12:58:38 +02001087
Kailang Yangc9b58002007-10-16 14:30:01 +02001088 spec->unsol_event = alc_sku_unsol_event;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001089}
1090
Takashi Iwai41e41f12005-06-08 14:48:49 +02001091/*
Takashi Iwaif95474e2007-07-10 00:47:43 +02001092 * Fix-up pin default configurations
1093 */
1094
1095struct alc_pincfg {
1096 hda_nid_t nid;
1097 u32 val;
1098};
1099
1100static void alc_fix_pincfg(struct hda_codec *codec,
1101 const struct snd_pci_quirk *quirk,
1102 const struct alc_pincfg **pinfix)
1103{
1104 const struct alc_pincfg *cfg;
1105
1106 quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk);
1107 if (!quirk)
1108 return;
1109
1110 cfg = pinfix[quirk->value];
1111 for (; cfg->nid; cfg++) {
1112 int i;
1113 u32 val = cfg->val;
1114 for (i = 0; i < 4; i++) {
1115 snd_hda_codec_write(codec, cfg->nid, 0,
1116 AC_VERB_SET_CONFIG_DEFAULT_BYTES_0 + i,
1117 val & 0xff);
1118 val >>= 8;
1119 }
1120 }
1121}
1122
1123/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001124 * ALC880 3-stack model
1125 *
1126 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0e)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001127 * Pin assignment: Front = 0x14, Line-In/Surr = 0x1a, Mic/CLFE = 0x18,
1128 * F-Mic = 0x1b, HP = 0x19
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129 */
1130
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001131static hda_nid_t alc880_dac_nids[4] = {
1132 /* front, rear, clfe, rear_surr */
1133 0x02, 0x05, 0x04, 0x03
1134};
1135
1136static hda_nid_t alc880_adc_nids[3] = {
1137 /* ADC0-2 */
1138 0x07, 0x08, 0x09,
1139};
1140
1141/* The datasheet says the node 0x07 is connected from inputs,
1142 * but it shows zero connection in the real implementation on some devices.
Kailang Yangdf694da2005-12-05 19:42:22 +01001143 * Note: this is a 915GAV bug, fixed on 915GLV
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001145static hda_nid_t alc880_adc_nids_alt[2] = {
1146 /* ADC1-2 */
1147 0x08, 0x09,
1148};
1149
1150#define ALC880_DIGOUT_NID 0x06
1151#define ALC880_DIGIN_NID 0x0a
1152
1153static struct hda_input_mux alc880_capture_source = {
1154 .num_items = 4,
1155 .items = {
1156 { "Mic", 0x0 },
1157 { "Front Mic", 0x3 },
1158 { "Line", 0x2 },
1159 { "CD", 0x4 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001161};
1162
1163/* channel source setting (2/6 channel selection for 3-stack) */
1164/* 2ch mode */
1165static struct hda_verb alc880_threestack_ch2_init[] = {
1166 /* set line-in to input, mute it */
1167 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
1168 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1169 /* set mic-in to input vref 80%, mute it */
1170 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1171 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172 { } /* end */
1173};
1174
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001175/* 6ch mode */
1176static struct hda_verb alc880_threestack_ch6_init[] = {
1177 /* set line-in to output, unmute it */
1178 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1179 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1180 /* set mic-in to output, unmute it */
1181 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1182 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1183 { } /* end */
1184};
1185
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001186static struct hda_channel_mode alc880_threestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001187 { 2, alc880_threestack_ch2_init },
1188 { 6, alc880_threestack_ch6_init },
1189};
1190
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01001191static struct snd_kcontrol_new alc880_three_stack_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02001192 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001193 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02001194 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001195 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02001196 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1197 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001198 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1199 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1201 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1202 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1203 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1204 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1205 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1206 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
1207 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
1208 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
1209 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210 HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001211 {
1212 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1213 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01001214 .info = alc_ch_mode_info,
1215 .get = alc_ch_mode_get,
1216 .put = alc_ch_mode_put,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001217 },
1218 { } /* end */
1219};
1220
1221/* capture mixer elements */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01001222static struct snd_kcontrol_new alc880_capture_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001223 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
1224 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
1225 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT),
1226 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT),
1227 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT),
1228 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT),
1229 {
1230 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1231 /* The multiple "Capture Source" controls confuse alsamixer
1232 * So call somewhat different..
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001233 */
1234 /* .name = "Capture Source", */
1235 .name = "Input Source",
1236 .count = 3,
1237 .info = alc_mux_enum_info,
1238 .get = alc_mux_enum_get,
1239 .put = alc_mux_enum_put,
1240 },
1241 { } /* end */
1242};
1243
1244/* capture mixer elements (in case NID 0x07 not available) */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01001245static struct snd_kcontrol_new alc880_capture_alt_mixer[] = {
Takashi Iwai71fe7b82005-05-25 18:11:40 +02001246 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
1247 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
1248 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
1249 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250 {
1251 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1252 /* The multiple "Capture Source" controls confuse alsamixer
1253 * So call somewhat different..
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254 */
1255 /* .name = "Capture Source", */
1256 .name = "Input Source",
1257 .count = 2,
1258 .info = alc_mux_enum_info,
1259 .get = alc_mux_enum_get,
1260 .put = alc_mux_enum_put,
1261 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262};
1263
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001264
1265
1266/*
1267 * ALC880 5-stack model
1268 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001269 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0d),
1270 * Side = 0x02 (0xd)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001271 * Pin assignment: Front = 0x14, Surr = 0x17, CLFE = 0x16
1272 * Line-In/Side = 0x1a, Mic = 0x18, F-Mic = 0x1b, HP = 0x19
1273 */
1274
1275/* additional mixers to alc880_three_stack_mixer */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01001276static struct snd_kcontrol_new alc880_five_stack_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001277 HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001278 HDA_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279 { } /* end */
1280};
1281
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001282/* channel source setting (6/8 channel selection for 5-stack) */
1283/* 6ch mode */
1284static struct hda_verb alc880_fivestack_ch6_init[] = {
1285 /* set line-in to input, mute it */
1286 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
1287 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02001288 { } /* end */
1289};
1290
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001291/* 8ch mode */
1292static struct hda_verb alc880_fivestack_ch8_init[] = {
1293 /* set line-in to output, unmute it */
1294 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1295 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1296 { } /* end */
1297};
1298
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001299static struct hda_channel_mode alc880_fivestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001300 { 6, alc880_fivestack_ch6_init },
1301 { 8, alc880_fivestack_ch8_init },
1302};
1303
1304
1305/*
1306 * ALC880 6-stack model
1307 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001308 * DAC: Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e),
1309 * Side = 0x05 (0x0f)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001310 * Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, Side = 0x17,
1311 * Mic = 0x18, F-Mic = 0x19, Line = 0x1a, HP = 0x1b
1312 */
1313
1314static hda_nid_t alc880_6st_dac_nids[4] = {
1315 /* front, rear, clfe, rear_surr */
1316 0x02, 0x03, 0x04, 0x05
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02001317};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001318
1319static struct hda_input_mux alc880_6stack_capture_source = {
1320 .num_items = 4,
1321 .items = {
1322 { "Mic", 0x0 },
1323 { "Front Mic", 0x1 },
1324 { "Line", 0x2 },
1325 { "CD", 0x4 },
1326 },
1327};
1328
1329/* fixed 8-channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001330static struct hda_channel_mode alc880_sixstack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001331 { 8, NULL },
1332};
1333
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01001334static struct snd_kcontrol_new alc880_six_stack_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001335 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001336 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001337 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001338 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001339 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1340 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001341 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1342 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001343 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001344 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001345 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1346 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1347 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1348 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1349 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1350 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1351 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1352 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
1353 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
1354 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001355 {
1356 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1357 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01001358 .info = alc_ch_mode_info,
1359 .get = alc_ch_mode_get,
1360 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02001361 },
1362 { } /* end */
1363};
1364
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001365
1366/*
1367 * ALC880 W810 model
1368 *
1369 * W810 has rear IO for:
1370 * Front (DAC 02)
1371 * Surround (DAC 03)
1372 * Center/LFE (DAC 04)
1373 * Digital out (06)
1374 *
1375 * The system also has a pair of internal speakers, and a headphone jack.
1376 * These are both connected to Line2 on the codec, hence to DAC 02.
Kailang Yangea1fb292008-08-26 12:58:38 +02001377 *
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001378 * There is a variable resistor to control the speaker or headphone
1379 * volume. This is a hardware-only device without a software API.
1380 *
1381 * Plugging headphones in will disable the internal speakers. This is
1382 * implemented in hardware, not via the driver using jack sense. In
1383 * a similar fashion, plugging into the rear socket marked "front" will
1384 * disable both the speakers and headphones.
1385 *
1386 * For input, there's a microphone jack, and an "audio in" jack.
1387 * These may not do anything useful with this driver yet, because I
1388 * haven't setup any initialization verbs for these yet...
1389 */
1390
1391static hda_nid_t alc880_w810_dac_nids[3] = {
1392 /* front, rear/surround, clfe */
1393 0x02, 0x03, 0x04
1394};
1395
1396/* fixed 6 channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001397static struct hda_channel_mode alc880_w810_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001398 { 6, NULL }
1399};
1400
1401/* Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, HP = 0x1b */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01001402static struct snd_kcontrol_new alc880_w810_base_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001403 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001404 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001405 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001406 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001407 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1408 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001409 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1410 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001411 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
1412 { } /* end */
1413};
1414
1415
1416/*
1417 * Z710V model
1418 *
1419 * DAC: Front = 0x02 (0x0c), HP = 0x03 (0x0d)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001420 * Pin assignment: Front = 0x14, HP = 0x15, Mic = 0x18, Mic2 = 0x19(?),
1421 * Line = 0x1a
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001422 */
1423
1424static hda_nid_t alc880_z71v_dac_nids[1] = {
1425 0x02
1426};
1427#define ALC880_Z71V_HP_DAC 0x03
1428
1429/* fixed 2 channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001430static struct hda_channel_mode alc880_2_jack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001431 { 2, NULL }
1432};
1433
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01001434static struct snd_kcontrol_new alc880_z71v_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001435 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001436 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001437 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001438 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001439 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1440 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1441 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1442 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1443 { } /* end */
1444};
1445
1446
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001447/*
1448 * ALC880 F1734 model
1449 *
1450 * DAC: HP = 0x02 (0x0c), Front = 0x03 (0x0d)
1451 * Pin assignment: HP = 0x14, Front = 0x15, Mic = 0x18
1452 */
1453
1454static hda_nid_t alc880_f1734_dac_nids[1] = {
1455 0x03
1456};
1457#define ALC880_F1734_HP_DAC 0x02
1458
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01001459static struct snd_kcontrol_new alc880_f1734_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001460 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001461 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01001462 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1463 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001464 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1465 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Takashi Iwai937b4162008-02-11 14:52:36 +01001466 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1467 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001468 { } /* end */
1469};
1470
Takashi Iwai937b4162008-02-11 14:52:36 +01001471static struct hda_input_mux alc880_f1734_capture_source = {
1472 .num_items = 2,
1473 .items = {
1474 { "Mic", 0x1 },
1475 { "CD", 0x4 },
1476 },
1477};
1478
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001479
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001480/*
1481 * ALC880 ASUS model
1482 *
1483 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
1484 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
1485 * Mic = 0x18, Line = 0x1a
1486 */
1487
1488#define alc880_asus_dac_nids alc880_w810_dac_nids /* identical with w810 */
1489#define alc880_asus_modes alc880_threestack_modes /* 2/6 channel mode */
1490
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01001491static struct snd_kcontrol_new alc880_asus_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001492 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001493 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001494 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001495 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001496 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1497 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001498 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1499 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001500 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1501 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1502 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1503 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1504 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1505 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001506 {
1507 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1508 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01001509 .info = alc_ch_mode_info,
1510 .get = alc_ch_mode_get,
1511 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02001512 },
1513 { } /* end */
1514};
1515
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001516/*
1517 * ALC880 ASUS W1V model
1518 *
1519 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
1520 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
1521 * Mic = 0x18, Line = 0x1a, Line2 = 0x1b
1522 */
1523
1524/* additional mixers to alc880_asus_mixer */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01001525static struct snd_kcontrol_new alc880_asus_w1v_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02001526 HDA_CODEC_VOLUME("Line2 Playback Volume", 0x0b, 0x03, HDA_INPUT),
1527 HDA_CODEC_MUTE("Line2 Playback Switch", 0x0b, 0x03, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02001528 { } /* end */
1529};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001530
Takashi Iwai3c10a9d2005-08-23 20:02:27 +02001531/* additional mixers to alc880_asus_mixer */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01001532static struct snd_kcontrol_new alc880_pcbeep_mixer[] = {
Takashi Iwai3c10a9d2005-08-23 20:02:27 +02001533 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
1534 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
1535 { } /* end */
1536};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001537
Kailang Yangdf694da2005-12-05 19:42:22 +01001538/* TCL S700 */
1539static struct snd_kcontrol_new alc880_tcl_s700_mixer[] = {
1540 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1541 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
1542 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
1543 HDA_CODEC_VOLUME("CD Playback Volume", 0x0B, 0x04, HDA_INPUT),
1544 HDA_CODEC_MUTE("CD Playback Switch", 0x0B, 0x04, HDA_INPUT),
1545 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0B, 0x0, HDA_INPUT),
1546 HDA_CODEC_MUTE("Mic Playback Switch", 0x0B, 0x0, HDA_INPUT),
1547 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
1548 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
1549 {
1550 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1551 /* The multiple "Capture Source" controls confuse alsamixer
1552 * So call somewhat different..
Kailang Yangdf694da2005-12-05 19:42:22 +01001553 */
1554 /* .name = "Capture Source", */
1555 .name = "Input Source",
1556 .count = 1,
1557 .info = alc_mux_enum_info,
1558 .get = alc_mux_enum_get,
1559 .put = alc_mux_enum_put,
1560 },
1561 { } /* end */
1562};
1563
Kailang Yangccc656c2006-10-17 12:32:26 +02001564/* Uniwill */
1565static struct snd_kcontrol_new alc880_uniwill_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01001566 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1567 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
1568 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1569 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02001570 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1571 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
1572 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1573 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
1574 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1575 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1576 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1577 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1578 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1579 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1580 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1581 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
1582 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
1583 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
1584 {
1585 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1586 .name = "Channel Mode",
1587 .info = alc_ch_mode_info,
1588 .get = alc_ch_mode_get,
1589 .put = alc_ch_mode_put,
1590 },
1591 { } /* end */
1592};
1593
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01001594static struct snd_kcontrol_new alc880_fujitsu_mixer[] = {
1595 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1596 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
1597 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1598 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
1599 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1600 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1601 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1602 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1603 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
1604 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
1605 { } /* end */
1606};
1607
Kailang Yangccc656c2006-10-17 12:32:26 +02001608static struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01001609 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1610 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
1611 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1612 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02001613 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1614 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1615 { } /* end */
1616};
1617
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618/*
Takashi Iwai2134ea42008-01-10 16:53:55 +01001619 * virtual master controls
1620 */
1621
1622/*
1623 * slave controls for virtual master
1624 */
1625static const char *alc_slave_vols[] = {
1626 "Front Playback Volume",
1627 "Surround Playback Volume",
1628 "Center Playback Volume",
1629 "LFE Playback Volume",
1630 "Side Playback Volume",
1631 "Headphone Playback Volume",
1632 "Speaker Playback Volume",
1633 "Mono Playback Volume",
Takashi Iwai2134ea42008-01-10 16:53:55 +01001634 "Line-Out Playback Volume",
1635 NULL,
1636};
1637
1638static const char *alc_slave_sws[] = {
1639 "Front Playback Switch",
1640 "Surround Playback Switch",
1641 "Center Playback Switch",
1642 "LFE Playback Switch",
1643 "Side Playback Switch",
1644 "Headphone Playback Switch",
1645 "Speaker Playback Switch",
1646 "Mono Playback Switch",
Takashi Iwaiedb54a52008-01-29 12:47:02 +01001647 "IEC958 Playback Switch",
Takashi Iwai2134ea42008-01-10 16:53:55 +01001648 NULL,
1649};
1650
1651/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001652 * build control elements
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653 */
Takashi Iwai603c4012008-07-30 15:01:44 +02001654
1655static void alc_free_kctls(struct hda_codec *codec);
1656
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657static int alc_build_controls(struct hda_codec *codec)
1658{
1659 struct alc_spec *spec = codec->spec;
1660 int err;
1661 int i;
1662
1663 for (i = 0; i < spec->num_mixers; i++) {
1664 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
1665 if (err < 0)
1666 return err;
1667 }
1668
1669 if (spec->multiout.dig_out_nid) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001670 err = snd_hda_create_spdif_out_ctls(codec,
1671 spec->multiout.dig_out_nid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672 if (err < 0)
1673 return err;
Takashi Iwai9a081602008-02-12 18:37:26 +01001674 err = snd_hda_create_spdif_share_sw(codec,
1675 &spec->multiout);
1676 if (err < 0)
1677 return err;
1678 spec->multiout.share_spdif = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679 }
1680 if (spec->dig_in_nid) {
1681 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
1682 if (err < 0)
1683 return err;
1684 }
Takashi Iwai2134ea42008-01-10 16:53:55 +01001685
1686 /* if we have no master control, let's create it */
1687 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001688 unsigned int vmaster_tlv[4];
Takashi Iwai2134ea42008-01-10 16:53:55 +01001689 snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001690 HDA_OUTPUT, vmaster_tlv);
Takashi Iwai2134ea42008-01-10 16:53:55 +01001691 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001692 vmaster_tlv, alc_slave_vols);
Takashi Iwai2134ea42008-01-10 16:53:55 +01001693 if (err < 0)
1694 return err;
1695 }
1696 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
1697 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
1698 NULL, alc_slave_sws);
1699 if (err < 0)
1700 return err;
1701 }
1702
Takashi Iwai603c4012008-07-30 15:01:44 +02001703 alc_free_kctls(codec); /* no longer needed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704 return 0;
1705}
1706
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001707
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708/*
1709 * initialize the codec volumes, etc
1710 */
1711
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001712/*
1713 * generic initialization of ADC, input mixers and output mixers
1714 */
1715static struct hda_verb alc880_volume_init_verbs[] = {
1716 /*
1717 * Unmute ADC0-2 and set the default input to mic-in
1718 */
Takashi Iwai71fe7b82005-05-25 18:11:40 +02001719 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001720 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02001721 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001722 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02001723 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001724 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001726 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
1727 * mixer widget
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001728 * Note: PASD motherboards uses the Line In 2 as the input for front
1729 * panel mic (mic 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001731 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02001732 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1733 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
1734 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
1735 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
1736 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
1737 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
1738 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001740 /*
1741 * Set up output mixers (0x0c - 0x0f)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001743 /* set vol=0 to output mixers */
1744 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1745 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1746 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1747 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
1748 /* set up input amps for analog loopback */
1749 /* Amp Indices: DAC = 0, mixer = 1 */
Takashi Iwai05acb862005-06-10 19:50:25 +02001750 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1751 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02001752 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1753 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02001754 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1755 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02001756 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1757 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758
1759 { }
1760};
1761
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001762/*
1763 * 3-stack pin configuration:
1764 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
1765 */
1766static struct hda_verb alc880_pin_3stack_init_verbs[] = {
1767 /*
1768 * preset connection lists of input pins
1769 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
1770 */
1771 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
1772 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1773 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
1774
1775 /*
1776 * Set pin mode and muting
1777 */
1778 /* set front pin widgets 0x14 for output */
1779 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1780 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1781 /* Mic1 (rear panel) pin widget for input and vref at 80% */
1782 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1783 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1784 /* Mic2 (as headphone out) for HP output */
1785 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1786 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1787 /* Line In pin widget for input */
1788 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1789 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1790 /* Line2 (as front mic) pin widget for input and vref at 80% */
1791 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1792 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1793 /* CD pin widget for input */
1794 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1795
1796 { }
1797};
1798
1799/*
1800 * 5-stack pin configuration:
1801 * front = 0x14, surround = 0x17, clfe = 0x16, mic = 0x18, HP = 0x19,
1802 * line-in/side = 0x1a, f-mic = 0x1b
1803 */
1804static struct hda_verb alc880_pin_5stack_init_verbs[] = {
1805 /*
1806 * preset connection lists of input pins
1807 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
1808 */
1809 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1810 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/side */
1811
1812 /*
1813 * Set pin mode and muting
1814 */
1815 /* set pin widgets 0x14-0x17 for output */
Takashi Iwai05acb862005-06-10 19:50:25 +02001816 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1817 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1818 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1819 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001820 /* unmute pins for output (no gain on this amp) */
1821 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1822 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1823 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1824 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1825
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02001827 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001828 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1829 /* Mic2 (as headphone out) for HP output */
1830 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02001831 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001832 /* Line In pin widget for input */
1833 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1834 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1835 /* Line2 (as front mic) pin widget for input and vref at 80% */
1836 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1837 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1838 /* CD pin widget for input */
1839 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840
1841 { }
1842};
1843
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001844/*
1845 * W810 pin configuration:
1846 * front = 0x14, surround = 0x15, clfe = 0x16, HP = 0x1b
1847 */
1848static struct hda_verb alc880_pin_w810_init_verbs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849 /* hphone/speaker input selector: front DAC */
1850 {0x13, AC_VERB_SET_CONNECT_SEL, 0x0},
1851
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001852 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1853 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1854 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1855 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1856 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1857 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1858
1859 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02001860 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862 { }
1863};
1864
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001865/*
1866 * Z71V pin configuration:
1867 * Speaker-out = 0x14, HP = 0x15, Mic = 0x18, Line-in = 0x1a, Mic2 = 0x1b (?)
1868 */
1869static struct hda_verb alc880_pin_z71v_init_verbs[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02001870 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001871 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai05acb862005-06-10 19:50:25 +02001872 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001873 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02001874
Takashi Iwai16ded522005-06-10 19:58:24 +02001875 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001876 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02001877 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001878 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02001879
1880 { }
1881};
1882
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001883/*
1884 * 6-stack pin configuration:
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001885 * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18,
1886 * f-mic = 0x19, line = 0x1a, HP = 0x1b
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001887 */
1888static struct hda_verb alc880_pin_6stack_init_verbs[] = {
1889 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1890
Takashi Iwai16ded522005-06-10 19:58:24 +02001891 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001892 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001893 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001894 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001895 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001896 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001897 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001898 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1899
Takashi Iwai16ded522005-06-10 19:58:24 +02001900 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001901 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001902 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001903 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001904 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001905 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001906 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai16ded522005-06-10 19:58:24 +02001907 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02001908 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangea1fb292008-08-26 12:58:38 +02001909
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001910 { }
1911};
Takashi Iwai16ded522005-06-10 19:58:24 +02001912
Kailang Yangccc656c2006-10-17 12:32:26 +02001913/*
1914 * Uniwill pin configuration:
1915 * HP = 0x14, InternalSpeaker = 0x15, mic = 0x18, internal mic = 0x19,
1916 * line = 0x1a
1917 */
1918static struct hda_verb alc880_uniwill_init_verbs[] = {
1919 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1920
1921 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1922 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1923 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1924 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1925 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1926 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1927 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1928 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1929 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1930 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1931 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1932 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1933 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1934 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1935
1936 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1937 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1938 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1939 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1940 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1941 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1942 /* {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, */
1943 /* {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
1944 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1945
1946 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
1947 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
1948
1949 { }
1950};
1951
1952/*
1953* Uniwill P53
Kailang Yangea1fb292008-08-26 12:58:38 +02001954* HP = 0x14, InternalSpeaker = 0x15, mic = 0x19,
Kailang Yangccc656c2006-10-17 12:32:26 +02001955 */
1956static struct hda_verb alc880_uniwill_p53_init_verbs[] = {
1957 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
1958
1959 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1960 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1961 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1962 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1963 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1964 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1965 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1966 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1967 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1968 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1969 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
1970 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
1971
1972 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1973 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1974 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1975 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1976 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1977 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1978
1979 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
1980 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_DCVOL_EVENT},
1981
1982 { }
1983};
1984
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01001985static struct hda_verb alc880_beep_init_verbs[] = {
1986 { 0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) },
1987 { }
1988};
1989
Kailang Yangccc656c2006-10-17 12:32:26 +02001990/* toggle speaker-output according to the hp-jack state */
Takashi Iwai458a4fa2007-05-05 12:18:40 +02001991static void alc880_uniwill_hp_automute(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02001992{
1993 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02001994 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02001995
1996 present = snd_hda_codec_read(codec, 0x14, 0,
1997 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02001998 bits = present ? HDA_AMP_MUTE : 0;
1999 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
2000 HDA_AMP_MUTE, bits);
2001 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
2002 HDA_AMP_MUTE, bits);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02002003}
2004
2005/* auto-toggle front mic */
2006static void alc880_uniwill_mic_automute(struct hda_codec *codec)
2007{
2008 unsigned int present;
2009 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02002010
2011 present = snd_hda_codec_read(codec, 0x18, 0,
2012 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02002013 bits = present ? HDA_AMP_MUTE : 0;
2014 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02002015}
2016
2017static void alc880_uniwill_automute(struct hda_codec *codec)
2018{
2019 alc880_uniwill_hp_automute(codec);
2020 alc880_uniwill_mic_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02002021}
2022
2023static void alc880_uniwill_unsol_event(struct hda_codec *codec,
2024 unsigned int res)
2025{
2026 /* Looks like the unsol event is incompatible with the standard
2027 * definition. 4bit tag is placed at 28 bit!
2028 */
Takashi Iwai458a4fa2007-05-05 12:18:40 +02002029 switch (res >> 28) {
2030 case ALC880_HP_EVENT:
2031 alc880_uniwill_hp_automute(codec);
2032 break;
2033 case ALC880_MIC_EVENT:
2034 alc880_uniwill_mic_automute(codec);
2035 break;
2036 }
Kailang Yangccc656c2006-10-17 12:32:26 +02002037}
2038
2039static void alc880_uniwill_p53_hp_automute(struct hda_codec *codec)
2040{
2041 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002042 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02002043
2044 present = snd_hda_codec_read(codec, 0x14, 0,
2045 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02002046 bits = present ? HDA_AMP_MUTE : 0;
Jiang zhe64654c22008-04-14 13:26:21 +02002047 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, HDA_AMP_MUTE, bits);
Kailang Yangccc656c2006-10-17 12:32:26 +02002048}
2049
2050static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec)
2051{
2052 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02002053
Kailang Yangccc656c2006-10-17 12:32:26 +02002054 present = snd_hda_codec_read(codec, 0x21, 0,
Takashi Iwai47fd8302007-08-10 17:11:07 +02002055 AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
2056 present &= HDA_AMP_VOLMASK;
2057 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0,
2058 HDA_AMP_VOLMASK, present);
2059 snd_hda_codec_amp_stereo(codec, 0x0d, HDA_OUTPUT, 0,
2060 HDA_AMP_VOLMASK, present);
Kailang Yangccc656c2006-10-17 12:32:26 +02002061}
Takashi Iwai47fd8302007-08-10 17:11:07 +02002062
Kailang Yangccc656c2006-10-17 12:32:26 +02002063static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec,
2064 unsigned int res)
2065{
2066 /* Looks like the unsol event is incompatible with the standard
2067 * definition. 4bit tag is placed at 28 bit!
2068 */
2069 if ((res >> 28) == ALC880_HP_EVENT)
2070 alc880_uniwill_p53_hp_automute(codec);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002071 if ((res >> 28) == ALC880_DCVOL_EVENT)
Kailang Yangccc656c2006-10-17 12:32:26 +02002072 alc880_uniwill_p53_dcvol_automute(codec);
2073}
2074
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002075/*
2076 * F1734 pin configuration:
2077 * HP = 0x14, speaker-out = 0x15, mic = 0x18
2078 */
2079static struct hda_verb alc880_pin_f1734_init_verbs[] = {
Michael Gruberee7a9c72008-03-10 11:30:59 +01002080 {0x07, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002081 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
2082 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
2083 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
2084 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
2085
2086 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2087 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2088 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2089 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2090
2091 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2092 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Michael Gruberee7a9c72008-03-10 11:30:59 +01002093 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002094 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2095 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2096 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2097 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2098 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2099 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02002100
Takashi Iwai937b4162008-02-11 14:52:36 +01002101 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
2102 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_DCVOL_EVENT},
2103
Takashi Iwai16ded522005-06-10 19:58:24 +02002104 { }
2105};
2106
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002107/*
2108 * ASUS pin configuration:
2109 * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a
2110 */
2111static struct hda_verb alc880_pin_asus_init_verbs[] = {
2112 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
2113 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
2114 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
2115 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
2116
2117 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2118 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2119 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2120 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2121 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2122 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2123 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2124 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2125
2126 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2127 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2128 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2129 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2130 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2131 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2132 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2133 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2134 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangea1fb292008-08-26 12:58:38 +02002135
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002136 { }
2137};
2138
2139/* Enable GPIO mask and set output */
Kailang Yangbc9f98a2007-04-12 13:06:07 +02002140#define alc880_gpio1_init_verbs alc_gpio1_init_verbs
2141#define alc880_gpio2_init_verbs alc_gpio2_init_verbs
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002142
Kailang Yangdf694da2005-12-05 19:42:22 +01002143/* Clevo m520g init */
2144static struct hda_verb alc880_pin_clevo_init_verbs[] = {
2145 /* headphone output */
2146 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
2147 /* line-out */
2148 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2149 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2150 /* Line-in */
2151 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2152 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2153 /* CD */
2154 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2155 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2156 /* Mic1 (rear panel) */
2157 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2158 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2159 /* Mic2 (front panel) */
2160 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2161 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2162 /* headphone */
2163 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2164 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2165 /* change to EAPD mode */
2166 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
2167 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
2168
2169 { }
2170};
2171
2172static struct hda_verb alc880_pin_tcl_S700_init_verbs[] = {
Takashi Iwai4b146cb2006-07-28 14:42:36 +02002173 /* change to EAPD mode */
2174 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
2175 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
2176
Kailang Yangdf694da2005-12-05 19:42:22 +01002177 /* Headphone output */
2178 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2179 /* Front output*/
2180 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2181 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
2182
2183 /* Line In pin widget for input */
2184 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2185 /* CD pin widget for input */
2186 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2187 /* Mic1 (rear panel) pin widget for input and vref at 80% */
2188 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2189
2190 /* change to EAPD mode */
2191 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
2192 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
2193
2194 { }
2195};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002196
2197/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002198 * LG m1 express dual
2199 *
2200 * Pin assignment:
2201 * Rear Line-In/Out (blue): 0x14
2202 * Build-in Mic-In: 0x15
2203 * Speaker-out: 0x17
2204 * HP-Out (green): 0x1b
2205 * Mic-In/Out (red): 0x19
2206 * SPDIF-Out: 0x1e
2207 */
2208
2209/* To make 5.1 output working (green=Front, blue=Surr, red=CLFE) */
2210static hda_nid_t alc880_lg_dac_nids[3] = {
2211 0x05, 0x02, 0x03
2212};
2213
2214/* seems analog CD is not working */
2215static struct hda_input_mux alc880_lg_capture_source = {
2216 .num_items = 3,
2217 .items = {
2218 { "Mic", 0x1 },
2219 { "Line", 0x5 },
2220 { "Internal Mic", 0x6 },
2221 },
2222};
2223
2224/* 2,4,6 channel modes */
2225static struct hda_verb alc880_lg_ch2_init[] = {
2226 /* set line-in and mic-in to input */
2227 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2228 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2229 { }
2230};
2231
2232static struct hda_verb alc880_lg_ch4_init[] = {
2233 /* set line-in to out and mic-in to input */
2234 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
2235 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2236 { }
2237};
2238
2239static struct hda_verb alc880_lg_ch6_init[] = {
2240 /* set line-in and mic-in to output */
2241 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
2242 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
2243 { }
2244};
2245
2246static struct hda_channel_mode alc880_lg_ch_modes[3] = {
2247 { 2, alc880_lg_ch2_init },
2248 { 4, alc880_lg_ch4_init },
2249 { 6, alc880_lg_ch6_init },
2250};
2251
2252static struct snd_kcontrol_new alc880_lg_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01002253 HDA_CODEC_VOLUME("Front Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
2254 HDA_BIND_MUTE("Front Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002255 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2256 HDA_BIND_MUTE("Surround Playback Switch", 0x0c, 2, HDA_INPUT),
2257 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
2258 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
2259 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
2260 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
2261 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2262 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
2263 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x06, HDA_INPUT),
2264 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x06, HDA_INPUT),
2265 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x07, HDA_INPUT),
2266 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x07, HDA_INPUT),
2267 {
2268 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2269 .name = "Channel Mode",
2270 .info = alc_ch_mode_info,
2271 .get = alc_ch_mode_get,
2272 .put = alc_ch_mode_put,
2273 },
2274 { } /* end */
2275};
2276
2277static struct hda_verb alc880_lg_init_verbs[] = {
2278 /* set capture source to mic-in */
2279 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2280 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2281 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2282 /* mute all amp mixer inputs */
2283 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02002284 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
2285 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002286 /* line-in to input */
2287 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2288 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2289 /* built-in mic */
2290 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2291 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2292 /* speaker-out */
2293 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2294 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2295 /* mic-in to input */
2296 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
2297 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2298 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2299 /* HP-out */
2300 {0x13, AC_VERB_SET_CONNECT_SEL, 0x03},
2301 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2302 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2303 /* jack sense */
2304 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | 0x1},
2305 { }
2306};
2307
2308/* toggle speaker-output according to the hp-jack state */
2309static void alc880_lg_automute(struct hda_codec *codec)
2310{
2311 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002312 unsigned char bits;
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002313
2314 present = snd_hda_codec_read(codec, 0x1b, 0,
2315 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02002316 bits = present ? HDA_AMP_MUTE : 0;
2317 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
2318 HDA_AMP_MUTE, bits);
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002319}
2320
2321static void alc880_lg_unsol_event(struct hda_codec *codec, unsigned int res)
2322{
2323 /* Looks like the unsol event is incompatible with the standard
2324 * definition. 4bit tag is placed at 28 bit!
2325 */
2326 if ((res >> 28) == 0x01)
2327 alc880_lg_automute(codec);
2328}
2329
2330/*
Takashi Iwaid6815182006-03-23 16:06:23 +01002331 * LG LW20
2332 *
2333 * Pin assignment:
2334 * Speaker-out: 0x14
2335 * Mic-In: 0x18
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02002336 * Built-in Mic-In: 0x19
2337 * Line-In: 0x1b
2338 * HP-Out: 0x1a
Takashi Iwaid6815182006-03-23 16:06:23 +01002339 * SPDIF-Out: 0x1e
2340 */
2341
Takashi Iwaid6815182006-03-23 16:06:23 +01002342static struct hda_input_mux alc880_lg_lw_capture_source = {
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02002343 .num_items = 3,
Takashi Iwaid6815182006-03-23 16:06:23 +01002344 .items = {
2345 { "Mic", 0x0 },
2346 { "Internal Mic", 0x1 },
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02002347 { "Line In", 0x2 },
Takashi Iwaid6815182006-03-23 16:06:23 +01002348 },
2349};
2350
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002351#define alc880_lg_lw_modes alc880_threestack_modes
2352
Takashi Iwaid6815182006-03-23 16:06:23 +01002353static struct snd_kcontrol_new alc880_lg_lw_mixer[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002354 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2355 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
2356 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
2357 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
2358 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2359 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
2360 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2361 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
2362 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2363 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaid6815182006-03-23 16:06:23 +01002364 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2365 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2366 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
2367 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002368 {
2369 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2370 .name = "Channel Mode",
2371 .info = alc_ch_mode_info,
2372 .get = alc_ch_mode_get,
2373 .put = alc_ch_mode_put,
2374 },
Takashi Iwaid6815182006-03-23 16:06:23 +01002375 { } /* end */
2376};
2377
2378static struct hda_verb alc880_lg_lw_init_verbs[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02002379 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2380 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
2381 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
2382
Takashi Iwaid6815182006-03-23 16:06:23 +01002383 /* set capture source to mic-in */
2384 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2385 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2386 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02002387 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaid6815182006-03-23 16:06:23 +01002388 /* speaker-out */
2389 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2390 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2391 /* HP-out */
Takashi Iwaid6815182006-03-23 16:06:23 +01002392 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2393 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2394 /* mic-in to input */
2395 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2396 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2397 /* built-in mic */
2398 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2399 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2400 /* jack sense */
2401 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | 0x1},
2402 { }
2403};
2404
2405/* toggle speaker-output according to the hp-jack state */
2406static void alc880_lg_lw_automute(struct hda_codec *codec)
2407{
2408 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002409 unsigned char bits;
Takashi Iwaid6815182006-03-23 16:06:23 +01002410
2411 present = snd_hda_codec_read(codec, 0x1b, 0,
2412 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02002413 bits = present ? HDA_AMP_MUTE : 0;
2414 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
2415 HDA_AMP_MUTE, bits);
Takashi Iwaid6815182006-03-23 16:06:23 +01002416}
2417
2418static void alc880_lg_lw_unsol_event(struct hda_codec *codec, unsigned int res)
2419{
2420 /* Looks like the unsol event is incompatible with the standard
2421 * definition. 4bit tag is placed at 28 bit!
2422 */
2423 if ((res >> 28) == 0x01)
2424 alc880_lg_lw_automute(codec);
2425}
2426
Takashi Iwaidf99cd32008-04-25 15:25:04 +02002427static struct snd_kcontrol_new alc880_medion_rim_mixer[] = {
2428 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2429 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
2430 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2431 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2432 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2433 HDA_CODEC_MUTE("Internal Playback Switch", 0x0b, 0x1, HDA_INPUT),
2434 { } /* end */
2435};
2436
2437static struct hda_input_mux alc880_medion_rim_capture_source = {
2438 .num_items = 2,
2439 .items = {
2440 { "Mic", 0x0 },
2441 { "Internal Mic", 0x1 },
2442 },
2443};
2444
2445static struct hda_verb alc880_medion_rim_init_verbs[] = {
2446 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2447
2448 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2449 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2450
2451 /* Mic1 (rear panel) pin widget for input and vref at 80% */
2452 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2453 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2454 /* Mic2 (as headphone out) for HP output */
2455 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2456 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2457 /* Internal Speaker */
2458 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2459 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2460
2461 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
2462 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
2463
2464 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
2465 { }
2466};
2467
2468/* toggle speaker-output according to the hp-jack state */
2469static void alc880_medion_rim_automute(struct hda_codec *codec)
2470{
2471 unsigned int present;
2472 unsigned char bits;
2473
2474 present = snd_hda_codec_read(codec, 0x14, 0,
2475 AC_VERB_GET_PIN_SENSE, 0)
2476 & AC_PINSENSE_PRESENCE;
2477 bits = present ? HDA_AMP_MUTE : 0;
2478 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
2479 HDA_AMP_MUTE, bits);
2480 if (present)
2481 snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0);
2482 else
2483 snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 2);
2484}
2485
2486static void alc880_medion_rim_unsol_event(struct hda_codec *codec,
2487 unsigned int res)
2488{
2489 /* Looks like the unsol event is incompatible with the standard
2490 * definition. 4bit tag is placed at 28 bit!
2491 */
2492 if ((res >> 28) == ALC880_HP_EVENT)
2493 alc880_medion_rim_automute(codec);
2494}
2495
Takashi Iwaicb53c622007-08-10 17:21:45 +02002496#ifdef CONFIG_SND_HDA_POWER_SAVE
2497static struct hda_amp_list alc880_loopbacks[] = {
2498 { 0x0b, HDA_INPUT, 0 },
2499 { 0x0b, HDA_INPUT, 1 },
2500 { 0x0b, HDA_INPUT, 2 },
2501 { 0x0b, HDA_INPUT, 3 },
2502 { 0x0b, HDA_INPUT, 4 },
2503 { } /* end */
2504};
2505
2506static struct hda_amp_list alc880_lg_loopbacks[] = {
2507 { 0x0b, HDA_INPUT, 1 },
2508 { 0x0b, HDA_INPUT, 6 },
2509 { 0x0b, HDA_INPUT, 7 },
2510 { } /* end */
2511};
2512#endif
2513
Takashi Iwaid6815182006-03-23 16:06:23 +01002514/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002515 * Common callbacks
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002516 */
Takashi Iwai16ded522005-06-10 19:58:24 +02002517
Linus Torvalds1da177e2005-04-16 15:20:36 -07002518static int alc_init(struct hda_codec *codec)
2519{
2520 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002521 unsigned int i;
2522
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02002523 alc_fix_pll(codec);
Takashi Iwai1082c742008-08-22 15:24:22 +02002524 if (codec->vendor_id == 0x10ec0888)
2525 alc888_coef_init(codec);
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02002526
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002527 for (i = 0; i < spec->num_init_verbs; i++)
2528 snd_hda_sequence_write(codec, spec->init_verbs[i]);
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002529
2530 if (spec->init_hook)
2531 spec->init_hook(codec);
2532
Linus Torvalds1da177e2005-04-16 15:20:36 -07002533 return 0;
2534}
2535
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002536static void alc_unsol_event(struct hda_codec *codec, unsigned int res)
2537{
2538 struct alc_spec *spec = codec->spec;
2539
2540 if (spec->unsol_event)
2541 spec->unsol_event(codec, res);
2542}
2543
Takashi Iwaicb53c622007-08-10 17:21:45 +02002544#ifdef CONFIG_SND_HDA_POWER_SAVE
2545static int alc_check_power_status(struct hda_codec *codec, hda_nid_t nid)
2546{
2547 struct alc_spec *spec = codec->spec;
2548 return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
2549}
2550#endif
2551
Linus Torvalds1da177e2005-04-16 15:20:36 -07002552/*
2553 * Analog playback callbacks
2554 */
2555static int alc880_playback_pcm_open(struct hda_pcm_stream *hinfo,
2556 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002557 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558{
2559 struct alc_spec *spec = codec->spec;
Takashi Iwai9a081602008-02-12 18:37:26 +01002560 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
2561 hinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002562}
2563
2564static int alc880_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
2565 struct hda_codec *codec,
2566 unsigned int stream_tag,
2567 unsigned int format,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002568 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002569{
2570 struct alc_spec *spec = codec->spec;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002571 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
2572 stream_tag, format, substream);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002573}
2574
2575static int alc880_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
2576 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002577 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002578{
2579 struct alc_spec *spec = codec->spec;
2580 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
2581}
2582
2583/*
2584 * Digital out
2585 */
2586static int alc880_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
2587 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002588 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002589{
2590 struct alc_spec *spec = codec->spec;
2591 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
2592}
2593
Takashi Iwai6b97eb42007-04-05 14:51:48 +02002594static int alc880_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
2595 struct hda_codec *codec,
2596 unsigned int stream_tag,
2597 unsigned int format,
2598 struct snd_pcm_substream *substream)
2599{
2600 struct alc_spec *spec = codec->spec;
2601 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
2602 stream_tag, format, substream);
2603}
2604
Linus Torvalds1da177e2005-04-16 15:20:36 -07002605static int alc880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
2606 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002607 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608{
2609 struct alc_spec *spec = codec->spec;
2610 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
2611}
2612
2613/*
2614 * Analog capture
2615 */
Takashi Iwai63300792008-01-24 15:31:36 +01002616static int alc880_alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002617 struct hda_codec *codec,
2618 unsigned int stream_tag,
2619 unsigned int format,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002620 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002621{
2622 struct alc_spec *spec = codec->spec;
2623
Takashi Iwai63300792008-01-24 15:31:36 +01002624 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1],
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625 stream_tag, 0, format);
2626 return 0;
2627}
2628
Takashi Iwai63300792008-01-24 15:31:36 +01002629static int alc880_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002630 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002631 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002632{
2633 struct alc_spec *spec = codec->spec;
2634
Takashi Iwai888afa12008-03-18 09:57:50 +01002635 snd_hda_codec_cleanup_stream(codec,
2636 spec->adc_nids[substream->number + 1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002637 return 0;
2638}
2639
2640
2641/*
2642 */
2643static struct hda_pcm_stream alc880_pcm_analog_playback = {
2644 .substreams = 1,
2645 .channels_min = 2,
2646 .channels_max = 8,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002647 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002648 .ops = {
2649 .open = alc880_playback_pcm_open,
2650 .prepare = alc880_playback_pcm_prepare,
2651 .cleanup = alc880_playback_pcm_cleanup
2652 },
2653};
2654
2655static struct hda_pcm_stream alc880_pcm_analog_capture = {
Takashi Iwai63300792008-01-24 15:31:36 +01002656 .substreams = 1,
2657 .channels_min = 2,
2658 .channels_max = 2,
2659 /* NID is set in alc_build_pcms */
2660};
2661
2662static struct hda_pcm_stream alc880_pcm_analog_alt_playback = {
2663 .substreams = 1,
2664 .channels_min = 2,
2665 .channels_max = 2,
2666 /* NID is set in alc_build_pcms */
2667};
2668
2669static struct hda_pcm_stream alc880_pcm_analog_alt_capture = {
2670 .substreams = 2, /* can be overridden */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671 .channels_min = 2,
2672 .channels_max = 2,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002673 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002674 .ops = {
Takashi Iwai63300792008-01-24 15:31:36 +01002675 .prepare = alc880_alt_capture_pcm_prepare,
2676 .cleanup = alc880_alt_capture_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677 },
2678};
2679
2680static struct hda_pcm_stream alc880_pcm_digital_playback = {
2681 .substreams = 1,
2682 .channels_min = 2,
2683 .channels_max = 2,
2684 /* NID is set in alc_build_pcms */
2685 .ops = {
2686 .open = alc880_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02002687 .close = alc880_dig_playback_pcm_close,
2688 .prepare = alc880_dig_playback_pcm_prepare
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689 },
2690};
2691
2692static struct hda_pcm_stream alc880_pcm_digital_capture = {
2693 .substreams = 1,
2694 .channels_min = 2,
2695 .channels_max = 2,
2696 /* NID is set in alc_build_pcms */
2697};
2698
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01002699/* Used by alc_build_pcms to flag that a PCM has no playback stream */
Takashi Iwai63300792008-01-24 15:31:36 +01002700static struct hda_pcm_stream alc_pcm_null_stream = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01002701 .substreams = 0,
2702 .channels_min = 0,
2703 .channels_max = 0,
2704};
2705
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706static int alc_build_pcms(struct hda_codec *codec)
2707{
2708 struct alc_spec *spec = codec->spec;
2709 struct hda_pcm *info = spec->pcm_rec;
2710 int i;
2711
2712 codec->num_pcms = 1;
2713 codec->pcm_info = info;
2714
2715 info->name = spec->stream_name_analog;
Takashi Iwai4a471b72005-12-07 13:56:29 +01002716 if (spec->stream_analog_playback) {
Takashi Iwaida3cec32008-08-08 17:12:14 +02002717 if (snd_BUG_ON(!spec->multiout.dac_nids))
2718 return -EINVAL;
Takashi Iwai4a471b72005-12-07 13:56:29 +01002719 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
2720 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
2721 }
2722 if (spec->stream_analog_capture) {
Takashi Iwaida3cec32008-08-08 17:12:14 +02002723 if (snd_BUG_ON(!spec->adc_nids))
2724 return -EINVAL;
Takashi Iwai4a471b72005-12-07 13:56:29 +01002725 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
2726 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
2727 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728
Takashi Iwai4a471b72005-12-07 13:56:29 +01002729 if (spec->channel_mode) {
2730 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0;
2731 for (i = 0; i < spec->num_channel_mode; i++) {
2732 if (spec->channel_mode[i].channels > info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max) {
2733 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->channel_mode[i].channels;
2734 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735 }
2736 }
2737
Takashi Iwaie08a0072006-09-07 17:52:14 +02002738 /* SPDIF for stream index #1 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
Takashi Iwaie08a0072006-09-07 17:52:14 +02002740 codec->num_pcms = 2;
Takashi Iwaic06134d2006-10-11 18:49:13 +02002741 info = spec->pcm_rec + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742 info->name = spec->stream_name_digital;
Takashi Iwai7ba72ba2008-02-06 14:03:20 +01002743 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Takashi Iwai4a471b72005-12-07 13:56:29 +01002744 if (spec->multiout.dig_out_nid &&
2745 spec->stream_digital_playback) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002746 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_digital_playback);
2747 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
2748 }
Takashi Iwai4a471b72005-12-07 13:56:29 +01002749 if (spec->dig_in_nid &&
2750 spec->stream_digital_capture) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002751 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_digital_capture);
2752 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
2753 }
Takashi Iwai963f8032008-08-11 10:04:40 +02002754 /* FIXME: do we need this for all Realtek codec models? */
2755 codec->spdif_status_reset = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756 }
2757
Takashi Iwaie08a0072006-09-07 17:52:14 +02002758 /* If the use of more than one ADC is requested for the current
2759 * model, configure a second analog capture-only PCM.
2760 */
2761 /* Additional Analaog capture for index #2 */
Takashi Iwai63300792008-01-24 15:31:36 +01002762 if ((spec->alt_dac_nid && spec->stream_analog_alt_playback) ||
2763 (spec->num_adc_nids > 1 && spec->stream_analog_alt_capture)) {
Takashi Iwaie08a0072006-09-07 17:52:14 +02002764 codec->num_pcms = 3;
Takashi Iwaic06134d2006-10-11 18:49:13 +02002765 info = spec->pcm_rec + 2;
Takashi Iwaie08a0072006-09-07 17:52:14 +02002766 info->name = spec->stream_name_analog;
Takashi Iwai63300792008-01-24 15:31:36 +01002767 if (spec->alt_dac_nid) {
2768 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
2769 *spec->stream_analog_alt_playback;
2770 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
2771 spec->alt_dac_nid;
2772 } else {
2773 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
2774 alc_pcm_null_stream;
2775 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
2776 }
2777 if (spec->num_adc_nids > 1) {
2778 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
2779 *spec->stream_analog_alt_capture;
2780 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
2781 spec->adc_nids[1];
2782 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams =
2783 spec->num_adc_nids - 1;
2784 } else {
2785 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
2786 alc_pcm_null_stream;
2787 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0;
Takashi Iwaie08a0072006-09-07 17:52:14 +02002788 }
2789 }
2790
Linus Torvalds1da177e2005-04-16 15:20:36 -07002791 return 0;
2792}
2793
Takashi Iwai603c4012008-07-30 15:01:44 +02002794static void alc_free_kctls(struct hda_codec *codec)
2795{
2796 struct alc_spec *spec = codec->spec;
2797
2798 if (spec->kctls.list) {
2799 struct snd_kcontrol_new *kctl = spec->kctls.list;
2800 int i;
2801 for (i = 0; i < spec->kctls.used; i++)
2802 kfree(kctl[i].name);
2803 }
2804 snd_array_free(&spec->kctls);
2805}
2806
Linus Torvalds1da177e2005-04-16 15:20:36 -07002807static void alc_free(struct hda_codec *codec)
2808{
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002809 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002810
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002811 if (!spec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002812 return;
2813
Takashi Iwai603c4012008-07-30 15:01:44 +02002814 alc_free_kctls(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002815 kfree(spec);
Takashi Iwai7943a8a2008-04-16 17:29:09 +02002816 codec->spec = NULL; /* to be sure */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002817}
2818
Takashi Iwaie044c392008-10-27 16:56:24 +01002819#ifdef SND_HDA_NEEDS_RESUME
2820static void store_pin_configs(struct hda_codec *codec)
2821{
2822 struct alc_spec *spec = codec->spec;
2823 hda_nid_t nid, end_nid;
2824
2825 end_nid = codec->start_nid + codec->num_nodes;
2826 for (nid = codec->start_nid; nid < end_nid; nid++) {
2827 unsigned int wid_caps = get_wcaps(codec, nid);
2828 unsigned int wid_type =
2829 (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
2830 if (wid_type != AC_WID_PIN)
2831 continue;
2832 if (spec->num_pins >= ARRAY_SIZE(spec->pin_nids))
2833 break;
2834 spec->pin_nids[spec->num_pins] = nid;
2835 spec->pin_cfgs[spec->num_pins] =
2836 snd_hda_codec_read(codec, nid, 0,
2837 AC_VERB_GET_CONFIG_DEFAULT, 0);
2838 spec->num_pins++;
2839 }
2840}
2841
2842static void resume_pin_configs(struct hda_codec *codec)
2843{
2844 struct alc_spec *spec = codec->spec;
2845 int i;
2846
2847 for (i = 0; i < spec->num_pins; i++) {
2848 hda_nid_t pin_nid = spec->pin_nids[i];
2849 unsigned int pin_config = spec->pin_cfgs[i];
2850 snd_hda_codec_write(codec, pin_nid, 0,
2851 AC_VERB_SET_CONFIG_DEFAULT_BYTES_0,
2852 pin_config & 0x000000ff);
2853 snd_hda_codec_write(codec, pin_nid, 0,
2854 AC_VERB_SET_CONFIG_DEFAULT_BYTES_1,
2855 (pin_config & 0x0000ff00) >> 8);
2856 snd_hda_codec_write(codec, pin_nid, 0,
2857 AC_VERB_SET_CONFIG_DEFAULT_BYTES_2,
2858 (pin_config & 0x00ff0000) >> 16);
2859 snd_hda_codec_write(codec, pin_nid, 0,
2860 AC_VERB_SET_CONFIG_DEFAULT_BYTES_3,
2861 pin_config >> 24);
2862 }
2863}
2864
2865static int alc_resume(struct hda_codec *codec)
2866{
2867 resume_pin_configs(codec);
2868 codec->patch_ops.init(codec);
2869 snd_hda_codec_resume_amp(codec);
2870 snd_hda_codec_resume_cache(codec);
2871 return 0;
2872}
2873#else
2874#define store_pin_configs(codec)
2875#endif
2876
Linus Torvalds1da177e2005-04-16 15:20:36 -07002877/*
2878 */
2879static struct hda_codec_ops alc_patch_ops = {
2880 .build_controls = alc_build_controls,
2881 .build_pcms = alc_build_pcms,
2882 .init = alc_init,
2883 .free = alc_free,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002884 .unsol_event = alc_unsol_event,
Takashi Iwaie044c392008-10-27 16:56:24 +01002885#ifdef SND_HDA_NEEDS_RESUME
2886 .resume = alc_resume,
2887#endif
Takashi Iwaicb53c622007-08-10 17:21:45 +02002888#ifdef CONFIG_SND_HDA_POWER_SAVE
2889 .check_power_status = alc_check_power_status,
2890#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002891};
2892
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002893
2894/*
2895 * Test configuration for debugging
2896 *
2897 * Almost all inputs/outputs are enabled. I/O pins can be configured via
2898 * enum controls.
2899 */
2900#ifdef CONFIG_SND_DEBUG
2901static hda_nid_t alc880_test_dac_nids[4] = {
2902 0x02, 0x03, 0x04, 0x05
2903};
2904
2905static struct hda_input_mux alc880_test_capture_source = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002906 .num_items = 7,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002907 .items = {
2908 { "In-1", 0x0 },
2909 { "In-2", 0x1 },
2910 { "In-3", 0x2 },
2911 { "In-4", 0x3 },
2912 { "CD", 0x4 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002913 { "Front", 0x5 },
2914 { "Surround", 0x6 },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002915 },
2916};
2917
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002918static struct hda_channel_mode alc880_test_modes[4] = {
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002919 { 2, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02002920 { 4, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002921 { 6, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02002922 { 8, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002923};
2924
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002925static int alc_test_pin_ctl_info(struct snd_kcontrol *kcontrol,
2926 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002927{
2928 static char *texts[] = {
2929 "N/A", "Line Out", "HP Out",
2930 "In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%"
2931 };
2932 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2933 uinfo->count = 1;
2934 uinfo->value.enumerated.items = 8;
2935 if (uinfo->value.enumerated.item >= 8)
2936 uinfo->value.enumerated.item = 7;
2937 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
2938 return 0;
2939}
2940
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002941static int alc_test_pin_ctl_get(struct snd_kcontrol *kcontrol,
2942 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002943{
2944 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2945 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
2946 unsigned int pin_ctl, item = 0;
2947
2948 pin_ctl = snd_hda_codec_read(codec, nid, 0,
2949 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
2950 if (pin_ctl & AC_PINCTL_OUT_EN) {
2951 if (pin_ctl & AC_PINCTL_HP_EN)
2952 item = 2;
2953 else
2954 item = 1;
2955 } else if (pin_ctl & AC_PINCTL_IN_EN) {
2956 switch (pin_ctl & AC_PINCTL_VREFEN) {
2957 case AC_PINCTL_VREF_HIZ: item = 3; break;
2958 case AC_PINCTL_VREF_50: item = 4; break;
2959 case AC_PINCTL_VREF_GRD: item = 5; break;
2960 case AC_PINCTL_VREF_80: item = 6; break;
2961 case AC_PINCTL_VREF_100: item = 7; break;
2962 }
2963 }
2964 ucontrol->value.enumerated.item[0] = item;
2965 return 0;
2966}
2967
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002968static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol,
2969 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002970{
2971 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2972 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
2973 static unsigned int ctls[] = {
2974 0, AC_PINCTL_OUT_EN, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN,
2975 AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ,
2976 AC_PINCTL_IN_EN | AC_PINCTL_VREF_50,
2977 AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD,
2978 AC_PINCTL_IN_EN | AC_PINCTL_VREF_80,
2979 AC_PINCTL_IN_EN | AC_PINCTL_VREF_100,
2980 };
2981 unsigned int old_ctl, new_ctl;
2982
2983 old_ctl = snd_hda_codec_read(codec, nid, 0,
2984 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
2985 new_ctl = ctls[ucontrol->value.enumerated.item[0]];
2986 if (old_ctl != new_ctl) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002987 int val;
2988 snd_hda_codec_write_cache(codec, nid, 0,
2989 AC_VERB_SET_PIN_WIDGET_CONTROL,
2990 new_ctl);
Takashi Iwai47fd8302007-08-10 17:11:07 +02002991 val = ucontrol->value.enumerated.item[0] >= 3 ?
2992 HDA_AMP_MUTE : 0;
2993 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
2994 HDA_AMP_MUTE, val);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002995 return 1;
2996 }
2997 return 0;
2998}
2999
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003000static int alc_test_pin_src_info(struct snd_kcontrol *kcontrol,
3001 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003002{
3003 static char *texts[] = {
3004 "Front", "Surround", "CLFE", "Side"
3005 };
3006 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
3007 uinfo->count = 1;
3008 uinfo->value.enumerated.items = 4;
3009 if (uinfo->value.enumerated.item >= 4)
3010 uinfo->value.enumerated.item = 3;
3011 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
3012 return 0;
3013}
3014
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003015static int alc_test_pin_src_get(struct snd_kcontrol *kcontrol,
3016 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003017{
3018 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3019 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
3020 unsigned int sel;
3021
3022 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0);
3023 ucontrol->value.enumerated.item[0] = sel & 3;
3024 return 0;
3025}
3026
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003027static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol,
3028 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003029{
3030 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3031 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
3032 unsigned int sel;
3033
3034 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3;
3035 if (ucontrol->value.enumerated.item[0] != sel) {
3036 sel = ucontrol->value.enumerated.item[0] & 3;
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003037 snd_hda_codec_write_cache(codec, nid, 0,
3038 AC_VERB_SET_CONNECT_SEL, sel);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003039 return 1;
3040 }
3041 return 0;
3042}
3043
3044#define PIN_CTL_TEST(xname,nid) { \
3045 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
3046 .name = xname, \
3047 .info = alc_test_pin_ctl_info, \
3048 .get = alc_test_pin_ctl_get, \
3049 .put = alc_test_pin_ctl_put, \
3050 .private_value = nid \
3051 }
3052
3053#define PIN_SRC_TEST(xname,nid) { \
3054 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
3055 .name = xname, \
3056 .info = alc_test_pin_src_info, \
3057 .get = alc_test_pin_src_get, \
3058 .put = alc_test_pin_src_put, \
3059 .private_value = nid \
3060 }
3061
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01003062static struct snd_kcontrol_new alc880_test_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02003063 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3064 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
3065 HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
3066 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003067 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
3068 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
3069 HDA_BIND_MUTE("CLFE Playback Switch", 0x0e, 2, HDA_INPUT),
3070 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003071 PIN_CTL_TEST("Front Pin Mode", 0x14),
3072 PIN_CTL_TEST("Surround Pin Mode", 0x15),
3073 PIN_CTL_TEST("CLFE Pin Mode", 0x16),
3074 PIN_CTL_TEST("Side Pin Mode", 0x17),
3075 PIN_CTL_TEST("In-1 Pin Mode", 0x18),
3076 PIN_CTL_TEST("In-2 Pin Mode", 0x19),
3077 PIN_CTL_TEST("In-3 Pin Mode", 0x1a),
3078 PIN_CTL_TEST("In-4 Pin Mode", 0x1b),
3079 PIN_SRC_TEST("In-1 Pin Source", 0x18),
3080 PIN_SRC_TEST("In-2 Pin Source", 0x19),
3081 PIN_SRC_TEST("In-3 Pin Source", 0x1a),
3082 PIN_SRC_TEST("In-4 Pin Source", 0x1b),
3083 HDA_CODEC_VOLUME("In-1 Playback Volume", 0x0b, 0x0, HDA_INPUT),
3084 HDA_CODEC_MUTE("In-1 Playback Switch", 0x0b, 0x0, HDA_INPUT),
3085 HDA_CODEC_VOLUME("In-2 Playback Volume", 0x0b, 0x1, HDA_INPUT),
3086 HDA_CODEC_MUTE("In-2 Playback Switch", 0x0b, 0x1, HDA_INPUT),
3087 HDA_CODEC_VOLUME("In-3 Playback Volume", 0x0b, 0x2, HDA_INPUT),
3088 HDA_CODEC_MUTE("In-3 Playback Switch", 0x0b, 0x2, HDA_INPUT),
3089 HDA_CODEC_VOLUME("In-4 Playback Volume", 0x0b, 0x3, HDA_INPUT),
3090 HDA_CODEC_MUTE("In-4 Playback Switch", 0x0b, 0x3, HDA_INPUT),
3091 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x4, HDA_INPUT),
3092 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x4, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003093 {
3094 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3095 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01003096 .info = alc_ch_mode_info,
3097 .get = alc_ch_mode_get,
3098 .put = alc_ch_mode_put,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003099 },
3100 { } /* end */
3101};
3102
3103static struct hda_verb alc880_test_init_verbs[] = {
3104 /* Unmute inputs of 0x0c - 0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02003105 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3106 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3107 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3108 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3109 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3110 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3111 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3112 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003113 /* Vol output for 0x0c-0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02003114 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3115 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3116 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3117 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003118 /* Set output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02003119 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3120 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3121 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3122 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003123 /* Unmute output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02003124 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3125 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3126 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3127 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003128 /* Set input pins 0x18-0x1c */
Takashi Iwai16ded522005-06-10 19:58:24 +02003129 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3130 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwai05acb862005-06-10 19:50:25 +02003131 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3132 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3133 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003134 /* Mute input pins 0x18-0x1b */
Takashi Iwai05acb862005-06-10 19:50:25 +02003135 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3136 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3137 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3138 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003139 /* ADC set up */
Takashi Iwai05acb862005-06-10 19:50:25 +02003140 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003141 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02003142 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003143 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02003144 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003145 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02003146 /* Analog input/passthru */
3147 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3148 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
3149 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
3150 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
3151 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003152 { }
3153};
3154#endif
3155
Linus Torvalds1da177e2005-04-16 15:20:36 -07003156/*
3157 */
3158
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003159static const char *alc880_models[ALC880_MODEL_LAST] = {
3160 [ALC880_3ST] = "3stack",
3161 [ALC880_TCL_S700] = "tcl",
3162 [ALC880_3ST_DIG] = "3stack-digout",
3163 [ALC880_CLEVO] = "clevo",
3164 [ALC880_5ST] = "5stack",
3165 [ALC880_5ST_DIG] = "5stack-digout",
3166 [ALC880_W810] = "w810",
3167 [ALC880_Z71V] = "z71v",
3168 [ALC880_6ST] = "6stack",
3169 [ALC880_6ST_DIG] = "6stack-digout",
3170 [ALC880_ASUS] = "asus",
3171 [ALC880_ASUS_W1V] = "asus-w1v",
3172 [ALC880_ASUS_DIG] = "asus-dig",
3173 [ALC880_ASUS_DIG2] = "asus-dig2",
3174 [ALC880_UNIWILL_DIG] = "uniwill",
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003175 [ALC880_UNIWILL_P53] = "uniwill-p53",
3176 [ALC880_FUJITSU] = "fujitsu",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003177 [ALC880_F1734] = "F1734",
3178 [ALC880_LG] = "lg",
3179 [ALC880_LG_LW] = "lg-lw",
Takashi Iwaidf99cd32008-04-25 15:25:04 +02003180 [ALC880_MEDION_RIM] = "medion",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003181#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003182 [ALC880_TEST] = "test",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003183#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003184 [ALC880_AUTO] = "auto",
3185};
3186
3187static struct snd_pci_quirk alc880_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003188 SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003189 SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG),
3190 SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST),
3191 SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_3ST_DIG),
3192 SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_6ST_DIG),
3193 SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_6ST_DIG),
3194 SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_6ST_DIG),
3195 SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_3ST_DIG),
3196 SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003197 SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_6ST_DIG),
3198 SND_PCI_QUIRK(0x103c, 0x2a09, "HP", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003199 SND_PCI_QUIRK(0x1043, 0x10b3, "ASUS W1V", ALC880_ASUS_W1V),
3200 SND_PCI_QUIRK(0x1043, 0x10c2, "ASUS W6A", ALC880_ASUS_DIG),
3201 SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS Wxx", ALC880_ASUS_DIG),
3202 SND_PCI_QUIRK(0x1043, 0x1113, "ASUS", ALC880_ASUS_DIG),
3203 SND_PCI_QUIRK(0x1043, 0x1123, "ASUS", ALC880_ASUS_DIG),
3204 SND_PCI_QUIRK(0x1043, 0x1173, "ASUS", ALC880_ASUS_DIG),
3205 SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_Z71V),
3206 /* SND_PCI_QUIRK(0x1043, 0x1964, "ASUS", ALC880_ASUS_DIG), */
3207 SND_PCI_QUIRK(0x1043, 0x1973, "ASUS", ALC880_ASUS_DIG),
3208 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS", ALC880_ASUS_DIG),
Travis Place186c3112008-05-20 11:54:41 +02003209 SND_PCI_QUIRK(0x1043, 0x814e, "ASUS P5GD1 w/SPDIF", ALC880_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003210 SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG),
3211 SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST),
3212 SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003213 SND_PCI_QUIRK(0x1043, 0, "ASUS", ALC880_ASUS), /* default ASUS */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003214 SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003215 SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST),
3216 SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003217 SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_5ST),
3218 SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003219 SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_6ST_DIG),
3220 SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_6ST_DIG),
3221 SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_6ST_DIG),
3222 SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003223 SND_PCI_QUIRK(0x1558, 0x0520, "Clevo m520G", ALC880_CLEVO),
3224 SND_PCI_QUIRK(0x1558, 0x0660, "Clevo m655n", ALC880_CLEVO),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003225 SND_PCI_QUIRK(0x1558, 0x5401, "ASUS", ALC880_ASUS_DIG2),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003226 SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003227 SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_UNIWILL_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003228 SND_PCI_QUIRK(0x1584, 0x9054, "Uniwlll", ALC880_F1734),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003229 SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL),
3230 SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003231 SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810),
Takashi Iwaidf99cd32008-04-25 15:25:04 +02003232 SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_MEDION_RIM),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003233 SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003234 SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003235 SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734),
Travis Place1d116042008-06-23 11:42:30 +02003236 SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FUJITSU),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003237 SND_PCI_QUIRK(0x1734, 0x10ac, "FSC", ALC880_UNIWILL),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003238 SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003239 SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003240 SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG),
3241 SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003242 SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003243 SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700),
3244 SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG), /* broken BIOS */
3245 SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG),
3246 SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003247 SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_5ST_DIG),
3248 SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003249 SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003250 SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003251 SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_3ST_DIG),
3252 SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003253 SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_5ST_DIG),
3254 SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_5ST_DIG),
3255 SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003256 SND_PCI_QUIRK(0x8086, 0, "Intel mobo", ALC880_3ST), /* default Intel */
3257 SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG),
3258 SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003259 {}
3260};
3261
Takashi Iwai16ded522005-06-10 19:58:24 +02003262/*
Kailang Yangdf694da2005-12-05 19:42:22 +01003263 * ALC880 codec presets
Takashi Iwai16ded522005-06-10 19:58:24 +02003264 */
Takashi Iwai16ded522005-06-10 19:58:24 +02003265static struct alc_config_preset alc880_presets[] = {
3266 [ALC880_3ST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003267 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003268 .init_verbs = { alc880_volume_init_verbs,
3269 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003270 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02003271 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003272 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
3273 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003274 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003275 .input_mux = &alc880_capture_source,
3276 },
3277 [ALC880_3ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003278 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003279 .init_verbs = { alc880_volume_init_verbs,
3280 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003281 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02003282 .dac_nids = alc880_dac_nids,
3283 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003284 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
3285 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003286 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003287 .input_mux = &alc880_capture_source,
3288 },
Kailang Yangdf694da2005-12-05 19:42:22 +01003289 [ALC880_TCL_S700] = {
3290 .mixers = { alc880_tcl_s700_mixer },
3291 .init_verbs = { alc880_volume_init_verbs,
3292 alc880_pin_tcl_S700_init_verbs,
3293 alc880_gpio2_init_verbs },
3294 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3295 .dac_nids = alc880_dac_nids,
3296 .hp_nid = 0x03,
3297 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3298 .channel_mode = alc880_2_jack_modes,
3299 .input_mux = &alc880_capture_source,
3300 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003301 [ALC880_5ST] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003302 .mixers = { alc880_three_stack_mixer,
3303 alc880_five_stack_mixer},
3304 .init_verbs = { alc880_volume_init_verbs,
3305 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003306 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3307 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003308 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
3309 .channel_mode = alc880_fivestack_modes,
3310 .input_mux = &alc880_capture_source,
3311 },
3312 [ALC880_5ST_DIG] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003313 .mixers = { alc880_three_stack_mixer,
3314 alc880_five_stack_mixer },
3315 .init_verbs = { alc880_volume_init_verbs,
3316 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003317 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3318 .dac_nids = alc880_dac_nids,
3319 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003320 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
3321 .channel_mode = alc880_fivestack_modes,
3322 .input_mux = &alc880_capture_source,
3323 },
Takashi Iwaib6482d42005-06-27 15:32:43 +02003324 [ALC880_6ST] = {
3325 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003326 .init_verbs = { alc880_volume_init_verbs,
3327 alc880_pin_6stack_init_verbs },
Takashi Iwaib6482d42005-06-27 15:32:43 +02003328 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
3329 .dac_nids = alc880_6st_dac_nids,
3330 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
3331 .channel_mode = alc880_sixstack_modes,
3332 .input_mux = &alc880_6stack_capture_source,
3333 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003334 [ALC880_6ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003335 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003336 .init_verbs = { alc880_volume_init_verbs,
3337 alc880_pin_6stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003338 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
3339 .dac_nids = alc880_6st_dac_nids,
3340 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003341 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
3342 .channel_mode = alc880_sixstack_modes,
3343 .input_mux = &alc880_6stack_capture_source,
3344 },
3345 [ALC880_W810] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003346 .mixers = { alc880_w810_base_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003347 .init_verbs = { alc880_volume_init_verbs,
3348 alc880_pin_w810_init_verbs,
Takashi Iwaib0af0de2005-06-21 14:49:19 +02003349 alc880_gpio2_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003350 .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids),
3351 .dac_nids = alc880_w810_dac_nids,
3352 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003353 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
3354 .channel_mode = alc880_w810_modes,
3355 .input_mux = &alc880_capture_source,
3356 },
3357 [ALC880_Z71V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003358 .mixers = { alc880_z71v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003359 .init_verbs = { alc880_volume_init_verbs,
3360 alc880_pin_z71v_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003361 .num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids),
3362 .dac_nids = alc880_z71v_dac_nids,
3363 .dig_out_nid = ALC880_DIGOUT_NID,
3364 .hp_nid = 0x03,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003365 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3366 .channel_mode = alc880_2_jack_modes,
Takashi Iwai16ded522005-06-10 19:58:24 +02003367 .input_mux = &alc880_capture_source,
3368 },
3369 [ALC880_F1734] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003370 .mixers = { alc880_f1734_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003371 .init_verbs = { alc880_volume_init_verbs,
3372 alc880_pin_f1734_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003373 .num_dacs = ARRAY_SIZE(alc880_f1734_dac_nids),
3374 .dac_nids = alc880_f1734_dac_nids,
3375 .hp_nid = 0x02,
3376 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3377 .channel_mode = alc880_2_jack_modes,
Takashi Iwai937b4162008-02-11 14:52:36 +01003378 .input_mux = &alc880_f1734_capture_source,
3379 .unsol_event = alc880_uniwill_p53_unsol_event,
3380 .init_hook = alc880_uniwill_p53_hp_automute,
Takashi Iwai16ded522005-06-10 19:58:24 +02003381 },
3382 [ALC880_ASUS] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003383 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003384 .init_verbs = { alc880_volume_init_verbs,
3385 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003386 alc880_gpio1_init_verbs },
3387 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3388 .dac_nids = alc880_asus_dac_nids,
3389 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3390 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003391 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003392 .input_mux = &alc880_capture_source,
3393 },
3394 [ALC880_ASUS_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003395 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003396 .init_verbs = { alc880_volume_init_verbs,
3397 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003398 alc880_gpio1_init_verbs },
3399 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3400 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003401 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003402 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3403 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003404 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003405 .input_mux = &alc880_capture_source,
3406 },
Kailang Yangdf694da2005-12-05 19:42:22 +01003407 [ALC880_ASUS_DIG2] = {
3408 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003409 .init_verbs = { alc880_volume_init_verbs,
3410 alc880_pin_asus_init_verbs,
Kailang Yangdf694da2005-12-05 19:42:22 +01003411 alc880_gpio2_init_verbs }, /* use GPIO2 */
3412 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3413 .dac_nids = alc880_asus_dac_nids,
3414 .dig_out_nid = ALC880_DIGOUT_NID,
3415 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3416 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003417 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01003418 .input_mux = &alc880_capture_source,
3419 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003420 [ALC880_ASUS_W1V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003421 .mixers = { alc880_asus_mixer, alc880_asus_w1v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003422 .init_verbs = { alc880_volume_init_verbs,
3423 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003424 alc880_gpio1_init_verbs },
3425 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3426 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003427 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003428 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3429 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003430 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003431 .input_mux = &alc880_capture_source,
3432 },
3433 [ALC880_UNIWILL_DIG] = {
Takashi Iwai3c10a9d2005-08-23 20:02:27 +02003434 .mixers = { alc880_asus_mixer, alc880_pcbeep_mixer },
Kailang Yangccc656c2006-10-17 12:32:26 +02003435 .init_verbs = { alc880_volume_init_verbs,
3436 alc880_pin_asus_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003437 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3438 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02003439 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003440 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
3441 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003442 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02003443 .input_mux = &alc880_capture_source,
3444 },
Kailang Yangccc656c2006-10-17 12:32:26 +02003445 [ALC880_UNIWILL] = {
3446 .mixers = { alc880_uniwill_mixer },
3447 .init_verbs = { alc880_volume_init_verbs,
3448 alc880_uniwill_init_verbs },
3449 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3450 .dac_nids = alc880_asus_dac_nids,
3451 .dig_out_nid = ALC880_DIGOUT_NID,
3452 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
3453 .channel_mode = alc880_threestack_modes,
3454 .need_dac_fix = 1,
3455 .input_mux = &alc880_capture_source,
3456 .unsol_event = alc880_uniwill_unsol_event,
3457 .init_hook = alc880_uniwill_automute,
3458 },
3459 [ALC880_UNIWILL_P53] = {
3460 .mixers = { alc880_uniwill_p53_mixer },
3461 .init_verbs = { alc880_volume_init_verbs,
3462 alc880_uniwill_p53_init_verbs },
3463 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
3464 .dac_nids = alc880_asus_dac_nids,
3465 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003466 .channel_mode = alc880_threestack_modes,
3467 .input_mux = &alc880_capture_source,
3468 .unsol_event = alc880_uniwill_p53_unsol_event,
3469 .init_hook = alc880_uniwill_p53_hp_automute,
3470 },
3471 [ALC880_FUJITSU] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003472 .mixers = { alc880_fujitsu_mixer,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003473 alc880_pcbeep_mixer, },
3474 .init_verbs = { alc880_volume_init_verbs,
3475 alc880_uniwill_p53_init_verbs,
3476 alc880_beep_init_verbs },
3477 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3478 .dac_nids = alc880_dac_nids,
Takashi Iwaid53d7d92007-08-20 15:20:02 +02003479 .dig_out_nid = ALC880_DIGOUT_NID,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003480 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3481 .channel_mode = alc880_2_jack_modes,
Kailang Yangccc656c2006-10-17 12:32:26 +02003482 .input_mux = &alc880_capture_source,
3483 .unsol_event = alc880_uniwill_p53_unsol_event,
3484 .init_hook = alc880_uniwill_p53_hp_automute,
3485 },
Kailang Yangdf694da2005-12-05 19:42:22 +01003486 [ALC880_CLEVO] = {
3487 .mixers = { alc880_three_stack_mixer },
3488 .init_verbs = { alc880_volume_init_verbs,
3489 alc880_pin_clevo_init_verbs },
3490 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3491 .dac_nids = alc880_dac_nids,
3492 .hp_nid = 0x03,
3493 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
3494 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003495 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01003496 .input_mux = &alc880_capture_source,
3497 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003498 [ALC880_LG] = {
3499 .mixers = { alc880_lg_mixer },
3500 .init_verbs = { alc880_volume_init_verbs,
3501 alc880_lg_init_verbs },
3502 .num_dacs = ARRAY_SIZE(alc880_lg_dac_nids),
3503 .dac_nids = alc880_lg_dac_nids,
3504 .dig_out_nid = ALC880_DIGOUT_NID,
3505 .num_channel_mode = ARRAY_SIZE(alc880_lg_ch_modes),
3506 .channel_mode = alc880_lg_ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02003507 .need_dac_fix = 1,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003508 .input_mux = &alc880_lg_capture_source,
3509 .unsol_event = alc880_lg_unsol_event,
3510 .init_hook = alc880_lg_automute,
Takashi Iwaicb53c622007-08-10 17:21:45 +02003511#ifdef CONFIG_SND_HDA_POWER_SAVE
3512 .loopbacks = alc880_lg_loopbacks,
3513#endif
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003514 },
Takashi Iwaid6815182006-03-23 16:06:23 +01003515 [ALC880_LG_LW] = {
3516 .mixers = { alc880_lg_lw_mixer },
3517 .init_verbs = { alc880_volume_init_verbs,
3518 alc880_lg_lw_init_verbs },
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003519 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwaid6815182006-03-23 16:06:23 +01003520 .dac_nids = alc880_dac_nids,
3521 .dig_out_nid = ALC880_DIGOUT_NID,
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003522 .num_channel_mode = ARRAY_SIZE(alc880_lg_lw_modes),
3523 .channel_mode = alc880_lg_lw_modes,
Takashi Iwaid6815182006-03-23 16:06:23 +01003524 .input_mux = &alc880_lg_lw_capture_source,
3525 .unsol_event = alc880_lg_lw_unsol_event,
3526 .init_hook = alc880_lg_lw_automute,
3527 },
Takashi Iwaidf99cd32008-04-25 15:25:04 +02003528 [ALC880_MEDION_RIM] = {
3529 .mixers = { alc880_medion_rim_mixer },
3530 .init_verbs = { alc880_volume_init_verbs,
3531 alc880_medion_rim_init_verbs,
3532 alc_gpio2_init_verbs },
3533 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
3534 .dac_nids = alc880_dac_nids,
3535 .dig_out_nid = ALC880_DIGOUT_NID,
3536 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
3537 .channel_mode = alc880_2_jack_modes,
3538 .input_mux = &alc880_medion_rim_capture_source,
3539 .unsol_event = alc880_medion_rim_unsol_event,
3540 .init_hook = alc880_medion_rim_automute,
3541 },
Takashi Iwai16ded522005-06-10 19:58:24 +02003542#ifdef CONFIG_SND_DEBUG
3543 [ALC880_TEST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003544 .mixers = { alc880_test_mixer },
3545 .init_verbs = { alc880_test_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02003546 .num_dacs = ARRAY_SIZE(alc880_test_dac_nids),
3547 .dac_nids = alc880_test_dac_nids,
3548 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02003549 .num_channel_mode = ARRAY_SIZE(alc880_test_modes),
3550 .channel_mode = alc880_test_modes,
3551 .input_mux = &alc880_test_capture_source,
3552 },
3553#endif
3554};
3555
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003556/*
3557 * Automatic parse of I/O pins from the BIOS configuration
3558 */
3559
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003560enum {
3561 ALC_CTL_WIDGET_VOL,
3562 ALC_CTL_WIDGET_MUTE,
3563 ALC_CTL_BIND_MUTE,
3564};
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01003565static struct snd_kcontrol_new alc880_control_templates[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003566 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
3567 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Takashi Iwai985be542005-11-02 18:26:49 +01003568 HDA_BIND_MUTE(NULL, 0, 0, 0),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003569};
3570
3571/* add dynamic controls */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003572static int add_control(struct alc_spec *spec, int type, const char *name,
3573 unsigned long val)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003574{
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01003575 struct snd_kcontrol_new *knew;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003576
Takashi Iwai603c4012008-07-30 15:01:44 +02003577 snd_array_init(&spec->kctls, sizeof(*knew), 32);
3578 knew = snd_array_new(&spec->kctls);
3579 if (!knew)
3580 return -ENOMEM;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003581 *knew = alc880_control_templates[type];
Paulo Marques543537b2005-06-23 00:09:02 -07003582 knew->name = kstrdup(name, GFP_KERNEL);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003583 if (!knew->name)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003584 return -ENOMEM;
3585 knew->private_value = val;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003586 return 0;
3587}
3588
3589#define alc880_is_fixed_pin(nid) ((nid) >= 0x14 && (nid) <= 0x17)
3590#define alc880_fixed_pin_idx(nid) ((nid) - 0x14)
3591#define alc880_is_multi_pin(nid) ((nid) >= 0x18)
3592#define alc880_multi_pin_idx(nid) ((nid) - 0x18)
3593#define alc880_is_input_pin(nid) ((nid) >= 0x18)
3594#define alc880_input_pin_idx(nid) ((nid) - 0x18)
3595#define alc880_idx_to_dac(nid) ((nid) + 0x02)
3596#define alc880_dac_to_idx(nid) ((nid) - 0x02)
3597#define alc880_idx_to_mixer(nid) ((nid) + 0x0c)
3598#define alc880_idx_to_selector(nid) ((nid) + 0x10)
3599#define ALC880_PIN_CD_NID 0x1c
3600
3601/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003602static int alc880_auto_fill_dac_nids(struct alc_spec *spec,
3603 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003604{
3605 hda_nid_t nid;
3606 int assigned[4];
3607 int i, j;
3608
3609 memset(assigned, 0, sizeof(assigned));
Takashi Iwaib0af0de2005-06-21 14:49:19 +02003610 spec->multiout.dac_nids = spec->private_dac_nids;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003611
3612 /* check the pins hardwired to audio widget */
3613 for (i = 0; i < cfg->line_outs; i++) {
3614 nid = cfg->line_out_pins[i];
3615 if (alc880_is_fixed_pin(nid)) {
3616 int idx = alc880_fixed_pin_idx(nid);
Libin Yang5014f192005-11-23 15:48:36 +01003617 spec->multiout.dac_nids[i] = alc880_idx_to_dac(idx);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003618 assigned[idx] = 1;
3619 }
3620 }
3621 /* left pins can be connect to any audio widget */
3622 for (i = 0; i < cfg->line_outs; i++) {
3623 nid = cfg->line_out_pins[i];
3624 if (alc880_is_fixed_pin(nid))
3625 continue;
3626 /* search for an empty channel */
3627 for (j = 0; j < cfg->line_outs; j++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003628 if (!assigned[j]) {
3629 spec->multiout.dac_nids[i] =
3630 alc880_idx_to_dac(j);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003631 assigned[j] = 1;
3632 break;
3633 }
3634 }
3635 }
3636 spec->multiout.num_dacs = cfg->line_outs;
3637 return 0;
3638}
3639
3640/* add playback controls from the parsed DAC table */
Kailang Yangdf694da2005-12-05 19:42:22 +01003641static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
3642 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003643{
3644 char name[32];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003645 static const char *chname[4] = {
3646 "Front", "Surround", NULL /*CLFE*/, "Side"
3647 };
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003648 hda_nid_t nid;
3649 int i, err;
3650
3651 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003652 if (!spec->multiout.dac_nids[i])
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003653 continue;
3654 nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i]));
3655 if (i == 2) {
3656 /* Center/LFE */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003657 err = add_control(spec, ALC_CTL_WIDGET_VOL,
3658 "Center Playback Volume",
3659 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
3660 HDA_OUTPUT));
3661 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003662 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003663 err = add_control(spec, ALC_CTL_WIDGET_VOL,
3664 "LFE Playback Volume",
3665 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
3666 HDA_OUTPUT));
3667 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003668 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003669 err = add_control(spec, ALC_CTL_BIND_MUTE,
3670 "Center Playback Switch",
3671 HDA_COMPOSE_AMP_VAL(nid, 1, 2,
3672 HDA_INPUT));
3673 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003674 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003675 err = add_control(spec, ALC_CTL_BIND_MUTE,
3676 "LFE Playback Switch",
3677 HDA_COMPOSE_AMP_VAL(nid, 2, 2,
3678 HDA_INPUT));
3679 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003680 return err;
3681 } else {
3682 sprintf(name, "%s Playback Volume", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003683 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
3684 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
3685 HDA_OUTPUT));
3686 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003687 return err;
3688 sprintf(name, "%s Playback Switch", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003689 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
3690 HDA_COMPOSE_AMP_VAL(nid, 3, 2,
3691 HDA_INPUT));
3692 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003693 return err;
3694 }
3695 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003696 return 0;
3697}
3698
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003699/* add playback controls for speaker and HP outputs */
3700static int alc880_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
3701 const char *pfx)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003702{
3703 hda_nid_t nid;
3704 int err;
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003705 char name[32];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003706
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003707 if (!pin)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003708 return 0;
3709
3710 if (alc880_is_fixed_pin(pin)) {
3711 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
Takashi Iwai82bc9552006-03-21 11:24:42 +01003712 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003713 if (!spec->multiout.hp_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003714 spec->multiout.hp_nid = nid;
Takashi Iwai82bc9552006-03-21 11:24:42 +01003715 else
3716 spec->multiout.extra_out_nid[0] = nid;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003717 /* control HP volume/switch on the output mixer amp */
3718 nid = alc880_idx_to_mixer(alc880_fixed_pin_idx(pin));
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003719 sprintf(name, "%s Playback Volume", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003720 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
3721 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
3722 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003723 return err;
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003724 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003725 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
3726 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
3727 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003728 return err;
3729 } else if (alc880_is_multi_pin(pin)) {
3730 /* set manual connection */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003731 /* we have only a switch on HP-out PIN */
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003732 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003733 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
3734 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
3735 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003736 return err;
3737 }
3738 return 0;
3739}
3740
3741/* create input playback/capture controls for the given pin */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003742static int new_analog_input(struct alc_spec *spec, hda_nid_t pin,
3743 const char *ctlname,
Kailang Yangdf694da2005-12-05 19:42:22 +01003744 int idx, hda_nid_t mix_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003745{
3746 char name[32];
Kailang Yangdf694da2005-12-05 19:42:22 +01003747 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003748
3749 sprintf(name, "%s Playback Volume", ctlname);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003750 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
3751 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
3752 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003753 return err;
3754 sprintf(name, "%s Playback Switch", ctlname);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003755 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
3756 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
3757 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003758 return err;
3759 return 0;
3760}
3761
3762/* create playback/capture controls for input pins */
Kailang Yangdf694da2005-12-05 19:42:22 +01003763static int alc880_auto_create_analog_input_ctls(struct alc_spec *spec,
3764 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003765{
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003766 struct hda_input_mux *imux = &spec->private_imux;
Kailang Yangdf694da2005-12-05 19:42:22 +01003767 int i, err, idx;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003768
3769 for (i = 0; i < AUTO_PIN_LAST; i++) {
3770 if (alc880_is_input_pin(cfg->input_pins[i])) {
Kailang Yangdf694da2005-12-05 19:42:22 +01003771 idx = alc880_input_pin_idx(cfg->input_pins[i]);
Takashi Iwai4a471b72005-12-07 13:56:29 +01003772 err = new_analog_input(spec, cfg->input_pins[i],
3773 auto_pin_cfg_labels[i],
Kailang Yangdf694da2005-12-05 19:42:22 +01003774 idx, 0x0b);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003775 if (err < 0)
3776 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003777 imux->items[imux->num_items].label =
3778 auto_pin_cfg_labels[i];
3779 imux->items[imux->num_items].index =
3780 alc880_input_pin_idx(cfg->input_pins[i]);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003781 imux->num_items++;
3782 }
3783 }
3784 return 0;
3785}
3786
Takashi Iwaif6c7e542008-02-12 18:32:23 +01003787static void alc_set_pin_output(struct hda_codec *codec, hda_nid_t nid,
3788 unsigned int pin_type)
3789{
3790 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
3791 pin_type);
3792 /* unmute pin */
Takashi Iwaid260cdf2008-02-13 17:19:35 +01003793 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
3794 AMP_OUT_UNMUTE);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01003795}
3796
Kailang Yangdf694da2005-12-05 19:42:22 +01003797static void alc880_auto_set_output_and_unmute(struct hda_codec *codec,
3798 hda_nid_t nid, int pin_type,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003799 int dac_idx)
3800{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01003801 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003802 /* need the manual connection? */
3803 if (alc880_is_multi_pin(nid)) {
3804 struct alc_spec *spec = codec->spec;
3805 int idx = alc880_multi_pin_idx(nid);
3806 snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
3807 AC_VERB_SET_CONNECT_SEL,
3808 alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
3809 }
3810}
3811
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02003812static int get_pin_type(int line_out_type)
3813{
3814 if (line_out_type == AUTO_PIN_HP_OUT)
3815 return PIN_HP;
3816 else
3817 return PIN_OUT;
3818}
3819
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003820static void alc880_auto_init_multi_out(struct hda_codec *codec)
3821{
3822 struct alc_spec *spec = codec->spec;
3823 int i;
Kailang Yangea1fb292008-08-26 12:58:38 +02003824
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003825 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003826 for (i = 0; i < spec->autocfg.line_outs; i++) {
3827 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02003828 int pin_type = get_pin_type(spec->autocfg.line_out_type);
3829 alc880_auto_set_output_and_unmute(codec, nid, pin_type, i);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003830 }
3831}
3832
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003833static void alc880_auto_init_extra_out(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003834{
3835 struct alc_spec *spec = codec->spec;
3836 hda_nid_t pin;
3837
Takashi Iwai82bc9552006-03-21 11:24:42 +01003838 pin = spec->autocfg.speaker_pins[0];
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003839 if (pin) /* connect to front */
3840 alc880_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02003841 pin = spec->autocfg.hp_pins[0];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003842 if (pin) /* connect to front */
3843 alc880_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
3844}
3845
3846static void alc880_auto_init_analog_input(struct hda_codec *codec)
3847{
3848 struct alc_spec *spec = codec->spec;
3849 int i;
3850
3851 for (i = 0; i < AUTO_PIN_LAST; i++) {
3852 hda_nid_t nid = spec->autocfg.input_pins[i];
3853 if (alc880_is_input_pin(nid)) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003854 snd_hda_codec_write(codec, nid, 0,
3855 AC_VERB_SET_PIN_WIDGET_CONTROL,
3856 i <= AUTO_PIN_FRONT_MIC ?
3857 PIN_VREF80 : PIN_IN);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003858 if (nid != ALC880_PIN_CD_NID)
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003859 snd_hda_codec_write(codec, nid, 0,
3860 AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003861 AMP_OUT_MUTE);
3862 }
3863 }
3864}
3865
3866/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003867/* return 1 if successful, 0 if the proper config is not found,
3868 * or a negative error code
3869 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003870static int alc880_parse_auto_config(struct hda_codec *codec)
3871{
3872 struct alc_spec *spec = codec->spec;
3873 int err;
Kailang Yangdf694da2005-12-05 19:42:22 +01003874 static hda_nid_t alc880_ignore[] = { 0x1d, 0 };
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003875
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003876 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
3877 alc880_ignore);
3878 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003879 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003880 if (!spec->autocfg.line_outs)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003881 return 0; /* can't find valid BIOS pin config */
Kailang Yangdf694da2005-12-05 19:42:22 +01003882
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003883 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
3884 if (err < 0)
3885 return err;
3886 err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
3887 if (err < 0)
3888 return err;
3889 err = alc880_auto_create_extra_out(spec,
3890 spec->autocfg.speaker_pins[0],
3891 "Speaker");
3892 if (err < 0)
3893 return err;
3894 err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
3895 "Headphone");
3896 if (err < 0)
3897 return err;
3898 err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg);
3899 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003900 return err;
3901
3902 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
3903
3904 if (spec->autocfg.dig_out_pin)
3905 spec->multiout.dig_out_nid = ALC880_DIGOUT_NID;
3906 if (spec->autocfg.dig_in_pin)
3907 spec->dig_in_nid = ALC880_DIGIN_NID;
3908
Takashi Iwai603c4012008-07-30 15:01:44 +02003909 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +01003910 add_mixer(spec, spec->kctls.list);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003911
Takashi Iwaid88897e2008-10-31 15:01:37 +01003912 add_verb(spec, alc880_volume_init_verbs);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003913
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02003914 spec->num_mux_defs = 1;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003915 spec->input_mux = &spec->private_imux;
3916
Takashi Iwaie044c392008-10-27 16:56:24 +01003917 store_pin_configs(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003918 return 1;
3919}
3920
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003921/* additional initialization for auto-configuration model */
3922static void alc880_auto_init(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003923{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01003924 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003925 alc880_auto_init_multi_out(codec);
Takashi Iwai8d88bc32005-11-17 11:09:23 +01003926 alc880_auto_init_extra_out(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003927 alc880_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01003928 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02003929 alc_inithook(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003930}
3931
3932/*
3933 * OK, here we have finally the patch for ALC880
3934 */
3935
Linus Torvalds1da177e2005-04-16 15:20:36 -07003936static int patch_alc880(struct hda_codec *codec)
3937{
3938 struct alc_spec *spec;
3939 int board_config;
Kailang Yangdf694da2005-12-05 19:42:22 +01003940 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003941
Takashi Iwaie560d8d2005-09-09 14:21:46 +02003942 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003943 if (spec == NULL)
3944 return -ENOMEM;
3945
3946 codec->spec = spec;
3947
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003948 board_config = snd_hda_check_board_config(codec, ALC880_MODEL_LAST,
3949 alc880_models,
3950 alc880_cfg_tbl);
3951 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003952 printk(KERN_INFO "hda_codec: Unknown model for ALC880, "
3953 "trying auto-probe from BIOS...\n");
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003954 board_config = ALC880_AUTO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003955 }
3956
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003957 if (board_config == ALC880_AUTO) {
3958 /* automatic parse from the BIOS config */
3959 err = alc880_parse_auto_config(codec);
3960 if (err < 0) {
3961 alc_free(codec);
3962 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003963 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003964 printk(KERN_INFO
3965 "hda_codec: Cannot set up configuration "
3966 "from BIOS. Using 3-stack mode...\n");
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003967 board_config = ALC880_3ST;
3968 }
3969 }
3970
Kailang Yangdf694da2005-12-05 19:42:22 +01003971 if (board_config != ALC880_AUTO)
3972 setup_preset(spec, &alc880_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003973
3974 spec->stream_name_analog = "ALC880 Analog";
3975 spec->stream_analog_playback = &alc880_pcm_analog_playback;
3976 spec->stream_analog_capture = &alc880_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01003977 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003978
3979 spec->stream_name_digital = "ALC880 Digital";
3980 spec->stream_digital_playback = &alc880_pcm_digital_playback;
3981 spec->stream_digital_capture = &alc880_pcm_digital_capture;
3982
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003983 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003984 /* check whether NID 0x07 is valid */
Takashi Iwai54d17402005-11-21 16:33:22 +01003985 unsigned int wcap = get_wcaps(codec, alc880_adc_nids[0]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003986 /* get type */
3987 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003988 if (wcap != AC_WID_AUD_IN) {
3989 spec->adc_nids = alc880_adc_nids_alt;
3990 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids_alt);
Takashi Iwaid88897e2008-10-31 15:01:37 +01003991 add_mixer(spec, alc880_capture_alt_mixer);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003992 } else {
3993 spec->adc_nids = alc880_adc_nids;
3994 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids);
Takashi Iwaid88897e2008-10-31 15:01:37 +01003995 add_mixer(spec, alc880_capture_mixer);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003996 }
3997 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003998
Takashi Iwai2134ea42008-01-10 16:53:55 +01003999 spec->vmaster_nid = 0x0c;
4000
Linus Torvalds1da177e2005-04-16 15:20:36 -07004001 codec->patch_ops = alc_patch_ops;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004002 if (board_config == ALC880_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004003 spec->init_hook = alc880_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02004004#ifdef CONFIG_SND_HDA_POWER_SAVE
4005 if (!spec->loopback.amplist)
4006 spec->loopback.amplist = alc880_loopbacks;
4007#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07004008
4009 return 0;
4010}
4011
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004012
Linus Torvalds1da177e2005-04-16 15:20:36 -07004013/*
4014 * ALC260 support
4015 */
4016
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004017static hda_nid_t alc260_dac_nids[1] = {
4018 /* front */
4019 0x02,
4020};
4021
4022static hda_nid_t alc260_adc_nids[1] = {
4023 /* ADC0 */
4024 0x04,
4025};
4026
Kailang Yangdf694da2005-12-05 19:42:22 +01004027static hda_nid_t alc260_adc_nids_alt[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004028 /* ADC1 */
4029 0x05,
4030};
4031
Kailang Yangdf694da2005-12-05 19:42:22 +01004032static hda_nid_t alc260_hp_adc_nids[2] = {
4033 /* ADC1, 0 */
4034 0x05, 0x04
4035};
4036
Jonathan Woithed57fdac2006-02-28 11:38:35 +01004037/* NIDs used when simultaneous access to both ADCs makes sense. Note that
4038 * alc260_capture_mixer assumes ADC0 (nid 0x04) is the first ADC.
4039 */
4040static hda_nid_t alc260_dual_adc_nids[2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004041 /* ADC0, ADC1 */
4042 0x04, 0x05
4043};
4044
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004045#define ALC260_DIGOUT_NID 0x03
4046#define ALC260_DIGIN_NID 0x06
4047
4048static struct hda_input_mux alc260_capture_source = {
4049 .num_items = 4,
4050 .items = {
4051 { "Mic", 0x0 },
4052 { "Front Mic", 0x1 },
4053 { "Line", 0x2 },
4054 { "CD", 0x4 },
4055 },
4056};
4057
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01004058/* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004059 * headphone jack and the internal CD lines since these are the only pins at
4060 * which audio can appear. For flexibility, also allow the option of
4061 * recording the mixer output on the second ADC (ADC0 doesn't have a
4062 * connection to the mixer output).
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004063 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004064static struct hda_input_mux alc260_fujitsu_capture_sources[2] = {
4065 {
4066 .num_items = 3,
4067 .items = {
4068 { "Mic/Line", 0x0 },
4069 { "CD", 0x4 },
4070 { "Headphone", 0x2 },
4071 },
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004072 },
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004073 {
4074 .num_items = 4,
4075 .items = {
4076 { "Mic/Line", 0x0 },
4077 { "CD", 0x4 },
4078 { "Headphone", 0x2 },
4079 { "Mixer", 0x5 },
4080 },
4081 },
4082
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004083};
4084
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004085/* Acer TravelMate(/Extensa/Aspire) notebooks have similar configuration to
4086 * the Fujitsu S702x, but jacks are marked differently.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004087 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004088static struct hda_input_mux alc260_acer_capture_sources[2] = {
4089 {
4090 .num_items = 4,
4091 .items = {
4092 { "Mic", 0x0 },
4093 { "Line", 0x2 },
4094 { "CD", 0x4 },
4095 { "Headphone", 0x5 },
4096 },
4097 },
4098 {
4099 .num_items = 5,
4100 .items = {
4101 { "Mic", 0x0 },
4102 { "Line", 0x2 },
4103 { "CD", 0x4 },
4104 { "Headphone", 0x6 },
4105 { "Mixer", 0x5 },
4106 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004107 },
4108};
Linus Torvalds1da177e2005-04-16 15:20:36 -07004109/*
4110 * This is just place-holder, so there's something for alc_build_pcms to look
4111 * at when it calculates the maximum number of channels. ALC260 has no mixer
4112 * element which allows changing the channel mode, so the verb list is
4113 * never used.
4114 */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01004115static struct hda_channel_mode alc260_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004116 { 2, NULL },
4117};
4118
Kailang Yangdf694da2005-12-05 19:42:22 +01004119
4120/* Mixer combinations
4121 *
4122 * basic: base_output + input + pc_beep + capture
4123 * HP: base_output + input + capture_alt
4124 * HP_3013: hp_3013 + input + capture
4125 * fujitsu: fujitsu + capture
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004126 * acer: acer + capture
Kailang Yangdf694da2005-12-05 19:42:22 +01004127 */
4128
4129static struct snd_kcontrol_new alc260_base_output_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02004130 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01004131 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01004132 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
4133 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
4134 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
4135 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
4136 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004137};
Kailang Yangdf694da2005-12-05 19:42:22 +01004138
4139static struct snd_kcontrol_new alc260_input_mixer[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004140 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4141 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
4142 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
4143 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
4144 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
4145 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
4146 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT),
4147 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004148 { } /* end */
4149};
4150
Kailang Yangdf694da2005-12-05 19:42:22 +01004151static struct snd_kcontrol_new alc260_pc_beep_mixer[] = {
4152 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x07, 0x05, HDA_INPUT),
4153 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x07, 0x05, HDA_INPUT),
4154 { } /* end */
4155};
4156
Takashi Iwaibec15c32008-01-28 18:16:30 +01004157/* update HP, line and mono out pins according to the master switch */
4158static void alc260_hp_master_update(struct hda_codec *codec,
4159 hda_nid_t hp, hda_nid_t line,
4160 hda_nid_t mono)
4161{
4162 struct alc_spec *spec = codec->spec;
4163 unsigned int val = spec->master_sw ? PIN_HP : 0;
4164 /* change HP and line-out pins */
4165 snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
4166 val);
4167 snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
4168 val);
4169 /* mono (speaker) depending on the HP jack sense */
4170 val = (val && !spec->jack_present) ? PIN_OUT : 0;
4171 snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
4172 val);
4173}
4174
4175static int alc260_hp_master_sw_get(struct snd_kcontrol *kcontrol,
4176 struct snd_ctl_elem_value *ucontrol)
4177{
4178 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4179 struct alc_spec *spec = codec->spec;
4180 *ucontrol->value.integer.value = spec->master_sw;
4181 return 0;
4182}
4183
4184static int alc260_hp_master_sw_put(struct snd_kcontrol *kcontrol,
4185 struct snd_ctl_elem_value *ucontrol)
4186{
4187 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4188 struct alc_spec *spec = codec->spec;
4189 int val = !!*ucontrol->value.integer.value;
4190 hda_nid_t hp, line, mono;
4191
4192 if (val == spec->master_sw)
4193 return 0;
4194 spec->master_sw = val;
4195 hp = (kcontrol->private_value >> 16) & 0xff;
4196 line = (kcontrol->private_value >> 8) & 0xff;
4197 mono = kcontrol->private_value & 0xff;
4198 alc260_hp_master_update(codec, hp, line, mono);
4199 return 1;
4200}
4201
4202static struct snd_kcontrol_new alc260_hp_output_mixer[] = {
4203 {
4204 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4205 .name = "Master Playback Switch",
4206 .info = snd_ctl_boolean_mono_info,
4207 .get = alc260_hp_master_sw_get,
4208 .put = alc260_hp_master_sw_put,
4209 .private_value = (0x0f << 16) | (0x10 << 8) | 0x11
4210 },
4211 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4212 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
4213 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
4214 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
4215 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
4216 HDA_OUTPUT),
4217 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2, HDA_INPUT),
4218 { } /* end */
4219};
4220
4221static struct hda_verb alc260_hp_unsol_verbs[] = {
4222 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
4223 {},
4224};
4225
4226static void alc260_hp_automute(struct hda_codec *codec)
4227{
4228 struct alc_spec *spec = codec->spec;
4229 unsigned int present;
4230
4231 present = snd_hda_codec_read(codec, 0x10, 0,
4232 AC_VERB_GET_PIN_SENSE, 0);
4233 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
4234 alc260_hp_master_update(codec, 0x0f, 0x10, 0x11);
4235}
4236
4237static void alc260_hp_unsol_event(struct hda_codec *codec, unsigned int res)
4238{
4239 if ((res >> 26) == ALC880_HP_EVENT)
4240 alc260_hp_automute(codec);
4241}
4242
Kailang Yangdf694da2005-12-05 19:42:22 +01004243static struct snd_kcontrol_new alc260_hp_3013_mixer[] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01004244 {
4245 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4246 .name = "Master Playback Switch",
4247 .info = snd_ctl_boolean_mono_info,
4248 .get = alc260_hp_master_sw_get,
4249 .put = alc260_hp_master_sw_put,
4250 .private_value = (0x10 << 16) | (0x15 << 8) | 0x11
4251 },
Kailang Yangdf694da2005-12-05 19:42:22 +01004252 HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT),
4253 HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT),
4254 HDA_CODEC_VOLUME("Aux-In Playback Volume", 0x07, 0x06, HDA_INPUT),
4255 HDA_CODEC_MUTE("Aux-In Playback Switch", 0x07, 0x06, HDA_INPUT),
4256 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4257 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01004258 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
4259 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02004260 { } /* end */
4261};
4262
Kailang Yang3f878302008-08-26 13:02:23 +02004263static struct hda_bind_ctls alc260_dc7600_bind_master_vol = {
4264 .ops = &snd_hda_bind_vol,
4265 .values = {
4266 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_OUTPUT),
4267 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_OUTPUT),
4268 HDA_COMPOSE_AMP_VAL(0x0a, 3, 0, HDA_OUTPUT),
4269 0
4270 },
4271};
4272
4273static struct hda_bind_ctls alc260_dc7600_bind_switch = {
4274 .ops = &snd_hda_bind_sw,
4275 .values = {
4276 HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT),
4277 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
4278 0
4279 },
4280};
4281
4282static struct snd_kcontrol_new alc260_hp_dc7600_mixer[] = {
4283 HDA_BIND_VOL("Master Playback Volume", &alc260_dc7600_bind_master_vol),
4284 HDA_BIND_SW("LineOut Playback Switch", &alc260_dc7600_bind_switch),
4285 HDA_CODEC_MUTE("Speaker Playback Switch", 0x0f, 0x0, HDA_OUTPUT),
4286 HDA_CODEC_MUTE("Headphone Playback Switch", 0x10, 0x0, HDA_OUTPUT),
4287 { } /* end */
4288};
4289
Takashi Iwaibec15c32008-01-28 18:16:30 +01004290static struct hda_verb alc260_hp_3013_unsol_verbs[] = {
4291 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
4292 {},
4293};
4294
4295static void alc260_hp_3013_automute(struct hda_codec *codec)
4296{
4297 struct alc_spec *spec = codec->spec;
4298 unsigned int present;
4299
4300 present = snd_hda_codec_read(codec, 0x15, 0,
4301 AC_VERB_GET_PIN_SENSE, 0);
4302 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
4303 alc260_hp_master_update(codec, 0x10, 0x15, 0x11);
4304}
4305
4306static void alc260_hp_3013_unsol_event(struct hda_codec *codec,
4307 unsigned int res)
4308{
4309 if ((res >> 26) == ALC880_HP_EVENT)
4310 alc260_hp_3013_automute(codec);
4311}
4312
Kailang Yang3f878302008-08-26 13:02:23 +02004313static void alc260_hp_3012_automute(struct hda_codec *codec)
4314{
4315 unsigned int present, bits;
4316
4317 present = snd_hda_codec_read(codec, 0x10, 0,
4318 AC_VERB_GET_PIN_SENSE, 0) & AC_PINSENSE_PRESENCE;
4319
4320 bits = present ? 0 : PIN_OUT;
4321 snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
4322 bits);
4323 snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
4324 bits);
4325 snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
4326 bits);
4327}
4328
4329static void alc260_hp_3012_unsol_event(struct hda_codec *codec,
4330 unsigned int res)
4331{
4332 if ((res >> 26) == ALC880_HP_EVENT)
4333 alc260_hp_3012_automute(codec);
4334}
4335
4336/* Fujitsu S702x series laptops. ALC260 pin usage: Mic/Line jack = 0x12,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004337 * HP jack = 0x14, CD audio = 0x16, internal speaker = 0x10.
4338 */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01004339static struct snd_kcontrol_new alc260_fujitsu_mixer[] = {
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004340 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01004341 HDA_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004342 ALC_PIN_MODE("Headphone Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004343 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4344 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
4345 HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT),
4346 HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004347 ALC_PIN_MODE("Mic/Line Jack Mode", 0x12, ALC_PIN_DIR_IN),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004348 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
4349 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01004350 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT),
4351 HDA_BIND_MUTE("Speaker Playback Switch", 0x09, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01004352 { } /* end */
4353};
4354
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004355/* Mixer for Acer TravelMate(/Extensa/Aspire) notebooks. Note that current
4356 * versions of the ALC260 don't act on requests to enable mic bias from NID
4357 * 0x0f (used to drive the headphone jack in these laptops). The ALC260
4358 * datasheet doesn't mention this restriction. At this stage it's not clear
4359 * whether this behaviour is intentional or is a hardware bug in chip
4360 * revisions available in early 2006. Therefore for now allow the
4361 * "Headphone Jack Mode" control to span all choices, but if it turns out
4362 * that the lack of mic bias for this NID is intentional we could change the
4363 * mode from ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
4364 *
4365 * In addition, Acer TravelMate(/Extensa/Aspire) notebooks in early 2006
4366 * don't appear to make the mic bias available from the "line" jack, even
4367 * though the NID used for this jack (0x14) can supply it. The theory is
4368 * that perhaps Acer have included blocking capacitors between the ALC260
4369 * and the output jack. If this turns out to be the case for all such
4370 * models the "Line Jack Mode" mode could be changed from ALC_PIN_DIR_INOUT
4371 * to ALC_PIN_DIR_INOUT_NOMICBIAS.
Jonathan Woithebd869482006-11-28 11:35:52 +01004372 *
4373 * The C20x Tablet series have a mono internal speaker which is controlled
4374 * via the chip's Mono sum widget and pin complex, so include the necessary
4375 * controls for such models. On models without a "mono speaker" the control
4376 * won't do anything.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004377 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004378static struct snd_kcontrol_new alc260_acer_mixer[] = {
4379 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4380 HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004381 ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01004382 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
Jonathan Woithebd869482006-11-28 11:35:52 +01004383 HDA_OUTPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01004384 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2,
Jonathan Woithebd869482006-11-28 11:35:52 +01004385 HDA_INPUT),
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004386 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4387 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
4388 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
4389 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
4390 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
4391 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
4392 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
4393 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
4394 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
4395 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
4396 { } /* end */
4397};
4398
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004399/* Packard bell V7900 ALC260 pin usage: HP = 0x0f, Mic jack = 0x12,
4400 * Line In jack = 0x14, CD audio = 0x16, pc beep = 0x17.
4401 */
4402static struct snd_kcontrol_new alc260_will_mixer[] = {
4403 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4404 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
4405 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
4406 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
4407 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
4408 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
4409 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
4410 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
4411 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4412 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
4413 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
4414 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
4415 { } /* end */
4416};
4417
4418/* Replacer 672V ALC260 pin usage: Mic jack = 0x12,
4419 * Line In jack = 0x14, ATAPI Mic = 0x13, speaker = 0x0f.
4420 */
4421static struct snd_kcontrol_new alc260_replacer_672v_mixer[] = {
4422 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4423 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
4424 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
4425 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
4426 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
4427 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x07, 0x1, HDA_INPUT),
4428 HDA_CODEC_MUTE("ATATI Mic Playback Switch", 0x07, 0x1, HDA_INPUT),
4429 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
4430 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
4431 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
4432 { } /* end */
4433};
4434
Kailang Yangdf694da2005-12-05 19:42:22 +01004435/* capture mixer elements */
4436static struct snd_kcontrol_new alc260_capture_mixer[] = {
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004437 HDA_CODEC_VOLUME("Capture Volume", 0x04, 0x0, HDA_INPUT),
4438 HDA_CODEC_MUTE("Capture Switch", 0x04, 0x0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01004439 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x05, 0x0, HDA_INPUT),
4440 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x05, 0x0, HDA_INPUT),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004441 {
4442 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Kailang Yangdf694da2005-12-05 19:42:22 +01004443 /* The multiple "Capture Source" controls confuse alsamixer
4444 * So call somewhat different..
Kailang Yangdf694da2005-12-05 19:42:22 +01004445 */
4446 /* .name = "Capture Source", */
4447 .name = "Input Source",
4448 .count = 2,
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004449 .info = alc_mux_enum_info,
4450 .get = alc_mux_enum_get,
4451 .put = alc_mux_enum_put,
4452 },
4453 { } /* end */
4454};
4455
Kailang Yangdf694da2005-12-05 19:42:22 +01004456static struct snd_kcontrol_new alc260_capture_alt_mixer[] = {
4457 HDA_CODEC_VOLUME("Capture Volume", 0x05, 0x0, HDA_INPUT),
4458 HDA_CODEC_MUTE("Capture Switch", 0x05, 0x0, HDA_INPUT),
4459 {
4460 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4461 /* The multiple "Capture Source" controls confuse alsamixer
4462 * So call somewhat different..
Kailang Yangdf694da2005-12-05 19:42:22 +01004463 */
4464 /* .name = "Capture Source", */
4465 .name = "Input Source",
4466 .count = 1,
4467 .info = alc_mux_enum_info,
4468 .get = alc_mux_enum_get,
4469 .put = alc_mux_enum_put,
4470 },
4471 { } /* end */
4472};
4473
4474/*
4475 * initialization verbs
4476 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004477static struct hda_verb alc260_init_verbs[] = {
4478 /* Line In pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02004479 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004480 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02004481 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004482 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02004483 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004484 /* Mic2 (front panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02004485 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004486 /* LINE-2 is used for line-out in rear */
Takashi Iwai05acb862005-06-10 19:50:25 +02004487 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004488 /* select line-out */
Jonathan Woithefd56f2d2006-01-24 10:35:46 +01004489 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004490 /* LINE-OUT pin */
Takashi Iwai05acb862005-06-10 19:50:25 +02004491 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004492 /* enable HP */
Takashi Iwai05acb862005-06-10 19:50:25 +02004493 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004494 /* enable Mono */
Takashi Iwai05acb862005-06-10 19:50:25 +02004495 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4496 /* mute capture amp left and right */
Takashi Iwai16ded522005-06-10 19:58:24 +02004497 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004498 /* set connection select to line in (default select for this ADC) */
4499 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai16ded522005-06-10 19:58:24 +02004500 /* mute capture amp left and right */
4501 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4502 /* set connection select to line in (default select for this ADC) */
4503 {0x05, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai05acb862005-06-10 19:50:25 +02004504 /* set vol=0 Line-Out mixer amp left and right */
4505 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4506 /* unmute pin widget amp left and right (no gain on this amp) */
4507 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4508 /* set vol=0 HP mixer amp left and right */
4509 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4510 /* unmute pin widget amp left and right (no gain on this amp) */
4511 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4512 /* set vol=0 Mono mixer amp left and right */
4513 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4514 /* unmute pin widget amp left and right (no gain on this amp) */
4515 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4516 /* unmute LINE-2 out pin */
4517 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004518 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
4519 * Line In 2 = 0x03
4520 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02004521 /* mute analog inputs */
4522 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4523 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4524 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4525 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4526 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004527 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
Takashi Iwai05acb862005-06-10 19:50:25 +02004528 /* mute Front out path */
4529 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4530 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4531 /* mute Headphone out path */
4532 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4533 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4534 /* mute Mono out path */
4535 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4536 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004537 { }
4538};
4539
Takashi Iwai474167d2006-05-17 17:17:43 +02004540#if 0 /* should be identical with alc260_init_verbs? */
Kailang Yangdf694da2005-12-05 19:42:22 +01004541static struct hda_verb alc260_hp_init_verbs[] = {
4542 /* Headphone and output */
4543 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
4544 /* mono output */
4545 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4546 /* Mic1 (rear panel) pin widget for input and vref at 80% */
4547 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4548 /* Mic2 (front panel) pin widget for input and vref at 80% */
4549 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4550 /* Line In pin widget for input */
4551 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4552 /* Line-2 pin widget for output */
4553 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4554 /* CD pin widget for input */
4555 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4556 /* unmute amp left and right */
4557 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
4558 /* set connection select to line in (default select for this ADC) */
4559 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
4560 /* unmute Line-Out mixer amp left and right (volume = 0) */
4561 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
4562 /* mute pin widget amp left and right (no gain on this amp) */
4563 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
4564 /* unmute HP mixer amp left and right (volume = 0) */
4565 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
4566 /* mute pin widget amp left and right (no gain on this amp) */
4567 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004568 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
4569 * Line In 2 = 0x03
4570 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02004571 /* mute analog inputs */
4572 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4573 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4574 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4575 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4576 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01004577 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
4578 /* Unmute Front out path */
4579 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4580 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4581 /* Unmute Headphone out path */
4582 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4583 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4584 /* Unmute Mono out path */
4585 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4586 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4587 { }
4588};
Takashi Iwai474167d2006-05-17 17:17:43 +02004589#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01004590
4591static struct hda_verb alc260_hp_3013_init_verbs[] = {
4592 /* Line out and output */
4593 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4594 /* mono output */
4595 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
4596 /* Mic1 (rear panel) pin widget for input and vref at 80% */
4597 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4598 /* Mic2 (front panel) pin widget for input and vref at 80% */
4599 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
4600 /* Line In pin widget for input */
4601 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4602 /* Headphone pin widget for output */
4603 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
4604 /* CD pin widget for input */
4605 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
4606 /* unmute amp left and right */
4607 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
4608 /* set connection select to line in (default select for this ADC) */
4609 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
4610 /* unmute Line-Out mixer amp left and right (volume = 0) */
4611 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
4612 /* mute pin widget amp left and right (no gain on this amp) */
4613 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
4614 /* unmute HP mixer amp left and right (volume = 0) */
4615 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
4616 /* mute pin widget amp left and right (no gain on this amp) */
4617 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004618 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
4619 * Line In 2 = 0x03
4620 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02004621 /* mute analog inputs */
4622 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4623 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4624 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4625 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4626 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01004627 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
4628 /* Unmute Front out path */
4629 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4630 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4631 /* Unmute Headphone out path */
4632 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4633 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4634 /* Unmute Mono out path */
4635 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
4636 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
4637 { }
4638};
4639
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004640/* Initialisation sequence for ALC260 as configured in Fujitsu S702x
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004641 * laptops. ALC260 pin usage: Mic/Line jack = 0x12, HP jack = 0x14, CD
4642 * audio = 0x16, internal speaker = 0x10.
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004643 */
4644static struct hda_verb alc260_fujitsu_init_verbs[] = {
4645 /* Disable all GPIOs */
4646 {0x01, AC_VERB_SET_GPIO_MASK, 0},
4647 /* Internal speaker is connected to headphone pin */
4648 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4649 /* Headphone/Line-out jack connects to Line1 pin; make it an output */
4650 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Jonathan Woithef7ace402006-02-28 11:46:14 +01004651 /* Mic/Line-in jack is connected to mic1 pin, so make it an input */
4652 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4653 /* Ensure all other unused pins are disabled and muted. */
4654 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4655 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004656 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01004657 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004658 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01004659 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4660 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4661 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004662
Jonathan Woithef7ace402006-02-28 11:46:14 +01004663 /* Disable digital (SPDIF) pins */
4664 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
4665 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004666
Kailang Yangea1fb292008-08-26 12:58:38 +02004667 /* Ensure Line1 pin widget takes its input from the OUT1 sum bus
Jonathan Woithef7ace402006-02-28 11:46:14 +01004668 * when acting as an output.
4669 */
4670 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
4671
4672 /* Start with output sum widgets muted and their output gains at min */
Takashi Iwai8b33a5a2006-02-09 11:57:01 +01004673 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4674 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4675 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4676 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4677 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4678 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4679 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4680 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4681 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004682
Jonathan Woithef7ace402006-02-28 11:46:14 +01004683 /* Unmute HP pin widget amp left and right (no equiv mixer ctrl) */
4684 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4685 /* Unmute Line1 pin widget output buffer since it starts as an output.
4686 * If the pin mode is changed by the user the pin mode control will
4687 * take care of enabling the pin's input/output buffers as needed.
4688 * Therefore there's no need to enable the input buffer at this
4689 * stage.
Jonathan Woithecdcd9262006-02-28 11:36:42 +01004690 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01004691 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +02004692 /* Unmute input buffer of pin widget used for Line-in (no equiv
Jonathan Woithecdcd9262006-02-28 11:36:42 +01004693 * mixer ctrl)
4694 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01004695 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004696
Jonathan Woithef7ace402006-02-28 11:46:14 +01004697 /* Mute capture amp left and right */
4698 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +02004699 /* Set ADC connection select to match default mixer setting - line
Jonathan Woithef7ace402006-02-28 11:46:14 +01004700 * in (on mic1 pin)
4701 */
4702 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004703
Jonathan Woithef7ace402006-02-28 11:46:14 +01004704 /* Do the same for the second ADC: mute capture input amp and
4705 * set ADC connection to line in (on mic1 pin)
4706 */
4707 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4708 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004709
Jonathan Woithef7ace402006-02-28 11:46:14 +01004710 /* Mute all inputs to mixer widget (even unconnected ones) */
4711 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
4712 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
4713 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
4714 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
4715 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
4716 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
4717 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
4718 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
Takashi Iwai4a471b72005-12-07 13:56:29 +01004719
4720 { }
Jonathan Woithea9430dd2005-09-16 19:12:48 +02004721};
4722
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004723/* Initialisation sequence for ALC260 as configured in Acer TravelMate and
4724 * similar laptops (adapted from Fujitsu init verbs).
4725 */
4726static struct hda_verb alc260_acer_init_verbs[] = {
4727 /* On TravelMate laptops, GPIO 0 enables the internal speaker and
4728 * the headphone jack. Turn this on and rely on the standard mute
4729 * methods whenever the user wants to turn these outputs off.
4730 */
4731 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
4732 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
4733 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
4734 /* Internal speaker/Headphone jack is connected to Line-out pin */
4735 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4736 /* Internal microphone/Mic jack is connected to Mic1 pin */
4737 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
4738 /* Line In jack is connected to Line1 pin */
4739 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Jonathan Woithebd869482006-11-28 11:35:52 +01004740 /* Some Acers (eg: C20x Tablets) use Mono pin for internal speaker */
4741 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004742 /* Ensure all other unused pins are disabled and muted. */
4743 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4744 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004745 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4746 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4747 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
4748 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4749 /* Disable digital (SPDIF) pins */
4750 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
4751 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
4752
Kailang Yangea1fb292008-08-26 12:58:38 +02004753 /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004754 * bus when acting as outputs.
4755 */
4756 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
4757 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
4758
4759 /* Start with output sum widgets muted and their output gains at min */
4760 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4761 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4762 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4763 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4764 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4765 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4766 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4767 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4768 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4769
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004770 /* Unmute Line-out pin widget amp left and right
4771 * (no equiv mixer ctrl)
4772 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004773 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithebd869482006-11-28 11:35:52 +01004774 /* Unmute mono pin widget amp output (no equiv mixer ctrl) */
4775 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004776 /* Unmute Mic1 and Line1 pin widget input buffers since they start as
4777 * inputs. If the pin mode is changed by the user the pin mode control
4778 * will take care of enabling the pin's input/output buffers as needed.
4779 * Therefore there's no need to enable the input buffer at this
4780 * stage.
4781 */
4782 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4783 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4784
4785 /* Mute capture amp left and right */
4786 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4787 /* Set ADC connection select to match default mixer setting - mic
4788 * (on mic1 pin)
4789 */
4790 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
4791
4792 /* Do similar with the second ADC: mute capture input amp and
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004793 * set ADC connection to mic to match ALSA's default state.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004794 */
4795 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004796 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01004797
4798 /* Mute all inputs to mixer widget (even unconnected ones) */
4799 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
4800 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
4801 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
4802 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
4803 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
4804 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
4805 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
4806 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
4807
4808 { }
4809};
4810
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004811static struct hda_verb alc260_will_verbs[] = {
4812 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4813 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x00},
4814 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
4815 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
4816 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
4817 {0x1a, AC_VERB_SET_PROC_COEF, 0x3040},
4818 {}
4819};
4820
4821static struct hda_verb alc260_replacer_672v_verbs[] = {
4822 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
4823 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
4824 {0x1a, AC_VERB_SET_PROC_COEF, 0x3050},
4825
4826 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
4827 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
4828 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
4829
4830 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
4831 {}
4832};
4833
4834/* toggle speaker-output according to the hp-jack state */
4835static void alc260_replacer_672v_automute(struct hda_codec *codec)
4836{
4837 unsigned int present;
4838
4839 /* speaker --> GPIO Data 0, hp or spdif --> GPIO data 1 */
4840 present = snd_hda_codec_read(codec, 0x0f, 0,
4841 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
4842 if (present) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02004843 snd_hda_codec_write_cache(codec, 0x01, 0,
4844 AC_VERB_SET_GPIO_DATA, 1);
4845 snd_hda_codec_write_cache(codec, 0x0f, 0,
4846 AC_VERB_SET_PIN_WIDGET_CONTROL,
4847 PIN_HP);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004848 } else {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02004849 snd_hda_codec_write_cache(codec, 0x01, 0,
4850 AC_VERB_SET_GPIO_DATA, 0);
4851 snd_hda_codec_write_cache(codec, 0x0f, 0,
4852 AC_VERB_SET_PIN_WIDGET_CONTROL,
4853 PIN_OUT);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02004854 }
4855}
4856
4857static void alc260_replacer_672v_unsol_event(struct hda_codec *codec,
4858 unsigned int res)
4859{
4860 if ((res >> 26) == ALC880_HP_EVENT)
4861 alc260_replacer_672v_automute(codec);
4862}
4863
Kailang Yang3f878302008-08-26 13:02:23 +02004864static struct hda_verb alc260_hp_dc7600_verbs[] = {
4865 {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
4866 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
4867 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4868 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4869 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4870 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4871 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4872 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
4873 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
4874 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
4875 {}
4876};
4877
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01004878/* Test configuration for debugging, modelled after the ALC880 test
4879 * configuration.
4880 */
4881#ifdef CONFIG_SND_DEBUG
4882static hda_nid_t alc260_test_dac_nids[1] = {
4883 0x02,
4884};
4885static hda_nid_t alc260_test_adc_nids[2] = {
4886 0x04, 0x05,
4887};
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004888/* For testing the ALC260, each input MUX needs its own definition since
Kailang Yangea1fb292008-08-26 12:58:38 +02004889 * the signal assignments are different. This assumes that the first ADC
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004890 * is NID 0x04.
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01004891 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004892static struct hda_input_mux alc260_test_capture_sources[2] = {
4893 {
4894 .num_items = 7,
4895 .items = {
4896 { "MIC1 pin", 0x0 },
4897 { "MIC2 pin", 0x1 },
4898 { "LINE1 pin", 0x2 },
4899 { "LINE2 pin", 0x3 },
4900 { "CD pin", 0x4 },
4901 { "LINE-OUT pin", 0x5 },
4902 { "HP-OUT pin", 0x6 },
4903 },
4904 },
4905 {
4906 .num_items = 8,
4907 .items = {
4908 { "MIC1 pin", 0x0 },
4909 { "MIC2 pin", 0x1 },
4910 { "LINE1 pin", 0x2 },
4911 { "LINE2 pin", 0x3 },
4912 { "CD pin", 0x4 },
4913 { "Mixer", 0x5 },
4914 { "LINE-OUT pin", 0x6 },
4915 { "HP-OUT pin", 0x7 },
4916 },
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01004917 },
4918};
4919static struct snd_kcontrol_new alc260_test_mixer[] = {
4920 /* Output driver widgets */
4921 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
4922 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
4923 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x09, 0x0, HDA_OUTPUT),
4924 HDA_BIND_MUTE("LOUT2 Playback Switch", 0x09, 2, HDA_INPUT),
4925 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x08, 0x0, HDA_OUTPUT),
4926 HDA_BIND_MUTE("LOUT1 Playback Switch", 0x08, 2, HDA_INPUT),
4927
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004928 /* Modes for retasking pin widgets
4929 * Note: the ALC260 doesn't seem to act on requests to enable mic
4930 * bias from NIDs 0x0f and 0x10. The ALC260 datasheet doesn't
4931 * mention this restriction. At this stage it's not clear whether
4932 * this behaviour is intentional or is a hardware bug in chip
4933 * revisions available at least up until early 2006. Therefore for
4934 * now allow the "HP-OUT" and "LINE-OUT" Mode controls to span all
4935 * choices, but if it turns out that the lack of mic bias for these
4936 * NIDs is intentional we could change their modes from
4937 * ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
4938 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01004939 ALC_PIN_MODE("HP-OUT pin mode", 0x10, ALC_PIN_DIR_INOUT),
4940 ALC_PIN_MODE("LINE-OUT pin mode", 0x0f, ALC_PIN_DIR_INOUT),
4941 ALC_PIN_MODE("LINE2 pin mode", 0x15, ALC_PIN_DIR_INOUT),
4942 ALC_PIN_MODE("LINE1 pin mode", 0x14, ALC_PIN_DIR_INOUT),
4943 ALC_PIN_MODE("MIC2 pin mode", 0x13, ALC_PIN_DIR_INOUT),
4944 ALC_PIN_MODE("MIC1 pin mode", 0x12, ALC_PIN_DIR_INOUT),
4945
4946 /* Loopback mixer controls */
4947 HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x07, 0x00, HDA_INPUT),
4948 HDA_CODEC_MUTE("MIC1 Playback Switch", 0x07, 0x00, HDA_INPUT),
4949 HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x07, 0x01, HDA_INPUT),
4950 HDA_CODEC_MUTE("MIC2 Playback Switch", 0x07, 0x01, HDA_INPUT),
4951 HDA_CODEC_VOLUME("LINE1 Playback Volume", 0x07, 0x02, HDA_INPUT),
4952 HDA_CODEC_MUTE("LINE1 Playback Switch", 0x07, 0x02, HDA_INPUT),
4953 HDA_CODEC_VOLUME("LINE2 Playback Volume", 0x07, 0x03, HDA_INPUT),
4954 HDA_CODEC_MUTE("LINE2 Playback Switch", 0x07, 0x03, HDA_INPUT),
4955 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
4956 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
4957 HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
4958 HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
4959 HDA_CODEC_VOLUME("LINE-OUT loopback Playback Volume", 0x07, 0x06, HDA_INPUT),
4960 HDA_CODEC_MUTE("LINE-OUT loopback Playback Switch", 0x07, 0x06, HDA_INPUT),
4961 HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x07, 0x7, HDA_INPUT),
4962 HDA_CODEC_MUTE("HP-OUT loopback Playback Switch", 0x07, 0x7, HDA_INPUT),
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01004963
4964 /* Controls for GPIO pins, assuming they are configured as outputs */
4965 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
4966 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
4967 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
4968 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
4969
Jonathan Woithe92621f12006-02-28 11:47:47 +01004970 /* Switches to allow the digital IO pins to be enabled. The datasheet
4971 * is ambigious as to which NID is which; testing on laptops which
Kailang Yangea1fb292008-08-26 12:58:38 +02004972 * make this output available should provide clarification.
Jonathan Woithe92621f12006-02-28 11:47:47 +01004973 */
4974 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x03, 0x01),
4975 ALC_SPDIF_CTRL_SWITCH("SPDIF Capture Switch", 0x06, 0x01),
4976
Jonathan Woithef8225f62008-01-08 12:16:54 +01004977 /* A switch allowing EAPD to be enabled. Some laptops seem to use
4978 * this output to turn on an external amplifier.
4979 */
4980 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
4981 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
4982
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01004983 { } /* end */
4984};
4985static struct hda_verb alc260_test_init_verbs[] = {
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01004986 /* Enable all GPIOs as outputs with an initial value of 0 */
4987 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f},
4988 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
4989 {0x01, AC_VERB_SET_GPIO_MASK, 0x0f},
4990
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01004991 /* Enable retasking pins as output, initially without power amp */
4992 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4993 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4994 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4995 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4996 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4997 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4998
Jonathan Woithe92621f12006-02-28 11:47:47 +01004999 /* Disable digital (SPDIF) pins initially, but users can enable
5000 * them via a mixer switch. In the case of SPDIF-out, this initverb
5001 * payload also sets the generation to 0, output to be in "consumer"
5002 * PCM format, copyright asserted, no pre-emphasis and no validity
5003 * control.
5004 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005005 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
5006 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
5007
Kailang Yangea1fb292008-08-26 12:58:38 +02005008 /* Ensure mic1, mic2, line1 and line2 pin widgets take input from the
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005009 * OUT1 sum bus when acting as an output.
5010 */
5011 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
5012 {0x0c, AC_VERB_SET_CONNECT_SEL, 0},
5013 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
5014 {0x0e, AC_VERB_SET_CONNECT_SEL, 0},
5015
5016 /* Start with output sum widgets muted and their output gains at min */
5017 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5018 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5019 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5020 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5021 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5022 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5023 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5024 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5025 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5026
Jonathan Woithecdcd9262006-02-28 11:36:42 +01005027 /* Unmute retasking pin widget output buffers since the default
5028 * state appears to be output. As the pin mode is changed by the
5029 * user the pin mode control will take care of enabling the pin's
5030 * input/output buffers as needed.
5031 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005032 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5033 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5034 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5035 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5036 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5037 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5038 /* Also unmute the mono-out pin widget */
5039 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5040
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005041 /* Mute capture amp left and right */
5042 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithef7ace402006-02-28 11:46:14 +01005043 /* Set ADC connection select to match default mixer setting (mic1
5044 * pin)
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005045 */
5046 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
5047
5048 /* Do the same for the second ADC: mute capture input amp and
Jonathan Woithef7ace402006-02-28 11:46:14 +01005049 * set ADC connection to mic1 pin
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005050 */
5051 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5052 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
5053
5054 /* Mute all inputs to mixer widget (even unconnected ones) */
5055 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
5056 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
5057 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
5058 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
5059 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
5060 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
5061 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
5062 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
5063
5064 { }
5065};
5066#endif
5067
Takashi Iwai63300792008-01-24 15:31:36 +01005068#define alc260_pcm_analog_playback alc880_pcm_analog_alt_playback
5069#define alc260_pcm_analog_capture alc880_pcm_analog_capture
Linus Torvalds1da177e2005-04-16 15:20:36 -07005070
Takashi Iwaia3bcba32005-12-06 19:05:29 +01005071#define alc260_pcm_digital_playback alc880_pcm_digital_playback
5072#define alc260_pcm_digital_capture alc880_pcm_digital_capture
5073
Kailang Yangdf694da2005-12-05 19:42:22 +01005074/*
5075 * for BIOS auto-configuration
5076 */
5077
5078static int alc260_add_playback_controls(struct alc_spec *spec, hda_nid_t nid,
Takashi Iwai863b4512008-10-21 17:01:47 +02005079 const char *pfx, int *vol_bits)
Kailang Yangdf694da2005-12-05 19:42:22 +01005080{
5081 hda_nid_t nid_vol;
5082 unsigned long vol_val, sw_val;
5083 char name[32];
5084 int err;
5085
5086 if (nid >= 0x0f && nid < 0x11) {
5087 nid_vol = nid - 0x7;
5088 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
5089 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
5090 } else if (nid == 0x11) {
5091 nid_vol = nid - 0x7;
5092 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT);
5093 sw_val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
5094 } else if (nid >= 0x12 && nid <= 0x15) {
5095 nid_vol = 0x08;
5096 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
5097 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
5098 } else
5099 return 0; /* N/A */
Kailang Yangea1fb292008-08-26 12:58:38 +02005100
Takashi Iwai863b4512008-10-21 17:01:47 +02005101 if (!(*vol_bits & (1 << nid_vol))) {
5102 /* first control for the volume widget */
5103 snprintf(name, sizeof(name), "%s Playback Volume", pfx);
5104 err = add_control(spec, ALC_CTL_WIDGET_VOL, name, vol_val);
5105 if (err < 0)
5106 return err;
5107 *vol_bits |= (1 << nid_vol);
5108 }
Kailang Yangdf694da2005-12-05 19:42:22 +01005109 snprintf(name, sizeof(name), "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005110 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, sw_val);
5111 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01005112 return err;
5113 return 1;
5114}
5115
5116/* add playback controls from the parsed DAC table */
5117static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec,
5118 const struct auto_pin_cfg *cfg)
5119{
5120 hda_nid_t nid;
5121 int err;
Takashi Iwai863b4512008-10-21 17:01:47 +02005122 int vols = 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01005123
5124 spec->multiout.num_dacs = 1;
5125 spec->multiout.dac_nids = spec->private_dac_nids;
5126 spec->multiout.dac_nids[0] = 0x02;
5127
5128 nid = cfg->line_out_pins[0];
5129 if (nid) {
Takashi Iwai863b4512008-10-21 17:01:47 +02005130 err = alc260_add_playback_controls(spec, nid, "Front", &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01005131 if (err < 0)
5132 return err;
5133 }
5134
Takashi Iwai82bc9552006-03-21 11:24:42 +01005135 nid = cfg->speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01005136 if (nid) {
Takashi Iwai863b4512008-10-21 17:01:47 +02005137 err = alc260_add_playback_controls(spec, nid, "Speaker", &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01005138 if (err < 0)
5139 return err;
5140 }
5141
Takashi Iwaieb06ed82006-09-20 17:10:27 +02005142 nid = cfg->hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01005143 if (nid) {
Takashi Iwai863b4512008-10-21 17:01:47 +02005144 err = alc260_add_playback_controls(spec, nid, "Headphone",
5145 &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01005146 if (err < 0)
5147 return err;
5148 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005149 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01005150}
5151
5152/* create playback/capture controls for input pins */
5153static int alc260_auto_create_analog_input_ctls(struct alc_spec *spec,
5154 const struct auto_pin_cfg *cfg)
5155{
Kailang Yangdf694da2005-12-05 19:42:22 +01005156 struct hda_input_mux *imux = &spec->private_imux;
5157 int i, err, idx;
5158
5159 for (i = 0; i < AUTO_PIN_LAST; i++) {
5160 if (cfg->input_pins[i] >= 0x12) {
5161 idx = cfg->input_pins[i] - 0x12;
Takashi Iwai4a471b72005-12-07 13:56:29 +01005162 err = new_analog_input(spec, cfg->input_pins[i],
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005163 auto_pin_cfg_labels[i], idx,
5164 0x07);
Kailang Yangdf694da2005-12-05 19:42:22 +01005165 if (err < 0)
5166 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005167 imux->items[imux->num_items].label =
5168 auto_pin_cfg_labels[i];
Kailang Yangdf694da2005-12-05 19:42:22 +01005169 imux->items[imux->num_items].index = idx;
5170 imux->num_items++;
5171 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005172 if (cfg->input_pins[i] >= 0x0f && cfg->input_pins[i] <= 0x10){
Kailang Yangdf694da2005-12-05 19:42:22 +01005173 idx = cfg->input_pins[i] - 0x09;
Takashi Iwai4a471b72005-12-07 13:56:29 +01005174 err = new_analog_input(spec, cfg->input_pins[i],
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005175 auto_pin_cfg_labels[i], idx,
5176 0x07);
Kailang Yangdf694da2005-12-05 19:42:22 +01005177 if (err < 0)
5178 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005179 imux->items[imux->num_items].label =
5180 auto_pin_cfg_labels[i];
Kailang Yangdf694da2005-12-05 19:42:22 +01005181 imux->items[imux->num_items].index = idx;
5182 imux->num_items++;
5183 }
5184 }
5185 return 0;
5186}
5187
5188static void alc260_auto_set_output_and_unmute(struct hda_codec *codec,
5189 hda_nid_t nid, int pin_type,
5190 int sel_idx)
5191{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005192 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01005193 /* need the manual connection? */
5194 if (nid >= 0x12) {
5195 int idx = nid - 0x12;
5196 snd_hda_codec_write(codec, idx + 0x0b, 0,
5197 AC_VERB_SET_CONNECT_SEL, sel_idx);
Kailang Yangdf694da2005-12-05 19:42:22 +01005198 }
5199}
5200
5201static void alc260_auto_init_multi_out(struct hda_codec *codec)
5202{
5203 struct alc_spec *spec = codec->spec;
5204 hda_nid_t nid;
5205
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005206 alc_subsystem_id(codec, 0x10, 0x15, 0x0f);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005207 nid = spec->autocfg.line_out_pins[0];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02005208 if (nid) {
5209 int pin_type = get_pin_type(spec->autocfg.line_out_type);
5210 alc260_auto_set_output_and_unmute(codec, nid, pin_type, 0);
5211 }
Kailang Yangea1fb292008-08-26 12:58:38 +02005212
Takashi Iwai82bc9552006-03-21 11:24:42 +01005213 nid = spec->autocfg.speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01005214 if (nid)
5215 alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
5216
Takashi Iwaieb06ed82006-09-20 17:10:27 +02005217 nid = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01005218 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02005219 alc260_auto_set_output_and_unmute(codec, nid, PIN_HP, 0);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005220}
Kailang Yangdf694da2005-12-05 19:42:22 +01005221
5222#define ALC260_PIN_CD_NID 0x16
5223static void alc260_auto_init_analog_input(struct hda_codec *codec)
5224{
5225 struct alc_spec *spec = codec->spec;
5226 int i;
5227
5228 for (i = 0; i < AUTO_PIN_LAST; i++) {
5229 hda_nid_t nid = spec->autocfg.input_pins[i];
5230 if (nid >= 0x12) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005231 snd_hda_codec_write(codec, nid, 0,
5232 AC_VERB_SET_PIN_WIDGET_CONTROL,
5233 i <= AUTO_PIN_FRONT_MIC ?
5234 PIN_VREF80 : PIN_IN);
Kailang Yangdf694da2005-12-05 19:42:22 +01005235 if (nid != ALC260_PIN_CD_NID)
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005236 snd_hda_codec_write(codec, nid, 0,
5237 AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangdf694da2005-12-05 19:42:22 +01005238 AMP_OUT_MUTE);
5239 }
5240 }
5241}
5242
5243/*
5244 * generic initialization of ADC, input mixers and output mixers
5245 */
5246static struct hda_verb alc260_volume_init_verbs[] = {
5247 /*
5248 * Unmute ADC0-1 and set the default input to mic-in
5249 */
5250 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
5251 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5252 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
5253 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +02005254
Kailang Yangdf694da2005-12-05 19:42:22 +01005255 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
5256 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005257 * Note: PASD motherboards uses the Line In 2 as the input for
5258 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01005259 */
5260 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02005261 /* mute analog inputs */
5262 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5263 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5264 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5265 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5266 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01005267
5268 /*
5269 * Set up output mixers (0x08 - 0x0a)
5270 */
5271 /* set vol=0 to output mixers */
5272 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5273 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5274 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5275 /* set up input amps for analog loopback */
5276 /* Amp Indices: DAC = 0, mixer = 1 */
5277 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5278 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5279 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5280 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5281 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5282 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +02005283
Kailang Yangdf694da2005-12-05 19:42:22 +01005284 { }
5285};
5286
5287static int alc260_parse_auto_config(struct hda_codec *codec)
5288{
5289 struct alc_spec *spec = codec->spec;
5290 unsigned int wcap;
5291 int err;
5292 static hda_nid_t alc260_ignore[] = { 0x17, 0 };
5293
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005294 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
5295 alc260_ignore);
5296 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01005297 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005298 err = alc260_auto_create_multi_out_ctls(spec, &spec->autocfg);
5299 if (err < 0)
Takashi Iwai4a471b72005-12-07 13:56:29 +01005300 return err;
Takashi Iwai603c4012008-07-30 15:01:44 +02005301 if (!spec->kctls.list)
Kailang Yangdf694da2005-12-05 19:42:22 +01005302 return 0; /* can't find valid BIOS pin config */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005303 err = alc260_auto_create_analog_input_ctls(spec, &spec->autocfg);
5304 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01005305 return err;
5306
5307 spec->multiout.max_channels = 2;
5308
5309 if (spec->autocfg.dig_out_pin)
5310 spec->multiout.dig_out_nid = ALC260_DIGOUT_NID;
Takashi Iwai603c4012008-07-30 15:01:44 +02005311 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +01005312 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +01005313
Takashi Iwaid88897e2008-10-31 15:01:37 +01005314 add_verb(spec, alc260_volume_init_verbs);
Kailang Yangdf694da2005-12-05 19:42:22 +01005315
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005316 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +01005317 spec->input_mux = &spec->private_imux;
5318
5319 /* check whether NID 0x04 is valid */
Takashi Iwai4a471b72005-12-07 13:56:29 +01005320 wcap = get_wcaps(codec, 0x04);
Kailang Yangdf694da2005-12-05 19:42:22 +01005321 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; /* get type */
Takashi Iwai67ebcb02008-02-19 15:03:57 +01005322 if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
Kailang Yangdf694da2005-12-05 19:42:22 +01005323 spec->adc_nids = alc260_adc_nids_alt;
5324 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt);
Takashi Iwaid88897e2008-10-31 15:01:37 +01005325 add_mixer(spec, alc260_capture_alt_mixer);
Kailang Yangdf694da2005-12-05 19:42:22 +01005326 } else {
5327 spec->adc_nids = alc260_adc_nids;
5328 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids);
Takashi Iwaid88897e2008-10-31 15:01:37 +01005329 add_mixer(spec, alc260_capture_mixer);
Kailang Yangdf694da2005-12-05 19:42:22 +01005330 }
5331
Takashi Iwaie044c392008-10-27 16:56:24 +01005332 store_pin_configs(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01005333 return 1;
5334}
5335
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005336/* additional initialization for auto-configuration model */
5337static void alc260_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01005338{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005339 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01005340 alc260_auto_init_multi_out(codec);
5341 alc260_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005342 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02005343 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01005344}
5345
Takashi Iwaicb53c622007-08-10 17:21:45 +02005346#ifdef CONFIG_SND_HDA_POWER_SAVE
5347static struct hda_amp_list alc260_loopbacks[] = {
5348 { 0x07, HDA_INPUT, 0 },
5349 { 0x07, HDA_INPUT, 1 },
5350 { 0x07, HDA_INPUT, 2 },
5351 { 0x07, HDA_INPUT, 3 },
5352 { 0x07, HDA_INPUT, 4 },
5353 { } /* end */
5354};
5355#endif
5356
Kailang Yangdf694da2005-12-05 19:42:22 +01005357/*
5358 * ALC260 configurations
5359 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005360static const char *alc260_models[ALC260_MODEL_LAST] = {
5361 [ALC260_BASIC] = "basic",
5362 [ALC260_HP] = "hp",
5363 [ALC260_HP_3013] = "hp-3013",
Takashi Iwai2922c9a2008-08-27 18:12:42 +02005364 [ALC260_HP_DC7600] = "hp-dc7600",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005365 [ALC260_FUJITSU_S702X] = "fujitsu",
5366 [ALC260_ACER] = "acer",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005367 [ALC260_WILL] = "will",
5368 [ALC260_REPLACER_672V] = "replacer",
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005369#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005370 [ALC260_TEST] = "test",
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005371#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005372 [ALC260_AUTO] = "auto",
5373};
5374
5375static struct snd_pci_quirk alc260_cfg_tbl[] = {
Jonathan Woithebd869482006-11-28 11:35:52 +01005376 SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005377 SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER),
Takashi Iwai9720b712007-03-13 21:46:23 +01005378 SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013),
Takashi Iwaia8a5d062007-03-15 15:10:28 +01005379 SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_HP_3013),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005380 SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013),
Jaroslav Kysela34ec8a02008-07-10 14:49:19 +02005381 SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP_3013),
Kailang Yang3f878302008-08-26 13:02:23 +02005382 SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_DC7600),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005383 SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013),
5384 SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP),
5385 SND_PCI_QUIRK(0x103c, 0x3015, "HP", ALC260_HP),
5386 SND_PCI_QUIRK(0x103c, 0x3016, "HP", ALC260_HP),
5387 SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_BASIC),
5388 SND_PCI_QUIRK(0x104d, 0x81cc, "Sony VAIO", ALC260_BASIC),
5389 SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC),
5390 SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X),
5391 SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005392 SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_REPLACER_672V),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01005393 SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_WILL),
Takashi Iwai16ded522005-06-10 19:58:24 +02005394 {}
5395};
5396
Kailang Yangdf694da2005-12-05 19:42:22 +01005397static struct alc_config_preset alc260_presets[] = {
5398 [ALC260_BASIC] = {
5399 .mixers = { alc260_base_output_mixer,
5400 alc260_input_mixer,
5401 alc260_pc_beep_mixer,
5402 alc260_capture_mixer },
5403 .init_verbs = { alc260_init_verbs },
5404 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5405 .dac_nids = alc260_dac_nids,
5406 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
5407 .adc_nids = alc260_adc_nids,
5408 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5409 .channel_mode = alc260_modes,
5410 .input_mux = &alc260_capture_source,
5411 },
5412 [ALC260_HP] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01005413 .mixers = { alc260_hp_output_mixer,
Kailang Yangdf694da2005-12-05 19:42:22 +01005414 alc260_input_mixer,
5415 alc260_capture_alt_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01005416 .init_verbs = { alc260_init_verbs,
5417 alc260_hp_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01005418 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5419 .dac_nids = alc260_dac_nids,
5420 .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids),
5421 .adc_nids = alc260_hp_adc_nids,
5422 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5423 .channel_mode = alc260_modes,
5424 .input_mux = &alc260_capture_source,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005425 .unsol_event = alc260_hp_unsol_event,
5426 .init_hook = alc260_hp_automute,
Kailang Yangdf694da2005-12-05 19:42:22 +01005427 },
Kailang Yang3f878302008-08-26 13:02:23 +02005428 [ALC260_HP_DC7600] = {
5429 .mixers = { alc260_hp_dc7600_mixer,
5430 alc260_input_mixer,
5431 alc260_capture_alt_mixer },
5432 .init_verbs = { alc260_init_verbs,
5433 alc260_hp_dc7600_verbs },
5434 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5435 .dac_nids = alc260_dac_nids,
5436 .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids),
5437 .adc_nids = alc260_hp_adc_nids,
5438 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5439 .channel_mode = alc260_modes,
5440 .input_mux = &alc260_capture_source,
5441 .unsol_event = alc260_hp_3012_unsol_event,
5442 .init_hook = alc260_hp_3012_automute,
5443 },
Kailang Yangdf694da2005-12-05 19:42:22 +01005444 [ALC260_HP_3013] = {
5445 .mixers = { alc260_hp_3013_mixer,
5446 alc260_input_mixer,
5447 alc260_capture_alt_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01005448 .init_verbs = { alc260_hp_3013_init_verbs,
5449 alc260_hp_3013_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01005450 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5451 .dac_nids = alc260_dac_nids,
5452 .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids),
5453 .adc_nids = alc260_hp_adc_nids,
5454 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5455 .channel_mode = alc260_modes,
5456 .input_mux = &alc260_capture_source,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005457 .unsol_event = alc260_hp_3013_unsol_event,
5458 .init_hook = alc260_hp_3013_automute,
Kailang Yangdf694da2005-12-05 19:42:22 +01005459 },
5460 [ALC260_FUJITSU_S702X] = {
5461 .mixers = { alc260_fujitsu_mixer,
5462 alc260_capture_mixer },
5463 .init_verbs = { alc260_fujitsu_init_verbs },
5464 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5465 .dac_nids = alc260_dac_nids,
Jonathan Woithed57fdac2006-02-28 11:38:35 +01005466 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
5467 .adc_nids = alc260_dual_adc_nids,
Kailang Yangdf694da2005-12-05 19:42:22 +01005468 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5469 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005470 .num_mux_defs = ARRAY_SIZE(alc260_fujitsu_capture_sources),
5471 .input_mux = alc260_fujitsu_capture_sources,
Kailang Yangdf694da2005-12-05 19:42:22 +01005472 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005473 [ALC260_ACER] = {
5474 .mixers = { alc260_acer_mixer,
5475 alc260_capture_mixer },
5476 .init_verbs = { alc260_acer_init_verbs },
5477 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5478 .dac_nids = alc260_dac_nids,
5479 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
5480 .adc_nids = alc260_dual_adc_nids,
5481 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5482 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005483 .num_mux_defs = ARRAY_SIZE(alc260_acer_capture_sources),
5484 .input_mux = alc260_acer_capture_sources,
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005485 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005486 [ALC260_WILL] = {
5487 .mixers = { alc260_will_mixer,
5488 alc260_capture_mixer },
5489 .init_verbs = { alc260_init_verbs, alc260_will_verbs },
5490 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5491 .dac_nids = alc260_dac_nids,
5492 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
5493 .adc_nids = alc260_adc_nids,
5494 .dig_out_nid = ALC260_DIGOUT_NID,
5495 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5496 .channel_mode = alc260_modes,
5497 .input_mux = &alc260_capture_source,
5498 },
5499 [ALC260_REPLACER_672V] = {
5500 .mixers = { alc260_replacer_672v_mixer,
5501 alc260_capture_mixer },
5502 .init_verbs = { alc260_init_verbs, alc260_replacer_672v_verbs },
5503 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
5504 .dac_nids = alc260_dac_nids,
5505 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
5506 .adc_nids = alc260_adc_nids,
5507 .dig_out_nid = ALC260_DIGOUT_NID,
5508 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5509 .channel_mode = alc260_modes,
5510 .input_mux = &alc260_capture_source,
5511 .unsol_event = alc260_replacer_672v_unsol_event,
5512 .init_hook = alc260_replacer_672v_automute,
5513 },
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005514#ifdef CONFIG_SND_DEBUG
5515 [ALC260_TEST] = {
5516 .mixers = { alc260_test_mixer,
5517 alc260_capture_mixer },
5518 .init_verbs = { alc260_test_init_verbs },
5519 .num_dacs = ARRAY_SIZE(alc260_test_dac_nids),
5520 .dac_nids = alc260_test_dac_nids,
5521 .num_adc_nids = ARRAY_SIZE(alc260_test_adc_nids),
5522 .adc_nids = alc260_test_adc_nids,
5523 .num_channel_mode = ARRAY_SIZE(alc260_modes),
5524 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005525 .num_mux_defs = ARRAY_SIZE(alc260_test_capture_sources),
5526 .input_mux = alc260_test_capture_sources,
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005527 },
5528#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01005529};
5530
Linus Torvalds1da177e2005-04-16 15:20:36 -07005531static int patch_alc260(struct hda_codec *codec)
5532{
5533 struct alc_spec *spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01005534 int err, board_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005535
Takashi Iwaie560d8d2005-09-09 14:21:46 +02005536 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005537 if (spec == NULL)
5538 return -ENOMEM;
5539
5540 codec->spec = spec;
5541
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005542 board_config = snd_hda_check_board_config(codec, ALC260_MODEL_LAST,
5543 alc260_models,
5544 alc260_cfg_tbl);
5545 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02005546 snd_printd(KERN_INFO "hda_codec: Unknown model for ALC260, "
5547 "trying auto-probe from BIOS...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01005548 board_config = ALC260_AUTO;
Takashi Iwai16ded522005-06-10 19:58:24 +02005549 }
5550
Kailang Yangdf694da2005-12-05 19:42:22 +01005551 if (board_config == ALC260_AUTO) {
5552 /* automatic parse from the BIOS config */
5553 err = alc260_parse_auto_config(codec);
5554 if (err < 0) {
5555 alc_free(codec);
5556 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005557 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02005558 printk(KERN_INFO
5559 "hda_codec: Cannot set up configuration "
5560 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01005561 board_config = ALC260_BASIC;
5562 }
Takashi Iwai16ded522005-06-10 19:58:24 +02005563 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005564
Kailang Yangdf694da2005-12-05 19:42:22 +01005565 if (board_config != ALC260_AUTO)
5566 setup_preset(spec, &alc260_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005567
5568 spec->stream_name_analog = "ALC260 Analog";
5569 spec->stream_analog_playback = &alc260_pcm_analog_playback;
5570 spec->stream_analog_capture = &alc260_pcm_analog_capture;
5571
Takashi Iwaia3bcba32005-12-06 19:05:29 +01005572 spec->stream_name_digital = "ALC260 Digital";
5573 spec->stream_digital_playback = &alc260_pcm_digital_playback;
5574 spec->stream_digital_capture = &alc260_pcm_digital_capture;
5575
Takashi Iwai2134ea42008-01-10 16:53:55 +01005576 spec->vmaster_nid = 0x08;
5577
Linus Torvalds1da177e2005-04-16 15:20:36 -07005578 codec->patch_ops = alc_patch_ops;
Kailang Yangdf694da2005-12-05 19:42:22 +01005579 if (board_config == ALC260_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005580 spec->init_hook = alc260_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02005581#ifdef CONFIG_SND_HDA_POWER_SAVE
5582 if (!spec->loopback.amplist)
5583 spec->loopback.amplist = alc260_loopbacks;
5584#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005585
5586 return 0;
5587}
5588
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005589
Linus Torvalds1da177e2005-04-16 15:20:36 -07005590/*
5591 * ALC882 support
5592 *
5593 * ALC882 is almost identical with ALC880 but has cleaner and more flexible
5594 * configuration. Each pin widget can choose any input DACs and a mixer.
5595 * Each ADC is connected from a mixer of all inputs. This makes possible
5596 * 6-channel independent captures.
5597 *
5598 * In addition, an independent DAC for the multi-playback (not used in this
5599 * driver yet).
5600 */
Kailang Yangdf694da2005-12-05 19:42:22 +01005601#define ALC882_DIGOUT_NID 0x06
5602#define ALC882_DIGIN_NID 0x0a
Linus Torvalds1da177e2005-04-16 15:20:36 -07005603
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01005604static struct hda_channel_mode alc882_ch_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005605 { 8, NULL }
5606};
5607
5608static hda_nid_t alc882_dac_nids[4] = {
5609 /* front, rear, clfe, rear_surr */
5610 0x02, 0x03, 0x04, 0x05
5611};
5612
Kailang Yangdf694da2005-12-05 19:42:22 +01005613/* identical with ALC880 */
5614#define alc882_adc_nids alc880_adc_nids
5615#define alc882_adc_nids_alt alc880_adc_nids_alt
Linus Torvalds1da177e2005-04-16 15:20:36 -07005616
Takashi Iwaie1406342008-02-11 18:32:32 +01005617static hda_nid_t alc882_capsrc_nids[3] = { 0x24, 0x23, 0x22 };
5618static hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 };
5619
Linus Torvalds1da177e2005-04-16 15:20:36 -07005620/* input MUX */
5621/* FIXME: should be a matrix-type input source selection */
5622
5623static struct hda_input_mux alc882_capture_source = {
5624 .num_items = 4,
5625 .items = {
5626 { "Mic", 0x0 },
5627 { "Front Mic", 0x1 },
5628 { "Line", 0x2 },
5629 { "CD", 0x4 },
5630 },
5631};
Linus Torvalds1da177e2005-04-16 15:20:36 -07005632#define alc882_mux_enum_info alc_mux_enum_info
5633#define alc882_mux_enum_get alc_mux_enum_get
5634
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005635static int alc882_mux_enum_put(struct snd_kcontrol *kcontrol,
5636 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005637{
5638 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
5639 struct alc_spec *spec = codec->spec;
5640 const struct hda_input_mux *imux = spec->input_mux;
5641 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Takashi Iwai88c71a92008-02-14 17:27:17 +01005642 hda_nid_t nid = spec->capsrc_nids ?
5643 spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx];
Linus Torvalds1da177e2005-04-16 15:20:36 -07005644 unsigned int *cur_val = &spec->cur_mux[adc_idx];
5645 unsigned int i, idx;
5646
5647 idx = ucontrol->value.enumerated.item[0];
5648 if (idx >= imux->num_items)
5649 idx = imux->num_items - 1;
Takashi Iwai82beb8f2007-08-10 17:09:26 +02005650 if (*cur_val == idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005651 return 0;
5652 for (i = 0; i < imux->num_items; i++) {
Takashi Iwai47fd8302007-08-10 17:11:07 +02005653 unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE;
5654 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT,
Takashi Iwai82beb8f2007-08-10 17:09:26 +02005655 imux->items[i].index,
Takashi Iwai47fd8302007-08-10 17:11:07 +02005656 HDA_AMP_MUTE, v);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005657 }
5658 *cur_val = idx;
5659 return 1;
5660}
5661
Kailang Yangdf694da2005-12-05 19:42:22 +01005662/*
Kailang Yang272a5272007-05-14 11:00:38 +02005663 * 2ch mode
5664 */
5665static struct hda_verb alc882_3ST_ch2_init[] = {
5666 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
5667 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
5668 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
5669 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
5670 { } /* end */
5671};
5672
5673/*
5674 * 6ch mode
5675 */
5676static struct hda_verb alc882_3ST_ch6_init[] = {
5677 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5678 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
5679 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
5680 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5681 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
5682 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
5683 { } /* end */
5684};
5685
5686static struct hda_channel_mode alc882_3ST_6ch_modes[2] = {
5687 { 2, alc882_3ST_ch2_init },
5688 { 6, alc882_3ST_ch6_init },
5689};
5690
5691/*
Kailang Yangdf694da2005-12-05 19:42:22 +01005692 * 6ch mode
5693 */
5694static struct hda_verb alc882_sixstack_ch6_init[] = {
5695 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
5696 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5697 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5698 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5699 { } /* end */
5700};
5701
5702/*
5703 * 8ch mode
5704 */
5705static struct hda_verb alc882_sixstack_ch8_init[] = {
5706 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5707 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5708 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5709 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5710 { } /* end */
5711};
5712
5713static struct hda_channel_mode alc882_sixstack_modes[2] = {
5714 { 6, alc882_sixstack_ch6_init },
5715 { 8, alc882_sixstack_ch8_init },
5716};
5717
Takashi Iwai87350ad2007-08-16 18:19:38 +02005718/*
5719 * macbook pro ALC885 can switch LineIn to LineOut without loosing Mic
5720 */
5721
5722/*
5723 * 2ch mode
5724 */
5725static struct hda_verb alc885_mbp_ch2_init[] = {
5726 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
5727 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5728 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5729 { } /* end */
5730};
5731
5732/*
5733 * 6ch mode
5734 */
5735static struct hda_verb alc885_mbp_ch6_init[] = {
5736 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
5737 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5738 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
5739 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5740 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5741 { } /* end */
5742};
5743
5744static struct hda_channel_mode alc885_mbp_6ch_modes[2] = {
5745 { 2, alc885_mbp_ch2_init },
5746 { 6, alc885_mbp_ch6_init },
5747};
5748
5749
Linus Torvalds1da177e2005-04-16 15:20:36 -07005750/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
5751 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
5752 */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01005753static struct snd_kcontrol_new alc882_base_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02005754 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005755 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02005756 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005757 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02005758 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
5759 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005760 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
5761 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02005762 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005763 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005764 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
5765 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5766 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5767 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5768 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5769 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01005770 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005771 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
5772 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01005773 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005774 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
5775 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
5776 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005777 { } /* end */
5778};
5779
Takashi Iwai87350ad2007-08-16 18:19:38 +02005780static struct snd_kcontrol_new alc885_mbp3_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01005781 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
5782 HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
5783 HDA_CODEC_MUTE ("Speaker Playback Switch", 0x14, 0x00, HDA_OUTPUT),
5784 HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
5785 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5786 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02005787 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
5788 HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01005789 HDA_CODEC_VOLUME("Line Boost", 0x1a, 0x00, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02005790 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT),
5791 { } /* end */
5792};
Kailang Yangbdd148a2007-05-08 15:19:08 +02005793static struct snd_kcontrol_new alc882_w2jc_mixer[] = {
5794 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5795 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
5796 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5797 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5798 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5799 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5800 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5801 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
5802 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
5803 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
5804 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
5805 { } /* end */
5806};
5807
Kailang Yang272a5272007-05-14 11:00:38 +02005808static struct snd_kcontrol_new alc882_targa_mixer[] = {
5809 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5810 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
5811 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
5812 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5813 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5814 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5815 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5816 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5817 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai96fe7cc2007-09-07 10:57:44 +02005818 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02005819 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
5820 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai96fe7cc2007-09-07 10:57:44 +02005821 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02005822 { } /* end */
5823};
5824
5825/* Pin assignment: Front=0x14, HP = 0x15, Front = 0x16, ???
5826 * Front Mic=0x18, Line In = 0x1a, Line In = 0x1b, CD = 0x1c
5827 */
5828static struct snd_kcontrol_new alc882_asus_a7j_mixer[] = {
5829 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5830 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
5831 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
5832 HDA_CODEC_MUTE("Mobile Front Playback Switch", 0x16, 0x0, HDA_OUTPUT),
5833 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5834 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5835 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5836 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5837 HDA_CODEC_VOLUME("Mobile Line Playback Volume", 0x0b, 0x03, HDA_INPUT),
5838 HDA_CODEC_MUTE("Mobile Line Playback Switch", 0x0b, 0x03, HDA_INPUT),
5839 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5840 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai96fe7cc2007-09-07 10:57:44 +02005841 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02005842 { } /* end */
5843};
5844
Takashi Iwai914759b2007-09-06 14:52:04 +02005845static struct snd_kcontrol_new alc882_asus_a7m_mixer[] = {
5846 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5847 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
5848 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
5849 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
5850 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
5851 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
5852 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
5853 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
5854 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
5855 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
5856 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
5857 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
5858 { } /* end */
5859};
5860
Kailang Yangdf694da2005-12-05 19:42:22 +01005861static struct snd_kcontrol_new alc882_chmode_mixer[] = {
5862 {
5863 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5864 .name = "Channel Mode",
5865 .info = alc_ch_mode_info,
5866 .get = alc_ch_mode_get,
5867 .put = alc_ch_mode_put,
5868 },
5869 { } /* end */
5870};
5871
Linus Torvalds1da177e2005-04-16 15:20:36 -07005872static struct hda_verb alc882_init_verbs[] = {
5873 /* Front mixer: unmute input/output amp left and right (volume = 0) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005874 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5875 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5876 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005877 /* Rear mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02005878 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5879 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5880 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005881 /* CLFE mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02005882 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5883 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5884 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005885 /* Side mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02005886 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5887 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5888 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005889
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005890 /* Front Pin: output 0 (0x0c) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005891 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02005892 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005893 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005894 /* Rear Pin: output 1 (0x0d) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005895 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02005896 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005897 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005898 /* CLFE Pin: output 2 (0x0e) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005899 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02005900 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005901 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005902 /* Side Pin: output 3 (0x0f) */
Takashi Iwai05acb862005-06-10 19:50:25 +02005903 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02005904 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005905 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005906 /* Mic (rear) pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02005907 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005908 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5909 /* Front Mic pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02005910 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005911 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5912 /* Line In pin: input */
Takashi Iwai05acb862005-06-10 19:50:25 +02005913 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005914 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5915 /* Line-2 In: Headphone output (output 0 - 0x0c) */
5916 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5917 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5918 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005919 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02005920 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005921
5922 /* FIXME: use matrix-type input source selection */
5923 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
5924 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
Takashi Iwai05acb862005-06-10 19:50:25 +02005925 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5926 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5927 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5928 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005929 /* Input mixer2 */
Takashi Iwai05acb862005-06-10 19:50:25 +02005930 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5931 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5932 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5933 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005934 /* Input mixer3 */
Takashi Iwai05acb862005-06-10 19:50:25 +02005935 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5936 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5937 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5938 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5939 /* ADC1: mute amp left and right */
5940 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02005941 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02005942 /* ADC2: mute amp left and right */
5943 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02005944 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02005945 /* ADC3: mute amp left and right */
5946 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02005947 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005948
5949 { }
5950};
5951
Takashi Iwai4b146cb2006-07-28 14:42:36 +02005952static struct hda_verb alc882_eapd_verbs[] = {
5953 /* change to EAPD mode */
5954 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01005955 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005956 { }
Takashi Iwai4b146cb2006-07-28 14:42:36 +02005957};
5958
Tobin Davis9102cd12006-12-15 10:02:12 +01005959/* Mac Pro test */
5960static struct snd_kcontrol_new alc882_macpro_mixer[] = {
5961 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
5962 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
5963 HDA_CODEC_MUTE("Headphone Playback Switch", 0x18, 0x0, HDA_OUTPUT),
5964 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
5965 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
5966 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x02, HDA_INPUT),
5967 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x02, HDA_INPUT),
5968 { } /* end */
5969};
5970
5971static struct hda_verb alc882_macpro_init_verbs[] = {
5972 /* Front mixer: unmute input/output amp left and right (volume = 0) */
5973 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5974 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5975 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5976 /* Front Pin: output 0 (0x0c) */
5977 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5978 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5979 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
5980 /* Front Mic pin: input vref at 80% */
5981 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
5982 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5983 /* Speaker: output */
5984 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5985 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5986 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x04},
5987 /* Headphone output (output 0 - 0x0c) */
5988 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5989 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5990 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
5991
5992 /* FIXME: use matrix-type input source selection */
5993 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
5994 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
5995 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5996 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5997 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5998 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5999 /* Input mixer2 */
6000 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6001 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6002 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6003 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6004 /* Input mixer3 */
6005 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6006 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6007 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6008 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6009 /* ADC1: mute amp left and right */
6010 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6011 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
6012 /* ADC2: mute amp left and right */
6013 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6014 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
6015 /* ADC3: mute amp left and right */
6016 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6017 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
6018
6019 { }
6020};
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006021
Takashi Iwai87350ad2007-08-16 18:19:38 +02006022/* Macbook Pro rev3 */
6023static struct hda_verb alc885_mbp3_init_verbs[] = {
6024 /* Front mixer: unmute input/output amp left and right (volume = 0) */
6025 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6026 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6027 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6028 /* Rear mixer */
6029 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6030 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6031 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6032 /* Front Pin: output 0 (0x0c) */
6033 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6034 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6035 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
6036 /* HP Pin: output 0 (0x0d) */
6037 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
6038 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6039 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
6040 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
6041 /* Mic (rear) pin: input vref at 80% */
6042 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
6043 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6044 /* Front Mic pin: input vref at 80% */
6045 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
6046 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6047 /* Line In pin: use output 1 when in LineOut mode */
6048 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
6049 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6050 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
6051
6052 /* FIXME: use matrix-type input source selection */
6053 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
6054 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
6055 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6056 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6057 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6058 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6059 /* Input mixer2 */
6060 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6061 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6062 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6063 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6064 /* Input mixer3 */
6065 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6066 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6067 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6068 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
6069 /* ADC1: mute amp left and right */
6070 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6071 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
6072 /* ADC2: mute amp left and right */
6073 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6074 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
6075 /* ADC3: mute amp left and right */
6076 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6077 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
6078
6079 { }
6080};
6081
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006082/* iMac 24 mixer. */
6083static struct snd_kcontrol_new alc885_imac24_mixer[] = {
6084 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
6085 HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x00, HDA_INPUT),
6086 { } /* end */
6087};
6088
6089/* iMac 24 init verbs. */
6090static struct hda_verb alc885_imac24_init_verbs[] = {
6091 /* Internal speakers: output 0 (0x0c) */
6092 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6093 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6094 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
6095 /* Internal speakers: output 0 (0x0c) */
6096 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6097 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6098 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
6099 /* Headphone: output 0 (0x0c) */
6100 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6101 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6102 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
6103 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
6104 /* Front Mic: input vref at 80% */
6105 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
6106 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6107 { }
6108};
6109
6110/* Toggle speaker-output according to the hp-jack state */
6111static void alc885_imac24_automute(struct hda_codec *codec)
6112{
6113 unsigned int present;
6114
6115 present = snd_hda_codec_read(codec, 0x14, 0,
6116 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02006117 snd_hda_codec_amp_stereo(codec, 0x18, HDA_OUTPUT, 0,
6118 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
6119 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0,
6120 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006121}
6122
6123/* Processes unsolicited events. */
6124static void alc885_imac24_unsol_event(struct hda_codec *codec,
6125 unsigned int res)
6126{
6127 /* Headphone insertion or removal. */
6128 if ((res >> 26) == ALC880_HP_EVENT)
6129 alc885_imac24_automute(codec);
6130}
6131
Takashi Iwai87350ad2007-08-16 18:19:38 +02006132static void alc885_mbp3_automute(struct hda_codec *codec)
6133{
6134 unsigned int present;
6135
6136 present = snd_hda_codec_read(codec, 0x15, 0,
6137 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
6138 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
6139 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
6140 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
6141 HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE);
6142
6143}
6144static void alc885_mbp3_unsol_event(struct hda_codec *codec,
6145 unsigned int res)
6146{
6147 /* Headphone insertion or removal. */
6148 if ((res >> 26) == ALC880_HP_EVENT)
6149 alc885_mbp3_automute(codec);
6150}
6151
6152
Kailang Yang272a5272007-05-14 11:00:38 +02006153static struct hda_verb alc882_targa_verbs[] = {
6154 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6155 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6156
6157 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6158 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02006159
Kailang Yang272a5272007-05-14 11:00:38 +02006160 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
6161 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
6162 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
6163
6164 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
6165 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
6166 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
6167 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
6168 { } /* end */
6169};
6170
6171/* toggle speaker-output according to the hp-jack state */
6172static void alc882_targa_automute(struct hda_codec *codec)
6173{
6174 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02006175
Kailang Yang272a5272007-05-14 11:00:38 +02006176 present = snd_hda_codec_read(codec, 0x14, 0,
6177 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02006178 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
6179 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02006180 snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
6181 present ? 1 : 3);
Kailang Yang272a5272007-05-14 11:00:38 +02006182}
6183
6184static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res)
6185{
6186 /* Looks like the unsol event is incompatible with the standard
6187 * definition. 4bit tag is placed at 26 bit!
6188 */
6189 if (((res >> 26) == ALC880_HP_EVENT)) {
6190 alc882_targa_automute(codec);
6191 }
6192}
6193
6194static struct hda_verb alc882_asus_a7j_verbs[] = {
6195 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6196 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6197
6198 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6199 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6200 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02006201
Kailang Yang272a5272007-05-14 11:00:38 +02006202 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
6203 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
6204 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
6205
6206 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
6207 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
6208 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
6209 { } /* end */
6210};
6211
Takashi Iwai914759b2007-09-06 14:52:04 +02006212static struct hda_verb alc882_asus_a7m_verbs[] = {
6213 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6214 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6215
6216 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6217 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6218 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02006219
Takashi Iwai914759b2007-09-06 14:52:04 +02006220 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
6221 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
6222 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
6223
6224 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
6225 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
6226 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
6227 { } /* end */
6228};
6229
Tobin Davis9102cd12006-12-15 10:02:12 +01006230static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted)
6231{
6232 unsigned int gpiostate, gpiomask, gpiodir;
6233
6234 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
6235 AC_VERB_GET_GPIO_DATA, 0);
6236
6237 if (!muted)
6238 gpiostate |= (1 << pin);
6239 else
6240 gpiostate &= ~(1 << pin);
6241
6242 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
6243 AC_VERB_GET_GPIO_MASK, 0);
6244 gpiomask |= (1 << pin);
6245
6246 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
6247 AC_VERB_GET_GPIO_DIRECTION, 0);
6248 gpiodir |= (1 << pin);
6249
6250
6251 snd_hda_codec_write(codec, codec->afg, 0,
6252 AC_VERB_SET_GPIO_MASK, gpiomask);
6253 snd_hda_codec_write(codec, codec->afg, 0,
6254 AC_VERB_SET_GPIO_DIRECTION, gpiodir);
6255
6256 msleep(1);
6257
6258 snd_hda_codec_write(codec, codec->afg, 0,
6259 AC_VERB_SET_GPIO_DATA, gpiostate);
6260}
6261
Takashi Iwai7debbe52007-08-16 15:01:03 +02006262/* set up GPIO at initialization */
6263static void alc885_macpro_init_hook(struct hda_codec *codec)
6264{
6265 alc882_gpio_mute(codec, 0, 0);
6266 alc882_gpio_mute(codec, 1, 0);
6267}
6268
6269/* set up GPIO and update auto-muting at initialization */
6270static void alc885_imac24_init_hook(struct hda_codec *codec)
6271{
6272 alc885_macpro_init_hook(codec);
6273 alc885_imac24_automute(codec);
6274}
6275
Kailang Yangdf694da2005-12-05 19:42:22 +01006276/*
6277 * generic initialization of ADC, input mixers and output mixers
6278 */
6279static struct hda_verb alc882_auto_init_verbs[] = {
6280 /*
6281 * Unmute ADC0-2 and set the default input to mic-in
6282 */
6283 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
6284 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6285 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
6286 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6287 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
6288 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6289
Takashi Iwaicb53c622007-08-10 17:21:45 +02006290 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +01006291 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006292 * Note: PASD motherboards uses the Line In 2 as the input for
6293 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01006294 */
6295 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02006296 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6297 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6298 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6299 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6300 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01006301
6302 /*
6303 * Set up output mixers (0x0c - 0x0f)
6304 */
6305 /* set vol=0 to output mixers */
6306 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6307 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6308 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6309 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6310 /* set up input amps for analog loopback */
6311 /* Amp Indices: DAC = 0, mixer = 1 */
6312 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6313 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6314 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6315 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6316 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6317 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6318 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6319 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6320 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6321 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6322
6323 /* FIXME: use matrix-type input source selection */
6324 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
6325 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
6326 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6327 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
6328 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
6329 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
6330 /* Input mixer2 */
6331 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6332 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
6333 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
6334 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
6335 /* Input mixer3 */
6336 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6337 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
6338 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
6339 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
6340
6341 { }
6342};
6343
6344/* capture mixer elements */
6345static struct snd_kcontrol_new alc882_capture_alt_mixer[] = {
6346 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
6347 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
6348 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
6349 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
6350 {
6351 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6352 /* The multiple "Capture Source" controls confuse alsamixer
6353 * So call somewhat different..
Kailang Yangdf694da2005-12-05 19:42:22 +01006354 */
6355 /* .name = "Capture Source", */
6356 .name = "Input Source",
6357 .count = 2,
6358 .info = alc882_mux_enum_info,
6359 .get = alc882_mux_enum_get,
6360 .put = alc882_mux_enum_put,
6361 },
6362 { } /* end */
6363};
6364
6365static struct snd_kcontrol_new alc882_capture_mixer[] = {
6366 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
6367 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
6368 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT),
6369 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT),
6370 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT),
6371 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT),
6372 {
6373 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6374 /* The multiple "Capture Source" controls confuse alsamixer
6375 * So call somewhat different..
Kailang Yangdf694da2005-12-05 19:42:22 +01006376 */
6377 /* .name = "Capture Source", */
6378 .name = "Input Source",
6379 .count = 3,
6380 .info = alc882_mux_enum_info,
6381 .get = alc882_mux_enum_get,
6382 .put = alc882_mux_enum_put,
6383 },
6384 { } /* end */
6385};
6386
Takashi Iwaicb53c622007-08-10 17:21:45 +02006387#ifdef CONFIG_SND_HDA_POWER_SAVE
6388#define alc882_loopbacks alc880_loopbacks
6389#endif
6390
Kailang Yangdf694da2005-12-05 19:42:22 +01006391/* pcm configuration: identiacal with ALC880 */
6392#define alc882_pcm_analog_playback alc880_pcm_analog_playback
6393#define alc882_pcm_analog_capture alc880_pcm_analog_capture
6394#define alc882_pcm_digital_playback alc880_pcm_digital_playback
6395#define alc882_pcm_digital_capture alc880_pcm_digital_capture
6396
6397/*
6398 * configuration and preset
6399 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006400static const char *alc882_models[ALC882_MODEL_LAST] = {
6401 [ALC882_3ST_DIG] = "3stack-dig",
6402 [ALC882_6ST_DIG] = "6stack-dig",
6403 [ALC882_ARIMA] = "arima",
Kailang Yangbdd148a2007-05-08 15:19:08 +02006404 [ALC882_W2JC] = "w2jc",
Takashi Iwai0438a002007-09-06 14:54:11 +02006405 [ALC882_TARGA] = "targa",
6406 [ALC882_ASUS_A7J] = "asus-a7j",
6407 [ALC882_ASUS_A7M] = "asus-a7m",
Tobin Davis9102cd12006-12-15 10:02:12 +01006408 [ALC885_MACPRO] = "macpro",
Takashi Iwai87350ad2007-08-16 18:19:38 +02006409 [ALC885_MBP3] = "mbp3",
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006410 [ALC885_IMAC24] = "imac24",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006411 [ALC882_AUTO] = "auto",
6412};
6413
6414static struct snd_pci_quirk alc882_cfg_tbl[] = {
6415 SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG),
Kailang Yang272a5272007-05-14 11:00:38 +02006416 SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J),
Kailang Yangac8842a2007-09-20 12:51:39 +02006417 SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J),
Takashi Iwai914759b2007-09-06 14:52:04 +02006418 SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01006419 SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC),
Claudio Matsuokac5d9f1c2007-07-19 23:18:32 +02006420 SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG),
Tobin Davis7b9470d2006-12-28 13:56:48 +01006421 SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01006422 SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG),
Jiang zhe44447042008-01-28 12:28:24 +01006423 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01006424 SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */
6425 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG),
6426 SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA),
Kailang Yangdf694da2005-12-05 19:42:22 +01006427 {}
6428};
6429
6430static struct alc_config_preset alc882_presets[] = {
6431 [ALC882_3ST_DIG] = {
6432 .mixers = { alc882_base_mixer },
6433 .init_verbs = { alc882_init_verbs },
6434 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6435 .dac_nids = alc882_dac_nids,
6436 .dig_out_nid = ALC882_DIGOUT_NID,
Kailang Yangdf694da2005-12-05 19:42:22 +01006437 .dig_in_nid = ALC882_DIGIN_NID,
6438 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
6439 .channel_mode = alc882_ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02006440 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01006441 .input_mux = &alc882_capture_source,
6442 },
6443 [ALC882_6ST_DIG] = {
6444 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
6445 .init_verbs = { alc882_init_verbs },
6446 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6447 .dac_nids = alc882_dac_nids,
6448 .dig_out_nid = ALC882_DIGOUT_NID,
Kailang Yangdf694da2005-12-05 19:42:22 +01006449 .dig_in_nid = ALC882_DIGIN_NID,
6450 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
6451 .channel_mode = alc882_sixstack_modes,
6452 .input_mux = &alc882_capture_source,
6453 },
Takashi Iwai4b146cb2006-07-28 14:42:36 +02006454 [ALC882_ARIMA] = {
6455 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
6456 .init_verbs = { alc882_init_verbs, alc882_eapd_verbs },
6457 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6458 .dac_nids = alc882_dac_nids,
6459 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
6460 .channel_mode = alc882_sixstack_modes,
6461 .input_mux = &alc882_capture_source,
6462 },
Kailang Yangbdd148a2007-05-08 15:19:08 +02006463 [ALC882_W2JC] = {
6464 .mixers = { alc882_w2jc_mixer, alc882_chmode_mixer },
6465 .init_verbs = { alc882_init_verbs, alc882_eapd_verbs,
6466 alc880_gpio1_init_verbs },
6467 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6468 .dac_nids = alc882_dac_nids,
6469 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
6470 .channel_mode = alc880_threestack_modes,
6471 .need_dac_fix = 1,
6472 .input_mux = &alc882_capture_source,
6473 .dig_out_nid = ALC882_DIGOUT_NID,
6474 },
Takashi Iwai87350ad2007-08-16 18:19:38 +02006475 [ALC885_MBP3] = {
6476 .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer },
6477 .init_verbs = { alc885_mbp3_init_verbs,
6478 alc880_gpio1_init_verbs },
6479 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6480 .dac_nids = alc882_dac_nids,
6481 .channel_mode = alc885_mbp_6ch_modes,
6482 .num_channel_mode = ARRAY_SIZE(alc885_mbp_6ch_modes),
6483 .input_mux = &alc882_capture_source,
6484 .dig_out_nid = ALC882_DIGOUT_NID,
6485 .dig_in_nid = ALC882_DIGIN_NID,
6486 .unsol_event = alc885_mbp3_unsol_event,
6487 .init_hook = alc885_mbp3_automute,
6488 },
Tobin Davis9102cd12006-12-15 10:02:12 +01006489 [ALC885_MACPRO] = {
6490 .mixers = { alc882_macpro_mixer },
6491 .init_verbs = { alc882_macpro_init_verbs },
6492 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6493 .dac_nids = alc882_dac_nids,
6494 .dig_out_nid = ALC882_DIGOUT_NID,
6495 .dig_in_nid = ALC882_DIGIN_NID,
6496 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
6497 .channel_mode = alc882_ch_modes,
6498 .input_mux = &alc882_capture_source,
Takashi Iwai7debbe52007-08-16 15:01:03 +02006499 .init_hook = alc885_macpro_init_hook,
Tobin Davis9102cd12006-12-15 10:02:12 +01006500 },
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006501 [ALC885_IMAC24] = {
6502 .mixers = { alc885_imac24_mixer },
6503 .init_verbs = { alc885_imac24_init_verbs },
6504 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6505 .dac_nids = alc882_dac_nids,
6506 .dig_out_nid = ALC882_DIGOUT_NID,
6507 .dig_in_nid = ALC882_DIGIN_NID,
6508 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
6509 .channel_mode = alc882_ch_modes,
6510 .input_mux = &alc882_capture_source,
6511 .unsol_event = alc885_imac24_unsol_event,
Takashi Iwai7debbe52007-08-16 15:01:03 +02006512 .init_hook = alc885_imac24_init_hook,
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006513 },
Kailang Yang272a5272007-05-14 11:00:38 +02006514 [ALC882_TARGA] = {
6515 .mixers = { alc882_targa_mixer, alc882_chmode_mixer,
6516 alc882_capture_mixer },
6517 .init_verbs = { alc882_init_verbs, alc882_targa_verbs},
6518 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6519 .dac_nids = alc882_dac_nids,
6520 .dig_out_nid = ALC882_DIGOUT_NID,
6521 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
6522 .adc_nids = alc882_adc_nids,
Takashi Iwaie1406342008-02-11 18:32:32 +01006523 .capsrc_nids = alc882_capsrc_nids,
Kailang Yang272a5272007-05-14 11:00:38 +02006524 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
6525 .channel_mode = alc882_3ST_6ch_modes,
6526 .need_dac_fix = 1,
6527 .input_mux = &alc882_capture_source,
6528 .unsol_event = alc882_targa_unsol_event,
6529 .init_hook = alc882_targa_automute,
6530 },
6531 [ALC882_ASUS_A7J] = {
6532 .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer,
6533 alc882_capture_mixer },
6534 .init_verbs = { alc882_init_verbs, alc882_asus_a7j_verbs},
6535 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6536 .dac_nids = alc882_dac_nids,
6537 .dig_out_nid = ALC882_DIGOUT_NID,
6538 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
6539 .adc_nids = alc882_adc_nids,
Takashi Iwaie1406342008-02-11 18:32:32 +01006540 .capsrc_nids = alc882_capsrc_nids,
Kailang Yang272a5272007-05-14 11:00:38 +02006541 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
6542 .channel_mode = alc882_3ST_6ch_modes,
6543 .need_dac_fix = 1,
6544 .input_mux = &alc882_capture_source,
Kailang Yangea1fb292008-08-26 12:58:38 +02006545 },
Takashi Iwai914759b2007-09-06 14:52:04 +02006546 [ALC882_ASUS_A7M] = {
6547 .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer },
6548 .init_verbs = { alc882_init_verbs, alc882_eapd_verbs,
6549 alc880_gpio1_init_verbs,
6550 alc882_asus_a7m_verbs },
6551 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
6552 .dac_nids = alc882_dac_nids,
6553 .dig_out_nid = ALC882_DIGOUT_NID,
6554 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
6555 .channel_mode = alc880_threestack_modes,
6556 .need_dac_fix = 1,
6557 .input_mux = &alc882_capture_source,
Kailang Yangea1fb292008-08-26 12:58:38 +02006558 },
Kailang Yangdf694da2005-12-05 19:42:22 +01006559};
6560
6561
6562/*
Takashi Iwaif95474e2007-07-10 00:47:43 +02006563 * Pin config fixes
6564 */
Kailang Yangea1fb292008-08-26 12:58:38 +02006565enum {
Takashi Iwaif95474e2007-07-10 00:47:43 +02006566 PINFIX_ABIT_AW9D_MAX
6567};
6568
6569static struct alc_pincfg alc882_abit_aw9d_pinfix[] = {
6570 { 0x15, 0x01080104 }, /* side */
6571 { 0x16, 0x01011012 }, /* rear */
6572 { 0x17, 0x01016011 }, /* clfe */
6573 { }
6574};
6575
6576static const struct alc_pincfg *alc882_pin_fixes[] = {
6577 [PINFIX_ABIT_AW9D_MAX] = alc882_abit_aw9d_pinfix,
6578};
6579
6580static struct snd_pci_quirk alc882_pinfix_tbl[] = {
6581 SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
6582 {}
6583};
6584
6585/*
Kailang Yangdf694da2005-12-05 19:42:22 +01006586 * BIOS auto configuration
6587 */
6588static void alc882_auto_set_output_and_unmute(struct hda_codec *codec,
6589 hda_nid_t nid, int pin_type,
6590 int dac_idx)
6591{
6592 /* set as output */
6593 struct alc_spec *spec = codec->spec;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006594 int idx;
6595
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006596 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01006597 if (spec->multiout.dac_nids[dac_idx] == 0x25)
6598 idx = 4;
6599 else
6600 idx = spec->multiout.dac_nids[dac_idx] - 2;
Kailang Yangdf694da2005-12-05 19:42:22 +01006601 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
6602
6603}
6604
6605static void alc882_auto_init_multi_out(struct hda_codec *codec)
6606{
6607 struct alc_spec *spec = codec->spec;
6608 int i;
6609
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006610 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Kailang Yangdf694da2005-12-05 19:42:22 +01006611 for (i = 0; i <= HDA_SIDE; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006612 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02006613 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01006614 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02006615 alc882_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006616 i);
Kailang Yangdf694da2005-12-05 19:42:22 +01006617 }
6618}
6619
6620static void alc882_auto_init_hp_out(struct hda_codec *codec)
6621{
6622 struct alc_spec *spec = codec->spec;
6623 hda_nid_t pin;
6624
Takashi Iwaieb06ed82006-09-20 17:10:27 +02006625 pin = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006626 if (pin) /* connect to front */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006627 /* use dac 0 */
6628 alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006629 pin = spec->autocfg.speaker_pins[0];
6630 if (pin)
6631 alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Kailang Yangdf694da2005-12-05 19:42:22 +01006632}
6633
6634#define alc882_is_input_pin(nid) alc880_is_input_pin(nid)
6635#define ALC882_PIN_CD_NID ALC880_PIN_CD_NID
6636
6637static void alc882_auto_init_analog_input(struct hda_codec *codec)
6638{
6639 struct alc_spec *spec = codec->spec;
6640 int i;
6641
6642 for (i = 0; i < AUTO_PIN_LAST; i++) {
6643 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwai7194cae2008-03-06 16:58:17 +01006644 unsigned int vref;
6645 if (!nid)
6646 continue;
6647 vref = PIN_IN;
6648 if (1 /*i <= AUTO_PIN_FRONT_MIC*/) {
Kailang Yang531240f2008-05-27 12:10:25 +02006649 unsigned int pincap;
6650 pincap = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
6651 if ((pincap >> AC_PINCAP_VREF_SHIFT) &
Takashi Iwai7194cae2008-03-06 16:58:17 +01006652 AC_PINCAP_VREF_80)
6653 vref = PIN_VREF80;
Kailang Yangdf694da2005-12-05 19:42:22 +01006654 }
Takashi Iwai7194cae2008-03-06 16:58:17 +01006655 snd_hda_codec_write(codec, nid, 0,
6656 AC_VERB_SET_PIN_WIDGET_CONTROL, vref);
6657 if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
6658 snd_hda_codec_write(codec, nid, 0,
6659 AC_VERB_SET_AMP_GAIN_MUTE,
6660 AMP_OUT_MUTE);
Kailang Yangdf694da2005-12-05 19:42:22 +01006661 }
6662}
6663
Takashi Iwaif511b012008-08-15 16:46:42 +02006664static void alc882_auto_init_input_src(struct hda_codec *codec)
6665{
6666 struct alc_spec *spec = codec->spec;
6667 const struct hda_input_mux *imux = spec->input_mux;
6668 int c;
6669
6670 for (c = 0; c < spec->num_adc_nids; c++) {
6671 hda_nid_t conn_list[HDA_MAX_NUM_INPUTS];
6672 hda_nid_t nid = spec->capsrc_nids[c];
6673 int conns, mute, idx, item;
6674
6675 conns = snd_hda_get_connections(codec, nid, conn_list,
6676 ARRAY_SIZE(conn_list));
6677 if (conns < 0)
6678 continue;
6679 for (idx = 0; idx < conns; idx++) {
6680 /* if the current connection is the selected one,
6681 * unmute it as default - otherwise mute it
6682 */
6683 mute = AMP_IN_MUTE(idx);
6684 for (item = 0; item < imux->num_items; item++) {
6685 if (imux->items[item].index == idx) {
6686 if (spec->cur_mux[c] == item)
6687 mute = AMP_IN_UNMUTE(idx);
6688 break;
6689 }
6690 }
6691 snd_hda_codec_write(codec, nid, 0,
6692 AC_VERB_SET_AMP_GAIN_MUTE, mute);
6693 }
6694 }
6695}
6696
Takashi Iwai776e1842007-08-29 15:07:11 +02006697/* add mic boosts if needed */
6698static int alc_auto_add_mic_boost(struct hda_codec *codec)
6699{
6700 struct alc_spec *spec = codec->spec;
6701 int err;
6702 hda_nid_t nid;
6703
6704 nid = spec->autocfg.input_pins[AUTO_PIN_MIC];
Takashi Iwaice22e032008-01-11 17:38:35 +01006705 if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
Takashi Iwai776e1842007-08-29 15:07:11 +02006706 err = add_control(spec, ALC_CTL_WIDGET_VOL,
6707 "Mic Boost",
6708 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
6709 if (err < 0)
6710 return err;
6711 }
6712 nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC];
Takashi Iwaice22e032008-01-11 17:38:35 +01006713 if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
Takashi Iwai776e1842007-08-29 15:07:11 +02006714 err = add_control(spec, ALC_CTL_WIDGET_VOL,
6715 "Front Mic Boost",
6716 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
6717 if (err < 0)
6718 return err;
6719 }
6720 return 0;
6721}
6722
Kailang Yangdf694da2005-12-05 19:42:22 +01006723/* almost identical with ALC880 parser... */
6724static int alc882_parse_auto_config(struct hda_codec *codec)
6725{
6726 struct alc_spec *spec = codec->spec;
6727 int err = alc880_parse_auto_config(codec);
6728
6729 if (err < 0)
6730 return err;
Takashi Iwai776e1842007-08-29 15:07:11 +02006731 else if (!err)
6732 return 0; /* no config found */
6733
6734 err = alc_auto_add_mic_boost(codec);
6735 if (err < 0)
6736 return err;
6737
6738 /* hack - override the init verbs */
6739 spec->init_verbs[0] = alc882_auto_init_verbs;
6740
6741 return 1; /* config found */
Kailang Yangdf694da2005-12-05 19:42:22 +01006742}
6743
Takashi Iwaiae6b8132006-03-03 16:47:17 +01006744/* additional initialization for auto-configuration model */
6745static void alc882_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01006746{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006747 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01006748 alc882_auto_init_multi_out(codec);
6749 alc882_auto_init_hp_out(codec);
6750 alc882_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +02006751 alc882_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006752 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02006753 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01006754}
6755
Takashi Iwai7943a8a2008-04-16 17:29:09 +02006756static int patch_alc883(struct hda_codec *codec); /* called in patch_alc882() */
6757
Linus Torvalds1da177e2005-04-16 15:20:36 -07006758static int patch_alc882(struct hda_codec *codec)
6759{
6760 struct alc_spec *spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01006761 int err, board_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006762
Takashi Iwaie560d8d2005-09-09 14:21:46 +02006763 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006764 if (spec == NULL)
6765 return -ENOMEM;
6766
Linus Torvalds1da177e2005-04-16 15:20:36 -07006767 codec->spec = spec;
6768
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006769 board_config = snd_hda_check_board_config(codec, ALC882_MODEL_LAST,
6770 alc882_models,
6771 alc882_cfg_tbl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006772
Kailang Yangdf694da2005-12-05 19:42:22 +01006773 if (board_config < 0 || board_config >= ALC882_MODEL_LAST) {
Tobin Davis081d17c2007-02-15 17:46:18 +01006774 /* Pick up systems that don't supply PCI SSID */
6775 switch (codec->subsystem_id) {
6776 case 0x106b0c00: /* Mac Pro */
6777 board_config = ALC885_MACPRO;
6778 break;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006779 case 0x106b1000: /* iMac 24 */
Peter Korsgaardf3911c52008-09-27 09:13:45 +02006780 case 0x106b2800: /* AppleTV */
Nicola Fagnanic54728d2007-07-19 23:28:52 +02006781 board_config = ALC885_IMAC24;
6782 break;
Takashi Iwaic7e07572008-06-26 14:42:51 +02006783 case 0x106b00a1: /* Macbook (might be wrong - PCI SSID?) */
David Woodhouse9c95c432008-09-18 13:37:13 -07006784 case 0x106b00a4: /* MacbookPro4,1 */
Takashi Iwai87350ad2007-08-16 18:19:38 +02006785 case 0x106b2c00: /* Macbook Pro rev3 */
Takashi Iwaic7e07572008-06-26 14:42:51 +02006786 case 0x106b3600: /* Macbook 3.1 */
Takashi Iwai87350ad2007-08-16 18:19:38 +02006787 board_config = ALC885_MBP3;
6788 break;
Tobin Davis081d17c2007-02-15 17:46:18 +01006789 default:
Takashi Iwai7943a8a2008-04-16 17:29:09 +02006790 /* ALC889A is handled better as ALC888-compatible */
Clive Messer669faba2008-09-30 15:49:13 +02006791 if (codec->revision_id == 0x100101 ||
6792 codec->revision_id == 0x100103) {
Takashi Iwai7943a8a2008-04-16 17:29:09 +02006793 alc_free(codec);
6794 return patch_alc883(codec);
6795 }
Tobin Davis081d17c2007-02-15 17:46:18 +01006796 printk(KERN_INFO "hda_codec: Unknown model for ALC882, "
6797 "trying auto-probe from BIOS...\n");
6798 board_config = ALC882_AUTO;
6799 }
Kailang Yangdf694da2005-12-05 19:42:22 +01006800 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006801
Takashi Iwaif95474e2007-07-10 00:47:43 +02006802 alc_fix_pincfg(codec, alc882_pinfix_tbl, alc882_pin_fixes);
6803
Kailang Yangdf694da2005-12-05 19:42:22 +01006804 if (board_config == ALC882_AUTO) {
6805 /* automatic parse from the BIOS config */
6806 err = alc882_parse_auto_config(codec);
6807 if (err < 0) {
6808 alc_free(codec);
6809 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006810 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006811 printk(KERN_INFO
6812 "hda_codec: Cannot set up configuration "
6813 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01006814 board_config = ALC882_3ST_DIG;
6815 }
6816 }
6817
6818 if (board_config != ALC882_AUTO)
6819 setup_preset(spec, &alc882_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006820
Kailang Yang2f893282008-05-27 12:14:47 +02006821 if (codec->vendor_id == 0x10ec0885) {
6822 spec->stream_name_analog = "ALC885 Analog";
6823 spec->stream_name_digital = "ALC885 Digital";
6824 } else {
6825 spec->stream_name_analog = "ALC882 Analog";
6826 spec->stream_name_digital = "ALC882 Digital";
6827 }
6828
Kailang Yangdf694da2005-12-05 19:42:22 +01006829 spec->stream_analog_playback = &alc882_pcm_analog_playback;
6830 spec->stream_analog_capture = &alc882_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01006831 /* FIXME: setup DAC5 */
6832 /*spec->stream_analog_alt_playback = &alc880_pcm_analog_alt_playback;*/
6833 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006834
Kailang Yangdf694da2005-12-05 19:42:22 +01006835 spec->stream_digital_playback = &alc882_pcm_digital_playback;
6836 spec->stream_digital_capture = &alc882_pcm_digital_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006837
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006838 if (!spec->adc_nids && spec->input_mux) {
Kailang Yangdf694da2005-12-05 19:42:22 +01006839 /* check whether NID 0x07 is valid */
Takashi Iwai4a471b72005-12-07 13:56:29 +01006840 unsigned int wcap = get_wcaps(codec, 0x07);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006841 /* get type */
6842 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Kailang Yangdf694da2005-12-05 19:42:22 +01006843 if (wcap != AC_WID_AUD_IN) {
6844 spec->adc_nids = alc882_adc_nids_alt;
6845 spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids_alt);
Takashi Iwaie1406342008-02-11 18:32:32 +01006846 spec->capsrc_nids = alc882_capsrc_nids_alt;
Takashi Iwaid88897e2008-10-31 15:01:37 +01006847 add_mixer(spec, alc882_capture_alt_mixer);
Kailang Yangdf694da2005-12-05 19:42:22 +01006848 } else {
6849 spec->adc_nids = alc882_adc_nids;
6850 spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids);
Takashi Iwaie1406342008-02-11 18:32:32 +01006851 spec->capsrc_nids = alc882_capsrc_nids;
Takashi Iwaid88897e2008-10-31 15:01:37 +01006852 add_mixer(spec, alc882_capture_mixer);
Kailang Yangdf694da2005-12-05 19:42:22 +01006853 }
6854 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006855
Takashi Iwai2134ea42008-01-10 16:53:55 +01006856 spec->vmaster_nid = 0x0c;
6857
Linus Torvalds1da177e2005-04-16 15:20:36 -07006858 codec->patch_ops = alc_patch_ops;
Kailang Yangdf694da2005-12-05 19:42:22 +01006859 if (board_config == ALC882_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01006860 spec->init_hook = alc882_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02006861#ifdef CONFIG_SND_HDA_POWER_SAVE
6862 if (!spec->loopback.amplist)
6863 spec->loopback.amplist = alc882_loopbacks;
6864#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006865
6866 return 0;
6867}
6868
6869/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006870 * ALC883 support
6871 *
6872 * ALC883 is almost identical with ALC880 but has cleaner and more flexible
6873 * configuration. Each pin widget can choose any input DACs and a mixer.
6874 * Each ADC is connected from a mixer of all inputs. This makes possible
6875 * 6-channel independent captures.
6876 *
6877 * In addition, an independent DAC for the multi-playback (not used in this
6878 * driver yet).
6879 */
6880#define ALC883_DIGOUT_NID 0x06
6881#define ALC883_DIGIN_NID 0x0a
6882
6883static hda_nid_t alc883_dac_nids[4] = {
6884 /* front, rear, clfe, rear_surr */
Herton Ronaldo Krzesinskif32a19e2008-03-18 09:27:08 +01006885 0x02, 0x03, 0x04, 0x05
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006886};
6887
6888static hda_nid_t alc883_adc_nids[2] = {
6889 /* ADC1-2 */
6890 0x08, 0x09,
6891};
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006892
Takashi Iwaie1406342008-02-11 18:32:32 +01006893static hda_nid_t alc883_capsrc_nids[2] = { 0x23, 0x22 };
6894
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006895/* input MUX */
6896/* FIXME: should be a matrix-type input source selection */
6897
6898static struct hda_input_mux alc883_capture_source = {
6899 .num_items = 4,
6900 .items = {
6901 { "Mic", 0x0 },
6902 { "Front Mic", 0x1 },
6903 { "Line", 0x2 },
6904 { "CD", 0x4 },
6905 },
6906};
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006907
Jiang zhe17bba1b2008-06-04 12:11:07 +02006908static struct hda_input_mux alc883_3stack_6ch_intel = {
6909 .num_items = 4,
6910 .items = {
6911 { "Mic", 0x1 },
6912 { "Front Mic", 0x0 },
6913 { "Line", 0x2 },
6914 { "CD", 0x4 },
6915 },
6916};
6917
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006918static struct hda_input_mux alc883_lenovo_101e_capture_source = {
6919 .num_items = 2,
6920 .items = {
6921 { "Mic", 0x1 },
6922 { "Line", 0x2 },
6923 },
6924};
6925
Kailang Yang272a5272007-05-14 11:00:38 +02006926static struct hda_input_mux alc883_lenovo_nb0763_capture_source = {
6927 .num_items = 4,
6928 .items = {
6929 { "Mic", 0x0 },
6930 { "iMic", 0x1 },
6931 { "Line", 0x2 },
6932 { "CD", 0x4 },
6933 },
6934};
6935
Jiang zhefb97dc62008-03-06 11:07:11 +01006936static struct hda_input_mux alc883_fujitsu_pi2515_capture_source = {
6937 .num_items = 2,
6938 .items = {
6939 { "Mic", 0x0 },
6940 { "Int Mic", 0x1 },
6941 },
6942};
6943
Kailang Yange2757d52008-08-26 13:17:46 +02006944static struct hda_input_mux alc883_lenovo_sky_capture_source = {
6945 .num_items = 3,
6946 .items = {
6947 { "Mic", 0x0 },
6948 { "Front Mic", 0x1 },
6949 { "Line", 0x4 },
6950 },
6951};
6952
6953static struct hda_input_mux alc883_asus_eee1601_capture_source = {
6954 .num_items = 2,
6955 .items = {
6956 { "Mic", 0x0 },
6957 { "Line", 0x2 },
6958 },
6959};
6960
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006961#define alc883_mux_enum_info alc_mux_enum_info
6962#define alc883_mux_enum_get alc_mux_enum_get
Takashi Iwaie1406342008-02-11 18:32:32 +01006963/* ALC883 has the ALC882-type input selection */
6964#define alc883_mux_enum_put alc882_mux_enum_put
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006965
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006966/*
6967 * 2ch mode
6968 */
6969static struct hda_channel_mode alc883_3ST_2ch_modes[1] = {
6970 { 2, NULL }
6971};
6972
6973/*
6974 * 2ch mode
6975 */
6976static struct hda_verb alc883_3ST_ch2_init[] = {
6977 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
6978 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6979 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
6980 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6981 { } /* end */
6982};
6983
6984/*
Tobin Davisb2011312007-09-17 12:45:11 +02006985 * 4ch mode
6986 */
6987static struct hda_verb alc883_3ST_ch4_init[] = {
6988 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
6989 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6990 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6991 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6992 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6993 { } /* end */
6994};
6995
6996/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006997 * 6ch mode
6998 */
6999static struct hda_verb alc883_3ST_ch6_init[] = {
7000 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7001 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7002 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7003 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7004 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7005 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7006 { } /* end */
7007};
7008
Tobin Davisb2011312007-09-17 12:45:11 +02007009static struct hda_channel_mode alc883_3ST_6ch_modes[3] = {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007010 { 2, alc883_3ST_ch2_init },
Tobin Davisb2011312007-09-17 12:45:11 +02007011 { 4, alc883_3ST_ch4_init },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007012 { 6, alc883_3ST_ch6_init },
7013};
7014
7015/*
Jiang zhe17bba1b2008-06-04 12:11:07 +02007016 * 2ch mode
7017 */
7018static struct hda_verb alc883_3ST_ch2_intel_init[] = {
7019 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7020 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7021 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7022 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7023 { } /* end */
7024};
7025
7026/*
7027 * 4ch mode
7028 */
7029static struct hda_verb alc883_3ST_ch4_intel_init[] = {
7030 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7031 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7032 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7033 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7034 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7035 { } /* end */
7036};
7037
7038/*
7039 * 6ch mode
7040 */
7041static struct hda_verb alc883_3ST_ch6_intel_init[] = {
7042 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7043 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7044 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x02 },
7045 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7046 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7047 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7048 { } /* end */
7049};
7050
7051static struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = {
7052 { 2, alc883_3ST_ch2_intel_init },
7053 { 4, alc883_3ST_ch4_intel_init },
7054 { 6, alc883_3ST_ch6_intel_init },
7055};
7056
7057/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007058 * 6ch mode
7059 */
7060static struct hda_verb alc883_sixstack_ch6_init[] = {
7061 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
7062 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7063 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7064 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7065 { } /* end */
7066};
7067
7068/*
7069 * 8ch mode
7070 */
7071static struct hda_verb alc883_sixstack_ch8_init[] = {
7072 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7073 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7074 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7075 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7076 { } /* end */
7077};
7078
7079static struct hda_channel_mode alc883_sixstack_modes[2] = {
7080 { 6, alc883_sixstack_ch6_init },
7081 { 8, alc883_sixstack_ch8_init },
7082};
7083
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01007084static struct hda_verb alc883_medion_eapd_verbs[] = {
7085 /* eanable EAPD on medion laptop */
7086 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
7087 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
7088 { }
7089};
7090
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007091/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
7092 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
7093 */
7094
7095static struct snd_kcontrol_new alc883_base_mixer[] = {
7096 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7097 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7098 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7099 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
7100 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7101 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
7102 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7103 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
7104 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
7105 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
7106 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7107 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7108 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7109 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7110 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7111 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007112 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007113 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7114 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007115 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007116 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
7117 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
7118 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
7119 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7120 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
7121 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
7122 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
7123 {
7124 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7125 /* .name = "Capture Source", */
7126 .name = "Input Source",
7127 .count = 2,
7128 .info = alc883_mux_enum_info,
7129 .get = alc883_mux_enum_get,
7130 .put = alc883_mux_enum_put,
7131 },
7132 { } /* end */
7133};
7134
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01007135static struct snd_kcontrol_new alc883_mitac_mixer[] = {
7136 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7137 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7138 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7139 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
7140 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7141 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
7142 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
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("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7147 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
7148 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
7149 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7150 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
7151 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
7152 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
7153 {
7154 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7155 /* .name = "Capture Source", */
7156 .name = "Input Source",
7157 .count = 2,
7158 .info = alc883_mux_enum_info,
7159 .get = alc883_mux_enum_get,
7160 .put = alc883_mux_enum_put,
7161 },
7162 { } /* end */
7163};
7164
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007165static struct snd_kcontrol_new alc883_clevo_m720_mixer[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01007166 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7167 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
7168 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7169 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
7170 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7171 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7172 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7173 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7174 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
7175 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
7176 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7177 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
7178 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
7179 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
7180 {
7181 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7182 /* .name = "Capture Source", */
7183 .name = "Input Source",
7184 .count = 2,
7185 .info = alc883_mux_enum_info,
7186 .get = alc883_mux_enum_get,
7187 .put = alc883_mux_enum_put,
7188 },
7189 { } /* end */
7190};
7191
Jiang zhefb97dc62008-03-06 11:07:11 +01007192static struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = {
7193 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7194 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
7195 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7196 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
7197 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7198 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7199 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7200 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7201 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
7202 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
7203 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7204 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
7205 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
7206 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
7207 {
7208 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7209 /* .name = "Capture Source", */
7210 .name = "Input Source",
7211 .count = 2,
7212 .info = alc883_mux_enum_info,
7213 .get = alc883_mux_enum_get,
7214 .put = alc883_mux_enum_put,
7215 },
7216 { } /* end */
7217};
7218
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007219static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = {
7220 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7221 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7222 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7223 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7224 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7225 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7226 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7227 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007228 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007229 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7230 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007231 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007232 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
7233 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
7234 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
7235 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7236 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
7237 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
7238 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
7239 {
7240 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7241 /* .name = "Capture Source", */
7242 .name = "Input Source",
7243 .count = 2,
7244 .info = alc883_mux_enum_info,
7245 .get = alc883_mux_enum_get,
7246 .put = alc883_mux_enum_put,
7247 },
7248 { } /* end */
7249};
7250
7251static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
7252 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7253 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7254 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7255 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
7256 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7257 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
7258 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7259 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
7260 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7261 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7262 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7263 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7264 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7265 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007266 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007267 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7268 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007269 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007270 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
7271 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
7272 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
7273 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7274 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007275 {
7276 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7277 /* .name = "Capture Source", */
7278 .name = "Input Source",
Kailang Yange2757d52008-08-26 13:17:46 +02007279 .count = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007280 .info = alc883_mux_enum_info,
7281 .get = alc883_mux_enum_get,
7282 .put = alc883_mux_enum_put,
7283 },
7284 { } /* end */
7285};
7286
Jiang zhe17bba1b2008-06-04 12:11:07 +02007287static struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = {
7288 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7289 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7290 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7291 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
7292 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
7293 HDA_OUTPUT),
7294 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
7295 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7296 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
7297 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
7298 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7299 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7300 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7301 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7302 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7303 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
7304 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
7305 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7306 HDA_CODEC_VOLUME("Front Mic Boost", 0x18, 0, HDA_INPUT),
7307 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7308 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
7309 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
7310 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7311 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
7312 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
7313 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
7314 {
7315 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7316 /* .name = "Capture Source", */
7317 .name = "Input Source",
7318 .count = 2,
7319 .info = alc883_mux_enum_info,
7320 .get = alc883_mux_enum_get,
7321 .put = alc883_mux_enum_put,
7322 },
7323 { } /* end */
7324};
7325
Takashi Iwaid1d985f2006-11-23 19:27:12 +01007326static struct snd_kcontrol_new alc883_fivestack_mixer[] = {
Tobin Davisc07584c2006-10-13 12:32:16 +02007327 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02007328 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007329 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02007330 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007331 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7332 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02007333 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7334 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007335 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7336 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7337 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7338 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7339 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7340 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007341 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007342 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7343 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007344 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02007345 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
7346 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
7347 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
7348 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7349 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
7350
7351 {
7352 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7353 /* .name = "Capture Source", */
7354 .name = "Input Source",
7355 .count = 1,
7356 .info = alc883_mux_enum_info,
7357 .get = alc883_mux_enum_get,
7358 .put = alc883_mux_enum_put,
7359 },
7360 { } /* end */
7361};
7362
Kailang Yangccc656c2006-10-17 12:32:26 +02007363static struct snd_kcontrol_new alc883_tagra_mixer[] = {
7364 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7365 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7366 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7367 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7368 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
7369 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7370 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
7371 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7372 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
7373 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7374 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7375 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7376 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7377 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007378 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02007379 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7380 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7381 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
7382 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
7383 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
7384 {
7385 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7386 /* .name = "Capture Source", */
7387 .name = "Input Source",
7388 .count = 2,
7389 .info = alc883_mux_enum_info,
7390 .get = alc883_mux_enum_get,
7391 .put = alc883_mux_enum_put,
7392 },
7393 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007394};
Kailang Yangccc656c2006-10-17 12:32:26 +02007395
7396static struct snd_kcontrol_new alc883_tagra_2ch_mixer[] = {
7397 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7398 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7399 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7400 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7401 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7402 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007403 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02007404 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Jiang zhe4383fae2008-04-14 12:58:57 +02007405 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7406 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
7407 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02007408 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7409 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
7410 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
7411 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
7412 {
7413 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7414 /* .name = "Capture Source", */
7415 .name = "Input Source",
7416 .count = 2,
7417 .info = alc883_mux_enum_info,
7418 .get = alc883_mux_enum_get,
7419 .put = alc883_mux_enum_put,
7420 },
7421 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007422};
Kailang Yangccc656c2006-10-17 12:32:26 +02007423
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007424static struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = {
7425 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7426 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01007427 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
7428 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007429 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7430 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7431 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7432 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
7433 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7434 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
7435 {
7436 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7437 /* .name = "Capture Source", */
7438 .name = "Input Source",
7439 .count = 1,
7440 .info = alc883_mux_enum_info,
7441 .get = alc883_mux_enum_get,
7442 .put = alc883_mux_enum_put,
7443 },
7444 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007445};
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007446
Kailang Yang272a5272007-05-14 11:00:38 +02007447static struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = {
7448 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7449 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
7450 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7451 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7452 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7453 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7454 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7455 HDA_CODEC_VOLUME("iMic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7456 HDA_CODEC_MUTE("iMic Playback Switch", 0x0b, 0x1, HDA_INPUT),
7457 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7458 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
7459 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
7460 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
7461 {
7462 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7463 /* .name = "Capture Source", */
7464 .name = "Input Source",
7465 .count = 2,
7466 .info = alc883_mux_enum_info,
7467 .get = alc883_mux_enum_get,
7468 .put = alc883_mux_enum_put,
7469 },
7470 { } /* end */
7471};
7472
7473static struct snd_kcontrol_new alc883_medion_md2_mixer[] = {
7474 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7475 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7476 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
7477 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7478 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7479 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7480 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7481 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7482 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7483 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7484 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
7485 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
7486 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
7487 {
7488 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7489 /* .name = "Capture Source", */
7490 .name = "Input Source",
7491 .count = 2,
7492 .info = alc883_mux_enum_info,
7493 .get = alc883_mux_enum_get,
7494 .put = alc883_mux_enum_put,
7495 },
7496 { } /* end */
Kailang Yangea1fb292008-08-26 12:58:38 +02007497};
Kailang Yang272a5272007-05-14 11:00:38 +02007498
Tobin Davis2880a862007-08-07 11:50:26 +02007499static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = {
Kailang Yangd1a991a2007-08-15 16:21:59 +02007500 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7501 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02007502 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02007503 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7504 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Kailang Yangd1a991a2007-08-15 16:21:59 +02007505 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7506 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7507 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02007508 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7509 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
7510 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
7511 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
7512 {
7513 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7514 /* .name = "Capture Source", */
7515 .name = "Input Source",
7516 .count = 2,
7517 .info = alc883_mux_enum_info,
7518 .get = alc883_mux_enum_get,
7519 .put = alc883_mux_enum_put,
7520 },
7521 { } /* end */
Kailang Yangd1a991a2007-08-15 16:21:59 +02007522};
Tobin Davis2880a862007-08-07 11:50:26 +02007523
Kailang Yange2757d52008-08-26 13:17:46 +02007524static struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = {
7525 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7526 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7527 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
7528 HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
7529 HDA_CODEC_VOLUME_MONO("Center Playback Volume",
7530 0x0d, 1, 0x0, HDA_OUTPUT),
7531 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
7532 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
7533 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
7534 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
7535 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
7536 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7537 HDA_CODEC_MUTE("iSpeaker Playback Switch", 0x1a, 0x0, HDA_OUTPUT),
7538 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7539 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7540 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7541 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7542 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7543 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7544 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7545 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7546 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
7547 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
7548 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
7549 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
7550 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
7551 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
7552 {
7553 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7554 /* .name = "Capture Source", */
7555 .name = "Input Source",
7556 .count = 2,
7557 .info = alc883_mux_enum_info,
7558 .get = alc883_mux_enum_get,
7559 .put = alc883_mux_enum_put,
7560 },
7561 { } /* end */
7562};
7563
7564static struct hda_bind_ctls alc883_bind_cap_vol = {
7565 .ops = &snd_hda_bind_vol,
7566 .values = {
7567 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
7568 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
7569 0
7570 },
7571};
7572
7573static struct hda_bind_ctls alc883_bind_cap_switch = {
7574 .ops = &snd_hda_bind_sw,
7575 .values = {
7576 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
7577 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
7578 0
7579 },
7580};
7581
7582static struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = {
7583 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7584 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7585 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7586 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7587 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7588 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7589 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7590 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7591 HDA_BIND_VOL("Capture Volume", &alc883_bind_cap_vol),
7592 HDA_BIND_SW("Capture Switch", &alc883_bind_cap_switch),
7593 {
7594 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7595 /* .name = "Capture Source", */
7596 .name = "Input Source",
7597 .count = 1,
7598 .info = alc883_mux_enum_info,
7599 .get = alc883_mux_enum_get,
7600 .put = alc883_mux_enum_put,
7601 },
7602 { } /* end */
7603};
7604
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007605static struct snd_kcontrol_new alc883_chmode_mixer[] = {
7606 {
7607 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7608 .name = "Channel Mode",
7609 .info = alc_ch_mode_info,
7610 .get = alc_ch_mode_get,
7611 .put = alc_ch_mode_put,
7612 },
7613 { } /* end */
7614};
7615
7616static struct hda_verb alc883_init_verbs[] = {
7617 /* ADC1: mute amp left and right */
Kailang Yange2757d52008-08-26 13:17:46 +02007618 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007619 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
7620 /* ADC2: mute amp left and right */
7621 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7622 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
7623 /* Front mixer: unmute input/output amp left and right (volume = 0) */
7624 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7625 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7626 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7627 /* Rear mixer */
7628 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7629 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7630 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7631 /* CLFE mixer */
7632 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7633 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7634 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7635 /* Side mixer */
7636 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7637 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7638 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7639
Takashi Iwaicb53c622007-08-10 17:21:45 +02007640 /* mute analog input loopbacks */
7641 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7642 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7643 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7644 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7645 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007646
7647 /* Front Pin: output 0 (0x0c) */
7648 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7649 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7650 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
7651 /* Rear Pin: output 1 (0x0d) */
7652 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7653 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7654 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
7655 /* CLFE Pin: output 2 (0x0e) */
7656 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7657 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7658 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
7659 /* Side Pin: output 3 (0x0f) */
7660 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7661 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7662 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
7663 /* Mic (rear) pin: input vref at 80% */
7664 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7665 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7666 /* Front Mic pin: input vref at 80% */
7667 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7668 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7669 /* Line In pin: input */
7670 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
7671 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7672 /* Line-2 In: Headphone output (output 0 - 0x0c) */
7673 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7674 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7675 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
7676 /* CD pin widget for input */
7677 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
7678
7679 /* FIXME: use matrix-type input source selection */
7680 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
7681 /* Input mixer2 */
7682 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yange2757d52008-08-26 13:17:46 +02007683 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7684 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7685 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007686 /* Input mixer3 */
7687 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yange2757d52008-08-26 13:17:46 +02007688 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7689 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7690 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007691 { }
7692};
7693
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01007694/* toggle speaker-output according to the hp-jack state */
7695static void alc883_mitac_hp_automute(struct hda_codec *codec)
7696{
7697 unsigned int present;
7698
7699 present = snd_hda_codec_read(codec, 0x15, 0,
7700 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7701 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7702 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7703 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
7704 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7705}
7706
7707/* auto-toggle front mic */
7708/*
7709static void alc883_mitac_mic_automute(struct hda_codec *codec)
7710{
7711 unsigned int present;
7712 unsigned char bits;
7713
7714 present = snd_hda_codec_read(codec, 0x18, 0,
7715 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7716 bits = present ? HDA_AMP_MUTE : 0;
7717 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
7718}
7719*/
7720
7721static void alc883_mitac_automute(struct hda_codec *codec)
7722{
7723 alc883_mitac_hp_automute(codec);
7724 /* alc883_mitac_mic_automute(codec); */
7725}
7726
7727static void alc883_mitac_unsol_event(struct hda_codec *codec,
7728 unsigned int res)
7729{
7730 switch (res >> 26) {
7731 case ALC880_HP_EVENT:
7732 alc883_mitac_hp_automute(codec);
7733 break;
7734 case ALC880_MIC_EVENT:
7735 /* alc883_mitac_mic_automute(codec); */
7736 break;
7737 }
7738}
7739
7740static struct hda_verb alc883_mitac_verbs[] = {
7741 /* HP */
7742 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7743 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7744 /* Subwoofer */
7745 {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
7746 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7747
7748 /* enable unsolicited event */
7749 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7750 /* {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, */
7751
7752 { } /* end */
7753};
7754
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007755static struct hda_verb alc883_clevo_m720_verbs[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01007756 /* HP */
7757 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7758 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7759 /* Int speaker */
7760 {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
7761 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7762
7763 /* enable unsolicited event */
7764 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007765 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Jiang zhe368c7a92008-03-04 11:20:33 +01007766
7767 { } /* end */
7768};
7769
Jiang zhefb97dc62008-03-06 11:07:11 +01007770static struct hda_verb alc883_2ch_fujitsu_pi2515_verbs[] = {
7771 /* HP */
7772 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
7773 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7774 /* Subwoofer */
7775 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
7776 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7777
7778 /* enable unsolicited event */
7779 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7780
7781 { } /* end */
7782};
7783
Kailang Yangccc656c2006-10-17 12:32:26 +02007784static struct hda_verb alc883_tagra_verbs[] = {
7785 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7786 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7787
7788 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7789 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02007790
Kailang Yangccc656c2006-10-17 12:32:26 +02007791 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
7792 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
7793 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
7794
7795 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007796 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
7797 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
7798 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
Kailang Yangccc656c2006-10-17 12:32:26 +02007799
7800 { } /* end */
7801};
7802
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007803static struct hda_verb alc883_lenovo_101e_verbs[] = {
7804 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7805 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT|AC_USRSP_EN},
7806 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT|AC_USRSP_EN},
7807 { } /* end */
7808};
7809
Kailang Yang272a5272007-05-14 11:00:38 +02007810static struct hda_verb alc883_lenovo_nb0763_verbs[] = {
7811 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7812 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7813 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7814 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7815 { } /* end */
7816};
7817
7818static struct hda_verb alc888_lenovo_ms7195_verbs[] = {
7819 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7820 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7821 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7822 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT | AC_USRSP_EN},
7823 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7824 { } /* end */
7825};
7826
Kailang Yang189609a2007-08-20 11:31:23 +02007827static struct hda_verb alc883_haier_w66_verbs[] = {
7828 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7829 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7830
7831 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7832
7833 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
7834 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7835 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7836 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7837 { } /* end */
7838};
7839
Kailang Yange2757d52008-08-26 13:17:46 +02007840static struct hda_verb alc888_lenovo_sky_verbs[] = {
7841 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7842 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7843 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7844 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7845 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7846 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7847 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
7848 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7849 { } /* end */
7850};
7851
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007852static struct hda_verb alc888_3st_hp_verbs[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007853 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */
Herton Ronaldo Krzesinskif32a19e2008-03-18 09:27:08 +01007854 {0x16, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Rear : output 1 (0x0d) */
7855 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* CLFE : output 2 (0x0e) */
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007856 { }
7857};
7858
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007859static struct hda_verb alc888_6st_dell_verbs[] = {
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01007860 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7861 { }
7862};
7863
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007864static struct hda_verb alc888_3st_hp_2ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007865 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7866 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7867 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7868 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7869 { }
7870};
7871
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007872static struct hda_verb alc888_3st_hp_6ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007873 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7874 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7875 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7876 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7877 { }
7878};
7879
Claudio Matsuoka4723c022007-07-13 14:36:19 +02007880static struct hda_channel_mode alc888_3st_hp_modes[2] = {
7881 { 2, alc888_3st_hp_2ch_init },
7882 { 6, alc888_3st_hp_6ch_init },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02007883};
7884
Kailang Yang272a5272007-05-14 11:00:38 +02007885/* toggle front-jack and RCA according to the hp-jack state */
7886static void alc888_lenovo_ms7195_front_automute(struct hda_codec *codec)
7887{
7888 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02007889
Kailang Yang272a5272007-05-14 11:00:38 +02007890 present = snd_hda_codec_read(codec, 0x1b, 0,
7891 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007892 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7893 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7894 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7895 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02007896}
7897
7898/* toggle RCA according to the front-jack state */
7899static void alc888_lenovo_ms7195_rca_automute(struct hda_codec *codec)
7900{
7901 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02007902
Kailang Yang272a5272007-05-14 11:00:38 +02007903 present = snd_hda_codec_read(codec, 0x14, 0,
7904 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007905 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7906 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02007907}
Takashi Iwai47fd8302007-08-10 17:11:07 +02007908
Kailang Yang272a5272007-05-14 11:00:38 +02007909static void alc883_lenovo_ms7195_unsol_event(struct hda_codec *codec,
7910 unsigned int res)
7911{
7912 if ((res >> 26) == ALC880_HP_EVENT)
7913 alc888_lenovo_ms7195_front_automute(codec);
7914 if ((res >> 26) == ALC880_FRONT_EVENT)
7915 alc888_lenovo_ms7195_rca_automute(codec);
7916}
7917
7918static struct hda_verb alc883_medion_md2_verbs[] = {
7919 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7920 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7921
7922 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7923
7924 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7925 { } /* end */
7926};
7927
7928/* toggle speaker-output according to the hp-jack state */
7929static void alc883_medion_md2_automute(struct hda_codec *codec)
7930{
7931 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02007932
Kailang Yang272a5272007-05-14 11:00:38 +02007933 present = snd_hda_codec_read(codec, 0x14, 0,
7934 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007935 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7936 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02007937}
7938
7939static void alc883_medion_md2_unsol_event(struct hda_codec *codec,
7940 unsigned int res)
7941{
7942 if ((res >> 26) == ALC880_HP_EVENT)
7943 alc883_medion_md2_automute(codec);
7944}
7945
Kailang Yangccc656c2006-10-17 12:32:26 +02007946/* toggle speaker-output according to the hp-jack state */
7947static void alc883_tagra_automute(struct hda_codec *codec)
7948{
7949 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007950 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02007951
7952 present = snd_hda_codec_read(codec, 0x14, 0,
7953 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02007954 bits = present ? HDA_AMP_MUTE : 0;
7955 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
7956 HDA_AMP_MUTE, bits);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02007957 snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
7958 present ? 1 : 3);
Kailang Yangccc656c2006-10-17 12:32:26 +02007959}
7960
7961static void alc883_tagra_unsol_event(struct hda_codec *codec, unsigned int res)
7962{
7963 if ((res >> 26) == ALC880_HP_EVENT)
7964 alc883_tagra_automute(codec);
7965}
7966
Jiang zhe368c7a92008-03-04 11:20:33 +01007967/* toggle speaker-output according to the hp-jack state */
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007968static void alc883_clevo_m720_hp_automute(struct hda_codec *codec)
Jiang zhe368c7a92008-03-04 11:20:33 +01007969{
7970 unsigned int present;
7971 unsigned char bits;
7972
7973 present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0)
7974 & AC_PINSENSE_PRESENCE;
7975 bits = present ? HDA_AMP_MUTE : 0;
7976 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
7977 HDA_AMP_MUTE, bits);
7978}
7979
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007980static void alc883_clevo_m720_mic_automute(struct hda_codec *codec)
7981{
7982 unsigned int present;
7983
7984 present = snd_hda_codec_read(codec, 0x18, 0,
7985 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7986 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
7987 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7988}
7989
7990static void alc883_clevo_m720_automute(struct hda_codec *codec)
7991{
7992 alc883_clevo_m720_hp_automute(codec);
7993 alc883_clevo_m720_mic_automute(codec);
7994}
7995
7996static void alc883_clevo_m720_unsol_event(struct hda_codec *codec,
Jiang zhe368c7a92008-03-04 11:20:33 +01007997 unsigned int res)
7998{
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01007999 switch (res >> 26) {
8000 case ALC880_HP_EVENT:
8001 alc883_clevo_m720_hp_automute(codec);
8002 break;
8003 case ALC880_MIC_EVENT:
8004 alc883_clevo_m720_mic_automute(codec);
8005 break;
8006 }
Jiang zhe368c7a92008-03-04 11:20:33 +01008007}
8008
Jiang zhefb97dc62008-03-06 11:07:11 +01008009/* toggle speaker-output according to the hp-jack state */
8010static void alc883_2ch_fujitsu_pi2515_automute(struct hda_codec *codec)
8011{
8012 unsigned int present;
8013 unsigned char bits;
8014
8015 present = snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0)
8016 & AC_PINSENSE_PRESENCE;
8017 bits = present ? HDA_AMP_MUTE : 0;
8018 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8019 HDA_AMP_MUTE, bits);
8020}
8021
8022static void alc883_2ch_fujitsu_pi2515_unsol_event(struct hda_codec *codec,
8023 unsigned int res)
8024{
8025 if ((res >> 26) == ALC880_HP_EVENT)
8026 alc883_2ch_fujitsu_pi2515_automute(codec);
8027}
8028
Kailang Yang189609a2007-08-20 11:31:23 +02008029static void alc883_haier_w66_automute(struct hda_codec *codec)
8030{
8031 unsigned int present;
8032 unsigned char bits;
8033
8034 present = snd_hda_codec_read(codec, 0x1b, 0,
8035 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
8036 bits = present ? 0x80 : 0;
8037 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8038 0x80, bits);
8039}
8040
8041static void alc883_haier_w66_unsol_event(struct hda_codec *codec,
8042 unsigned int res)
8043{
8044 if ((res >> 26) == ALC880_HP_EVENT)
8045 alc883_haier_w66_automute(codec);
8046}
8047
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008048static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
8049{
8050 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008051 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008052
8053 present = snd_hda_codec_read(codec, 0x14, 0,
8054 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02008055 bits = present ? HDA_AMP_MUTE : 0;
8056 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8057 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008058}
8059
8060static void alc883_lenovo_101e_all_automute(struct hda_codec *codec)
8061{
8062 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008063 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008064
8065 present = snd_hda_codec_read(codec, 0x1b, 0,
8066 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +02008067 bits = present ? HDA_AMP_MUTE : 0;
8068 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8069 HDA_AMP_MUTE, bits);
8070 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8071 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008072}
8073
8074static void alc883_lenovo_101e_unsol_event(struct hda_codec *codec,
8075 unsigned int res)
8076{
8077 if ((res >> 26) == ALC880_HP_EVENT)
8078 alc883_lenovo_101e_all_automute(codec);
8079 if ((res >> 26) == ALC880_FRONT_EVENT)
8080 alc883_lenovo_101e_ispeaker_automute(codec);
8081}
8082
Takashi Iwai676a9b52007-08-16 15:23:35 +02008083/* toggle speaker-output according to the hp-jack state */
8084static void alc883_acer_aspire_automute(struct hda_codec *codec)
8085{
8086 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02008087
Takashi Iwai676a9b52007-08-16 15:23:35 +02008088 present = snd_hda_codec_read(codec, 0x14, 0,
8089 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
8090 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8091 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
8092 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
8093 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
8094}
8095
8096static void alc883_acer_aspire_unsol_event(struct hda_codec *codec,
8097 unsigned int res)
8098{
8099 if ((res >> 26) == ALC880_HP_EVENT)
8100 alc883_acer_aspire_automute(codec);
8101}
8102
Kailang Yangd1a991a2007-08-15 16:21:59 +02008103static struct hda_verb alc883_acer_eapd_verbs[] = {
8104 /* HP Pin: output 0 (0x0c) */
8105 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8106 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8107 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8108 /* Front Pin: output 0 (0x0c) */
Takashi Iwai676a9b52007-08-16 15:23:35 +02008109 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8110 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangd1a991a2007-08-15 16:21:59 +02008111 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangd1a991a2007-08-15 16:21:59 +02008112 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
8113 /* eanable EAPD on medion laptop */
8114 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
8115 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
Takashi Iwai676a9b52007-08-16 15:23:35 +02008116 /* enable unsolicited event */
8117 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yangd1a991a2007-08-15 16:21:59 +02008118 { }
8119};
8120
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008121static void alc888_6st_dell_front_automute(struct hda_codec *codec)
8122{
8123 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02008124
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008125 present = snd_hda_codec_read(codec, 0x1b, 0,
8126 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
8127 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8128 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
8129 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8130 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
8131 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
8132 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
8133 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
8134 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
8135}
8136
8137static void alc888_6st_dell_unsol_event(struct hda_codec *codec,
8138 unsigned int res)
8139{
8140 switch (res >> 26) {
8141 case ALC880_HP_EVENT:
8142 printk("hp_event\n");
8143 alc888_6st_dell_front_automute(codec);
8144 break;
8145 }
8146}
8147
Kailang Yange2757d52008-08-26 13:17:46 +02008148static void alc888_lenovo_sky_front_automute(struct hda_codec *codec)
8149{
8150 unsigned int mute;
8151 unsigned int present;
8152
8153 snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
8154 present = snd_hda_codec_read(codec, 0x1b, 0,
8155 AC_VERB_GET_PIN_SENSE, 0);
8156 present = (present & 0x80000000) != 0;
8157 if (present) {
8158 /* mute internal speaker */
8159 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8160 HDA_AMP_MUTE, HDA_AMP_MUTE);
8161 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8162 HDA_AMP_MUTE, HDA_AMP_MUTE);
8163 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
8164 HDA_AMP_MUTE, HDA_AMP_MUTE);
8165 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
8166 HDA_AMP_MUTE, HDA_AMP_MUTE);
8167 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0,
8168 HDA_AMP_MUTE, HDA_AMP_MUTE);
8169 } else {
8170 /* unmute internal speaker if necessary */
8171 mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
8172 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8173 HDA_AMP_MUTE, mute);
8174 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8175 HDA_AMP_MUTE, mute);
8176 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
8177 HDA_AMP_MUTE, mute);
8178 snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
8179 HDA_AMP_MUTE, mute);
8180 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0,
8181 HDA_AMP_MUTE, mute);
8182 }
8183}
8184
8185static void alc883_lenovo_sky_unsol_event(struct hda_codec *codec,
8186 unsigned int res)
8187{
8188 if ((res >> 26) == ALC880_HP_EVENT)
8189 alc888_lenovo_sky_front_automute(codec);
8190}
8191
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008192/*
8193 * generic initialization of ADC, input mixers and output mixers
8194 */
8195static struct hda_verb alc883_auto_init_verbs[] = {
8196 /*
8197 * Unmute ADC0-2 and set the default input to mic-in
8198 */
8199 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8200 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8201 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8202 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8203
Takashi Iwaicb53c622007-08-10 17:21:45 +02008204 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008205 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008206 * Note: PASD motherboards uses the Line In 2 as the input for
8207 * front panel mic (mic 2)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008208 */
8209 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02008210 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8211 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8212 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8213 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8214 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008215
8216 /*
8217 * Set up output mixers (0x0c - 0x0f)
8218 */
8219 /* set vol=0 to output mixers */
8220 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8221 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8222 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8223 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8224 /* set up input amps for analog loopback */
8225 /* Amp Indices: DAC = 0, mixer = 1 */
8226 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8227 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8228 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8229 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8230 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8231 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8232 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8233 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8234 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8235 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8236
8237 /* FIXME: use matrix-type input source selection */
8238 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
8239 /* Input mixer1 */
8240 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8241 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8242 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008243 /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, */
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008244 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
8245 /* Input mixer2 */
8246 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8247 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8248 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008249 /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, */
Andy Shevchenkoe3cde642007-12-03 16:50:58 +01008250 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008251
8252 { }
8253};
8254
8255/* capture mixer elements */
8256static struct snd_kcontrol_new alc883_capture_mixer[] = {
8257 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
8258 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
8259 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
8260 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
8261 {
8262 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8263 /* The multiple "Capture Source" controls confuse alsamixer
8264 * So call somewhat different..
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008265 */
8266 /* .name = "Capture Source", */
8267 .name = "Input Source",
8268 .count = 2,
8269 .info = alc882_mux_enum_info,
8270 .get = alc882_mux_enum_get,
8271 .put = alc882_mux_enum_put,
8272 },
8273 { } /* end */
8274};
8275
Kailang Yange2757d52008-08-26 13:17:46 +02008276static struct hda_verb alc888_asus_m90v_verbs[] = {
8277 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8278 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8279 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8280 /* enable unsolicited event */
8281 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8282 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
8283 { } /* end */
8284};
8285
8286static void alc883_nb_mic_automute(struct hda_codec *codec)
8287{
8288 unsigned int present;
8289
8290 present = snd_hda_codec_read(codec, 0x18, 0,
8291 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
8292 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
8293 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
8294 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
8295 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
8296}
8297
8298static void alc883_M90V_speaker_automute(struct hda_codec *codec)
8299{
8300 unsigned int present;
8301 unsigned char bits;
8302
8303 present = snd_hda_codec_read(codec, 0x1b, 0,
8304 AC_VERB_GET_PIN_SENSE, 0)
8305 & AC_PINSENSE_PRESENCE;
8306 bits = present ? 0 : PIN_OUT;
8307 snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
8308 bits);
8309 snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
8310 bits);
8311 snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
8312 bits);
8313}
8314
8315static void alc883_mode2_unsol_event(struct hda_codec *codec,
8316 unsigned int res)
8317{
8318 switch (res >> 26) {
8319 case ALC880_HP_EVENT:
8320 alc883_M90V_speaker_automute(codec);
8321 break;
8322 case ALC880_MIC_EVENT:
8323 alc883_nb_mic_automute(codec);
8324 break;
8325 }
8326}
8327
8328static void alc883_mode2_inithook(struct hda_codec *codec)
8329{
8330 alc883_M90V_speaker_automute(codec);
8331 alc883_nb_mic_automute(codec);
8332}
8333
8334static struct hda_verb alc888_asus_eee1601_verbs[] = {
8335 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8336 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8337 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8338 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8339 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8340 {0x20, AC_VERB_SET_COEF_INDEX, 0x0b},
8341 {0x20, AC_VERB_SET_PROC_COEF, 0x0838},
8342 /* enable unsolicited event */
8343 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8344 { } /* end */
8345};
8346
8347static void alc883_eee1601_speaker_automute(struct hda_codec *codec)
8348{
8349 unsigned int present;
8350 unsigned char bits;
8351
8352 present = snd_hda_codec_read(codec, 0x14, 0,
8353 AC_VERB_GET_PIN_SENSE, 0)
8354 & AC_PINSENSE_PRESENCE;
8355 bits = present ? 0 : PIN_OUT;
8356 snd_hda_codec_write(codec, 0x1b, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
8357 bits);
8358}
8359
8360static void alc883_eee1601_unsol_event(struct hda_codec *codec,
8361 unsigned int res)
8362{
8363 switch (res >> 26) {
8364 case ALC880_HP_EVENT:
8365 alc883_eee1601_speaker_automute(codec);
8366 break;
8367 }
8368}
8369
8370static void alc883_eee1601_inithook(struct hda_codec *codec)
8371{
8372 alc883_eee1601_speaker_automute(codec);
8373}
8374
Takashi Iwaicb53c622007-08-10 17:21:45 +02008375#ifdef CONFIG_SND_HDA_POWER_SAVE
8376#define alc883_loopbacks alc880_loopbacks
8377#endif
8378
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008379/* pcm configuration: identiacal with ALC880 */
8380#define alc883_pcm_analog_playback alc880_pcm_analog_playback
8381#define alc883_pcm_analog_capture alc880_pcm_analog_capture
Takashi Iwai63300792008-01-24 15:31:36 +01008382#define alc883_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008383#define alc883_pcm_digital_playback alc880_pcm_digital_playback
8384#define alc883_pcm_digital_capture alc880_pcm_digital_capture
8385
8386/*
8387 * configuration and preset
8388 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008389static const char *alc883_models[ALC883_MODEL_LAST] = {
8390 [ALC883_3ST_2ch_DIG] = "3stack-dig",
8391 [ALC883_3ST_6ch_DIG] = "3stack-6ch-dig",
8392 [ALC883_3ST_6ch] = "3stack-6ch",
8393 [ALC883_6ST_DIG] = "6stack-dig",
8394 [ALC883_TARGA_DIG] = "targa-dig",
8395 [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008396 [ALC883_ACER] = "acer",
Tobin Davis2880a862007-08-07 11:50:26 +02008397 [ALC883_ACER_ASPIRE] = "acer-aspire",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008398 [ALC883_MEDION] = "medion",
Kailang Yang272a5272007-05-14 11:00:38 +02008399 [ALC883_MEDION_MD2] = "medion-md2",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008400 [ALC883_LAPTOP_EAPD] = "laptop-eapd",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008401 [ALC883_LENOVO_101E_2ch] = "lenovo-101e",
Kailang Yang272a5272007-05-14 11:00:38 +02008402 [ALC883_LENOVO_NB0763] = "lenovo-nb0763",
8403 [ALC888_LENOVO_MS7195_DIG] = "lenovo-ms7195-dig",
Kailang Yange2757d52008-08-26 13:17:46 +02008404 [ALC888_LENOVO_SKY] = "lenovo-sky",
Kailang Yang189609a2007-08-20 11:31:23 +02008405 [ALC883_HAIER_W66] = "haier-w66",
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008406 [ALC888_3ST_HP] = "3stack-hp",
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008407 [ALC888_6ST_DELL] = "6stack-dell",
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008408 [ALC883_MITAC] = "mitac",
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008409 [ALC883_CLEVO_M720] = "clevo-m720",
Jiang zhefb97dc62008-03-06 11:07:11 +01008410 [ALC883_FUJITSU_PI2515] = "fujitsu-pi2515",
Jiang zhe17bba1b2008-06-04 12:11:07 +02008411 [ALC883_3ST_6ch_INTEL] = "3stack-6ch-intel",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008412 [ALC883_AUTO] = "auto",
8413};
8414
8415static struct snd_pci_quirk alc883_cfg_tbl[] = {
8416 SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC883_3ST_6ch_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008417 SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE),
8418 SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE),
8419 SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE),
Jaroslav Kysela0b18cb12008-07-28 17:07:07 +02008420 SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_ACER_ASPIRE),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008421 SND_PCI_QUIRK(0x1025, 0, "Acer laptop", ALC883_ACER), /* default Acer */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008422 SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL),
Tobin Davisfebe3372007-06-12 11:27:46 +02008423 SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008424 SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP),
8425 SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP),
Herton Ronaldo Krzesinski5d85f8d2008-03-20 12:13:46 +01008426 SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG),
Kailang Yanga01c30c2008-10-15 11:14:58 +02008427 SND_PCI_QUIRK(0x1043, 0x1873, "Asus M90V", ALC888_ASUS_M90V),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008428 SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG),
Kailang Yange2757d52008-08-26 13:17:46 +02008429 SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_ASUS_EEE1601),
Travis Place97ec7102008-05-23 18:31:46 +02008430 SND_PCI_QUIRK(0x105b, 0x0ce8, "Foxconn P35AX-S", ALC883_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008431 SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008432 SND_PCI_QUIRK(0x1071, 0x8253, "Mitac 8252d", ALC883_MITAC),
8433 SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD),
Kailang Yange2757d52008-08-26 13:17:46 +02008434 SND_PCI_QUIRK(0x10f1, 0x2350, "TYAN-S2350", ALC888_6ST_DELL),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008435 SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch),
Tobin Davis57b14f22007-04-18 23:05:36 +02008436 SND_PCI_QUIRK(0x1458, 0xa002, "MSI", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008437 SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG),
8438 SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG),
8439 SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG),
Jiang zhe4383fae2008-04-14 12:58:57 +02008440 SND_PCI_QUIRK(0x1462, 0x2fb3, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008441 SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG),
Pascal Terjan82808232008-03-04 11:33:28 +01008442 SND_PCI_QUIRK(0x1462, 0x3783, "NEC S970", ALC883_TARGA_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008443 SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG),
8444 SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG),
8445 SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG),
8446 SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG),
8447 SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG),
8448 SND_PCI_QUIRK(0x1462, 0x3fdf, "MSI", ALC883_TARGA_DIG),
8449 SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG),
8450 SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG),
8451 SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008452 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG),
8453 SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG),
Tobin Davis799f88a2007-05-29 14:29:08 +02008454 SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG),
Herton Ronaldo Krzesinski86d34b72008-03-18 09:27:59 +01008455 SND_PCI_QUIRK(0x1462, 0x7267, "MSI", ALC883_3ST_6ch_DIG),
Leonard Norrgard2a296cb2007-01-08 11:28:22 +01008456 SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG),
Tobin Davis2dcd5222007-07-10 17:04:57 +02008457 SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008458 SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008459 SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG),
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008460 SND_PCI_QUIRK(0x1558, 0x0721, "Clevo laptop M720R", ALC883_CLEVO_M720),
8461 SND_PCI_QUIRK(0x1558, 0x0722, "Clevo laptop M720SR", ALC883_CLEVO_M720),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008462 SND_PCI_QUIRK(0x1558, 0, "Clevo laptop", ALC883_LAPTOP_EAPD),
Daniel T Chene60623b2007-05-29 03:41:55 -04008463 SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008464 SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION),
Jiang zhefb97dc62008-03-06 11:07:11 +01008465 SND_PCI_QUIRK(0x1734, 0x1108, "Fujitsu AMILO Pi2515", ALC883_FUJITSU_PI2515),
Kailang Yang272a5272007-05-14 11:00:38 +02008466 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch),
Kailang Yang272a5272007-05-14 11:00:38 +02008467 SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008468 SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763),
8469 SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Kailang Yange2757d52008-08-26 13:17:46 +02008470 SND_PCI_QUIRK(0x17aa, 0x101d, "Lenovo Sky", ALC888_LENOVO_SKY),
Kailang Yang272a5272007-05-14 11:00:38 +02008471 SND_PCI_QUIRK(0x17c0, 0x4071, "MEDION MD2", ALC883_MEDION_MD2),
Andrew Paprocki0b167bf2008-02-03 10:15:44 +01008472 SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG),
Kailang Yang189609a2007-08-20 11:31:23 +02008473 SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66),
Jiang zhe17bba1b2008-06-04 12:11:07 +02008474 SND_PCI_QUIRK(0x8086, 0x0001, "DG33BUC", ALC883_3ST_6ch_INTEL),
8475 SND_PCI_QUIRK(0x8086, 0x0002, "DG33FBC", ALC883_3ST_6ch_INTEL),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008476 SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008477 {}
8478};
8479
8480static struct alc_config_preset alc883_presets[] = {
8481 [ALC883_3ST_2ch_DIG] = {
8482 .mixers = { alc883_3ST_2ch_mixer },
8483 .init_verbs = { alc883_init_verbs },
8484 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8485 .dac_nids = alc883_dac_nids,
8486 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008487 .dig_in_nid = ALC883_DIGIN_NID,
8488 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8489 .channel_mode = alc883_3ST_2ch_modes,
8490 .input_mux = &alc883_capture_source,
8491 },
8492 [ALC883_3ST_6ch_DIG] = {
8493 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
8494 .init_verbs = { alc883_init_verbs },
8495 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8496 .dac_nids = alc883_dac_nids,
8497 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008498 .dig_in_nid = ALC883_DIGIN_NID,
8499 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
8500 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02008501 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008502 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008503 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008504 [ALC883_3ST_6ch] = {
8505 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
8506 .init_verbs = { alc883_init_verbs },
8507 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8508 .dac_nids = alc883_dac_nids,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008509 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
8510 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02008511 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008512 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008513 },
Jiang zhe17bba1b2008-06-04 12:11:07 +02008514 [ALC883_3ST_6ch_INTEL] = {
8515 .mixers = { alc883_3ST_6ch_intel_mixer, alc883_chmode_mixer },
8516 .init_verbs = { alc883_init_verbs },
8517 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8518 .dac_nids = alc883_dac_nids,
8519 .dig_out_nid = ALC883_DIGOUT_NID,
8520 .dig_in_nid = ALC883_DIGIN_NID,
8521 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_intel_modes),
8522 .channel_mode = alc883_3ST_6ch_intel_modes,
8523 .need_dac_fix = 1,
8524 .input_mux = &alc883_3stack_6ch_intel,
8525 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008526 [ALC883_6ST_DIG] = {
8527 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
8528 .init_verbs = { alc883_init_verbs },
8529 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8530 .dac_nids = alc883_dac_nids,
8531 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008532 .dig_in_nid = ALC883_DIGIN_NID,
8533 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
8534 .channel_mode = alc883_sixstack_modes,
8535 .input_mux = &alc883_capture_source,
8536 },
Kailang Yangccc656c2006-10-17 12:32:26 +02008537 [ALC883_TARGA_DIG] = {
8538 .mixers = { alc883_tagra_mixer, alc883_chmode_mixer },
8539 .init_verbs = { alc883_init_verbs, alc883_tagra_verbs},
8540 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8541 .dac_nids = alc883_dac_nids,
8542 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +02008543 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
8544 .channel_mode = alc883_3ST_6ch_modes,
8545 .need_dac_fix = 1,
8546 .input_mux = &alc883_capture_source,
8547 .unsol_event = alc883_tagra_unsol_event,
8548 .init_hook = alc883_tagra_automute,
8549 },
8550 [ALC883_TARGA_2ch_DIG] = {
8551 .mixers = { alc883_tagra_2ch_mixer},
8552 .init_verbs = { alc883_init_verbs, alc883_tagra_verbs},
8553 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8554 .dac_nids = alc883_dac_nids,
8555 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +02008556 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8557 .channel_mode = alc883_3ST_2ch_modes,
8558 .input_mux = &alc883_capture_source,
8559 .unsol_event = alc883_tagra_unsol_event,
8560 .init_hook = alc883_tagra_automute,
8561 },
Vladimir Avdoninbab282b2006-08-22 13:31:58 +02008562 [ALC883_ACER] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02008563 .mixers = { alc883_base_mixer },
Vladimir Avdoninbab282b2006-08-22 13:31:58 +02008564 /* On TravelMate laptops, GPIO 0 enables the internal speaker
8565 * and the headphone jack. Turn this on and rely on the
8566 * standard mute methods whenever the user wants to turn
8567 * these outputs off.
8568 */
8569 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs },
8570 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8571 .dac_nids = alc883_dac_nids,
Vladimir Avdoninbab282b2006-08-22 13:31:58 +02008572 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8573 .channel_mode = alc883_3ST_2ch_modes,
8574 .input_mux = &alc883_capture_source,
8575 },
Tobin Davis2880a862007-08-07 11:50:26 +02008576 [ALC883_ACER_ASPIRE] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02008577 .mixers = { alc883_acer_aspire_mixer },
Kailang Yangd1a991a2007-08-15 16:21:59 +02008578 .init_verbs = { alc883_init_verbs, alc883_acer_eapd_verbs },
Tobin Davis2880a862007-08-07 11:50:26 +02008579 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8580 .dac_nids = alc883_dac_nids,
8581 .dig_out_nid = ALC883_DIGOUT_NID,
Tobin Davis2880a862007-08-07 11:50:26 +02008582 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8583 .channel_mode = alc883_3ST_2ch_modes,
8584 .input_mux = &alc883_capture_source,
Takashi Iwai676a9b52007-08-16 15:23:35 +02008585 .unsol_event = alc883_acer_aspire_unsol_event,
8586 .init_hook = alc883_acer_aspire_automute,
Kailang Yangd1a991a2007-08-15 16:21:59 +02008587 },
Tobin Davisc07584c2006-10-13 12:32:16 +02008588 [ALC883_MEDION] = {
8589 .mixers = { alc883_fivestack_mixer,
8590 alc883_chmode_mixer },
8591 .init_verbs = { alc883_init_verbs,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008592 alc883_medion_eapd_verbs },
Tobin Davisc07584c2006-10-13 12:32:16 +02008593 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8594 .dac_nids = alc883_dac_nids,
Tobin Davisc07584c2006-10-13 12:32:16 +02008595 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
8596 .channel_mode = alc883_sixstack_modes,
8597 .input_mux = &alc883_capture_source,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008598 },
Kailang Yang272a5272007-05-14 11:00:38 +02008599 [ALC883_MEDION_MD2] = {
8600 .mixers = { alc883_medion_md2_mixer},
8601 .init_verbs = { alc883_init_verbs, alc883_medion_md2_verbs},
8602 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8603 .dac_nids = alc883_dac_nids,
8604 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang272a5272007-05-14 11:00:38 +02008605 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8606 .channel_mode = alc883_3ST_2ch_modes,
8607 .input_mux = &alc883_capture_source,
8608 .unsol_event = alc883_medion_md2_unsol_event,
8609 .init_hook = alc883_medion_md2_automute,
Kailang Yangea1fb292008-08-26 12:58:38 +02008610 },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008611 [ALC883_LAPTOP_EAPD] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02008612 .mixers = { alc883_base_mixer },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008613 .init_verbs = { alc883_init_verbs, alc882_eapd_verbs },
8614 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8615 .dac_nids = alc883_dac_nids,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008616 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8617 .channel_mode = alc883_3ST_2ch_modes,
8618 .input_mux = &alc883_capture_source,
8619 },
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008620 [ALC883_CLEVO_M720] = {
8621 .mixers = { alc883_clevo_m720_mixer },
8622 .init_verbs = { alc883_init_verbs, alc883_clevo_m720_verbs },
Jiang zhe368c7a92008-03-04 11:20:33 +01008623 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8624 .dac_nids = alc883_dac_nids,
8625 .dig_out_nid = ALC883_DIGOUT_NID,
8626 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8627 .channel_mode = alc883_3ST_2ch_modes,
8628 .input_mux = &alc883_capture_source,
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008629 .unsol_event = alc883_clevo_m720_unsol_event,
8630 .init_hook = alc883_clevo_m720_automute,
Jiang zhe368c7a92008-03-04 11:20:33 +01008631 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008632 [ALC883_LENOVO_101E_2ch] = {
8633 .mixers = { alc883_lenovo_101e_2ch_mixer},
8634 .init_verbs = { alc883_init_verbs, alc883_lenovo_101e_verbs},
8635 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8636 .dac_nids = alc883_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008637 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8638 .channel_mode = alc883_3ST_2ch_modes,
8639 .input_mux = &alc883_lenovo_101e_capture_source,
8640 .unsol_event = alc883_lenovo_101e_unsol_event,
8641 .init_hook = alc883_lenovo_101e_all_automute,
8642 },
Kailang Yang272a5272007-05-14 11:00:38 +02008643 [ALC883_LENOVO_NB0763] = {
8644 .mixers = { alc883_lenovo_nb0763_mixer },
8645 .init_verbs = { alc883_init_verbs, alc883_lenovo_nb0763_verbs},
8646 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8647 .dac_nids = alc883_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +02008648 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8649 .channel_mode = alc883_3ST_2ch_modes,
8650 .need_dac_fix = 1,
8651 .input_mux = &alc883_lenovo_nb0763_capture_source,
8652 .unsol_event = alc883_medion_md2_unsol_event,
8653 .init_hook = alc883_medion_md2_automute,
8654 },
8655 [ALC888_LENOVO_MS7195_DIG] = {
8656 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
8657 .init_verbs = { alc883_init_verbs, alc888_lenovo_ms7195_verbs},
8658 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8659 .dac_nids = alc883_dac_nids,
8660 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang272a5272007-05-14 11:00:38 +02008661 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
8662 .channel_mode = alc883_3ST_6ch_modes,
8663 .need_dac_fix = 1,
8664 .input_mux = &alc883_capture_source,
8665 .unsol_event = alc883_lenovo_ms7195_unsol_event,
8666 .init_hook = alc888_lenovo_ms7195_front_automute,
Kailang Yang189609a2007-08-20 11:31:23 +02008667 },
8668 [ALC883_HAIER_W66] = {
8669 .mixers = { alc883_tagra_2ch_mixer},
8670 .init_verbs = { alc883_init_verbs, alc883_haier_w66_verbs},
8671 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8672 .dac_nids = alc883_dac_nids,
8673 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang189609a2007-08-20 11:31:23 +02008674 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8675 .channel_mode = alc883_3ST_2ch_modes,
8676 .input_mux = &alc883_capture_source,
8677 .unsol_event = alc883_haier_w66_unsol_event,
8678 .init_hook = alc883_haier_w66_automute,
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +01008679 },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008680 [ALC888_3ST_HP] = {
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +01008681 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008682 .init_verbs = { alc883_init_verbs, alc888_3st_hp_verbs },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008683 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8684 .dac_nids = alc883_dac_nids,
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008685 .num_channel_mode = ARRAY_SIZE(alc888_3st_hp_modes),
8686 .channel_mode = alc888_3st_hp_modes,
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008687 .need_dac_fix = 1,
8688 .input_mux = &alc883_capture_source,
8689 },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008690 [ALC888_6ST_DELL] = {
Herton Ronaldo Krzesinskif24dbdc2008-03-20 12:14:28 +01008691 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008692 .init_verbs = { alc883_init_verbs, alc888_6st_dell_verbs },
8693 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8694 .dac_nids = alc883_dac_nids,
8695 .dig_out_nid = ALC883_DIGOUT_NID,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008696 .dig_in_nid = ALC883_DIGIN_NID,
8697 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
8698 .channel_mode = alc883_sixstack_modes,
8699 .input_mux = &alc883_capture_source,
8700 .unsol_event = alc888_6st_dell_unsol_event,
8701 .init_hook = alc888_6st_dell_front_automute,
8702 },
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008703 [ALC883_MITAC] = {
8704 .mixers = { alc883_mitac_mixer },
8705 .init_verbs = { alc883_init_verbs, alc883_mitac_verbs },
8706 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8707 .dac_nids = alc883_dac_nids,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008708 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8709 .channel_mode = alc883_3ST_2ch_modes,
8710 .input_mux = &alc883_capture_source,
8711 .unsol_event = alc883_mitac_unsol_event,
8712 .init_hook = alc883_mitac_automute,
8713 },
Jiang zhefb97dc62008-03-06 11:07:11 +01008714 [ALC883_FUJITSU_PI2515] = {
8715 .mixers = { alc883_2ch_fujitsu_pi2515_mixer },
8716 .init_verbs = { alc883_init_verbs,
8717 alc883_2ch_fujitsu_pi2515_verbs},
8718 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8719 .dac_nids = alc883_dac_nids,
8720 .dig_out_nid = ALC883_DIGOUT_NID,
8721 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8722 .channel_mode = alc883_3ST_2ch_modes,
8723 .input_mux = &alc883_fujitsu_pi2515_capture_source,
8724 .unsol_event = alc883_2ch_fujitsu_pi2515_unsol_event,
8725 .init_hook = alc883_2ch_fujitsu_pi2515_automute,
8726 },
Kailang Yange2757d52008-08-26 13:17:46 +02008727 [ALC888_LENOVO_SKY] = {
8728 .mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer },
8729 .init_verbs = { alc883_init_verbs, alc888_lenovo_sky_verbs},
8730 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8731 .dac_nids = alc883_dac_nids,
8732 .dig_out_nid = ALC883_DIGOUT_NID,
8733 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
8734 .adc_nids = alc883_adc_nids,
8735 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
8736 .channel_mode = alc883_sixstack_modes,
8737 .need_dac_fix = 1,
8738 .input_mux = &alc883_lenovo_sky_capture_source,
8739 .unsol_event = alc883_lenovo_sky_unsol_event,
8740 .init_hook = alc888_lenovo_sky_front_automute,
8741 },
8742 [ALC888_ASUS_M90V] = {
8743 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
8744 .init_verbs = { alc883_init_verbs, alc888_asus_m90v_verbs },
8745 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8746 .dac_nids = alc883_dac_nids,
8747 .dig_out_nid = ALC883_DIGOUT_NID,
8748 .dig_in_nid = ALC883_DIGIN_NID,
8749 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
8750 .channel_mode = alc883_3ST_6ch_modes,
8751 .need_dac_fix = 1,
8752 .input_mux = &alc883_fujitsu_pi2515_capture_source,
8753 .unsol_event = alc883_mode2_unsol_event,
8754 .init_hook = alc883_mode2_inithook,
8755 },
8756 [ALC888_ASUS_EEE1601] = {
8757 .mixers = { alc883_asus_eee1601_mixer },
8758 .init_verbs = { alc883_init_verbs, alc888_asus_eee1601_verbs },
8759 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
8760 .dac_nids = alc883_dac_nids,
8761 .dig_out_nid = ALC883_DIGOUT_NID,
8762 .dig_in_nid = ALC883_DIGIN_NID,
8763 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
8764 .channel_mode = alc883_3ST_2ch_modes,
8765 .need_dac_fix = 1,
8766 .input_mux = &alc883_asus_eee1601_capture_source,
8767 .unsol_event = alc883_eee1601_unsol_event,
8768 .init_hook = alc883_eee1601_inithook,
8769 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008770};
8771
8772
8773/*
8774 * BIOS auto configuration
8775 */
8776static void alc883_auto_set_output_and_unmute(struct hda_codec *codec,
8777 hda_nid_t nid, int pin_type,
8778 int dac_idx)
8779{
8780 /* set as output */
8781 struct alc_spec *spec = codec->spec;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008782 int idx;
8783
Takashi Iwaif6c7e542008-02-12 18:32:23 +01008784 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008785 if (spec->multiout.dac_nids[dac_idx] == 0x25)
8786 idx = 4;
8787 else
8788 idx = spec->multiout.dac_nids[dac_idx] - 2;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008789 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
8790
8791}
8792
8793static void alc883_auto_init_multi_out(struct hda_codec *codec)
8794{
8795 struct alc_spec *spec = codec->spec;
8796 int i;
8797
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008798 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008799 for (i = 0; i <= HDA_SIDE; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008800 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02008801 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008802 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02008803 alc883_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008804 i);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008805 }
8806}
8807
8808static void alc883_auto_init_hp_out(struct hda_codec *codec)
8809{
8810 struct alc_spec *spec = codec->spec;
8811 hda_nid_t pin;
8812
Takashi Iwaieb06ed82006-09-20 17:10:27 +02008813 pin = spec->autocfg.hp_pins[0];
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008814 if (pin) /* connect to front */
8815 /* use dac 0 */
8816 alc883_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01008817 pin = spec->autocfg.speaker_pins[0];
8818 if (pin)
8819 alc883_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008820}
8821
8822#define alc883_is_input_pin(nid) alc880_is_input_pin(nid)
8823#define ALC883_PIN_CD_NID ALC880_PIN_CD_NID
8824
8825static void alc883_auto_init_analog_input(struct hda_codec *codec)
8826{
8827 struct alc_spec *spec = codec->spec;
8828 int i;
8829
8830 for (i = 0; i < AUTO_PIN_LAST; i++) {
8831 hda_nid_t nid = spec->autocfg.input_pins[i];
8832 if (alc883_is_input_pin(nid)) {
8833 snd_hda_codec_write(codec, nid, 0,
8834 AC_VERB_SET_PIN_WIDGET_CONTROL,
8835 (i <= AUTO_PIN_FRONT_MIC ?
8836 PIN_VREF80 : PIN_IN));
8837 if (nid != ALC883_PIN_CD_NID)
8838 snd_hda_codec_write(codec, nid, 0,
8839 AC_VERB_SET_AMP_GAIN_MUTE,
8840 AMP_OUT_MUTE);
8841 }
8842 }
8843}
8844
Takashi Iwaif511b012008-08-15 16:46:42 +02008845#define alc883_auto_init_input_src alc882_auto_init_input_src
8846
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008847/* almost identical with ALC880 parser... */
8848static int alc883_parse_auto_config(struct hda_codec *codec)
8849{
8850 struct alc_spec *spec = codec->spec;
8851 int err = alc880_parse_auto_config(codec);
8852
8853 if (err < 0)
8854 return err;
Takashi Iwai776e1842007-08-29 15:07:11 +02008855 else if (!err)
8856 return 0; /* no config found */
8857
8858 err = alc_auto_add_mic_boost(codec);
8859 if (err < 0)
8860 return err;
8861
8862 /* hack - override the init verbs */
8863 spec->init_verbs[0] = alc883_auto_init_verbs;
Takashi Iwaid88897e2008-10-31 15:01:37 +01008864 add_mixer(spec, alc883_capture_mixer);
Takashi Iwai776e1842007-08-29 15:07:11 +02008865
8866 return 1; /* config found */
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008867}
8868
8869/* additional initialization for auto-configuration model */
8870static void alc883_auto_init(struct hda_codec *codec)
8871{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01008872 struct alc_spec *spec = codec->spec;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008873 alc883_auto_init_multi_out(codec);
8874 alc883_auto_init_hp_out(codec);
8875 alc883_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +02008876 alc883_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01008877 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02008878 alc_inithook(codec);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008879}
8880
8881static int patch_alc883(struct hda_codec *codec)
8882{
8883 struct alc_spec *spec;
8884 int err, board_config;
8885
8886 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
8887 if (spec == NULL)
8888 return -ENOMEM;
8889
8890 codec->spec = spec;
8891
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02008892 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
8893
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008894 board_config = snd_hda_check_board_config(codec, ALC883_MODEL_LAST,
8895 alc883_models,
8896 alc883_cfg_tbl);
8897 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008898 printk(KERN_INFO "hda_codec: Unknown model for ALC883, "
8899 "trying auto-probe from BIOS...\n");
8900 board_config = ALC883_AUTO;
8901 }
8902
8903 if (board_config == ALC883_AUTO) {
8904 /* automatic parse from the BIOS config */
8905 err = alc883_parse_auto_config(codec);
8906 if (err < 0) {
8907 alc_free(codec);
8908 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008909 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008910 printk(KERN_INFO
8911 "hda_codec: Cannot set up configuration "
8912 "from BIOS. Using base mode...\n");
8913 board_config = ALC883_3ST_2ch_DIG;
8914 }
8915 }
8916
8917 if (board_config != ALC883_AUTO)
8918 setup_preset(spec, &alc883_presets[board_config]);
8919
Kailang Yang2f893282008-05-27 12:14:47 +02008920 switch (codec->vendor_id) {
8921 case 0x10ec0888:
Kailang Yang44426082008-10-15 11:18:05 +02008922 if (codec->revision_id == 0x100101) {
8923 spec->stream_name_analog = "ALC1200 Analog";
8924 spec->stream_name_digital = "ALC1200 Digital";
8925 } else {
8926 spec->stream_name_analog = "ALC888 Analog";
8927 spec->stream_name_digital = "ALC888 Digital";
8928 }
Kailang Yang2f893282008-05-27 12:14:47 +02008929 break;
8930 case 0x10ec0889:
8931 spec->stream_name_analog = "ALC889 Analog";
8932 spec->stream_name_digital = "ALC889 Digital";
8933 break;
8934 default:
8935 spec->stream_name_analog = "ALC883 Analog";
8936 spec->stream_name_digital = "ALC883 Digital";
8937 break;
8938 }
8939
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008940 spec->stream_analog_playback = &alc883_pcm_analog_playback;
8941 spec->stream_analog_capture = &alc883_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01008942 spec->stream_analog_alt_capture = &alc883_pcm_analog_alt_capture;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008943
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008944 spec->stream_digital_playback = &alc883_pcm_digital_playback;
8945 spec->stream_digital_capture = &alc883_pcm_digital_capture;
8946
Takashi Iwaie1406342008-02-11 18:32:32 +01008947 spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids);
8948 spec->adc_nids = alc883_adc_nids;
8949 spec->capsrc_nids = alc883_capsrc_nids;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008950
Takashi Iwai2134ea42008-01-10 16:53:55 +01008951 spec->vmaster_nid = 0x0c;
8952
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008953 codec->patch_ops = alc_patch_ops;
8954 if (board_config == ALC883_AUTO)
8955 spec->init_hook = alc883_auto_init;
Kailang Yangf9423e72008-05-27 12:32:25 +02008956
Takashi Iwaicb53c622007-08-10 17:21:45 +02008957#ifdef CONFIG_SND_HDA_POWER_SAVE
8958 if (!spec->loopback.amplist)
8959 spec->loopback.amplist = alc883_loopbacks;
8960#endif
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008961
8962 return 0;
8963}
8964
8965/*
Kailang Yangdf694da2005-12-05 19:42:22 +01008966 * ALC262 support
8967 */
8968
8969#define ALC262_DIGOUT_NID ALC880_DIGOUT_NID
8970#define ALC262_DIGIN_NID ALC880_DIGIN_NID
8971
8972#define alc262_dac_nids alc260_dac_nids
8973#define alc262_adc_nids alc882_adc_nids
8974#define alc262_adc_nids_alt alc882_adc_nids_alt
Takashi Iwai88c71a92008-02-14 17:27:17 +01008975#define alc262_capsrc_nids alc882_capsrc_nids
8976#define alc262_capsrc_nids_alt alc882_capsrc_nids_alt
Kailang Yangdf694da2005-12-05 19:42:22 +01008977
8978#define alc262_modes alc260_modes
Takashi Iwaic5f2ea02005-12-06 18:54:31 +01008979#define alc262_capture_source alc882_capture_source
Kailang Yangdf694da2005-12-05 19:42:22 +01008980
Kailang Yang4e555fe2008-08-26 13:05:55 +02008981static hda_nid_t alc262_dmic_adc_nids[1] = {
8982 /* ADC0 */
8983 0x09
8984};
8985
8986static hda_nid_t alc262_dmic_capsrc_nids[1] = { 0x22 };
8987
Kailang Yangdf694da2005-12-05 19:42:22 +01008988static struct snd_kcontrol_new alc262_base_mixer[] = {
8989 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8990 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8991 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8992 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8993 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8994 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8995 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8996 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01008997 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01008998 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
8999 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01009000 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01009001 /* HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01009002 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT), */
Kailang Yangdf694da2005-12-05 19:42:22 +01009003 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),
9004 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9005 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
9006 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01009007 { } /* end */
Takashi Iwai834be882006-03-01 14:16:17 +01009008};
9009
Kailang Yangccc656c2006-10-17 12:32:26 +02009010static struct snd_kcontrol_new alc262_hippo1_mixer[] = {
9011 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9012 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9013 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9014 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9015 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9016 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9017 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9018 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01009019 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009020 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
9021 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01009022 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009023 /* HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01009024 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT), */
Kailang Yangccc656c2006-10-17 12:32:26 +02009025 /*HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),*/
9026 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
9027 { } /* end */
9028};
9029
Takashi Iwaice875f02008-01-28 18:17:43 +01009030/* update HP, line and mono-out pins according to the master switch */
9031static void alc262_hp_master_update(struct hda_codec *codec)
9032{
9033 struct alc_spec *spec = codec->spec;
9034 int val = spec->master_sw;
9035
9036 /* HP & line-out */
9037 snd_hda_codec_write_cache(codec, 0x1b, 0,
9038 AC_VERB_SET_PIN_WIDGET_CONTROL,
9039 val ? PIN_HP : 0);
9040 snd_hda_codec_write_cache(codec, 0x15, 0,
9041 AC_VERB_SET_PIN_WIDGET_CONTROL,
9042 val ? PIN_HP : 0);
9043 /* mono (speaker) depending on the HP jack sense */
9044 val = val && !spec->jack_present;
9045 snd_hda_codec_write_cache(codec, 0x16, 0,
9046 AC_VERB_SET_PIN_WIDGET_CONTROL,
9047 val ? PIN_OUT : 0);
9048}
9049
9050static void alc262_hp_bpc_automute(struct hda_codec *codec)
9051{
9052 struct alc_spec *spec = codec->spec;
9053 unsigned int presence;
9054 presence = snd_hda_codec_read(codec, 0x1b, 0,
9055 AC_VERB_GET_PIN_SENSE, 0);
9056 spec->jack_present = !!(presence & AC_PINSENSE_PRESENCE);
9057 alc262_hp_master_update(codec);
9058}
9059
9060static void alc262_hp_bpc_unsol_event(struct hda_codec *codec, unsigned int res)
9061{
9062 if ((res >> 26) != ALC880_HP_EVENT)
9063 return;
9064 alc262_hp_bpc_automute(codec);
9065}
9066
9067static void alc262_hp_wildwest_automute(struct hda_codec *codec)
9068{
9069 struct alc_spec *spec = codec->spec;
9070 unsigned int presence;
9071 presence = snd_hda_codec_read(codec, 0x15, 0,
9072 AC_VERB_GET_PIN_SENSE, 0);
9073 spec->jack_present = !!(presence & AC_PINSENSE_PRESENCE);
9074 alc262_hp_master_update(codec);
9075}
9076
9077static void alc262_hp_wildwest_unsol_event(struct hda_codec *codec,
9078 unsigned int res)
9079{
9080 if ((res >> 26) != ALC880_HP_EVENT)
9081 return;
9082 alc262_hp_wildwest_automute(codec);
9083}
9084
9085static int alc262_hp_master_sw_get(struct snd_kcontrol *kcontrol,
9086 struct snd_ctl_elem_value *ucontrol)
9087{
9088 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
9089 struct alc_spec *spec = codec->spec;
9090 *ucontrol->value.integer.value = spec->master_sw;
9091 return 0;
9092}
9093
9094static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol,
9095 struct snd_ctl_elem_value *ucontrol)
9096{
9097 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
9098 struct alc_spec *spec = codec->spec;
9099 int val = !!*ucontrol->value.integer.value;
9100
9101 if (val == spec->master_sw)
9102 return 0;
9103 spec->master_sw = val;
9104 alc262_hp_master_update(codec);
9105 return 1;
9106}
9107
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009108static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
Takashi Iwaice875f02008-01-28 18:17:43 +01009109 {
9110 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9111 .name = "Master Playback Switch",
9112 .info = snd_ctl_boolean_mono_info,
9113 .get = alc262_hp_master_sw_get,
9114 .put = alc262_hp_master_sw_put,
9115 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009116 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9117 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9118 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +01009119 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
9120 HDA_OUTPUT),
9121 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
9122 HDA_OUTPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009123 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9124 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01009125 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009126 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
9127 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01009128 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009129 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9130 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9131 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9132 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9133 HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
9134 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT),
9135 HDA_CODEC_VOLUME("AUX IN Playback Volume", 0x0b, 0x06, HDA_INPUT),
9136 HDA_CODEC_MUTE("AUX IN Playback Switch", 0x0b, 0x06, HDA_INPUT),
9137 { } /* end */
9138};
9139
Kailang Yangcd7509a2007-01-26 18:33:17 +01009140static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = {
Takashi Iwaice875f02008-01-28 18:17:43 +01009141 {
9142 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9143 .name = "Master Playback Switch",
9144 .info = snd_ctl_boolean_mono_info,
9145 .get = alc262_hp_master_sw_get,
9146 .put = alc262_hp_master_sw_put,
9147 },
Kailang Yangcd7509a2007-01-26 18:33:17 +01009148 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9149 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
9150 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
9151 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +01009152 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
9153 HDA_OUTPUT),
9154 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
9155 HDA_OUTPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +01009156 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT),
9157 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01009158 HDA_CODEC_VOLUME("Front Mic Boost", 0x1a, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +01009159 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
9160 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
9161 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9162 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9163 HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x0b, 0x05, HDA_INPUT),
9164 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x0b, 0x05, HDA_INPUT),
9165 { } /* end */
9166};
9167
9168static struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = {
9169 HDA_CODEC_VOLUME("Rear Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9170 HDA_CODEC_MUTE("Rear Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +01009171 HDA_CODEC_VOLUME("Rear Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +01009172 { } /* end */
9173};
9174
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009175/* mute/unmute internal speaker according to the hp jack and mute state */
9176static void alc262_hp_t5735_automute(struct hda_codec *codec, int force)
9177{
9178 struct alc_spec *spec = codec->spec;
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009179
9180 if (force || !spec->sense_updated) {
9181 unsigned int present;
9182 present = snd_hda_codec_read(codec, 0x15, 0,
9183 AC_VERB_GET_PIN_SENSE, 0);
Takashi Iwai4bb26132008-01-28 18:12:42 +01009184 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009185 spec->sense_updated = 1;
9186 }
Takashi Iwai4bb26132008-01-28 18:12:42 +01009187 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0, HDA_AMP_MUTE,
9188 spec->jack_present ? HDA_AMP_MUTE : 0);
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009189}
9190
9191static void alc262_hp_t5735_unsol_event(struct hda_codec *codec,
9192 unsigned int res)
9193{
9194 if ((res >> 26) != ALC880_HP_EVENT)
9195 return;
9196 alc262_hp_t5735_automute(codec, 1);
9197}
9198
9199static void alc262_hp_t5735_init_hook(struct hda_codec *codec)
9200{
9201 alc262_hp_t5735_automute(codec, 1);
9202}
9203
9204static struct snd_kcontrol_new alc262_hp_t5735_mixer[] = {
Takashi Iwai86cd9292008-01-28 18:09:56 +01009205 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9206 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang66d2a9d2007-11-14 12:06:21 +01009207 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
9208 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9209 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9210 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9211 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9212 { } /* end */
9213};
9214
9215static struct hda_verb alc262_hp_t5735_verbs[] = {
9216 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9217 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9218
9219 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9220 { }
9221};
9222
Kailang Yang8c427222008-01-10 13:03:59 +01009223static struct snd_kcontrol_new alc262_hp_rp5700_mixer[] = {
Takashi Iwaif2f48e12008-01-28 18:14:43 +01009224 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9225 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01009226 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
9227 HDA_CODEC_MUTE("Speaker Playback Switch", 0x16, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +01009228 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
9229 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
9230 { } /* end */
9231};
9232
9233static struct hda_verb alc262_hp_rp5700_verbs[] = {
9234 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9235 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9236 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9237 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9238 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
9239 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
9240 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
9241 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
9242 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
9243 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
9244 {}
9245};
9246
9247static struct hda_input_mux alc262_hp_rp5700_capture_source = {
9248 .num_items = 1,
9249 .items = {
9250 { "Line", 0x1 },
9251 },
9252};
9253
Takashi Iwai0724ea22007-08-23 00:31:43 +02009254/* bind hp and internal speaker mute (with plug check) */
9255static int alc262_sony_master_sw_put(struct snd_kcontrol *kcontrol,
9256 struct snd_ctl_elem_value *ucontrol)
9257{
9258 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
9259 long *valp = ucontrol->value.integer.value;
9260 int change;
9261
9262 /* change hp mute */
9263 change = snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0,
9264 HDA_AMP_MUTE,
9265 valp[0] ? 0 : HDA_AMP_MUTE);
9266 change |= snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0,
9267 HDA_AMP_MUTE,
9268 valp[1] ? 0 : HDA_AMP_MUTE);
9269 if (change) {
9270 /* change speaker according to HP jack state */
9271 struct alc_spec *spec = codec->spec;
9272 unsigned int mute;
9273 if (spec->jack_present)
9274 mute = HDA_AMP_MUTE;
9275 else
9276 mute = snd_hda_codec_amp_read(codec, 0x15, 0,
9277 HDA_OUTPUT, 0);
9278 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9279 HDA_AMP_MUTE, mute);
9280 }
9281 return change;
9282}
Takashi Iwai5b319542007-07-26 11:49:22 +02009283
Kailang Yang272a5272007-05-14 11:00:38 +02009284static struct snd_kcontrol_new alc262_sony_mixer[] = {
Takashi Iwai0724ea22007-08-23 00:31:43 +02009285 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9286 {
9287 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9288 .name = "Master Playback Switch",
9289 .info = snd_hda_mixer_amp_switch_info,
9290 .get = snd_hda_mixer_amp_switch_get,
9291 .put = alc262_sony_master_sw_put,
9292 .private_value = HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
9293 },
Kailang Yang272a5272007-05-14 11:00:38 +02009294 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9295 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9296 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
9297 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
9298 { } /* end */
9299};
9300
Kailang Yang83c34212007-07-05 11:43:05 +02009301static struct snd_kcontrol_new alc262_benq_t31_mixer[] = {
9302 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9303 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9304 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9305 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9306 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9307 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
9308 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
9309 { } /* end */
9310};
Kailang Yang272a5272007-05-14 11:00:38 +02009311
Kailang Yangdf694da2005-12-05 19:42:22 +01009312#define alc262_capture_mixer alc882_capture_mixer
9313#define alc262_capture_alt_mixer alc882_capture_alt_mixer
9314
9315/*
9316 * generic initialization of ADC, input mixers and output mixers
9317 */
9318static struct hda_verb alc262_init_verbs[] = {
9319 /*
9320 * Unmute ADC0-2 and set the default input to mic-in
9321 */
9322 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
9323 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9324 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
9325 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9326 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
9327 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9328
Takashi Iwaicb53c622007-08-10 17:21:45 +02009329 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +01009330 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009331 * Note: PASD motherboards uses the Line In 2 as the input for
9332 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01009333 */
9334 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02009335 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9336 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
9337 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
9338 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
9339 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01009340
9341 /*
9342 * Set up output mixers (0x0c - 0x0e)
9343 */
9344 /* set vol=0 to output mixers */
9345 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9346 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9347 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9348 /* set up input amps for analog loopback */
9349 /* Amp Indices: DAC = 0, mixer = 1 */
9350 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9351 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9352 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9353 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9354 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9355 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9356
9357 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
9358 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
9359 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
9360 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9361 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9362 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
9363
9364 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
9365 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
9366 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
9367 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
9368 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Kailang Yangea1fb292008-08-26 12:58:38 +02009369
Kailang Yangdf694da2005-12-05 19:42:22 +01009370 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
9371 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Kailang Yangea1fb292008-08-26 12:58:38 +02009372
Kailang Yangdf694da2005-12-05 19:42:22 +01009373 /* FIXME: use matrix-type input source selection */
9374 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
9375 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
9376 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9377 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
9378 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
9379 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
9380 /* Input mixer2 */
9381 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9382 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
9383 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
9384 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
9385 /* Input mixer3 */
9386 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
9387 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
9388 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009389 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
Kailang Yangdf694da2005-12-05 19:42:22 +01009390
9391 { }
9392};
9393
Kailang Yang4e555fe2008-08-26 13:05:55 +02009394static struct hda_verb alc262_eapd_verbs[] = {
9395 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
9396 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
9397 { }
9398};
9399
Kailang Yangccc656c2006-10-17 12:32:26 +02009400static struct hda_verb alc262_hippo_unsol_verbs[] = {
9401 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
9402 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9403 {}
9404};
9405
9406static struct hda_verb alc262_hippo1_unsol_verbs[] = {
9407 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
9408 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
9409 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
9410
9411 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
9412 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9413 {}
9414};
9415
Kailang Yang272a5272007-05-14 11:00:38 +02009416static struct hda_verb alc262_sony_unsol_verbs[] = {
9417 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
9418 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9419 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, // Front Mic
9420
9421 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
9422 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Akio Idehara7b1e8792008-06-09 22:46:07 +09009423 {}
Kailang Yang272a5272007-05-14 11:00:38 +02009424};
9425
Kailang Yang4e555fe2008-08-26 13:05:55 +02009426static struct hda_input_mux alc262_dmic_capture_source = {
9427 .num_items = 2,
9428 .items = {
9429 { "Int DMic", 0x9 },
9430 { "Mic", 0x0 },
9431 },
9432};
9433
9434static struct snd_kcontrol_new alc262_toshiba_s06_mixer[] = {
9435 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9436 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9437 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9438 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9439 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9440 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
9441 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
9442 {
9443 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9444 /* The multiple "Capture Source" controls confuse alsamixer
9445 * So call somewhat different..
9446 */
9447 /* .name = "Capture Source", */
9448 .name = "Input Source",
9449 .count = 1,
9450 .info = alc_mux_enum_info,
9451 .get = alc_mux_enum_get,
9452 .put = alc_mux_enum_put,
9453 },
9454 { } /* end */
9455};
9456
9457static struct hda_verb alc262_toshiba_s06_verbs[] = {
9458 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
9459 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9460 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9461 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9462 {0x22, AC_VERB_SET_CONNECT_SEL, 0x09},
9463 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9464 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
9465 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
9466 {}
9467};
9468
9469static void alc262_dmic_automute(struct hda_codec *codec)
9470{
9471 unsigned int present;
9472
9473 present = snd_hda_codec_read(codec, 0x18, 0,
9474 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
9475 snd_hda_codec_write(codec, 0x22, 0,
9476 AC_VERB_SET_CONNECT_SEL, present ? 0x0 : 0x09);
9477}
9478
9479/* toggle speaker-output according to the hp-jack state */
9480static void alc262_toshiba_s06_speaker_automute(struct hda_codec *codec)
9481{
9482 unsigned int present;
9483 unsigned char bits;
9484
9485 present = snd_hda_codec_read(codec, 0x15, 0,
9486 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
9487 bits = present ? 0 : PIN_OUT;
9488 snd_hda_codec_write(codec, 0x14, 0,
9489 AC_VERB_SET_PIN_WIDGET_CONTROL, bits);
9490}
9491
9492
9493
9494/* unsolicited event for HP jack sensing */
9495static void alc262_toshiba_s06_unsol_event(struct hda_codec *codec,
9496 unsigned int res)
9497{
9498 if ((res >> 26) == ALC880_HP_EVENT)
9499 alc262_toshiba_s06_speaker_automute(codec);
9500 if ((res >> 26) == ALC880_MIC_EVENT)
9501 alc262_dmic_automute(codec);
9502
9503}
9504
9505static void alc262_toshiba_s06_init_hook(struct hda_codec *codec)
9506{
9507 alc262_toshiba_s06_speaker_automute(codec);
9508 alc262_dmic_automute(codec);
9509}
9510
Kailang Yangccc656c2006-10-17 12:32:26 +02009511/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwai5b319542007-07-26 11:49:22 +02009512static void alc262_hippo_automute(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02009513{
9514 struct alc_spec *spec = codec->spec;
9515 unsigned int mute;
Takashi Iwai5b319542007-07-26 11:49:22 +02009516 unsigned int present;
Kailang Yangccc656c2006-10-17 12:32:26 +02009517
Takashi Iwai5b319542007-07-26 11:49:22 +02009518 /* need to execute and sync at first */
9519 snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0);
9520 present = snd_hda_codec_read(codec, 0x15, 0,
9521 AC_VERB_GET_PIN_SENSE, 0);
9522 spec->jack_present = (present & 0x80000000) != 0;
Kailang Yangccc656c2006-10-17 12:32:26 +02009523 if (spec->jack_present) {
9524 /* mute internal speaker */
Takashi Iwai47fd8302007-08-10 17:11:07 +02009525 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9526 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yangccc656c2006-10-17 12:32:26 +02009527 } else {
9528 /* unmute internal speaker if necessary */
9529 mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0);
Takashi Iwai47fd8302007-08-10 17:11:07 +02009530 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9531 HDA_AMP_MUTE, mute);
Kailang Yangccc656c2006-10-17 12:32:26 +02009532 }
9533}
9534
9535/* unsolicited event for HP jack sensing */
9536static void alc262_hippo_unsol_event(struct hda_codec *codec,
9537 unsigned int res)
9538{
9539 if ((res >> 26) != ALC880_HP_EVENT)
9540 return;
Takashi Iwai5b319542007-07-26 11:49:22 +02009541 alc262_hippo_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02009542}
9543
Takashi Iwai5b319542007-07-26 11:49:22 +02009544static void alc262_hippo1_automute(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02009545{
Kailang Yangccc656c2006-10-17 12:32:26 +02009546 unsigned int mute;
Takashi Iwai5b319542007-07-26 11:49:22 +02009547 unsigned int present;
Kailang Yangccc656c2006-10-17 12:32:26 +02009548
Takashi Iwai5b319542007-07-26 11:49:22 +02009549 snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
9550 present = snd_hda_codec_read(codec, 0x1b, 0,
9551 AC_VERB_GET_PIN_SENSE, 0);
9552 present = (present & 0x80000000) != 0;
9553 if (present) {
Kailang Yangccc656c2006-10-17 12:32:26 +02009554 /* mute internal speaker */
Takashi Iwai47fd8302007-08-10 17:11:07 +02009555 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9556 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yangccc656c2006-10-17 12:32:26 +02009557 } else {
9558 /* unmute internal speaker if necessary */
9559 mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
Takashi Iwai47fd8302007-08-10 17:11:07 +02009560 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9561 HDA_AMP_MUTE, mute);
Kailang Yangccc656c2006-10-17 12:32:26 +02009562 }
9563}
9564
9565/* unsolicited event for HP jack sensing */
9566static void alc262_hippo1_unsol_event(struct hda_codec *codec,
9567 unsigned int res)
9568{
9569 if ((res >> 26) != ALC880_HP_EVENT)
9570 return;
Takashi Iwai5b319542007-07-26 11:49:22 +02009571 alc262_hippo1_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02009572}
9573
Takashi Iwai834be882006-03-01 14:16:17 +01009574/*
Pascal Terjane8f9ae22008-08-04 14:36:05 +02009575 * nec model
9576 * 0x15 = headphone
9577 * 0x16 = internal speaker
9578 * 0x18 = external mic
9579 */
9580
9581static struct snd_kcontrol_new alc262_nec_mixer[] = {
9582 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
9583 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 0, 0x0, HDA_OUTPUT),
9584
9585 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9586 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9587 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9588
9589 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
9590 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9591 { } /* end */
9592};
9593
9594static struct hda_verb alc262_nec_verbs[] = {
9595 /* Unmute Speaker */
9596 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9597
9598 /* Headphone */
9599 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
9600 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9601
9602 /* External mic to headphone */
9603 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9604 /* External mic to speaker */
9605 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9606 {}
9607};
9608
9609/*
Takashi Iwai834be882006-03-01 14:16:17 +01009610 * fujitsu model
Tony Vroon5d9fab22008-03-14 17:09:18 +01009611 * 0x14 = headphone/spdif-out, 0x15 = internal speaker,
9612 * 0x1b = port replicator headphone out
Takashi Iwai834be882006-03-01 14:16:17 +01009613 */
9614
9615#define ALC_HP_EVENT 0x37
9616
9617static struct hda_verb alc262_fujitsu_unsol_verbs[] = {
9618 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
9619 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Tony Vroon5d9fab22008-03-14 17:09:18 +01009620 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
9621 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai834be882006-03-01 14:16:17 +01009622 {}
9623};
9624
Jiang zhe0e31daf2008-03-20 12:12:39 +01009625static struct hda_verb alc262_lenovo_3000_unsol_verbs[] = {
9626 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
9627 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9628 {}
9629};
9630
Takashi Iwai834be882006-03-01 14:16:17 +01009631static struct hda_input_mux alc262_fujitsu_capture_source = {
Takashi Iwai39d3ed32007-10-12 15:03:48 +02009632 .num_items = 3,
Takashi Iwai834be882006-03-01 14:16:17 +01009633 .items = {
9634 { "Mic", 0x0 },
Takashi Iwai39d3ed32007-10-12 15:03:48 +02009635 { "Int Mic", 0x1 },
Takashi Iwai834be882006-03-01 14:16:17 +01009636 { "CD", 0x4 },
9637 },
9638};
9639
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009640static struct hda_input_mux alc262_HP_capture_source = {
9641 .num_items = 5,
9642 .items = {
9643 { "Mic", 0x0 },
zhejiangaccbe492007-08-31 12:36:05 +02009644 { "Front Mic", 0x1 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009645 { "Line", 0x2 },
9646 { "CD", 0x4 },
9647 { "AUX IN", 0x6 },
9648 },
9649};
9650
zhejiangaccbe492007-08-31 12:36:05 +02009651static struct hda_input_mux alc262_HP_D7000_capture_source = {
9652 .num_items = 4,
9653 .items = {
9654 { "Mic", 0x0 },
9655 { "Front Mic", 0x2 },
9656 { "Line", 0x1 },
9657 { "CD", 0x4 },
9658 },
9659};
9660
Takashi Iwaiebc7a402008-05-20 09:23:05 +02009661/* mute/unmute internal speaker according to the hp jacks and mute state */
Takashi Iwai834be882006-03-01 14:16:17 +01009662static void alc262_fujitsu_automute(struct hda_codec *codec, int force)
9663{
9664 struct alc_spec *spec = codec->spec;
9665 unsigned int mute;
9666
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009667 if (force || !spec->sense_updated) {
Takashi Iwaiebc7a402008-05-20 09:23:05 +02009668 unsigned int present;
Takashi Iwai834be882006-03-01 14:16:17 +01009669 /* need to execute and sync at first */
9670 snd_hda_codec_read(codec, 0x14, 0, AC_VERB_SET_PIN_SENSE, 0);
Takashi Iwaiebc7a402008-05-20 09:23:05 +02009671 /* check laptop HP jack */
9672 present = snd_hda_codec_read(codec, 0x14, 0,
9673 AC_VERB_GET_PIN_SENSE, 0);
9674 /* need to execute and sync at first */
9675 snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
9676 /* check docking HP jack */
9677 present |= snd_hda_codec_read(codec, 0x1b, 0,
9678 AC_VERB_GET_PIN_SENSE, 0);
9679 if (present & AC_PINSENSE_PRESENCE)
9680 spec->jack_present = 1;
9681 else
9682 spec->jack_present = 0;
Takashi Iwai834be882006-03-01 14:16:17 +01009683 spec->sense_updated = 1;
9684 }
Takashi Iwaiebc7a402008-05-20 09:23:05 +02009685 /* unmute internal speaker only if both HPs are unplugged and
9686 * master switch is on
9687 */
9688 if (spec->jack_present)
9689 mute = HDA_AMP_MUTE;
9690 else
Takashi Iwai834be882006-03-01 14:16:17 +01009691 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
Takashi Iwaiebc7a402008-05-20 09:23:05 +02009692 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9693 HDA_AMP_MUTE, mute);
Takashi Iwai834be882006-03-01 14:16:17 +01009694}
9695
9696/* unsolicited event for HP jack sensing */
9697static void alc262_fujitsu_unsol_event(struct hda_codec *codec,
9698 unsigned int res)
9699{
9700 if ((res >> 26) != ALC_HP_EVENT)
9701 return;
9702 alc262_fujitsu_automute(codec, 1);
9703}
9704
Takashi Iwaiebc7a402008-05-20 09:23:05 +02009705static void alc262_fujitsu_init_hook(struct hda_codec *codec)
9706{
9707 alc262_fujitsu_automute(codec, 1);
9708}
9709
Takashi Iwai834be882006-03-01 14:16:17 +01009710/* bind volumes of both NID 0x0c and 0x0d */
Takashi Iwaicca3b372007-08-10 17:12:15 +02009711static struct hda_bind_ctls alc262_fujitsu_bind_master_vol = {
9712 .ops = &snd_hda_bind_vol,
9713 .values = {
9714 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT),
9715 HDA_COMPOSE_AMP_VAL(0x0d, 3, 0, HDA_OUTPUT),
9716 0
9717 },
9718};
Takashi Iwai834be882006-03-01 14:16:17 +01009719
Jiang zhe0e31daf2008-03-20 12:12:39 +01009720/* mute/unmute internal speaker according to the hp jack and mute state */
9721static void alc262_lenovo_3000_automute(struct hda_codec *codec, int force)
9722{
9723 struct alc_spec *spec = codec->spec;
9724 unsigned int mute;
9725
9726 if (force || !spec->sense_updated) {
9727 unsigned int present_int_hp;
9728 /* need to execute and sync at first */
9729 snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0);
9730 present_int_hp = snd_hda_codec_read(codec, 0x1b, 0,
9731 AC_VERB_GET_PIN_SENSE, 0);
9732 spec->jack_present = (present_int_hp & 0x80000000) != 0;
9733 spec->sense_updated = 1;
9734 }
9735 if (spec->jack_present) {
9736 /* mute internal speaker */
9737 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9738 HDA_AMP_MUTE, HDA_AMP_MUTE);
9739 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
9740 HDA_AMP_MUTE, HDA_AMP_MUTE);
9741 } else {
9742 /* unmute internal speaker if necessary */
9743 mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
9744 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9745 HDA_AMP_MUTE, mute);
9746 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
9747 HDA_AMP_MUTE, mute);
9748 }
9749}
9750
9751/* unsolicited event for HP jack sensing */
9752static void alc262_lenovo_3000_unsol_event(struct hda_codec *codec,
9753 unsigned int res)
9754{
9755 if ((res >> 26) != ALC_HP_EVENT)
9756 return;
9757 alc262_lenovo_3000_automute(codec, 1);
9758}
9759
Takashi Iwai834be882006-03-01 14:16:17 +01009760/* bind hp and internal speaker mute (with plug check) */
9761static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol,
9762 struct snd_ctl_elem_value *ucontrol)
9763{
9764 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
9765 long *valp = ucontrol->value.integer.value;
9766 int change;
9767
Tony Vroon5d9fab22008-03-14 17:09:18 +01009768 change = snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9769 HDA_AMP_MUTE,
9770 valp ? 0 : HDA_AMP_MUTE);
9771 change |= snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
9772 HDA_AMP_MUTE,
9773 valp ? 0 : HDA_AMP_MUTE);
9774
Takashi Iwai82beb8f2007-08-10 17:09:26 +02009775 if (change)
9776 alc262_fujitsu_automute(codec, 0);
Takashi Iwai834be882006-03-01 14:16:17 +01009777 return change;
9778}
9779
9780static struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02009781 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
Takashi Iwai834be882006-03-01 14:16:17 +01009782 {
9783 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9784 .name = "Master Playback Switch",
9785 .info = snd_hda_mixer_amp_switch_info,
9786 .get = snd_hda_mixer_amp_switch_get,
9787 .put = alc262_fujitsu_master_sw_put,
9788 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
9789 },
9790 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9791 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Tony Vroon06a9c302008-04-14 13:31:45 +02009792 HDA_CODEC_VOLUME("PC Speaker Volume", 0x0b, 0x05, HDA_INPUT),
9793 HDA_CODEC_MUTE("PC Speaker Switch", 0x0b, 0x05, HDA_INPUT),
Takashi Iwai834be882006-03-01 14:16:17 +01009794 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9795 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9796 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai39d3ed32007-10-12 15:03:48 +02009797 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
9798 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
9799 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai834be882006-03-01 14:16:17 +01009800 { } /* end */
9801};
9802
Jiang zhe0e31daf2008-03-20 12:12:39 +01009803/* bind hp and internal speaker mute (with plug check) */
9804static int alc262_lenovo_3000_master_sw_put(struct snd_kcontrol *kcontrol,
9805 struct snd_ctl_elem_value *ucontrol)
9806{
9807 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
9808 long *valp = ucontrol->value.integer.value;
9809 int change;
9810
9811 change = snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
9812 HDA_AMP_MUTE,
9813 valp ? 0 : HDA_AMP_MUTE);
9814
9815 if (change)
9816 alc262_lenovo_3000_automute(codec, 0);
9817 return change;
9818}
9819
9820static struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = {
9821 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
9822 {
9823 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9824 .name = "Master Playback Switch",
9825 .info = snd_hda_mixer_amp_switch_info,
9826 .get = snd_hda_mixer_amp_switch_get,
9827 .put = alc262_lenovo_3000_master_sw_put,
9828 .private_value = HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
9829 },
9830 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9831 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9832 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9833 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9834 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9835 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
9836 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
9837 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
9838 { } /* end */
9839};
9840
Hiroshi Miura9f99a632008-08-28 16:09:06 +02009841static struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = {
9842 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
9843 {
9844 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9845 .name = "Master Playback Switch",
9846 .info = snd_hda_mixer_amp_switch_info,
9847 .get = snd_hda_mixer_amp_switch_get,
9848 .put = alc262_sony_master_sw_put,
9849 .private_value = HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
9850 },
9851 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9852 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9853 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
9854 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
9855 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
9856 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
9857 { } /* end */
9858};
9859
Takashi Iwai304dcaa2006-07-25 14:51:16 +02009860/* additional init verbs for Benq laptops */
9861static struct hda_verb alc262_EAPD_verbs[] = {
9862 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
9863 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
9864 {}
9865};
9866
Kailang Yang83c34212007-07-05 11:43:05 +02009867static struct hda_verb alc262_benq_t31_EAPD_verbs[] = {
9868 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9869 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
9870
9871 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
9872 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
9873 {}
9874};
9875
Tobin Davisf651b502007-10-26 12:40:47 +02009876/* Samsung Q1 Ultra Vista model setup */
9877static struct snd_kcontrol_new alc262_ultra_mixer[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01009878 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9879 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +02009880 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
9881 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
9882 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01009883 HDA_CODEC_VOLUME("Headphone Mic Boost", 0x15, 0, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +02009884 { } /* end */
9885};
9886
9887static struct hda_verb alc262_ultra_verbs[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01009888 /* output mixer */
9889 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9890 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
9891 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9892 /* speaker */
9893 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9894 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9895 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9896 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
9897 /* HP */
Tobin Davisf651b502007-10-26 12:40:47 +02009898 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01009899 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
9900 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9901 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9902 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
9903 /* internal mic */
9904 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
9905 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
9906 /* ADC, choose mic */
9907 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9908 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9909 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9910 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
9911 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
9912 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
9913 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
9914 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
9915 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
9916 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(8)},
Tobin Davisf651b502007-10-26 12:40:47 +02009917 {}
9918};
9919
Tobin Davisf651b502007-10-26 12:40:47 +02009920/* mute/unmute internal speaker according to the hp jack and mute state */
9921static void alc262_ultra_automute(struct hda_codec *codec)
9922{
9923 struct alc_spec *spec = codec->spec;
9924 unsigned int mute;
Tobin Davisf651b502007-10-26 12:40:47 +02009925
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01009926 mute = 0;
9927 /* auto-mute only when HP is used as HP */
9928 if (!spec->cur_mux[0]) {
9929 unsigned int present;
9930 /* need to execute and sync at first */
9931 snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0);
9932 present = snd_hda_codec_read(codec, 0x15, 0,
9933 AC_VERB_GET_PIN_SENSE, 0);
9934 spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
9935 if (spec->jack_present)
9936 mute = HDA_AMP_MUTE;
Tobin Davisf651b502007-10-26 12:40:47 +02009937 }
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01009938 /* mute/unmute internal speaker */
9939 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9940 HDA_AMP_MUTE, mute);
9941 /* mute/unmute HP */
9942 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9943 HDA_AMP_MUTE, mute ? 0 : HDA_AMP_MUTE);
Tobin Davisf651b502007-10-26 12:40:47 +02009944}
9945
9946/* unsolicited event for HP jack sensing */
9947static void alc262_ultra_unsol_event(struct hda_codec *codec,
9948 unsigned int res)
9949{
9950 if ((res >> 26) != ALC880_HP_EVENT)
9951 return;
9952 alc262_ultra_automute(codec);
9953}
9954
Takashi Iwaibb9f76c2008-03-12 12:51:09 +01009955static struct hda_input_mux alc262_ultra_capture_source = {
9956 .num_items = 2,
9957 .items = {
9958 { "Mic", 0x1 },
9959 { "Headphone", 0x7 },
9960 },
9961};
9962
9963static int alc262_ultra_mux_enum_put(struct snd_kcontrol *kcontrol,
9964 struct snd_ctl_elem_value *ucontrol)
9965{
9966 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
9967 struct alc_spec *spec = codec->spec;
9968 int ret;
9969
9970 ret = alc882_mux_enum_put(kcontrol, ucontrol);
9971 if (!ret)
9972 return 0;
9973 /* reprogram the HP pin as mic or HP according to the input source */
9974 snd_hda_codec_write_cache(codec, 0x15, 0,
9975 AC_VERB_SET_PIN_WIDGET_CONTROL,
9976 spec->cur_mux[0] ? PIN_VREF80 : PIN_HP);
9977 alc262_ultra_automute(codec); /* mute/unmute HP */
9978 return ret;
9979}
9980
9981static struct snd_kcontrol_new alc262_ultra_capture_mixer[] = {
9982 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
9983 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
9984 {
9985 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9986 .name = "Capture Source",
9987 .info = alc882_mux_enum_info,
9988 .get = alc882_mux_enum_get,
9989 .put = alc262_ultra_mux_enum_put,
9990 },
9991 { } /* end */
9992};
9993
Kailang Yangdf694da2005-12-05 19:42:22 +01009994/* add playback controls from the parsed DAC table */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009995static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
9996 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +01009997{
9998 hda_nid_t nid;
9999 int err;
10000
10001 spec->multiout.num_dacs = 1; /* only use one dac */
10002 spec->multiout.dac_nids = spec->private_dac_nids;
10003 spec->multiout.dac_nids[0] = 2;
10004
10005 nid = cfg->line_out_pins[0];
10006 if (nid) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010007 err = add_control(spec, ALC_CTL_WIDGET_VOL,
10008 "Front Playback Volume",
10009 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT));
10010 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010011 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010012 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10013 "Front Playback Switch",
10014 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
10015 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010016 return err;
10017 }
10018
Takashi Iwai82bc9552006-03-21 11:24:42 +010010019 nid = cfg->speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010010020 if (nid) {
10021 if (nid == 0x16) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010022 err = add_control(spec, ALC_CTL_WIDGET_VOL,
10023 "Speaker Playback Volume",
10024 HDA_COMPOSE_AMP_VAL(0x0e, 2, 0,
10025 HDA_OUTPUT));
10026 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010027 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010028 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10029 "Speaker Playback Switch",
10030 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
10031 HDA_OUTPUT));
10032 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010033 return err;
10034 } else {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010035 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10036 "Speaker Playback Switch",
10037 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
10038 HDA_OUTPUT));
10039 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010040 return err;
10041 }
10042 }
Takashi Iwaieb06ed82006-09-20 17:10:27 +020010043 nid = cfg->hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010010044 if (nid) {
10045 /* spec->multiout.hp_nid = 2; */
10046 if (nid == 0x16) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010047 err = add_control(spec, ALC_CTL_WIDGET_VOL,
10048 "Headphone Playback Volume",
10049 HDA_COMPOSE_AMP_VAL(0x0e, 2, 0,
10050 HDA_OUTPUT));
10051 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010052 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010053 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10054 "Headphone Playback Switch",
10055 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
10056 HDA_OUTPUT));
10057 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010058 return err;
10059 } else {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010060 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
10061 "Headphone Playback Switch",
10062 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
10063 HDA_OUTPUT));
10064 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010065 return err;
10066 }
10067 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010068 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +010010069}
10070
10071/* identical with ALC880 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010072#define alc262_auto_create_analog_input_ctls \
10073 alc880_auto_create_analog_input_ctls
Kailang Yangdf694da2005-12-05 19:42:22 +010010074
10075/*
10076 * generic initialization of ADC, input mixers and output mixers
10077 */
10078static struct hda_verb alc262_volume_init_verbs[] = {
10079 /*
10080 * Unmute ADC0-2 and set the default input to mic-in
10081 */
10082 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
10083 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10084 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
10085 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10086 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
10087 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10088
Takashi Iwaicb53c622007-08-10 17:21:45 +020010089 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +010010090 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010091 * Note: PASD motherboards uses the Line In 2 as the input for
10092 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +010010093 */
10094 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020010095 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
10096 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10097 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
10098 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
10099 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +010010100
10101 /*
10102 * Set up output mixers (0x0c - 0x0f)
10103 */
10104 /* set vol=0 to output mixers */
10105 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10106 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10107 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yangea1fb292008-08-26 12:58:38 +020010108
Kailang Yangdf694da2005-12-05 19:42:22 +010010109 /* set up input amps for analog loopback */
10110 /* Amp Indices: DAC = 0, mixer = 1 */
10111 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10112 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10113 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10114 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10115 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10116 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10117
10118 /* FIXME: use matrix-type input source selection */
10119 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
10120 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
10121 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10122 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
10123 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
10124 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
10125 /* Input mixer2 */
10126 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10127 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
10128 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
10129 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
10130 /* Input mixer3 */
10131 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10132 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
10133 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
10134 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
10135
10136 { }
10137};
10138
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010139static struct hda_verb alc262_HP_BPC_init_verbs[] = {
10140 /*
10141 * Unmute ADC0-2 and set the default input to mic-in
10142 */
10143 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
10144 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10145 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
10146 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10147 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
10148 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10149
Takashi Iwaicb53c622007-08-10 17:21:45 +020010150 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010151 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010152 * Note: PASD motherboards uses the Line In 2 as the input for
10153 * front panel mic (mic 2)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010154 */
10155 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020010156 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
10157 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10158 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
10159 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
10160 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
10161 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
10162 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
Kailang Yangea1fb292008-08-26 12:58:38 +020010163
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010164 /*
10165 * Set up output mixers (0x0c - 0x0e)
10166 */
10167 /* set vol=0 to output mixers */
10168 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10169 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10170 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10171
10172 /* set up input amps for analog loopback */
10173 /* Amp Indices: DAC = 0, mixer = 1 */
10174 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10175 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10176 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10177 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10178 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10179 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10180
Takashi Iwaice875f02008-01-28 18:17:43 +010010181 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010182 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
10183 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
10184
10185 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
10186 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
10187
10188 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
10189 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
10190
10191 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10192 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
10193 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
10194 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10195 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10196
10197 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
10198 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10199 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10200 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
10201 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10202 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10203
10204
10205 /* FIXME: use matrix-type input source selection */
10206 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
10207 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
10208 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10209 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
10210 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
10211 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
10212 /* Input mixer2 */
10213 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10214 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
10215 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
10216 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
10217 /* Input mixer3 */
10218 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10219 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
10220 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
10221 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
10222
Takashi Iwaice875f02008-01-28 18:17:43 +010010223 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
10224
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010225 { }
10226};
10227
Kailang Yangcd7509a2007-01-26 18:33:17 +010010228static struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = {
10229 /*
10230 * Unmute ADC0-2 and set the default input to mic-in
10231 */
10232 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
10233 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10234 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
10235 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10236 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
10237 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10238
Takashi Iwaicb53c622007-08-10 17:21:45 +020010239 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangcd7509a2007-01-26 18:33:17 +010010240 * mixer widget
10241 * Note: PASD motherboards uses the Line In 2 as the input for front
10242 * panel mic (mic 2)
10243 */
10244 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020010245 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
10246 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10247 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
10248 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
10249 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
10250 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
10251 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
10252 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Kailang Yangcd7509a2007-01-26 18:33:17 +010010253 /*
10254 * Set up output mixers (0x0c - 0x0e)
10255 */
10256 /* set vol=0 to output mixers */
10257 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10258 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10259 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10260
10261 /* set up input amps for analog loopback */
10262 /* Amp Indices: DAC = 0, mixer = 1 */
10263 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10264 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10265 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10266 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10267 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10268 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10269
10270
10271 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP */
10272 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Mono */
10273 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* rear MIC */
10274 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* Line in */
10275 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
10276 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Line out */
10277 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD in */
10278
10279 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
10280 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
10281
10282 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
10283 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
10284
10285 /* {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, */
10286 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10287 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10288 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
10289 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10290 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
10291
10292 /* FIXME: use matrix-type input source selection */
10293 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
10294 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
10295 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, /*rear MIC*/
10296 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, /*Line in*/
10297 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, /*F MIC*/
10298 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, /*Front*/
10299 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, /*CD*/
10300 /* {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
10301 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, /*HP*/
10302 /* Input mixer2 */
10303 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10304 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
10305 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
10306 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
10307 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
10308 /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
10309 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
10310 /* Input mixer3 */
10311 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10312 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
10313 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
10314 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
10315 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
10316 /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
10317 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
10318
Takashi Iwaice875f02008-01-28 18:17:43 +010010319 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
10320
Kailang Yangcd7509a2007-01-26 18:33:17 +010010321 { }
10322};
10323
Hiroshi Miura9f99a632008-08-28 16:09:06 +020010324static struct hda_verb alc262_toshiba_rx1_unsol_verbs[] = {
10325
10326 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Front Speaker */
10327 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
10328 {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
10329
10330 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* MIC jack */
10331 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
10332 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
10333 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
10334
10335 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP jack */
10336 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
10337 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
10338 {}
10339};
10340
10341
Takashi Iwaicb53c622007-08-10 17:21:45 +020010342#ifdef CONFIG_SND_HDA_POWER_SAVE
10343#define alc262_loopbacks alc880_loopbacks
10344#endif
10345
Kailang Yangdf694da2005-12-05 19:42:22 +010010346/* pcm configuration: identiacal with ALC880 */
10347#define alc262_pcm_analog_playback alc880_pcm_analog_playback
10348#define alc262_pcm_analog_capture alc880_pcm_analog_capture
10349#define alc262_pcm_digital_playback alc880_pcm_digital_playback
10350#define alc262_pcm_digital_capture alc880_pcm_digital_capture
10351
10352/*
10353 * BIOS auto configuration
10354 */
10355static int alc262_parse_auto_config(struct hda_codec *codec)
10356{
10357 struct alc_spec *spec = codec->spec;
10358 int err;
10359 static hda_nid_t alc262_ignore[] = { 0x1d, 0 };
10360
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010361 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
10362 alc262_ignore);
10363 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010364 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010365 if (!spec->autocfg.line_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +010010366 return 0; /* can't find valid BIOS pin config */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010367 err = alc262_auto_create_multi_out_ctls(spec, &spec->autocfg);
10368 if (err < 0)
10369 return err;
10370 err = alc262_auto_create_analog_input_ctls(spec, &spec->autocfg);
10371 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010010372 return err;
10373
10374 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
10375
10376 if (spec->autocfg.dig_out_pin)
10377 spec->multiout.dig_out_nid = ALC262_DIGOUT_NID;
10378 if (spec->autocfg.dig_in_pin)
10379 spec->dig_in_nid = ALC262_DIGIN_NID;
10380
Takashi Iwai603c4012008-07-30 15:01:44 +020010381 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010010382 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +010010383
Takashi Iwaid88897e2008-10-31 15:01:37 +010010384 add_verb(spec, alc262_volume_init_verbs);
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020010385 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +010010386 spec->input_mux = &spec->private_imux;
10387
Takashi Iwai776e1842007-08-29 15:07:11 +020010388 err = alc_auto_add_mic_boost(codec);
10389 if (err < 0)
10390 return err;
10391
Takashi Iwaie044c392008-10-27 16:56:24 +010010392 store_pin_configs(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010010393 return 1;
10394}
10395
10396#define alc262_auto_init_multi_out alc882_auto_init_multi_out
10397#define alc262_auto_init_hp_out alc882_auto_init_hp_out
10398#define alc262_auto_init_analog_input alc882_auto_init_analog_input
Takashi Iwaif511b012008-08-15 16:46:42 +020010399#define alc262_auto_init_input_src alc882_auto_init_input_src
Kailang Yangdf694da2005-12-05 19:42:22 +010010400
10401
10402/* init callback for auto-configuration model -- overriding the default init */
Takashi Iwaiae6b8132006-03-03 16:47:17 +010010403static void alc262_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010010404{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010405 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010010406 alc262_auto_init_multi_out(codec);
10407 alc262_auto_init_hp_out(codec);
10408 alc262_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020010409 alc262_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010410 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020010411 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010010412}
10413
10414/*
10415 * configuration and preset
10416 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010417static const char *alc262_models[ALC262_MODEL_LAST] = {
10418 [ALC262_BASIC] = "basic",
10419 [ALC262_HIPPO] = "hippo",
10420 [ALC262_HIPPO_1] = "hippo_1",
10421 [ALC262_FUJITSU] = "fujitsu",
10422 [ALC262_HP_BPC] = "hp-bpc",
Kailang Yangcd7509a2007-01-26 18:33:17 +010010423 [ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000",
Takashi Iwai61dc35d2007-11-14 12:26:44 +010010424 [ALC262_HP_TC_T5735] = "hp-tc-t5735",
Kailang Yang8c427222008-01-10 13:03:59 +010010425 [ALC262_HP_RP5700] = "hp-rp5700",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010426 [ALC262_BENQ_ED8] = "benq",
Takashi Iwai0f405022007-07-06 12:24:11 +020010427 [ALC262_BENQ_T31] = "benq-t31",
10428 [ALC262_SONY_ASSAMD] = "sony-assamd",
Takashi Iwai2922c9a2008-08-27 18:12:42 +020010429 [ALC262_TOSHIBA_S06] = "toshiba-s06",
Hiroshi Miura9f99a632008-08-28 16:09:06 +020010430 [ALC262_TOSHIBA_RX1] = "toshiba-rx1",
Tobin Davisf651b502007-10-26 12:40:47 +020010431 [ALC262_ULTRA] = "ultra",
Jiang zhe0e31daf2008-03-20 12:12:39 +010010432 [ALC262_LENOVO_3000] = "lenovo-3000",
Pascal Terjane8f9ae22008-08-04 14:36:05 +020010433 [ALC262_NEC] = "nec",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010434 [ALC262_AUTO] = "auto",
10435};
10436
10437static struct snd_pci_quirk alc262_cfg_tbl[] = {
10438 SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO),
Pascal Terjane8f9ae22008-08-04 14:36:05 +020010439 SND_PCI_QUIRK(0x1033, 0x8895, "NEC Versa S9100", ALC262_NEC),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010440 SND_PCI_QUIRK(0x103c, 0x12fe, "HP xw9400", ALC262_HP_BPC),
Kailang Yang7d87de22007-06-05 12:17:21 +020010441 SND_PCI_QUIRK(0x103c, 0x12ff, "HP xw4550", ALC262_HP_BPC),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010442 SND_PCI_QUIRK(0x103c, 0x1306, "HP xw8600", ALC262_HP_BPC),
10443 SND_PCI_QUIRK(0x103c, 0x1307, "HP xw6600", ALC262_HP_BPC),
Kailang Yang7d87de22007-06-05 12:17:21 +020010444 SND_PCI_QUIRK(0x103c, 0x1308, "HP xw4600", ALC262_HP_BPC),
Takashi Iwaib98f9332007-11-07 14:18:01 +010010445 SND_PCI_QUIRK(0x103c, 0x1309, "HP xw4*00", ALC262_HP_BPC),
Takashi Iwaib98f9332007-11-07 14:18:01 +010010446 SND_PCI_QUIRK(0x103c, 0x130a, "HP xw6*00", ALC262_HP_BPC),
Takashi Iwaib98f9332007-11-07 14:18:01 +010010447 SND_PCI_QUIRK(0x103c, 0x130b, "HP xw8*00", ALC262_HP_BPC),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010448 SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010449 SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010450 SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010451 SND_PCI_QUIRK(0x103c, 0x2803, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010452 SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010453 SND_PCI_QUIRK(0x103c, 0x2805, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010454 SND_PCI_QUIRK(0x103c, 0x2806, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010455 SND_PCI_QUIRK(0x103c, 0x2807, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010456 SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC),
10457 SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC),
10458 SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC),
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010459 SND_PCI_QUIRK(0x103c, 0x302f, "HP Thin Client T5735",
10460 ALC262_HP_TC_T5735),
Kailang Yang8c427222008-01-10 13:03:59 +010010461 SND_PCI_QUIRK(0x103c, 0x2817, "HP RP5700", ALC262_HP_RP5700),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010462 SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010463 SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010464 SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD),
10465 SND_PCI_QUIRK(0x104d, 0x900e, "Sony ASSAMD", ALC262_SONY_ASSAMD),
10466 SND_PCI_QUIRK(0x104d, 0x9015, "Sony 0x9015", ALC262_SONY_ASSAMD),
Akio Idehara36ca6e12008-06-09 22:57:40 +090010467 SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1",
Hiroshi Miura9f99a632008-08-28 16:09:06 +020010468 ALC262_TOSHIBA_RX1),
Kailang Yang80ffe862008-10-15 11:23:27 +020010469 SND_PCI_QUIRK(0x1179, 0xff7b, "Toshiba S06", ALC262_TOSHIBA_S06),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010470 SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU),
Tony Vroon3f1eeae2008-02-25 16:44:13 +010010471 SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010472 SND_PCI_QUIRK(0x144d, 0xc032, "Samsung Q1 Ultra", ALC262_ULTRA),
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010473 SND_PCI_QUIRK(0x144d, 0xc039, "Samsung Q1U EL", ALC262_ULTRA),
Jiang zhe0e31daf2008-03-20 12:12:39 +010010474 SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 y410", ALC262_LENOVO_3000),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010475 SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8),
Kailang Yang83c34212007-07-05 11:43:05 +020010476 SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010477 SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1),
Kailang Yangdf694da2005-12-05 19:42:22 +010010478 {}
10479};
10480
10481static struct alc_config_preset alc262_presets[] = {
10482 [ALC262_BASIC] = {
10483 .mixers = { alc262_base_mixer },
10484 .init_verbs = { alc262_init_verbs },
10485 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10486 .dac_nids = alc262_dac_nids,
10487 .hp_nid = 0x03,
10488 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10489 .channel_mode = alc262_modes,
Takashi Iwaia3bcba32005-12-06 19:05:29 +010010490 .input_mux = &alc262_capture_source,
Kailang Yangdf694da2005-12-05 19:42:22 +010010491 },
Kailang Yangccc656c2006-10-17 12:32:26 +020010492 [ALC262_HIPPO] = {
10493 .mixers = { alc262_base_mixer },
10494 .init_verbs = { alc262_init_verbs, alc262_hippo_unsol_verbs},
10495 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10496 .dac_nids = alc262_dac_nids,
10497 .hp_nid = 0x03,
10498 .dig_out_nid = ALC262_DIGOUT_NID,
10499 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10500 .channel_mode = alc262_modes,
10501 .input_mux = &alc262_capture_source,
10502 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +020010503 .init_hook = alc262_hippo_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020010504 },
10505 [ALC262_HIPPO_1] = {
10506 .mixers = { alc262_hippo1_mixer },
10507 .init_verbs = { alc262_init_verbs, alc262_hippo1_unsol_verbs},
10508 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10509 .dac_nids = alc262_dac_nids,
10510 .hp_nid = 0x02,
10511 .dig_out_nid = ALC262_DIGOUT_NID,
10512 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10513 .channel_mode = alc262_modes,
10514 .input_mux = &alc262_capture_source,
10515 .unsol_event = alc262_hippo1_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +020010516 .init_hook = alc262_hippo1_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020010517 },
Takashi Iwai834be882006-03-01 14:16:17 +010010518 [ALC262_FUJITSU] = {
10519 .mixers = { alc262_fujitsu_mixer },
Takashi Iwai39d3ed32007-10-12 15:03:48 +020010520 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
10521 alc262_fujitsu_unsol_verbs },
Takashi Iwai834be882006-03-01 14:16:17 +010010522 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10523 .dac_nids = alc262_dac_nids,
10524 .hp_nid = 0x03,
10525 .dig_out_nid = ALC262_DIGOUT_NID,
10526 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10527 .channel_mode = alc262_modes,
10528 .input_mux = &alc262_fujitsu_capture_source,
Takashi Iwaiae6b8132006-03-03 16:47:17 +010010529 .unsol_event = alc262_fujitsu_unsol_event,
Takashi Iwaiebc7a402008-05-20 09:23:05 +020010530 .init_hook = alc262_fujitsu_init_hook,
Takashi Iwai834be882006-03-01 14:16:17 +010010531 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010532 [ALC262_HP_BPC] = {
10533 .mixers = { alc262_HP_BPC_mixer },
10534 .init_verbs = { alc262_HP_BPC_init_verbs },
10535 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10536 .dac_nids = alc262_dac_nids,
10537 .hp_nid = 0x03,
10538 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10539 .channel_mode = alc262_modes,
10540 .input_mux = &alc262_HP_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010010541 .unsol_event = alc262_hp_bpc_unsol_event,
10542 .init_hook = alc262_hp_bpc_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010543 },
Kailang Yangcd7509a2007-01-26 18:33:17 +010010544 [ALC262_HP_BPC_D7000_WF] = {
10545 .mixers = { alc262_HP_BPC_WildWest_mixer },
10546 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
10547 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10548 .dac_nids = alc262_dac_nids,
10549 .hp_nid = 0x03,
10550 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10551 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +020010552 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010010553 .unsol_event = alc262_hp_wildwest_unsol_event,
10554 .init_hook = alc262_hp_wildwest_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010555 },
Kailang Yangcd7509a2007-01-26 18:33:17 +010010556 [ALC262_HP_BPC_D7000_WL] = {
10557 .mixers = { alc262_HP_BPC_WildWest_mixer,
10558 alc262_HP_BPC_WildWest_option_mixer },
10559 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
10560 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10561 .dac_nids = alc262_dac_nids,
10562 .hp_nid = 0x03,
10563 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10564 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +020010565 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010010566 .unsol_event = alc262_hp_wildwest_unsol_event,
10567 .init_hook = alc262_hp_wildwest_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010568 },
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010569 [ALC262_HP_TC_T5735] = {
10570 .mixers = { alc262_hp_t5735_mixer },
10571 .init_verbs = { alc262_init_verbs, alc262_hp_t5735_verbs },
10572 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10573 .dac_nids = alc262_dac_nids,
10574 .hp_nid = 0x03,
10575 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10576 .channel_mode = alc262_modes,
10577 .input_mux = &alc262_capture_source,
10578 .unsol_event = alc262_hp_t5735_unsol_event,
10579 .init_hook = alc262_hp_t5735_init_hook,
Kailang Yang8c427222008-01-10 13:03:59 +010010580 },
10581 [ALC262_HP_RP5700] = {
10582 .mixers = { alc262_hp_rp5700_mixer },
10583 .init_verbs = { alc262_init_verbs, alc262_hp_rp5700_verbs },
10584 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10585 .dac_nids = alc262_dac_nids,
10586 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10587 .channel_mode = alc262_modes,
10588 .input_mux = &alc262_hp_rp5700_capture_source,
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010589 },
Takashi Iwai304dcaa2006-07-25 14:51:16 +020010590 [ALC262_BENQ_ED8] = {
10591 .mixers = { alc262_base_mixer },
10592 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs },
10593 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10594 .dac_nids = alc262_dac_nids,
10595 .hp_nid = 0x03,
10596 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10597 .channel_mode = alc262_modes,
10598 .input_mux = &alc262_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010599 },
Kailang Yang272a5272007-05-14 11:00:38 +020010600 [ALC262_SONY_ASSAMD] = {
10601 .mixers = { alc262_sony_mixer },
10602 .init_verbs = { alc262_init_verbs, alc262_sony_unsol_verbs},
10603 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10604 .dac_nids = alc262_dac_nids,
10605 .hp_nid = 0x02,
10606 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10607 .channel_mode = alc262_modes,
10608 .input_mux = &alc262_capture_source,
10609 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +020010610 .init_hook = alc262_hippo_automute,
Kailang Yang83c34212007-07-05 11:43:05 +020010611 },
10612 [ALC262_BENQ_T31] = {
10613 .mixers = { alc262_benq_t31_mixer },
10614 .init_verbs = { alc262_init_verbs, alc262_benq_t31_EAPD_verbs, alc262_hippo_unsol_verbs },
10615 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10616 .dac_nids = alc262_dac_nids,
10617 .hp_nid = 0x03,
10618 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10619 .channel_mode = alc262_modes,
10620 .input_mux = &alc262_capture_source,
10621 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai5b319542007-07-26 11:49:22 +020010622 .init_hook = alc262_hippo_automute,
Kailang Yangea1fb292008-08-26 12:58:38 +020010623 },
Tobin Davisf651b502007-10-26 12:40:47 +020010624 [ALC262_ULTRA] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010625 .mixers = { alc262_ultra_mixer, alc262_ultra_capture_mixer },
10626 .init_verbs = { alc262_ultra_verbs },
Tobin Davisf651b502007-10-26 12:40:47 +020010627 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10628 .dac_nids = alc262_dac_nids,
Tobin Davisf651b502007-10-26 12:40:47 +020010629 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10630 .channel_mode = alc262_modes,
10631 .input_mux = &alc262_ultra_capture_source,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010010632 .adc_nids = alc262_adc_nids, /* ADC0 */
10633 .capsrc_nids = alc262_capsrc_nids,
10634 .num_adc_nids = 1, /* single ADC */
Tobin Davisf651b502007-10-26 12:40:47 +020010635 .unsol_event = alc262_ultra_unsol_event,
10636 .init_hook = alc262_ultra_automute,
10637 },
Jiang zhe0e31daf2008-03-20 12:12:39 +010010638 [ALC262_LENOVO_3000] = {
10639 .mixers = { alc262_lenovo_3000_mixer },
10640 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
10641 alc262_lenovo_3000_unsol_verbs },
10642 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10643 .dac_nids = alc262_dac_nids,
10644 .hp_nid = 0x03,
10645 .dig_out_nid = ALC262_DIGOUT_NID,
10646 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10647 .channel_mode = alc262_modes,
10648 .input_mux = &alc262_fujitsu_capture_source,
10649 .unsol_event = alc262_lenovo_3000_unsol_event,
10650 },
Pascal Terjane8f9ae22008-08-04 14:36:05 +020010651 [ALC262_NEC] = {
10652 .mixers = { alc262_nec_mixer },
10653 .init_verbs = { alc262_nec_verbs },
10654 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10655 .dac_nids = alc262_dac_nids,
10656 .hp_nid = 0x03,
10657 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10658 .channel_mode = alc262_modes,
10659 .input_mux = &alc262_capture_source,
10660 },
Kailang Yang4e555fe2008-08-26 13:05:55 +020010661 [ALC262_TOSHIBA_S06] = {
10662 .mixers = { alc262_toshiba_s06_mixer },
10663 .init_verbs = { alc262_init_verbs, alc262_toshiba_s06_verbs,
10664 alc262_eapd_verbs },
10665 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10666 .capsrc_nids = alc262_dmic_capsrc_nids,
10667 .dac_nids = alc262_dac_nids,
10668 .adc_nids = alc262_dmic_adc_nids, /* ADC0 */
10669 .dig_out_nid = ALC262_DIGOUT_NID,
10670 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10671 .channel_mode = alc262_modes,
10672 .input_mux = &alc262_dmic_capture_source,
10673 .unsol_event = alc262_toshiba_s06_unsol_event,
10674 .init_hook = alc262_toshiba_s06_init_hook,
10675 },
Hiroshi Miura9f99a632008-08-28 16:09:06 +020010676 [ALC262_TOSHIBA_RX1] = {
10677 .mixers = { alc262_toshiba_rx1_mixer },
10678 .init_verbs = { alc262_init_verbs, alc262_toshiba_rx1_unsol_verbs },
10679 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
10680 .dac_nids = alc262_dac_nids,
10681 .hp_nid = 0x03,
10682 .num_channel_mode = ARRAY_SIZE(alc262_modes),
10683 .channel_mode = alc262_modes,
10684 .input_mux = &alc262_capture_source,
10685 .unsol_event = alc262_hippo_unsol_event,
10686 .init_hook = alc262_hippo_automute,
10687 },
Kailang Yangdf694da2005-12-05 19:42:22 +010010688};
10689
10690static int patch_alc262(struct hda_codec *codec)
10691{
10692 struct alc_spec *spec;
10693 int board_config;
10694 int err;
10695
Robert P. J. Daydc041e02006-12-19 14:44:15 +010010696 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010010697 if (spec == NULL)
10698 return -ENOMEM;
10699
10700 codec->spec = spec;
10701#if 0
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010702 /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is
10703 * under-run
10704 */
Kailang Yangdf694da2005-12-05 19:42:22 +010010705 {
10706 int tmp;
10707 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
10708 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
10709 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
10710 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80);
10711 }
10712#endif
10713
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020010714 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
10715
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010716 board_config = snd_hda_check_board_config(codec, ALC262_MODEL_LAST,
10717 alc262_models,
10718 alc262_cfg_tbl);
Kailang Yangcd7509a2007-01-26 18:33:17 +010010719
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010720 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010721 printk(KERN_INFO "hda_codec: Unknown model for ALC262, "
10722 "trying auto-probe from BIOS...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010010723 board_config = ALC262_AUTO;
10724 }
10725
10726 if (board_config == ALC262_AUTO) {
10727 /* automatic parse from the BIOS config */
10728 err = alc262_parse_auto_config(codec);
10729 if (err < 0) {
10730 alc_free(codec);
10731 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010732 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010733 printk(KERN_INFO
10734 "hda_codec: Cannot set up configuration "
10735 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010010736 board_config = ALC262_BASIC;
10737 }
10738 }
10739
10740 if (board_config != ALC262_AUTO)
10741 setup_preset(spec, &alc262_presets[board_config]);
10742
10743 spec->stream_name_analog = "ALC262 Analog";
10744 spec->stream_analog_playback = &alc262_pcm_analog_playback;
10745 spec->stream_analog_capture = &alc262_pcm_analog_capture;
Kailang Yangea1fb292008-08-26 12:58:38 +020010746
Kailang Yangdf694da2005-12-05 19:42:22 +010010747 spec->stream_name_digital = "ALC262 Digital";
10748 spec->stream_digital_playback = &alc262_pcm_digital_playback;
10749 spec->stream_digital_capture = &alc262_pcm_digital_capture;
10750
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010751 if (!spec->adc_nids && spec->input_mux) {
Kailang Yangdf694da2005-12-05 19:42:22 +010010752 /* check whether NID 0x07 is valid */
Takashi Iwai4a471b72005-12-07 13:56:29 +010010753 unsigned int wcap = get_wcaps(codec, 0x07);
10754
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010755 /* get type */
10756 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Kailang Yangdf694da2005-12-05 19:42:22 +010010757 if (wcap != AC_WID_AUD_IN) {
10758 spec->adc_nids = alc262_adc_nids_alt;
10759 spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids_alt);
Takashi Iwai88c71a92008-02-14 17:27:17 +010010760 spec->capsrc_nids = alc262_capsrc_nids_alt;
Takashi Iwaid88897e2008-10-31 15:01:37 +010010761 add_mixer(spec, alc262_capture_alt_mixer);
Kailang Yangdf694da2005-12-05 19:42:22 +010010762 } else {
10763 spec->adc_nids = alc262_adc_nids;
10764 spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids);
Takashi Iwai88c71a92008-02-14 17:27:17 +010010765 spec->capsrc_nids = alc262_capsrc_nids;
Takashi Iwaid88897e2008-10-31 15:01:37 +010010766 add_mixer(spec, alc262_capture_mixer);
Kailang Yangdf694da2005-12-05 19:42:22 +010010767 }
10768 }
10769
Takashi Iwai2134ea42008-01-10 16:53:55 +010010770 spec->vmaster_nid = 0x0c;
10771
Kailang Yangdf694da2005-12-05 19:42:22 +010010772 codec->patch_ops = alc_patch_ops;
10773 if (board_config == ALC262_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +010010774 spec->init_hook = alc262_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020010775#ifdef CONFIG_SND_HDA_POWER_SAVE
10776 if (!spec->loopback.amplist)
10777 spec->loopback.amplist = alc262_loopbacks;
10778#endif
Kailang Yangea1fb292008-08-26 12:58:38 +020010779
Kailang Yangdf694da2005-12-05 19:42:22 +010010780 return 0;
10781}
10782
Kailang Yangdf694da2005-12-05 19:42:22 +010010783/*
Kailang Yanga361d842007-06-05 12:30:55 +020010784 * ALC268 channel source setting (2 channel)
10785 */
10786#define ALC268_DIGOUT_NID ALC880_DIGOUT_NID
10787#define alc268_modes alc260_modes
Kailang Yangea1fb292008-08-26 12:58:38 +020010788
Kailang Yanga361d842007-06-05 12:30:55 +020010789static hda_nid_t alc268_dac_nids[2] = {
10790 /* front, hp */
10791 0x02, 0x03
10792};
10793
10794static hda_nid_t alc268_adc_nids[2] = {
10795 /* ADC0-1 */
10796 0x08, 0x07
10797};
10798
10799static hda_nid_t alc268_adc_nids_alt[1] = {
10800 /* ADC0 */
10801 0x08
10802};
10803
Takashi Iwaie1406342008-02-11 18:32:32 +010010804static hda_nid_t alc268_capsrc_nids[2] = { 0x23, 0x24 };
10805
Kailang Yanga361d842007-06-05 12:30:55 +020010806static struct snd_kcontrol_new alc268_base_mixer[] = {
10807 /* output mixer control */
10808 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
10809 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
10810 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
10811 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai33bf17a2007-08-21 11:51:42 +020010812 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10813 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
10814 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
Kailang Yanga361d842007-06-05 12:30:55 +020010815 { }
10816};
10817
Takashi Iwaiaef9d312008-02-19 13:16:41 +010010818/* bind Beep switches of both NID 0x0f and 0x10 */
10819static struct hda_bind_ctls alc268_bind_beep_sw = {
10820 .ops = &snd_hda_bind_sw,
10821 .values = {
10822 HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT),
10823 HDA_COMPOSE_AMP_VAL(0x10, 3, 1, HDA_INPUT),
10824 0
10825 },
10826};
10827
10828static struct snd_kcontrol_new alc268_beep_mixer[] = {
10829 HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT),
10830 HDA_BIND_SW("Beep Playback Switch", &alc268_bind_beep_sw),
10831 { }
10832};
10833
Kailang Yangd1a991a2007-08-15 16:21:59 +020010834static struct hda_verb alc268_eapd_verbs[] = {
10835 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
10836 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
10837 { }
10838};
10839
Takashi Iwaid2738092007-08-16 14:59:45 +020010840/* Toshiba specific */
10841#define alc268_toshiba_automute alc262_hippo_automute
10842
10843static struct hda_verb alc268_toshiba_verbs[] = {
10844 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
10845 { } /* end */
10846};
10847
Kailang Yang8ef355d2008-08-26 13:10:22 +020010848static struct hda_input_mux alc268_acer_lc_capture_source = {
10849 .num_items = 2,
10850 .items = {
10851 { "i-Mic", 0x6 },
10852 { "E-Mic", 0x0 },
10853 },
10854};
10855
Takashi Iwaid2738092007-08-16 14:59:45 +020010856/* Acer specific */
Takashi Iwai889c4392007-08-23 18:56:52 +020010857/* bind volumes of both NID 0x02 and 0x03 */
Takashi Iwai6bc96852007-08-17 09:02:12 +020010858static struct hda_bind_ctls alc268_acer_bind_master_vol = {
10859 .ops = &snd_hda_bind_vol,
10860 .values = {
10861 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
10862 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
10863 0
10864 },
10865};
10866
Takashi Iwai889c4392007-08-23 18:56:52 +020010867/* mute/unmute internal speaker according to the hp jack and mute state */
10868static void alc268_acer_automute(struct hda_codec *codec, int force)
10869{
10870 struct alc_spec *spec = codec->spec;
10871 unsigned int mute;
10872
10873 if (force || !spec->sense_updated) {
10874 unsigned int present;
10875 present = snd_hda_codec_read(codec, 0x14, 0,
10876 AC_VERB_GET_PIN_SENSE, 0);
10877 spec->jack_present = (present & 0x80000000) != 0;
10878 spec->sense_updated = 1;
10879 }
10880 if (spec->jack_present)
10881 mute = HDA_AMP_MUTE; /* mute internal speaker */
10882 else /* unmute internal speaker if necessary */
10883 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
10884 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
10885 HDA_AMP_MUTE, mute);
10886}
10887
10888
10889/* bind hp and internal speaker mute (with plug check) */
10890static int alc268_acer_master_sw_put(struct snd_kcontrol *kcontrol,
10891 struct snd_ctl_elem_value *ucontrol)
10892{
10893 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
10894 long *valp = ucontrol->value.integer.value;
10895 int change;
10896
10897 change = snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0,
10898 HDA_AMP_MUTE,
10899 valp[0] ? 0 : HDA_AMP_MUTE);
10900 change |= snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0,
10901 HDA_AMP_MUTE,
10902 valp[1] ? 0 : HDA_AMP_MUTE);
10903 if (change)
10904 alc268_acer_automute(codec, 0);
10905 return change;
10906}
Takashi Iwaid2738092007-08-16 14:59:45 +020010907
Kailang Yang8ef355d2008-08-26 13:10:22 +020010908static struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = {
10909 /* output mixer control */
10910 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
10911 {
10912 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10913 .name = "Master Playback Switch",
10914 .info = snd_hda_mixer_amp_switch_info,
10915 .get = snd_hda_mixer_amp_switch_get,
10916 .put = alc268_acer_master_sw_put,
10917 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
10918 },
10919 HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x18, 0, HDA_INPUT),
10920 { }
10921};
10922
Takashi Iwaid2738092007-08-16 14:59:45 +020010923static struct snd_kcontrol_new alc268_acer_mixer[] = {
10924 /* output mixer control */
10925 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
10926 {
10927 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10928 .name = "Master Playback Switch",
10929 .info = snd_hda_mixer_amp_switch_info,
10930 .get = snd_hda_mixer_amp_switch_get,
10931 .put = alc268_acer_master_sw_put,
10932 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
10933 },
Takashi Iwai33bf17a2007-08-21 11:51:42 +020010934 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10935 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
10936 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
Takashi Iwaid2738092007-08-16 14:59:45 +020010937 { }
10938};
10939
Kailang Yang8ef355d2008-08-26 13:10:22 +020010940static struct hda_verb alc268_acer_aspire_one_verbs[] = {
10941 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
10942 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
10943 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
10944 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
10945 {0x23, AC_VERB_SET_CONNECT_SEL, 0x06},
10946 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, 0xa017},
10947 { }
10948};
10949
Takashi Iwaid2738092007-08-16 14:59:45 +020010950static struct hda_verb alc268_acer_verbs[] = {
Takashi Iwai0ccb5412008-03-06 16:58:35 +010010951 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* internal dmic? */
10952 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaid2738092007-08-16 14:59:45 +020010953 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
10954 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai0ccb5412008-03-06 16:58:35 +010010955 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
10956 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaid2738092007-08-16 14:59:45 +020010957 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
10958 { }
10959};
10960
10961/* unsolicited event for HP jack sensing */
10962static void alc268_toshiba_unsol_event(struct hda_codec *codec,
10963 unsigned int res)
10964{
Takashi Iwai889c4392007-08-23 18:56:52 +020010965 if ((res >> 26) != ALC880_HP_EVENT)
Takashi Iwaid2738092007-08-16 14:59:45 +020010966 return;
10967 alc268_toshiba_automute(codec);
10968}
10969
10970static void alc268_acer_unsol_event(struct hda_codec *codec,
10971 unsigned int res)
10972{
Takashi Iwai889c4392007-08-23 18:56:52 +020010973 if ((res >> 26) != ALC880_HP_EVENT)
Takashi Iwaid2738092007-08-16 14:59:45 +020010974 return;
10975 alc268_acer_automute(codec, 1);
10976}
10977
Takashi Iwai889c4392007-08-23 18:56:52 +020010978static void alc268_acer_init_hook(struct hda_codec *codec)
10979{
10980 alc268_acer_automute(codec, 1);
10981}
10982
Kailang Yang8ef355d2008-08-26 13:10:22 +020010983/* toggle speaker-output according to the hp-jack state */
10984static void alc268_aspire_one_speaker_automute(struct hda_codec *codec)
10985{
10986 unsigned int present;
10987 unsigned char bits;
10988
10989 present = snd_hda_codec_read(codec, 0x15, 0,
10990 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
10991 bits = present ? AMP_IN_MUTE(0) : 0;
10992 snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 0,
10993 AMP_IN_MUTE(0), bits);
10994 snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 1,
10995 AMP_IN_MUTE(0), bits);
10996}
10997
10998
10999static void alc268_acer_mic_automute(struct hda_codec *codec)
11000{
11001 unsigned int present;
11002
11003 present = snd_hda_codec_read(codec, 0x18, 0,
11004 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
11005 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_CONNECT_SEL,
11006 present ? 0x0 : 0x6);
11007}
11008
11009static void alc268_acer_lc_unsol_event(struct hda_codec *codec,
11010 unsigned int res)
11011{
11012 if ((res >> 26) == ALC880_HP_EVENT)
11013 alc268_aspire_one_speaker_automute(codec);
11014 if ((res >> 26) == ALC880_MIC_EVENT)
11015 alc268_acer_mic_automute(codec);
11016}
11017
11018static void alc268_acer_lc_init_hook(struct hda_codec *codec)
11019{
11020 alc268_aspire_one_speaker_automute(codec);
11021 alc268_acer_mic_automute(codec);
11022}
11023
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011024static struct snd_kcontrol_new alc268_dell_mixer[] = {
11025 /* output mixer control */
11026 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
11027 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11028 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
11029 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11030 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11031 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
11032 { }
11033};
11034
11035static struct hda_verb alc268_dell_verbs[] = {
11036 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11037 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11038 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
11039 { }
11040};
11041
11042/* mute/unmute internal speaker according to the hp jack and mute state */
11043static void alc268_dell_automute(struct hda_codec *codec)
11044{
11045 unsigned int present;
11046 unsigned int mute;
11047
11048 present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0);
11049 if (present & 0x80000000)
11050 mute = HDA_AMP_MUTE;
11051 else
11052 mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0);
11053 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
11054 HDA_AMP_MUTE, mute);
11055}
11056
11057static void alc268_dell_unsol_event(struct hda_codec *codec,
11058 unsigned int res)
11059{
11060 if ((res >> 26) != ALC880_HP_EVENT)
11061 return;
11062 alc268_dell_automute(codec);
11063}
11064
11065#define alc268_dell_init_hook alc268_dell_automute
11066
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020011067static struct snd_kcontrol_new alc267_quanta_il1_mixer[] = {
11068 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x2, 0x0, HDA_OUTPUT),
11069 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11070 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
11071 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11072 HDA_CODEC_VOLUME("Mic Capture Volume", 0x23, 0x0, HDA_OUTPUT),
11073 HDA_BIND_MUTE("Mic Capture Switch", 0x23, 2, HDA_OUTPUT),
11074 HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
11075 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
11076 { }
11077};
11078
11079static struct hda_verb alc267_quanta_il1_verbs[] = {
11080 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
11081 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
11082 { }
11083};
11084
11085static void alc267_quanta_il1_hp_automute(struct hda_codec *codec)
11086{
11087 unsigned int present;
11088
11089 present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0)
11090 & AC_PINSENSE_PRESENCE;
11091 snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
11092 present ? 0 : PIN_OUT);
11093}
11094
11095static void alc267_quanta_il1_mic_automute(struct hda_codec *codec)
11096{
11097 unsigned int present;
11098
11099 present = snd_hda_codec_read(codec, 0x18, 0,
11100 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
11101 snd_hda_codec_write(codec, 0x23, 0,
11102 AC_VERB_SET_CONNECT_SEL,
11103 present ? 0x00 : 0x01);
11104}
11105
11106static void alc267_quanta_il1_automute(struct hda_codec *codec)
11107{
11108 alc267_quanta_il1_hp_automute(codec);
11109 alc267_quanta_il1_mic_automute(codec);
11110}
11111
11112static void alc267_quanta_il1_unsol_event(struct hda_codec *codec,
11113 unsigned int res)
11114{
11115 switch (res >> 26) {
11116 case ALC880_HP_EVENT:
11117 alc267_quanta_il1_hp_automute(codec);
11118 break;
11119 case ALC880_MIC_EVENT:
11120 alc267_quanta_il1_mic_automute(codec);
11121 break;
11122 }
11123}
11124
Kailang Yanga361d842007-06-05 12:30:55 +020011125/*
11126 * generic initialization of ADC, input mixers and output mixers
11127 */
11128static struct hda_verb alc268_base_init_verbs[] = {
11129 /* Unmute DAC0-1 and set vol = 0 */
11130 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11131 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11132 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11133 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11134 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11135 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11136
11137 /*
11138 * Set up output mixers (0x0c - 0x0e)
11139 */
11140 /* set vol=0 to output mixers */
11141 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11142 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11143 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11144 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
11145
11146 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11147 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11148
11149 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
11150 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
11151 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
11152 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11153 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11154 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11155 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11156 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11157
11158 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11159 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11160 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11161 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11162 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11163 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11164 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011165
11166 /* set PCBEEP vol = 0, mute connections */
11167 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11168 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11169 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020011170
Jiang Zhea9b3aa82007-12-20 13:13:13 +010011171 /* Unmute Selector 23h,24h and set the default input to mic-in */
Kailang Yangea1fb292008-08-26 12:58:38 +020011172
Jiang Zhea9b3aa82007-12-20 13:13:13 +010011173 {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
11174 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11175 {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
11176 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020011177
Kailang Yanga361d842007-06-05 12:30:55 +020011178 { }
11179};
11180
11181/*
11182 * generic initialization of ADC, input mixers and output mixers
11183 */
11184static struct hda_verb alc268_volume_init_verbs[] = {
11185 /* set output DAC */
11186 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11187 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11188 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11189 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11190
11191 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11192 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11193 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11194 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11195 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11196
11197 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11198 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11199 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11200 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11201 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11202
11203 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11204 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11205 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11206 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11207
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011208 /* set PCBEEP vol = 0, mute connections */
11209 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11210 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11211 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020011212
11213 { }
11214};
11215
11216#define alc268_mux_enum_info alc_mux_enum_info
11217#define alc268_mux_enum_get alc_mux_enum_get
Takashi Iwaie1406342008-02-11 18:32:32 +010011218#define alc268_mux_enum_put alc_mux_enum_put
Kailang Yanga361d842007-06-05 12:30:55 +020011219
11220static struct snd_kcontrol_new alc268_capture_alt_mixer[] = {
11221 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
11222 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
11223 {
11224 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11225 /* The multiple "Capture Source" controls confuse alsamixer
11226 * So call somewhat different..
Kailang Yanga361d842007-06-05 12:30:55 +020011227 */
11228 /* .name = "Capture Source", */
11229 .name = "Input Source",
11230 .count = 1,
11231 .info = alc268_mux_enum_info,
11232 .get = alc268_mux_enum_get,
11233 .put = alc268_mux_enum_put,
11234 },
11235 { } /* end */
11236};
11237
11238static struct snd_kcontrol_new alc268_capture_mixer[] = {
11239 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
11240 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
11241 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x24, 0x0, HDA_OUTPUT),
11242 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x24, 0x0, HDA_OUTPUT),
11243 {
11244 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11245 /* The multiple "Capture Source" controls confuse alsamixer
11246 * So call somewhat different..
Kailang Yanga361d842007-06-05 12:30:55 +020011247 */
11248 /* .name = "Capture Source", */
11249 .name = "Input Source",
11250 .count = 2,
11251 .info = alc268_mux_enum_info,
11252 .get = alc268_mux_enum_get,
11253 .put = alc268_mux_enum_put,
11254 },
11255 { } /* end */
11256};
11257
11258static struct hda_input_mux alc268_capture_source = {
11259 .num_items = 4,
11260 .items = {
11261 { "Mic", 0x0 },
11262 { "Front Mic", 0x1 },
11263 { "Line", 0x2 },
11264 { "CD", 0x3 },
11265 },
11266};
11267
Takashi Iwai0ccb5412008-03-06 16:58:35 +010011268static struct hda_input_mux alc268_acer_capture_source = {
11269 .num_items = 3,
11270 .items = {
11271 { "Mic", 0x0 },
11272 { "Internal Mic", 0x6 },
11273 { "Line", 0x2 },
11274 },
11275};
11276
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010011277#ifdef CONFIG_SND_DEBUG
11278static struct snd_kcontrol_new alc268_test_mixer[] = {
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010011279 /* Volume widgets */
11280 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x02, 0x0, HDA_OUTPUT),
11281 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x03, 0x0, HDA_OUTPUT),
11282 HDA_BIND_MUTE_MONO("Mono sum Playback Switch", 0x0e, 1, 2, HDA_INPUT),
11283 HDA_BIND_MUTE("LINE-OUT sum Playback Switch", 0x0f, 2, HDA_INPUT),
11284 HDA_BIND_MUTE("HP-OUT sum Playback Switch", 0x10, 2, HDA_INPUT),
11285 HDA_BIND_MUTE("LINE-OUT Playback Switch", 0x14, 2, HDA_OUTPUT),
11286 HDA_BIND_MUTE("HP-OUT Playback Switch", 0x15, 2, HDA_OUTPUT),
11287 HDA_BIND_MUTE("Mono Playback Switch", 0x16, 2, HDA_OUTPUT),
11288 HDA_CODEC_VOLUME("MIC1 Capture Volume", 0x18, 0x0, HDA_INPUT),
11289 HDA_BIND_MUTE("MIC1 Capture Switch", 0x18, 2, HDA_OUTPUT),
11290 HDA_CODEC_VOLUME("MIC2 Capture Volume", 0x19, 0x0, HDA_INPUT),
11291 HDA_CODEC_VOLUME("LINE1 Capture Volume", 0x1a, 0x0, HDA_INPUT),
11292 HDA_BIND_MUTE("LINE1 Capture Switch", 0x1a, 2, HDA_OUTPUT),
Takashi Iwaif0747ee2008-01-15 11:41:41 +010011293 /* The below appears problematic on some hardwares */
11294 /*HDA_CODEC_VOLUME("PCBEEP Playback Volume", 0x1d, 0x0, HDA_INPUT),*/
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010011295 HDA_CODEC_VOLUME("PCM-IN1 Capture Volume", 0x23, 0x0, HDA_OUTPUT),
11296 HDA_BIND_MUTE("PCM-IN1 Capture Switch", 0x23, 2, HDA_OUTPUT),
11297 HDA_CODEC_VOLUME("PCM-IN2 Capture Volume", 0x24, 0x0, HDA_OUTPUT),
11298 HDA_BIND_MUTE("PCM-IN2 Capture Switch", 0x24, 2, HDA_OUTPUT),
11299
11300 /* Modes for retasking pin widgets */
11301 ALC_PIN_MODE("LINE-OUT pin mode", 0x14, ALC_PIN_DIR_INOUT),
11302 ALC_PIN_MODE("HP-OUT pin mode", 0x15, ALC_PIN_DIR_INOUT),
11303 ALC_PIN_MODE("MIC1 pin mode", 0x18, ALC_PIN_DIR_INOUT),
11304 ALC_PIN_MODE("LINE1 pin mode", 0x1a, ALC_PIN_DIR_INOUT),
11305
11306 /* Controls for GPIO pins, assuming they are configured as outputs */
11307 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
11308 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
11309 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
11310 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
11311
11312 /* Switches to allow the digital SPDIF output pin to be enabled.
11313 * The ALC268 does not have an SPDIF input.
11314 */
11315 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x06, 0x01),
11316
11317 /* A switch allowing EAPD to be enabled. Some laptops seem to use
11318 * this output to turn on an external amplifier.
11319 */
11320 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
11321 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
11322
11323 { } /* end */
11324};
11325#endif
11326
Kailang Yanga361d842007-06-05 12:30:55 +020011327/* create input playback/capture controls for the given pin */
11328static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
11329 const char *ctlname, int idx)
11330{
11331 char name[32];
11332 int err;
11333
11334 sprintf(name, "%s Playback Volume", ctlname);
11335 if (nid == 0x14) {
11336 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
11337 HDA_COMPOSE_AMP_VAL(0x02, 3, idx,
11338 HDA_OUTPUT));
11339 if (err < 0)
11340 return err;
11341 } else if (nid == 0x15) {
11342 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
11343 HDA_COMPOSE_AMP_VAL(0x03, 3, idx,
11344 HDA_OUTPUT));
11345 if (err < 0)
11346 return err;
11347 } else
11348 return -1;
11349 sprintf(name, "%s Playback Switch", ctlname);
11350 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
11351 HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
11352 if (err < 0)
11353 return err;
11354 return 0;
11355}
11356
11357/* add playback controls from the parsed DAC table */
11358static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
11359 const struct auto_pin_cfg *cfg)
11360{
11361 hda_nid_t nid;
11362 int err;
11363
11364 spec->multiout.num_dacs = 2; /* only use one dac */
11365 spec->multiout.dac_nids = spec->private_dac_nids;
11366 spec->multiout.dac_nids[0] = 2;
11367 spec->multiout.dac_nids[1] = 3;
11368
11369 nid = cfg->line_out_pins[0];
11370 if (nid)
Kailang Yangea1fb292008-08-26 12:58:38 +020011371 alc268_new_analog_output(spec, nid, "Front", 0);
Kailang Yanga361d842007-06-05 12:30:55 +020011372
11373 nid = cfg->speaker_pins[0];
11374 if (nid == 0x1d) {
11375 err = add_control(spec, ALC_CTL_WIDGET_VOL,
11376 "Speaker Playback Volume",
11377 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
11378 if (err < 0)
11379 return err;
11380 }
11381 nid = cfg->hp_pins[0];
11382 if (nid)
11383 alc268_new_analog_output(spec, nid, "Headphone", 0);
11384
11385 nid = cfg->line_out_pins[1] | cfg->line_out_pins[2];
11386 if (nid == 0x16) {
11387 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
11388 "Mono Playback Switch",
11389 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_INPUT));
11390 if (err < 0)
11391 return err;
11392 }
Kailang Yangea1fb292008-08-26 12:58:38 +020011393 return 0;
Kailang Yanga361d842007-06-05 12:30:55 +020011394}
11395
11396/* create playback/capture controls for input pins */
11397static int alc268_auto_create_analog_input_ctls(struct alc_spec *spec,
11398 const struct auto_pin_cfg *cfg)
11399{
11400 struct hda_input_mux *imux = &spec->private_imux;
11401 int i, idx1;
11402
11403 for (i = 0; i < AUTO_PIN_LAST; i++) {
11404 switch(cfg->input_pins[i]) {
11405 case 0x18:
11406 idx1 = 0; /* Mic 1 */
11407 break;
11408 case 0x19:
11409 idx1 = 1; /* Mic 2 */
11410 break;
11411 case 0x1a:
11412 idx1 = 2; /* Line In */
11413 break;
Kailang Yangea1fb292008-08-26 12:58:38 +020011414 case 0x1c:
Kailang Yanga361d842007-06-05 12:30:55 +020011415 idx1 = 3; /* CD */
11416 break;
Takashi Iwai7194cae2008-03-06 16:58:17 +010011417 case 0x12:
11418 case 0x13:
11419 idx1 = 6; /* digital mics */
11420 break;
Kailang Yanga361d842007-06-05 12:30:55 +020011421 default:
11422 continue;
11423 }
11424 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
11425 imux->items[imux->num_items].index = idx1;
Kailang Yangea1fb292008-08-26 12:58:38 +020011426 imux->num_items++;
Kailang Yanga361d842007-06-05 12:30:55 +020011427 }
11428 return 0;
11429}
11430
11431static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec)
11432{
11433 struct alc_spec *spec = codec->spec;
11434 hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
11435 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
11436 hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
11437 unsigned int dac_vol1, dac_vol2;
11438
11439 if (speaker_nid) {
11440 snd_hda_codec_write(codec, speaker_nid, 0,
11441 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
11442 snd_hda_codec_write(codec, 0x0f, 0,
11443 AC_VERB_SET_AMP_GAIN_MUTE,
11444 AMP_IN_UNMUTE(1));
11445 snd_hda_codec_write(codec, 0x10, 0,
11446 AC_VERB_SET_AMP_GAIN_MUTE,
11447 AMP_IN_UNMUTE(1));
11448 } else {
11449 snd_hda_codec_write(codec, 0x0f, 0,
11450 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
11451 snd_hda_codec_write(codec, 0x10, 0,
11452 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
11453 }
11454
11455 dac_vol1 = dac_vol2 = 0xb000 | 0x40; /* set max volume */
Kailang Yangea1fb292008-08-26 12:58:38 +020011456 if (line_nid == 0x14)
Kailang Yanga361d842007-06-05 12:30:55 +020011457 dac_vol2 = AMP_OUT_ZERO;
11458 else if (line_nid == 0x15)
11459 dac_vol1 = AMP_OUT_ZERO;
Kailang Yangea1fb292008-08-26 12:58:38 +020011460 if (hp_nid == 0x14)
Kailang Yanga361d842007-06-05 12:30:55 +020011461 dac_vol2 = AMP_OUT_ZERO;
11462 else if (hp_nid == 0x15)
11463 dac_vol1 = AMP_OUT_ZERO;
11464 if (line_nid != 0x16 || hp_nid != 0x16 ||
11465 spec->autocfg.line_out_pins[1] != 0x16 ||
11466 spec->autocfg.line_out_pins[2] != 0x16)
11467 dac_vol1 = dac_vol2 = AMP_OUT_ZERO;
11468
11469 snd_hda_codec_write(codec, 0x02, 0,
11470 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol1);
11471 snd_hda_codec_write(codec, 0x03, 0,
11472 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol2);
11473}
11474
11475/* pcm configuration: identiacal with ALC880 */
11476#define alc268_pcm_analog_playback alc880_pcm_analog_playback
11477#define alc268_pcm_analog_capture alc880_pcm_analog_capture
Takashi Iwai63300792008-01-24 15:31:36 +010011478#define alc268_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
Kailang Yanga361d842007-06-05 12:30:55 +020011479#define alc268_pcm_digital_playback alc880_pcm_digital_playback
11480
11481/*
11482 * BIOS auto configuration
11483 */
11484static int alc268_parse_auto_config(struct hda_codec *codec)
11485{
11486 struct alc_spec *spec = codec->spec;
11487 int err;
11488 static hda_nid_t alc268_ignore[] = { 0 };
11489
11490 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
11491 alc268_ignore);
11492 if (err < 0)
11493 return err;
11494 if (!spec->autocfg.line_outs)
11495 return 0; /* can't find valid BIOS pin config */
11496
11497 err = alc268_auto_create_multi_out_ctls(spec, &spec->autocfg);
11498 if (err < 0)
11499 return err;
11500 err = alc268_auto_create_analog_input_ctls(spec, &spec->autocfg);
11501 if (err < 0)
11502 return err;
11503
11504 spec->multiout.max_channels = 2;
11505
11506 /* digital only support output */
11507 if (spec->autocfg.dig_out_pin)
11508 spec->multiout.dig_out_nid = ALC268_DIGOUT_NID;
11509
Takashi Iwai603c4012008-07-30 15:01:44 +020011510 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010011511 add_mixer(spec, spec->kctls.list);
Kailang Yanga361d842007-06-05 12:30:55 +020011512
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011513 if (spec->autocfg.speaker_pins[0] != 0x1d)
Takashi Iwaid88897e2008-10-31 15:01:37 +010011514 add_mixer(spec, alc268_beep_mixer);
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011515
Takashi Iwaid88897e2008-10-31 15:01:37 +010011516 add_verb(spec, alc268_volume_init_verbs);
Kailang Yanga361d842007-06-05 12:30:55 +020011517 spec->num_mux_defs = 1;
11518 spec->input_mux = &spec->private_imux;
11519
Takashi Iwai776e1842007-08-29 15:07:11 +020011520 err = alc_auto_add_mic_boost(codec);
11521 if (err < 0)
11522 return err;
11523
Takashi Iwaie044c392008-10-27 16:56:24 +010011524 store_pin_configs(codec);
Kailang Yanga361d842007-06-05 12:30:55 +020011525 return 1;
11526}
11527
11528#define alc268_auto_init_multi_out alc882_auto_init_multi_out
11529#define alc268_auto_init_hp_out alc882_auto_init_hp_out
11530#define alc268_auto_init_analog_input alc882_auto_init_analog_input
11531
11532/* init callback for auto-configuration model -- overriding the default init */
11533static void alc268_auto_init(struct hda_codec *codec)
11534{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010011535 struct alc_spec *spec = codec->spec;
Kailang Yanga361d842007-06-05 12:30:55 +020011536 alc268_auto_init_multi_out(codec);
11537 alc268_auto_init_hp_out(codec);
11538 alc268_auto_init_mono_speaker_out(codec);
11539 alc268_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010011540 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020011541 alc_inithook(codec);
Kailang Yanga361d842007-06-05 12:30:55 +020011542}
11543
11544/*
11545 * configuration and preset
11546 */
11547static const char *alc268_models[ALC268_MODEL_LAST] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020011548 [ALC267_QUANTA_IL1] = "quanta-il1",
Kailang Yanga361d842007-06-05 12:30:55 +020011549 [ALC268_3ST] = "3stack",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020011550 [ALC268_TOSHIBA] = "toshiba",
Takashi Iwaid2738092007-08-16 14:59:45 +020011551 [ALC268_ACER] = "acer",
Kailang Yang8ef355d2008-08-26 13:10:22 +020011552 [ALC268_ACER_ASPIRE_ONE] = "acer-aspire",
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011553 [ALC268_DELL] = "dell",
Mirco Tischlerf12462c2008-02-04 12:33:59 +010011554 [ALC268_ZEPTO] = "zepto",
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010011555#ifdef CONFIG_SND_DEBUG
11556 [ALC268_TEST] = "test",
11557#endif
Kailang Yanga361d842007-06-05 12:30:55 +020011558 [ALC268_AUTO] = "auto",
11559};
11560
11561static struct snd_pci_quirk alc268_cfg_tbl[] = {
Takashi Iwaia0b8f7d2008-04-22 19:39:49 +020011562 SND_PCI_QUIRK(0x1025, 0x011e, "Acer Aspire 5720z", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011563 SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER),
Andy Shevchenkodafc8352008-01-25 11:53:50 +010011564 SND_PCI_QUIRK(0x1025, 0x012e, "Acer Aspire 5310", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011565 SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER),
Andy Shevchenko29a52c22008-01-24 17:29:00 +010011566 SND_PCI_QUIRK(0x1025, 0x0136, "Acer Aspire 5315", ALC268_ACER),
Kailang Yang8ef355d2008-08-26 13:10:22 +020011567 SND_PCI_QUIRK(0x1025, 0x015b, "Acer Aspire One",
11568 ALC268_ACER_ASPIRE_ONE),
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011569 SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011570 SND_PCI_QUIRK(0x103c, 0x30cc, "TOSHIBA", ALC268_TOSHIBA),
Kailang Yanga361d842007-06-05 12:30:55 +020011571 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST),
Kailang Yangd1a991a2007-08-15 16:21:59 +020011572 SND_PCI_QUIRK(0x1179, 0xff10, "TOSHIBA A205", ALC268_TOSHIBA),
Takashi Iwai8e7f00f2007-09-07 10:58:58 +020011573 SND_PCI_QUIRK(0x1179, 0xff50, "TOSHIBA A305", ALC268_TOSHIBA),
Travis Place2346d0c2008-09-01 08:24:00 +020011574 SND_PCI_QUIRK(0x1179, 0xff64, "TOSHIBA L305", ALC268_TOSHIBA),
Tony Vroon378bd6a2008-06-04 12:08:30 +020011575 SND_PCI_QUIRK(0x14c0, 0x0025, "COMPAL IFL90/JFL-92", ALC268_TOSHIBA),
Takashi Iwaib875bf32007-09-06 15:00:27 +020011576 SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER),
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020011577 SND_PCI_QUIRK(0x152d, 0x0771, "Quanta IL1", ALC267_QUANTA_IL1),
Mirco Tischlerf12462c2008-02-04 12:33:59 +010011578 SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO),
Kailang Yanga361d842007-06-05 12:30:55 +020011579 {}
11580};
11581
11582static struct alc_config_preset alc268_presets[] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020011583 [ALC267_QUANTA_IL1] = {
11584 .mixers = { alc267_quanta_il1_mixer },
11585 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
11586 alc267_quanta_il1_verbs },
11587 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11588 .dac_nids = alc268_dac_nids,
11589 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
11590 .adc_nids = alc268_adc_nids_alt,
11591 .hp_nid = 0x03,
11592 .num_channel_mode = ARRAY_SIZE(alc268_modes),
11593 .channel_mode = alc268_modes,
11594 .input_mux = &alc268_capture_source,
11595 .unsol_event = alc267_quanta_il1_unsol_event,
11596 .init_hook = alc267_quanta_il1_automute,
11597 },
Kailang Yanga361d842007-06-05 12:30:55 +020011598 [ALC268_3ST] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011599 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
11600 alc268_beep_mixer },
Kailang Yanga361d842007-06-05 12:30:55 +020011601 .init_verbs = { alc268_base_init_verbs },
11602 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11603 .dac_nids = alc268_dac_nids,
11604 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
11605 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010011606 .capsrc_nids = alc268_capsrc_nids,
Kailang Yanga361d842007-06-05 12:30:55 +020011607 .hp_nid = 0x03,
11608 .dig_out_nid = ALC268_DIGOUT_NID,
11609 .num_channel_mode = ARRAY_SIZE(alc268_modes),
11610 .channel_mode = alc268_modes,
11611 .input_mux = &alc268_capture_source,
11612 },
Kailang Yangd1a991a2007-08-15 16:21:59 +020011613 [ALC268_TOSHIBA] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011614 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
11615 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020011616 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
11617 alc268_toshiba_verbs },
Kailang Yangd1a991a2007-08-15 16:21:59 +020011618 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11619 .dac_nids = alc268_dac_nids,
11620 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
11621 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010011622 .capsrc_nids = alc268_capsrc_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020011623 .hp_nid = 0x03,
11624 .num_channel_mode = ARRAY_SIZE(alc268_modes),
11625 .channel_mode = alc268_modes,
11626 .input_mux = &alc268_capture_source,
Takashi Iwaid2738092007-08-16 14:59:45 +020011627 .unsol_event = alc268_toshiba_unsol_event,
11628 .init_hook = alc268_toshiba_automute,
11629 },
11630 [ALC268_ACER] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011631 .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer,
11632 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020011633 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
11634 alc268_acer_verbs },
11635 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11636 .dac_nids = alc268_dac_nids,
11637 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
11638 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010011639 .capsrc_nids = alc268_capsrc_nids,
Takashi Iwaid2738092007-08-16 14:59:45 +020011640 .hp_nid = 0x02,
11641 .num_channel_mode = ARRAY_SIZE(alc268_modes),
11642 .channel_mode = alc268_modes,
Takashi Iwai0ccb5412008-03-06 16:58:35 +010011643 .input_mux = &alc268_acer_capture_source,
Takashi Iwaid2738092007-08-16 14:59:45 +020011644 .unsol_event = alc268_acer_unsol_event,
Takashi Iwai889c4392007-08-23 18:56:52 +020011645 .init_hook = alc268_acer_init_hook,
Kailang Yangd1a991a2007-08-15 16:21:59 +020011646 },
Kailang Yang8ef355d2008-08-26 13:10:22 +020011647 [ALC268_ACER_ASPIRE_ONE] = {
11648 .mixers = { alc268_acer_aspire_one_mixer,
11649 alc268_capture_alt_mixer },
11650 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
11651 alc268_acer_aspire_one_verbs },
11652 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11653 .dac_nids = alc268_dac_nids,
11654 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
11655 .adc_nids = alc268_adc_nids_alt,
11656 .capsrc_nids = alc268_capsrc_nids,
11657 .hp_nid = 0x03,
11658 .num_channel_mode = ARRAY_SIZE(alc268_modes),
11659 .channel_mode = alc268_modes,
11660 .input_mux = &alc268_acer_lc_capture_source,
11661 .unsol_event = alc268_acer_lc_unsol_event,
11662 .init_hook = alc268_acer_lc_init_hook,
11663 },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011664 [ALC268_DELL] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011665 .mixers = { alc268_dell_mixer, alc268_beep_mixer },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011666 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
11667 alc268_dell_verbs },
11668 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11669 .dac_nids = alc268_dac_nids,
11670 .hp_nid = 0x02,
11671 .num_channel_mode = ARRAY_SIZE(alc268_modes),
11672 .channel_mode = alc268_modes,
11673 .unsol_event = alc268_dell_unsol_event,
11674 .init_hook = alc268_dell_init_hook,
11675 .input_mux = &alc268_capture_source,
11676 },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010011677 [ALC268_ZEPTO] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011678 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
11679 alc268_beep_mixer },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010011680 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
11681 alc268_toshiba_verbs },
11682 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11683 .dac_nids = alc268_dac_nids,
11684 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
11685 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010011686 .capsrc_nids = alc268_capsrc_nids,
Mirco Tischlerf12462c2008-02-04 12:33:59 +010011687 .hp_nid = 0x03,
11688 .dig_out_nid = ALC268_DIGOUT_NID,
11689 .num_channel_mode = ARRAY_SIZE(alc268_modes),
11690 .channel_mode = alc268_modes,
11691 .input_mux = &alc268_capture_source,
11692 .unsol_event = alc268_toshiba_unsol_event,
11693 .init_hook = alc268_toshiba_automute
11694 },
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010011695#ifdef CONFIG_SND_DEBUG
11696 [ALC268_TEST] = {
11697 .mixers = { alc268_test_mixer, alc268_capture_mixer },
11698 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
11699 alc268_volume_init_verbs },
11700 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
11701 .dac_nids = alc268_dac_nids,
11702 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
11703 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010011704 .capsrc_nids = alc268_capsrc_nids,
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010011705 .hp_nid = 0x03,
11706 .dig_out_nid = ALC268_DIGOUT_NID,
11707 .num_channel_mode = ARRAY_SIZE(alc268_modes),
11708 .channel_mode = alc268_modes,
11709 .input_mux = &alc268_capture_source,
11710 },
11711#endif
Kailang Yanga361d842007-06-05 12:30:55 +020011712};
11713
11714static int patch_alc268(struct hda_codec *codec)
11715{
11716 struct alc_spec *spec;
11717 int board_config;
11718 int err;
11719
11720 spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
11721 if (spec == NULL)
11722 return -ENOMEM;
11723
11724 codec->spec = spec;
11725
11726 board_config = snd_hda_check_board_config(codec, ALC268_MODEL_LAST,
11727 alc268_models,
11728 alc268_cfg_tbl);
11729
11730 if (board_config < 0 || board_config >= ALC268_MODEL_LAST) {
11731 printk(KERN_INFO "hda_codec: Unknown model for ALC268, "
11732 "trying auto-probe from BIOS...\n");
11733 board_config = ALC268_AUTO;
11734 }
11735
11736 if (board_config == ALC268_AUTO) {
11737 /* automatic parse from the BIOS config */
11738 err = alc268_parse_auto_config(codec);
11739 if (err < 0) {
11740 alc_free(codec);
11741 return err;
11742 } else if (!err) {
11743 printk(KERN_INFO
11744 "hda_codec: Cannot set up configuration "
11745 "from BIOS. Using base mode...\n");
11746 board_config = ALC268_3ST;
11747 }
11748 }
11749
11750 if (board_config != ALC268_AUTO)
11751 setup_preset(spec, &alc268_presets[board_config]);
11752
Kailang Yang2f893282008-05-27 12:14:47 +020011753 if (codec->vendor_id == 0x10ec0267) {
11754 spec->stream_name_analog = "ALC267 Analog";
11755 spec->stream_name_digital = "ALC267 Digital";
11756 } else {
11757 spec->stream_name_analog = "ALC268 Analog";
11758 spec->stream_name_digital = "ALC268 Digital";
11759 }
11760
Kailang Yanga361d842007-06-05 12:30:55 +020011761 spec->stream_analog_playback = &alc268_pcm_analog_playback;
11762 spec->stream_analog_capture = &alc268_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +010011763 spec->stream_analog_alt_capture = &alc268_pcm_analog_alt_capture;
Kailang Yanga361d842007-06-05 12:30:55 +020011764
Kailang Yanga361d842007-06-05 12:30:55 +020011765 spec->stream_digital_playback = &alc268_pcm_digital_playback;
11766
Takashi Iwaiaef9d312008-02-19 13:16:41 +010011767 if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
11768 /* override the amp caps for beep generator */
11769 snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT,
11770 (0x0c << AC_AMPCAP_OFFSET_SHIFT) |
11771 (0x0c << AC_AMPCAP_NUM_STEPS_SHIFT) |
11772 (0x07 << AC_AMPCAP_STEP_SIZE_SHIFT) |
11773 (0 << AC_AMPCAP_MUTE_SHIFT));
11774
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011775 if (!spec->adc_nids && spec->input_mux) {
11776 /* check whether NID 0x07 is valid */
11777 unsigned int wcap = get_wcaps(codec, 0x07);
Takashi Iwai85860c02008-02-19 15:00:15 +010011778 int i;
Kailang Yanga361d842007-06-05 12:30:55 +020011779
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011780 /* get type */
11781 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
Takashi Iwai67ebcb02008-02-19 15:03:57 +010011782 if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011783 spec->adc_nids = alc268_adc_nids_alt;
11784 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt);
Takashi Iwaid88897e2008-10-31 15:01:37 +010011785 add_mixer(spec, alc268_capture_alt_mixer);
Takashi Iwai3866f0b2008-01-15 12:37:42 +010011786 } else {
11787 spec->adc_nids = alc268_adc_nids;
11788 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids);
Takashi Iwaid88897e2008-10-31 15:01:37 +010011789 add_mixer(spec, alc268_capture_mixer);
Kailang Yanga361d842007-06-05 12:30:55 +020011790 }
Takashi Iwaie1406342008-02-11 18:32:32 +010011791 spec->capsrc_nids = alc268_capsrc_nids;
Takashi Iwai85860c02008-02-19 15:00:15 +010011792 /* set default input source */
11793 for (i = 0; i < spec->num_adc_nids; i++)
11794 snd_hda_codec_write_cache(codec, alc268_capsrc_nids[i],
11795 0, AC_VERB_SET_CONNECT_SEL,
11796 spec->input_mux->items[0].index);
Kailang Yanga361d842007-06-05 12:30:55 +020011797 }
Takashi Iwai2134ea42008-01-10 16:53:55 +010011798
11799 spec->vmaster_nid = 0x02;
11800
Kailang Yanga361d842007-06-05 12:30:55 +020011801 codec->patch_ops = alc_patch_ops;
11802 if (board_config == ALC268_AUTO)
11803 spec->init_hook = alc268_auto_init;
Kailang Yangea1fb292008-08-26 12:58:38 +020011804
Kailang Yanga361d842007-06-05 12:30:55 +020011805 return 0;
11806}
11807
11808/*
Kailang Yangf6a92242007-12-13 16:52:54 +010011809 * ALC269 channel source setting (2 channel)
11810 */
11811#define ALC269_DIGOUT_NID ALC880_DIGOUT_NID
11812
11813#define alc269_dac_nids alc260_dac_nids
11814
11815static hda_nid_t alc269_adc_nids[1] = {
11816 /* ADC1 */
Kailang Yangf53281e2008-07-18 12:36:43 +020011817 0x08,
11818};
11819
Takashi Iwaie01bf502008-08-21 16:25:07 +020011820static hda_nid_t alc269_capsrc_nids[1] = {
11821 0x23,
11822};
11823
11824/* NOTE: ADC2 (0x07) is connected from a recording *MIXER* (0x24),
11825 * not a mux!
11826 */
11827
Kailang Yangf53281e2008-07-18 12:36:43 +020011828static struct hda_input_mux alc269_eeepc_dmic_capture_source = {
11829 .num_items = 2,
11830 .items = {
11831 { "i-Mic", 0x5 },
11832 { "e-Mic", 0x0 },
11833 },
11834};
11835
11836static struct hda_input_mux alc269_eeepc_amic_capture_source = {
11837 .num_items = 2,
11838 .items = {
11839 { "i-Mic", 0x1 },
11840 { "e-Mic", 0x0 },
11841 },
Kailang Yangf6a92242007-12-13 16:52:54 +010011842};
11843
11844#define alc269_modes alc260_modes
11845#define alc269_capture_source alc880_lg_lw_capture_source
11846
11847static struct snd_kcontrol_new alc269_base_mixer[] = {
11848 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
11849 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11850 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11851 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11852 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11853 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai2005af22008-08-20 18:38:26 +020011854 HDA_CODEC_VOLUME("Beep Playback Volume", 0x0b, 0x4, HDA_INPUT),
11855 HDA_CODEC_MUTE("Beep Playback Switch", 0x0b, 0x4, HDA_INPUT),
Kailang Yangf6a92242007-12-13 16:52:54 +010011856 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11857 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11858 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11859 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
11860 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11861 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
11862 { } /* end */
11863};
11864
Kailang Yang60db6b52008-08-26 13:13:00 +020011865static struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = {
11866 /* output mixer control */
11867 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
11868 {
11869 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11870 .name = "Master Playback Switch",
11871 .info = snd_hda_mixer_amp_switch_info,
11872 .get = snd_hda_mixer_amp_switch_get,
11873 .put = alc268_acer_master_sw_put,
11874 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
11875 },
11876 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11877 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11878 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11879 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11880 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11881 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
11882 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x04, HDA_INPUT),
11883 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x04, HDA_INPUT),
11884 { }
11885};
11886
Kailang Yangf53281e2008-07-18 12:36:43 +020011887/* bind volumes of both NID 0x0c and 0x0d */
11888static struct hda_bind_ctls alc269_epc_bind_vol = {
11889 .ops = &snd_hda_bind_vol,
11890 .values = {
11891 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
11892 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
11893 0
11894 },
11895};
11896
11897static struct snd_kcontrol_new alc269_eeepc_mixer[] = {
11898 HDA_CODEC_MUTE("iSpeaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11899 HDA_BIND_VOL("LineOut Playback Volume", &alc269_epc_bind_vol),
11900 HDA_CODEC_MUTE("LineOut Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11901 { } /* end */
11902};
11903
Kailang Yangf6a92242007-12-13 16:52:54 +010011904/* capture mixer elements */
11905static struct snd_kcontrol_new alc269_capture_mixer[] = {
Kailang Yangf53281e2008-07-18 12:36:43 +020011906 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
11907 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
Kailang Yangf6a92242007-12-13 16:52:54 +010011908 {
11909 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11910 /* The multiple "Capture Source" controls confuse alsamixer
11911 * So call somewhat different..
Kailang Yangf6a92242007-12-13 16:52:54 +010011912 */
11913 /* .name = "Capture Source", */
11914 .name = "Input Source",
11915 .count = 1,
11916 .info = alc_mux_enum_info,
11917 .get = alc_mux_enum_get,
11918 .put = alc_mux_enum_put,
11919 },
11920 { } /* end */
11921};
11922
Kailang Yangf53281e2008-07-18 12:36:43 +020011923/* capture mixer elements */
11924static struct snd_kcontrol_new alc269_epc_capture_mixer[] = {
11925 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
11926 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
11927 { } /* end */
11928};
11929
Takashi Iwai2005af22008-08-20 18:38:26 +020011930/* beep control */
11931static struct snd_kcontrol_new alc269_beep_mixer[] = {
11932 HDA_CODEC_VOLUME("Beep Playback Volume", 0x0b, 0x4, HDA_INPUT),
11933 HDA_CODEC_MUTE("Beep Playback Switch", 0x0b, 0x4, HDA_INPUT),
11934 { } /* end */
11935};
11936
Kailang Yang60db6b52008-08-26 13:13:00 +020011937static struct hda_verb alc269_quanta_fl1_verbs[] = {
11938 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
11939 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11940 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11941 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
11942 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
11943 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11944 { }
11945};
11946
11947/* toggle speaker-output according to the hp-jack state */
11948static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec)
11949{
11950 unsigned int present;
11951 unsigned char bits;
11952
11953 present = snd_hda_codec_read(codec, 0x15, 0,
11954 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
11955 bits = present ? AMP_IN_MUTE(0) : 0;
11956 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
11957 AMP_IN_MUTE(0), bits);
11958 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
11959 AMP_IN_MUTE(0), bits);
11960
11961 snd_hda_codec_write(codec, 0x20, 0,
11962 AC_VERB_SET_COEF_INDEX, 0x0c);
11963 snd_hda_codec_write(codec, 0x20, 0,
11964 AC_VERB_SET_PROC_COEF, 0x680);
11965
11966 snd_hda_codec_write(codec, 0x20, 0,
11967 AC_VERB_SET_COEF_INDEX, 0x0c);
11968 snd_hda_codec_write(codec, 0x20, 0,
11969 AC_VERB_SET_PROC_COEF, 0x480);
11970}
11971
11972static void alc269_quanta_fl1_mic_automute(struct hda_codec *codec)
11973{
11974 unsigned int present;
11975
11976 present = snd_hda_codec_read(codec, 0x18, 0,
11977 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
11978 snd_hda_codec_write(codec, 0x23, 0,
11979 AC_VERB_SET_CONNECT_SEL, present ? 0x0 : 0x1);
11980}
11981
11982static void alc269_quanta_fl1_unsol_event(struct hda_codec *codec,
11983 unsigned int res)
11984{
11985 if ((res >> 26) == ALC880_HP_EVENT)
11986 alc269_quanta_fl1_speaker_automute(codec);
11987 if ((res >> 26) == ALC880_MIC_EVENT)
11988 alc269_quanta_fl1_mic_automute(codec);
11989}
11990
11991static void alc269_quanta_fl1_init_hook(struct hda_codec *codec)
11992{
11993 alc269_quanta_fl1_speaker_automute(codec);
11994 alc269_quanta_fl1_mic_automute(codec);
11995}
11996
11997static struct hda_verb alc269_eeepc_dmic_init_verbs[] = {
11998 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
11999 {0x23, AC_VERB_SET_CONNECT_SEL, 0x05},
12000 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
12001 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
12002 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12003 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
12004 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
12005 {}
12006};
12007
12008static struct hda_verb alc269_eeepc_amic_init_verbs[] = {
12009 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
12010 {0x23, AC_VERB_SET_CONNECT_SEL, 0x01},
12011 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
12012 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x701b | (0x00 << 8))},
12013 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
12014 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
12015 {}
12016};
12017
12018/* toggle speaker-output according to the hp-jack state */
12019static void alc269_speaker_automute(struct hda_codec *codec)
12020{
12021 unsigned int present;
12022 unsigned char bits;
12023
12024 present = snd_hda_codec_read(codec, 0x15, 0,
12025 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
12026 bits = present ? AMP_IN_MUTE(0) : 0;
12027 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
12028 AMP_IN_MUTE(0), bits);
12029 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
12030 AMP_IN_MUTE(0), bits);
12031}
12032
12033static void alc269_eeepc_dmic_automute(struct hda_codec *codec)
12034{
12035 unsigned int present;
12036
12037 present = snd_hda_codec_read(codec, 0x18, 0,
12038 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
12039 snd_hda_codec_write(codec, 0x23, 0,
12040 AC_VERB_SET_CONNECT_SEL, (present ? 0 : 5));
12041}
12042
12043static void alc269_eeepc_amic_automute(struct hda_codec *codec)
12044{
12045 unsigned int present;
12046
12047 present = snd_hda_codec_read(codec, 0x18, 0,
12048 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
12049 snd_hda_codec_write(codec, 0x24, 0, AC_VERB_SET_AMP_GAIN_MUTE,
12050 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
12051 snd_hda_codec_write(codec, 0x24, 0, AC_VERB_SET_AMP_GAIN_MUTE,
12052 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
12053}
12054
12055/* unsolicited event for HP jack sensing */
12056static void alc269_eeepc_dmic_unsol_event(struct hda_codec *codec,
12057 unsigned int res)
12058{
12059 if ((res >> 26) == ALC880_HP_EVENT)
12060 alc269_speaker_automute(codec);
12061
12062 if ((res >> 26) == ALC880_MIC_EVENT)
12063 alc269_eeepc_dmic_automute(codec);
12064}
12065
12066static void alc269_eeepc_dmic_inithook(struct hda_codec *codec)
12067{
12068 alc269_speaker_automute(codec);
12069 alc269_eeepc_dmic_automute(codec);
12070}
12071
12072/* unsolicited event for HP jack sensing */
12073static void alc269_eeepc_amic_unsol_event(struct hda_codec *codec,
12074 unsigned int res)
12075{
12076 if ((res >> 26) == ALC880_HP_EVENT)
12077 alc269_speaker_automute(codec);
12078
12079 if ((res >> 26) == ALC880_MIC_EVENT)
12080 alc269_eeepc_amic_automute(codec);
12081}
12082
12083static void alc269_eeepc_amic_inithook(struct hda_codec *codec)
12084{
12085 alc269_speaker_automute(codec);
12086 alc269_eeepc_amic_automute(codec);
12087}
12088
Kailang Yangf6a92242007-12-13 16:52:54 +010012089/*
12090 * generic initialization of ADC, input mixers and output mixers
12091 */
12092static struct hda_verb alc269_init_verbs[] = {
12093 /*
12094 * Unmute ADC0 and set the default input to mic-in
12095 */
Kailang Yang60db6b52008-08-26 13:13:00 +020012096 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangf6a92242007-12-13 16:52:54 +010012097
12098 /* Mute input amps (PCBeep, Line In, Mic 1 & Mic 2) of the
12099 * analog-loopback mixer widget
12100 * Note: PASD motherboards uses the Line In 2 as the input for
12101 * front panel mic (mic 2)
12102 */
12103 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
12104 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12105 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12106 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12107 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12108 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
12109
12110 /*
12111 * Set up output mixers (0x0c - 0x0e)
12112 */
12113 /* set vol=0 to output mixers */
12114 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12115 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12116
12117 /* set up input amps for analog loopback */
12118 /* Amp Indices: DAC = 0, mixer = 1 */
12119 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12120 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12121 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12122 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12123 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12124 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12125
12126 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12127 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12128 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12129 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
12130 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
12131 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12132 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12133
12134 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12135 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12136 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12137 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12138 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12139 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12140 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12141
12142 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
12143 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
12144
12145 /* FIXME: use matrix-type input source selection */
12146 /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
12147 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yang60db6b52008-08-26 13:13:00 +020012148 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12149 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangf6a92242007-12-13 16:52:54 +010012150 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12151 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12152
12153 /* set EAPD */
12154 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
12155 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
12156 { }
12157};
12158
12159/* add playback controls from the parsed DAC table */
12160static int alc269_auto_create_multi_out_ctls(struct alc_spec *spec,
12161 const struct auto_pin_cfg *cfg)
12162{
12163 hda_nid_t nid;
12164 int err;
12165
12166 spec->multiout.num_dacs = 1; /* only use one dac */
12167 spec->multiout.dac_nids = spec->private_dac_nids;
12168 spec->multiout.dac_nids[0] = 2;
12169
12170 nid = cfg->line_out_pins[0];
12171 if (nid) {
12172 err = add_control(spec, ALC_CTL_WIDGET_VOL,
12173 "Front Playback Volume",
12174 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT));
12175 if (err < 0)
12176 return err;
12177 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
12178 "Front Playback Switch",
12179 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
12180 if (err < 0)
12181 return err;
12182 }
12183
12184 nid = cfg->speaker_pins[0];
12185 if (nid) {
12186 if (!cfg->line_out_pins[0]) {
12187 err = add_control(spec, ALC_CTL_WIDGET_VOL,
12188 "Speaker Playback Volume",
12189 HDA_COMPOSE_AMP_VAL(0x02, 3, 0,
12190 HDA_OUTPUT));
12191 if (err < 0)
12192 return err;
12193 }
12194 if (nid == 0x16) {
12195 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
12196 "Speaker Playback Switch",
12197 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
12198 HDA_OUTPUT));
12199 if (err < 0)
12200 return err;
12201 } else {
12202 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
12203 "Speaker Playback Switch",
12204 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
12205 HDA_OUTPUT));
12206 if (err < 0)
12207 return err;
12208 }
12209 }
12210 nid = cfg->hp_pins[0];
12211 if (nid) {
12212 /* spec->multiout.hp_nid = 2; */
12213 if (!cfg->line_out_pins[0] && !cfg->speaker_pins[0]) {
12214 err = add_control(spec, ALC_CTL_WIDGET_VOL,
12215 "Headphone Playback Volume",
12216 HDA_COMPOSE_AMP_VAL(0x02, 3, 0,
12217 HDA_OUTPUT));
12218 if (err < 0)
12219 return err;
12220 }
12221 if (nid == 0x16) {
12222 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
12223 "Headphone Playback Switch",
12224 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
12225 HDA_OUTPUT));
12226 if (err < 0)
12227 return err;
12228 } else {
12229 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
12230 "Headphone Playback Switch",
12231 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
12232 HDA_OUTPUT));
12233 if (err < 0)
12234 return err;
12235 }
12236 }
12237 return 0;
12238}
12239
Takashi Iwaiee956e02008-10-31 17:16:31 +010012240static int alc269_auto_create_analog_input_ctls(struct alc_spec *spec,
12241 const struct auto_pin_cfg *cfg)
12242{
12243 int err;
12244
12245 err = alc880_auto_create_analog_input_ctls(spec, cfg);
12246 if (err < 0)
12247 return err;
12248 /* digital-mic input pin is excluded in alc880_auto_create..()
12249 * because it's under 0x18
12250 */
12251 if (cfg->input_pins[AUTO_PIN_MIC] == 0x12 ||
12252 cfg->input_pins[AUTO_PIN_FRONT_MIC] == 0x12) {
12253 struct hda_input_mux *imux = &spec->private_imux;
12254 imux->items[imux->num_items].label = "Int Mic";
12255 imux->items[imux->num_items].index = 0x05;
12256 imux->num_items++;
12257 }
12258 return 0;
12259}
Kailang Yangf6a92242007-12-13 16:52:54 +010012260
12261#ifdef CONFIG_SND_HDA_POWER_SAVE
12262#define alc269_loopbacks alc880_loopbacks
12263#endif
12264
12265/* pcm configuration: identiacal with ALC880 */
12266#define alc269_pcm_analog_playback alc880_pcm_analog_playback
12267#define alc269_pcm_analog_capture alc880_pcm_analog_capture
12268#define alc269_pcm_digital_playback alc880_pcm_digital_playback
12269#define alc269_pcm_digital_capture alc880_pcm_digital_capture
12270
12271/*
12272 * BIOS auto configuration
12273 */
12274static int alc269_parse_auto_config(struct hda_codec *codec)
12275{
12276 struct alc_spec *spec = codec->spec;
Takashi Iwai2005af22008-08-20 18:38:26 +020012277 int i, err;
Kailang Yangf6a92242007-12-13 16:52:54 +010012278 static hda_nid_t alc269_ignore[] = { 0x1d, 0 };
12279
12280 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
12281 alc269_ignore);
12282 if (err < 0)
12283 return err;
12284
12285 err = alc269_auto_create_multi_out_ctls(spec, &spec->autocfg);
12286 if (err < 0)
12287 return err;
12288 err = alc269_auto_create_analog_input_ctls(spec, &spec->autocfg);
12289 if (err < 0)
12290 return err;
12291
12292 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
12293
12294 if (spec->autocfg.dig_out_pin)
12295 spec->multiout.dig_out_nid = ALC269_DIGOUT_NID;
12296
Takashi Iwai603c4012008-07-30 15:01:44 +020012297 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010012298 add_mixer(spec, spec->kctls.list);
Kailang Yangf6a92242007-12-13 16:52:54 +010012299
Takashi Iwai2005af22008-08-20 18:38:26 +020012300 /* create a beep mixer control if the pin 0x1d isn't assigned */
12301 for (i = 0; i < ARRAY_SIZE(spec->autocfg.input_pins); i++)
12302 if (spec->autocfg.input_pins[i] == 0x1d)
12303 break;
12304 if (i >= ARRAY_SIZE(spec->autocfg.input_pins))
Takashi Iwaid88897e2008-10-31 15:01:37 +010012305 add_mixer(spec, alc269_beep_mixer);
Takashi Iwai2005af22008-08-20 18:38:26 +020012306
Takashi Iwaid88897e2008-10-31 15:01:37 +010012307 add_verb(spec, alc269_init_verbs);
Kailang Yangf6a92242007-12-13 16:52:54 +010012308 spec->num_mux_defs = 1;
12309 spec->input_mux = &spec->private_imux;
Takashi Iwaie01bf502008-08-21 16:25:07 +020012310 /* set default input source */
12311 snd_hda_codec_write_cache(codec, alc269_capsrc_nids[0],
12312 0, AC_VERB_SET_CONNECT_SEL,
12313 spec->input_mux->items[0].index);
Kailang Yangf6a92242007-12-13 16:52:54 +010012314
12315 err = alc_auto_add_mic_boost(codec);
12316 if (err < 0)
12317 return err;
12318
Takashi Iwaid88897e2008-10-31 15:01:37 +010012319 add_mixer(spec, alc269_capture_mixer);
Kailang Yangf53281e2008-07-18 12:36:43 +020012320
Takashi Iwaie044c392008-10-27 16:56:24 +010012321 store_pin_configs(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010012322 return 1;
12323}
12324
12325#define alc269_auto_init_multi_out alc882_auto_init_multi_out
12326#define alc269_auto_init_hp_out alc882_auto_init_hp_out
12327#define alc269_auto_init_analog_input alc882_auto_init_analog_input
12328
12329
12330/* init callback for auto-configuration model -- overriding the default init */
12331static void alc269_auto_init(struct hda_codec *codec)
12332{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012333 struct alc_spec *spec = codec->spec;
Kailang Yangf6a92242007-12-13 16:52:54 +010012334 alc269_auto_init_multi_out(codec);
12335 alc269_auto_init_hp_out(codec);
12336 alc269_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012337 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020012338 alc_inithook(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010012339}
12340
12341/*
12342 * configuration and preset
12343 */
12344static const char *alc269_models[ALC269_MODEL_LAST] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020012345 [ALC269_BASIC] = "basic",
Takashi Iwai2922c9a2008-08-27 18:12:42 +020012346 [ALC269_QUANTA_FL1] = "quanta",
12347 [ALC269_ASUS_EEEPC_P703] = "eeepc-p703",
12348 [ALC269_ASUS_EEEPC_P901] = "eeepc-p901"
Kailang Yangf6a92242007-12-13 16:52:54 +010012349};
12350
12351static struct snd_pci_quirk alc269_cfg_tbl[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020012352 SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_QUANTA_FL1),
Kailang Yangf53281e2008-07-18 12:36:43 +020012353 SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A",
12354 ALC269_ASUS_EEEPC_P703),
12355 SND_PCI_QUIRK(0x1043, 0x831a, "ASUS Eeepc P901",
12356 ALC269_ASUS_EEEPC_P901),
Kailang Yang60db6b52008-08-26 13:13:00 +020012357 SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101",
12358 ALC269_ASUS_EEEPC_P901),
Kailang Yangf6a92242007-12-13 16:52:54 +010012359 {}
12360};
12361
12362static struct alc_config_preset alc269_presets[] = {
12363 [ALC269_BASIC] = {
Kailang Yangf53281e2008-07-18 12:36:43 +020012364 .mixers = { alc269_base_mixer, alc269_capture_mixer },
Kailang Yangf6a92242007-12-13 16:52:54 +010012365 .init_verbs = { alc269_init_verbs },
12366 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
12367 .dac_nids = alc269_dac_nids,
12368 .hp_nid = 0x03,
12369 .num_channel_mode = ARRAY_SIZE(alc269_modes),
12370 .channel_mode = alc269_modes,
12371 .input_mux = &alc269_capture_source,
12372 },
Kailang Yang60db6b52008-08-26 13:13:00 +020012373 [ALC269_QUANTA_FL1] = {
12374 .mixers = { alc269_quanta_fl1_mixer },
12375 .init_verbs = { alc269_init_verbs, alc269_quanta_fl1_verbs },
12376 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
12377 .dac_nids = alc269_dac_nids,
12378 .hp_nid = 0x03,
12379 .num_channel_mode = ARRAY_SIZE(alc269_modes),
12380 .channel_mode = alc269_modes,
12381 .input_mux = &alc269_capture_source,
12382 .unsol_event = alc269_quanta_fl1_unsol_event,
12383 .init_hook = alc269_quanta_fl1_init_hook,
12384 },
Kailang Yangf53281e2008-07-18 12:36:43 +020012385 [ALC269_ASUS_EEEPC_P703] = {
12386 .mixers = { alc269_eeepc_mixer, alc269_epc_capture_mixer },
12387 .init_verbs = { alc269_init_verbs,
12388 alc269_eeepc_amic_init_verbs },
12389 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
12390 .dac_nids = alc269_dac_nids,
12391 .hp_nid = 0x03,
12392 .num_channel_mode = ARRAY_SIZE(alc269_modes),
12393 .channel_mode = alc269_modes,
12394 .input_mux = &alc269_eeepc_amic_capture_source,
12395 .unsol_event = alc269_eeepc_amic_unsol_event,
12396 .init_hook = alc269_eeepc_amic_inithook,
12397 },
12398 [ALC269_ASUS_EEEPC_P901] = {
12399 .mixers = { alc269_eeepc_mixer, alc269_epc_capture_mixer},
12400 .init_verbs = { alc269_init_verbs,
12401 alc269_eeepc_dmic_init_verbs },
12402 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
12403 .dac_nids = alc269_dac_nids,
12404 .hp_nid = 0x03,
12405 .num_channel_mode = ARRAY_SIZE(alc269_modes),
12406 .channel_mode = alc269_modes,
12407 .input_mux = &alc269_eeepc_dmic_capture_source,
12408 .unsol_event = alc269_eeepc_dmic_unsol_event,
12409 .init_hook = alc269_eeepc_dmic_inithook,
12410 },
Kailang Yangf6a92242007-12-13 16:52:54 +010012411};
12412
12413static int patch_alc269(struct hda_codec *codec)
12414{
12415 struct alc_spec *spec;
12416 int board_config;
12417 int err;
12418
12419 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
12420 if (spec == NULL)
12421 return -ENOMEM;
12422
12423 codec->spec = spec;
12424
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020012425 alc_fix_pll_init(codec, 0x20, 0x04, 15);
12426
Kailang Yangf6a92242007-12-13 16:52:54 +010012427 board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST,
12428 alc269_models,
12429 alc269_cfg_tbl);
12430
12431 if (board_config < 0) {
12432 printk(KERN_INFO "hda_codec: Unknown model for ALC269, "
12433 "trying auto-probe from BIOS...\n");
12434 board_config = ALC269_AUTO;
12435 }
12436
12437 if (board_config == ALC269_AUTO) {
12438 /* automatic parse from the BIOS config */
12439 err = alc269_parse_auto_config(codec);
12440 if (err < 0) {
12441 alc_free(codec);
12442 return err;
12443 } else if (!err) {
12444 printk(KERN_INFO
12445 "hda_codec: Cannot set up configuration "
12446 "from BIOS. Using base mode...\n");
12447 board_config = ALC269_BASIC;
12448 }
12449 }
12450
12451 if (board_config != ALC269_AUTO)
12452 setup_preset(spec, &alc269_presets[board_config]);
12453
12454 spec->stream_name_analog = "ALC269 Analog";
12455 spec->stream_analog_playback = &alc269_pcm_analog_playback;
12456 spec->stream_analog_capture = &alc269_pcm_analog_capture;
12457
12458 spec->stream_name_digital = "ALC269 Digital";
12459 spec->stream_digital_playback = &alc269_pcm_digital_playback;
12460 spec->stream_digital_capture = &alc269_pcm_digital_capture;
12461
12462 spec->adc_nids = alc269_adc_nids;
12463 spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids);
Takashi Iwaie01bf502008-08-21 16:25:07 +020012464 spec->capsrc_nids = alc269_capsrc_nids;
Kailang Yangf6a92242007-12-13 16:52:54 +010012465
12466 codec->patch_ops = alc_patch_ops;
12467 if (board_config == ALC269_AUTO)
12468 spec->init_hook = alc269_auto_init;
12469#ifdef CONFIG_SND_HDA_POWER_SAVE
12470 if (!spec->loopback.amplist)
12471 spec->loopback.amplist = alc269_loopbacks;
12472#endif
12473
12474 return 0;
12475}
12476
12477/*
Kailang Yangdf694da2005-12-05 19:42:22 +010012478 * ALC861 channel source setting (2/6 channel selection for 3-stack)
12479 */
12480
12481/*
12482 * set the path ways for 2 channel output
12483 * need to set the codec line out and mic 1 pin widgets to inputs
12484 */
12485static struct hda_verb alc861_threestack_ch2_init[] = {
12486 /* set pin widget 1Ah (line in) for input */
12487 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012488 /* set pin widget 18h (mic1/2) for input, for mic also enable
12489 * the vref
12490 */
Kailang Yangdf694da2005-12-05 19:42:22 +010012491 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12492
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012493 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
12494#if 0
12495 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
12496 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
12497#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010012498 { } /* end */
12499};
12500/*
12501 * 6ch mode
12502 * need to set the codec line out and mic 1 pin widgets to outputs
12503 */
12504static struct hda_verb alc861_threestack_ch6_init[] = {
12505 /* set pin widget 1Ah (line in) for output (Back Surround)*/
12506 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12507 /* set pin widget 18h (mic1) for output (CLFE)*/
12508 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12509
12510 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012511 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010012512
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012513 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
12514#if 0
12515 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
12516 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
12517#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010012518 { } /* end */
12519};
12520
12521static struct hda_channel_mode alc861_threestack_modes[2] = {
12522 { 2, alc861_threestack_ch2_init },
12523 { 6, alc861_threestack_ch6_init },
12524};
Takashi Iwai22309c32006-08-09 16:57:28 +020012525/* Set mic1 as input and unmute the mixer */
12526static struct hda_verb alc861_uniwill_m31_ch2_init[] = {
12527 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12528 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
12529 { } /* end */
12530};
12531/* Set mic1 as output and mute mixer */
12532static struct hda_verb alc861_uniwill_m31_ch4_init[] = {
12533 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12534 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
12535 { } /* end */
12536};
12537
12538static struct hda_channel_mode alc861_uniwill_m31_modes[2] = {
12539 { 2, alc861_uniwill_m31_ch2_init },
12540 { 4, alc861_uniwill_m31_ch4_init },
12541};
Kailang Yangdf694da2005-12-05 19:42:22 +010012542
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012543/* Set mic1 and line-in as input and unmute the mixer */
12544static struct hda_verb alc861_asus_ch2_init[] = {
12545 /* set pin widget 1Ah (line in) for input */
12546 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012547 /* set pin widget 18h (mic1/2) for input, for mic also enable
12548 * the vref
12549 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012550 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12551
12552 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
12553#if 0
12554 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
12555 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
12556#endif
12557 { } /* end */
12558};
12559/* Set mic1 nad line-in as output and mute mixer */
12560static struct hda_verb alc861_asus_ch6_init[] = {
12561 /* set pin widget 1Ah (line in) for output (Back Surround)*/
12562 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12563 /* { 0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
12564 /* set pin widget 18h (mic1) for output (CLFE)*/
12565 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12566 /* { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
12567 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
12568 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
12569
12570 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
12571#if 0
12572 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
12573 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
12574#endif
12575 { } /* end */
12576};
12577
12578static struct hda_channel_mode alc861_asus_modes[2] = {
12579 { 2, alc861_asus_ch2_init },
12580 { 6, alc861_asus_ch6_init },
12581};
12582
Kailang Yangdf694da2005-12-05 19:42:22 +010012583/* patch-ALC861 */
12584
12585static struct snd_kcontrol_new alc861_base_mixer[] = {
12586 /* output mixer control */
12587 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
12588 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
12589 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
12590 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
12591 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
12592
12593 /*Input mixer control */
12594 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
12595 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
12596 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
12597 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
12598 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
12599 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
12600 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
12601 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
12602 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
12603 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012604
Kailang Yangdf694da2005-12-05 19:42:22 +010012605 /* Capture mixer control */
12606 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
12607 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
12608 {
12609 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12610 .name = "Capture Source",
12611 .count = 1,
12612 .info = alc_mux_enum_info,
12613 .get = alc_mux_enum_get,
12614 .put = alc_mux_enum_put,
12615 },
12616 { } /* end */
12617};
12618
12619static struct snd_kcontrol_new alc861_3ST_mixer[] = {
12620 /* output mixer control */
12621 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
12622 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
12623 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
12624 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
12625 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
12626
12627 /* Input mixer control */
12628 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
12629 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
12630 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
12631 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
12632 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
12633 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
12634 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
12635 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
12636 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
12637 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012638
Kailang Yangdf694da2005-12-05 19:42:22 +010012639 /* Capture mixer control */
12640 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
12641 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
12642 {
12643 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12644 .name = "Capture Source",
12645 .count = 1,
12646 .info = alc_mux_enum_info,
12647 .get = alc_mux_enum_get,
12648 .put = alc_mux_enum_put,
12649 },
12650 {
12651 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12652 .name = "Channel Mode",
12653 .info = alc_ch_mode_info,
12654 .get = alc_ch_mode_get,
12655 .put = alc_ch_mode_put,
12656 .private_value = ARRAY_SIZE(alc861_threestack_modes),
12657 },
12658 { } /* end */
Tobin Davisa53d1ae2006-10-17 12:00:28 +020012659};
12660
Takashi Iwaid1d985f2006-11-23 19:27:12 +010012661static struct snd_kcontrol_new alc861_toshiba_mixer[] = {
Tobin Davisa53d1ae2006-10-17 12:00:28 +020012662 /* output mixer control */
12663 HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT),
12664 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
12665 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
Kailang Yangea1fb292008-08-26 12:58:38 +020012666
Tobin Davisa53d1ae2006-10-17 12:00:28 +020012667 /*Capture mixer control */
12668 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
12669 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
12670 {
12671 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12672 .name = "Capture Source",
12673 .count = 1,
12674 .info = alc_mux_enum_info,
12675 .get = alc_mux_enum_get,
12676 .put = alc_mux_enum_put,
12677 },
12678
12679 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012680};
Tobin Davisa53d1ae2006-10-17 12:00:28 +020012681
Takashi Iwai22309c32006-08-09 16:57:28 +020012682static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = {
12683 /* output mixer control */
12684 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
12685 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
12686 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
12687 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
12688 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
12689
12690 /* Input mixer control */
12691 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
12692 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
12693 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
12694 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
12695 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
12696 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
12697 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
12698 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
12699 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
12700 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012701
Takashi Iwai22309c32006-08-09 16:57:28 +020012702 /* Capture mixer control */
12703 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
12704 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
12705 {
12706 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12707 .name = "Capture Source",
12708 .count = 1,
12709 .info = alc_mux_enum_info,
12710 .get = alc_mux_enum_get,
12711 .put = alc_mux_enum_put,
12712 },
12713 {
12714 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12715 .name = "Channel Mode",
12716 .info = alc_ch_mode_info,
12717 .get = alc_ch_mode_get,
12718 .put = alc_ch_mode_put,
12719 .private_value = ARRAY_SIZE(alc861_uniwill_m31_modes),
12720 },
12721 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012722};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012723
12724static struct snd_kcontrol_new alc861_asus_mixer[] = {
12725 /* output mixer control */
12726 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
12727 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
12728 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
12729 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
12730 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
12731
12732 /* Input mixer control */
12733 HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
12734 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT),
12735 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
12736 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
12737 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
12738 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
12739 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
12740 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
12741 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012742 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_OUTPUT),
12743
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012744 /* Capture mixer control */
12745 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
12746 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
12747 {
12748 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12749 .name = "Capture Source",
12750 .count = 1,
12751 .info = alc_mux_enum_info,
12752 .get = alc_mux_enum_get,
12753 .put = alc_mux_enum_put,
12754 },
12755 {
12756 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12757 .name = "Channel Mode",
12758 .info = alc_ch_mode_info,
12759 .get = alc_ch_mode_get,
12760 .put = alc_ch_mode_put,
12761 .private_value = ARRAY_SIZE(alc861_asus_modes),
12762 },
12763 { }
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010012764};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012765
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010012766/* additional mixer */
Takashi Iwaid1d985f2006-11-23 19:27:12 +010012767static struct snd_kcontrol_new alc861_asus_laptop_mixer[] = {
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010012768 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
12769 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
12770 HDA_CODEC_VOLUME("PC Beep Playback Volume", 0x23, 0x0, HDA_OUTPUT),
12771 HDA_CODEC_MUTE("PC Beep Playback Switch", 0x23, 0x0, HDA_OUTPUT),
12772 { }
12773};
12774
Kailang Yangdf694da2005-12-05 19:42:22 +010012775/*
12776 * generic initialization of ADC, input mixers and output mixers
12777 */
12778static struct hda_verb alc861_base_init_verbs[] = {
12779 /*
12780 * Unmute ADC0 and set the default input to mic-in
12781 */
12782 /* port-A for surround (rear panel) */
12783 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12784 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x00 },
12785 /* port-B for mic-in (rear panel) with vref */
12786 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12787 /* port-C for line-in (rear panel) */
12788 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
12789 /* port-D for Front */
12790 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12791 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
12792 /* port-E for HP out (front panel) */
12793 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
12794 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010012795 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010012796 /* port-F for mic-in (front panel) with vref */
12797 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12798 /* port-G for CLFE (rear panel) */
12799 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12800 { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x00 },
12801 /* port-H for side (rear panel) */
12802 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12803 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x00 },
12804 /* CD-in */
12805 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
12806 /* route front mic to ADC1*/
12807 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
12808 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020012809
Kailang Yangdf694da2005-12-05 19:42:22 +010012810 /* Unmute DAC0~3 & spdif out*/
12811 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12812 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12813 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12814 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12815 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020012816
Kailang Yangdf694da2005-12-05 19:42:22 +010012817 /* Unmute Mixer 14 (mic) 1c (Line in)*/
12818 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12819 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12820 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12821 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020012822
Kailang Yangdf694da2005-12-05 19:42:22 +010012823 /* Unmute Stereo Mixer 15 */
12824 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12825 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12826 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012827 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010012828
12829 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12830 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12831 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12832 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12833 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12834 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12835 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12836 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012837 /* hp used DAC 3 (Front) */
12838 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010012839 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
12840
12841 { }
12842};
12843
12844static struct hda_verb alc861_threestack_init_verbs[] = {
12845 /*
12846 * Unmute ADC0 and set the default input to mic-in
12847 */
12848 /* port-A for surround (rear panel) */
12849 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
12850 /* port-B for mic-in (rear panel) with vref */
12851 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12852 /* port-C for line-in (rear panel) */
12853 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
12854 /* port-D for Front */
12855 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12856 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
12857 /* port-E for HP out (front panel) */
12858 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
12859 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010012860 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010012861 /* port-F for mic-in (front panel) with vref */
12862 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12863 /* port-G for CLFE (rear panel) */
12864 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
12865 /* port-H for side (rear panel) */
12866 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
12867 /* CD-in */
12868 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
12869 /* route front mic to ADC1*/
12870 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
12871 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12872 /* Unmute DAC0~3 & spdif out*/
12873 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12874 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12875 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12876 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12877 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020012878
Kailang Yangdf694da2005-12-05 19:42:22 +010012879 /* Unmute Mixer 14 (mic) 1c (Line in)*/
12880 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12881 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12882 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12883 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020012884
Kailang Yangdf694da2005-12-05 19:42:22 +010012885 /* Unmute Stereo Mixer 15 */
12886 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12887 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12888 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012889 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010012890
12891 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12892 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12893 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12894 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12895 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12896 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12897 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12898 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012899 /* hp used DAC 3 (Front) */
12900 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010012901 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
12902 { }
12903};
Takashi Iwai22309c32006-08-09 16:57:28 +020012904
12905static struct hda_verb alc861_uniwill_m31_init_verbs[] = {
12906 /*
12907 * Unmute ADC0 and set the default input to mic-in
12908 */
12909 /* port-A for surround (rear panel) */
12910 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
12911 /* port-B for mic-in (rear panel) with vref */
12912 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12913 /* port-C for line-in (rear panel) */
12914 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
12915 /* port-D for Front */
12916 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12917 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
12918 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012919 /* this has to be set to VREF80 */
12920 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Takashi Iwai22309c32006-08-09 16:57:28 +020012921 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010012922 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai22309c32006-08-09 16:57:28 +020012923 /* port-F for mic-in (front panel) with vref */
12924 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12925 /* port-G for CLFE (rear panel) */
12926 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
12927 /* port-H for side (rear panel) */
12928 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
12929 /* CD-in */
12930 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
12931 /* route front mic to ADC1*/
12932 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
12933 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12934 /* Unmute DAC0~3 & spdif out*/
12935 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12936 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12937 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12938 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12939 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020012940
Takashi Iwai22309c32006-08-09 16:57:28 +020012941 /* Unmute Mixer 14 (mic) 1c (Line in)*/
12942 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12943 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12944 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12945 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020012946
Takashi Iwai22309c32006-08-09 16:57:28 +020012947 /* Unmute Stereo Mixer 15 */
12948 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12949 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12950 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012951 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Takashi Iwai22309c32006-08-09 16:57:28 +020012952
12953 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12954 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12955 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12956 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12957 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12958 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12959 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12960 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012961 /* hp used DAC 3 (Front) */
12962 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Takashi Iwai22309c32006-08-09 16:57:28 +020012963 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
12964 { }
12965};
12966
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012967static struct hda_verb alc861_asus_init_verbs[] = {
12968 /*
12969 * Unmute ADC0 and set the default input to mic-in
12970 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012971 /* port-A for surround (rear panel)
12972 * according to codec#0 this is the HP jack
12973 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012974 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* was 0x00 */
12975 /* route front PCM to HP */
12976 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x01 },
12977 /* port-B for mic-in (rear panel) with vref */
12978 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12979 /* port-C for line-in (rear panel) */
12980 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
12981 /* port-D for Front */
12982 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12983 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
12984 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012985 /* this has to be set to VREF80 */
12986 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012987 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010012988 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020012989 /* port-F for mic-in (front panel) with vref */
12990 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
12991 /* port-G for CLFE (rear panel) */
12992 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12993 /* port-H for side (rear panel) */
12994 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
12995 /* CD-in */
12996 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
12997 /* route front mic to ADC1*/
12998 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
12999 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13000 /* Unmute DAC0~3 & spdif out*/
13001 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13002 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13003 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13004 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13005 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13006 /* Unmute Mixer 14 (mic) 1c (Line in)*/
13007 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13008 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13009 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13010 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020013011
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013012 /* Unmute Stereo Mixer 15 */
13013 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13014 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13015 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013016 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013017
13018 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13019 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13020 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13021 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13022 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13023 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13024 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13025 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013026 /* hp used DAC 3 (Front) */
13027 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013028 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
13029 { }
13030};
13031
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010013032/* additional init verbs for ASUS laptops */
13033static struct hda_verb alc861_asus_laptop_init_verbs[] = {
13034 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x45 }, /* HP-out */
13035 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2) }, /* mute line-in */
13036 { }
13037};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013038
Kailang Yangdf694da2005-12-05 19:42:22 +010013039/*
13040 * generic initialization of ADC, input mixers and output mixers
13041 */
13042static struct hda_verb alc861_auto_init_verbs[] = {
13043 /*
13044 * Unmute ADC0 and set the default input to mic-in
13045 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013046 /* {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, */
Kailang Yangdf694da2005-12-05 19:42:22 +010013047 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020013048
Kailang Yangdf694da2005-12-05 19:42:22 +010013049 /* Unmute DAC0~3 & spdif out*/
13050 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13051 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13052 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13053 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13054 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020013055
Kailang Yangdf694da2005-12-05 19:42:22 +010013056 /* Unmute Mixer 14 (mic) 1c (Line in)*/
13057 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13058 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13059 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13060 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020013061
Kailang Yangdf694da2005-12-05 19:42:22 +010013062 /* Unmute Stereo Mixer 15 */
13063 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13064 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13065 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
13066 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c},
13067
13068 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13069 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13070 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13071 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13072 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13073 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13074 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13075 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13076
13077 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13078 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013079 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
13080 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010013081 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13082 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013083 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
13084 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010013085
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013086 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, /* set Mic 1 */
Kailang Yangdf694da2005-12-05 19:42:22 +010013087
13088 { }
13089};
13090
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013091static struct hda_verb alc861_toshiba_init_verbs[] = {
13092 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013093
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013094 { }
13095};
13096
13097/* toggle speaker-output according to the hp-jack state */
13098static void alc861_toshiba_automute(struct hda_codec *codec)
13099{
13100 unsigned int present;
13101
13102 present = snd_hda_codec_read(codec, 0x0f, 0,
13103 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020013104 snd_hda_codec_amp_stereo(codec, 0x16, HDA_INPUT, 0,
13105 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
13106 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_INPUT, 3,
13107 HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE);
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013108}
13109
13110static void alc861_toshiba_unsol_event(struct hda_codec *codec,
13111 unsigned int res)
13112{
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013113 if ((res >> 26) == ALC880_HP_EVENT)
13114 alc861_toshiba_automute(codec);
13115}
13116
Kailang Yangdf694da2005-12-05 19:42:22 +010013117/* pcm configuration: identiacal with ALC880 */
13118#define alc861_pcm_analog_playback alc880_pcm_analog_playback
13119#define alc861_pcm_analog_capture alc880_pcm_analog_capture
13120#define alc861_pcm_digital_playback alc880_pcm_digital_playback
13121#define alc861_pcm_digital_capture alc880_pcm_digital_capture
13122
13123
13124#define ALC861_DIGOUT_NID 0x07
13125
13126static struct hda_channel_mode alc861_8ch_modes[1] = {
13127 { 8, NULL }
13128};
13129
13130static hda_nid_t alc861_dac_nids[4] = {
13131 /* front, surround, clfe, side */
13132 0x03, 0x06, 0x05, 0x04
13133};
13134
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013135static hda_nid_t alc660_dac_nids[3] = {
13136 /* front, clfe, surround */
13137 0x03, 0x05, 0x06
13138};
13139
Kailang Yangdf694da2005-12-05 19:42:22 +010013140static hda_nid_t alc861_adc_nids[1] = {
13141 /* ADC0-2 */
13142 0x08,
13143};
13144
13145static struct hda_input_mux alc861_capture_source = {
13146 .num_items = 5,
13147 .items = {
13148 { "Mic", 0x0 },
13149 { "Front Mic", 0x3 },
13150 { "Line", 0x1 },
13151 { "CD", 0x4 },
13152 { "Mixer", 0x5 },
13153 },
13154};
13155
13156/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013157static int alc861_auto_fill_dac_nids(struct alc_spec *spec,
13158 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010013159{
13160 int i;
13161 hda_nid_t nid;
13162
13163 spec->multiout.dac_nids = spec->private_dac_nids;
13164 for (i = 0; i < cfg->line_outs; i++) {
13165 nid = cfg->line_out_pins[i];
13166 if (nid) {
13167 if (i >= ARRAY_SIZE(alc861_dac_nids))
13168 continue;
13169 spec->multiout.dac_nids[i] = alc861_dac_nids[i];
13170 }
13171 }
13172 spec->multiout.num_dacs = cfg->line_outs;
13173 return 0;
13174}
13175
13176/* add playback controls from the parsed DAC table */
13177static int alc861_auto_create_multi_out_ctls(struct alc_spec *spec,
13178 const struct auto_pin_cfg *cfg)
13179{
13180 char name[32];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013181 static const char *chname[4] = {
13182 "Front", "Surround", NULL /*CLFE*/, "Side"
13183 };
Kailang Yangdf694da2005-12-05 19:42:22 +010013184 hda_nid_t nid;
13185 int i, idx, err;
13186
13187 for (i = 0; i < cfg->line_outs; i++) {
13188 nid = spec->multiout.dac_nids[i];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013189 if (!nid)
Kailang Yangdf694da2005-12-05 19:42:22 +010013190 continue;
13191 if (nid == 0x05) {
13192 /* Center/LFE */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013193 err = add_control(spec, ALC_CTL_BIND_MUTE,
13194 "Center Playback Switch",
13195 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
13196 HDA_OUTPUT));
13197 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010013198 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013199 err = add_control(spec, ALC_CTL_BIND_MUTE,
13200 "LFE Playback Switch",
13201 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
13202 HDA_OUTPUT));
13203 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010013204 return err;
13205 } else {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013206 for (idx = 0; idx < ARRAY_SIZE(alc861_dac_nids) - 1;
13207 idx++)
Kailang Yangdf694da2005-12-05 19:42:22 +010013208 if (nid == alc861_dac_nids[idx])
13209 break;
13210 sprintf(name, "%s Playback Switch", chname[idx]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013211 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
13212 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
13213 HDA_OUTPUT));
13214 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010013215 return err;
13216 }
13217 }
13218 return 0;
13219}
13220
13221static int alc861_auto_create_hp_ctls(struct alc_spec *spec, hda_nid_t pin)
13222{
13223 int err;
13224 hda_nid_t nid;
13225
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013226 if (!pin)
Kailang Yangdf694da2005-12-05 19:42:22 +010013227 return 0;
13228
13229 if ((pin >= 0x0b && pin <= 0x10) || pin == 0x1f || pin == 0x20) {
13230 nid = 0x03;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013231 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
13232 "Headphone Playback Switch",
13233 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
13234 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010013235 return err;
13236 spec->multiout.hp_nid = nid;
13237 }
13238 return 0;
13239}
13240
13241/* create playback/capture controls for input pins */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013242static int alc861_auto_create_analog_input_ctls(struct alc_spec *spec,
13243 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010013244{
Kailang Yangdf694da2005-12-05 19:42:22 +010013245 struct hda_input_mux *imux = &spec->private_imux;
13246 int i, err, idx, idx1;
13247
13248 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013249 switch (cfg->input_pins[i]) {
Kailang Yangdf694da2005-12-05 19:42:22 +010013250 case 0x0c:
13251 idx1 = 1;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013252 idx = 2; /* Line In */
Kailang Yangdf694da2005-12-05 19:42:22 +010013253 break;
13254 case 0x0f:
13255 idx1 = 2;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013256 idx = 2; /* Line In */
Kailang Yangdf694da2005-12-05 19:42:22 +010013257 break;
13258 case 0x0d:
13259 idx1 = 0;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013260 idx = 1; /* Mic In */
Kailang Yangdf694da2005-12-05 19:42:22 +010013261 break;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013262 case 0x10:
Kailang Yangdf694da2005-12-05 19:42:22 +010013263 idx1 = 3;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013264 idx = 1; /* Mic In */
Kailang Yangdf694da2005-12-05 19:42:22 +010013265 break;
13266 case 0x11:
13267 idx1 = 4;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013268 idx = 0; /* CD */
Kailang Yangdf694da2005-12-05 19:42:22 +010013269 break;
13270 default:
13271 continue;
13272 }
13273
Takashi Iwai4a471b72005-12-07 13:56:29 +010013274 err = new_analog_input(spec, cfg->input_pins[i],
13275 auto_pin_cfg_labels[i], idx, 0x15);
Kailang Yangdf694da2005-12-05 19:42:22 +010013276 if (err < 0)
13277 return err;
13278
Takashi Iwai4a471b72005-12-07 13:56:29 +010013279 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
Kailang Yangdf694da2005-12-05 19:42:22 +010013280 imux->items[imux->num_items].index = idx1;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013281 imux->num_items++;
Kailang Yangdf694da2005-12-05 19:42:22 +010013282 }
13283 return 0;
13284}
13285
13286static struct snd_kcontrol_new alc861_capture_mixer[] = {
13287 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
13288 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
13289
13290 {
13291 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13292 /* The multiple "Capture Source" controls confuse alsamixer
13293 * So call somewhat different..
Kailang Yangdf694da2005-12-05 19:42:22 +010013294 */
13295 /* .name = "Capture Source", */
13296 .name = "Input Source",
13297 .count = 1,
13298 .info = alc_mux_enum_info,
13299 .get = alc_mux_enum_get,
13300 .put = alc_mux_enum_put,
13301 },
13302 { } /* end */
13303};
13304
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013305static void alc861_auto_set_output_and_unmute(struct hda_codec *codec,
13306 hda_nid_t nid,
Kailang Yangdf694da2005-12-05 19:42:22 +010013307 int pin_type, int dac_idx)
13308{
Jacek Luczak564c5be2008-05-03 18:41:23 +020013309 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
13310 pin_type);
13311 snd_hda_codec_write(codec, dac_idx, 0, AC_VERB_SET_AMP_GAIN_MUTE,
13312 AMP_OUT_UNMUTE);
Kailang Yangdf694da2005-12-05 19:42:22 +010013313}
13314
13315static void alc861_auto_init_multi_out(struct hda_codec *codec)
13316{
13317 struct alc_spec *spec = codec->spec;
13318 int i;
13319
Kailang Yangbc9f98a2007-04-12 13:06:07 +020013320 alc_subsystem_id(codec, 0x0e, 0x0f, 0x0b);
Kailang Yangdf694da2005-12-05 19:42:22 +010013321 for (i = 0; i < spec->autocfg.line_outs; i++) {
13322 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020013323 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangdf694da2005-12-05 19:42:22 +010013324 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020013325 alc861_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013326 spec->multiout.dac_nids[i]);
Kailang Yangdf694da2005-12-05 19:42:22 +010013327 }
13328}
13329
13330static void alc861_auto_init_hp_out(struct hda_codec *codec)
13331{
13332 struct alc_spec *spec = codec->spec;
13333 hda_nid_t pin;
13334
Takashi Iwaieb06ed82006-09-20 17:10:27 +020013335 pin = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010013336 if (pin) /* connect to front */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013337 alc861_auto_set_output_and_unmute(codec, pin, PIN_HP,
13338 spec->multiout.dac_nids[0]);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013339 pin = spec->autocfg.speaker_pins[0];
13340 if (pin)
13341 alc861_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Kailang Yangdf694da2005-12-05 19:42:22 +010013342}
13343
13344static void alc861_auto_init_analog_input(struct hda_codec *codec)
13345{
13346 struct alc_spec *spec = codec->spec;
13347 int i;
13348
13349 for (i = 0; i < AUTO_PIN_LAST; i++) {
13350 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013351 if (nid >= 0x0c && nid <= 0x11) {
13352 snd_hda_codec_write(codec, nid, 0,
13353 AC_VERB_SET_PIN_WIDGET_CONTROL,
13354 i <= AUTO_PIN_FRONT_MIC ?
13355 PIN_VREF80 : PIN_IN);
Kailang Yangdf694da2005-12-05 19:42:22 +010013356 }
13357 }
13358}
13359
13360/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013361/* return 1 if successful, 0 if the proper config is not found,
13362 * or a negative error code
13363 */
Kailang Yangdf694da2005-12-05 19:42:22 +010013364static int alc861_parse_auto_config(struct hda_codec *codec)
13365{
13366 struct alc_spec *spec = codec->spec;
13367 int err;
13368 static hda_nid_t alc861_ignore[] = { 0x1d, 0 };
13369
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013370 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
13371 alc861_ignore);
13372 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010013373 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013374 if (!spec->autocfg.line_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +010013375 return 0; /* can't find valid BIOS pin config */
13376
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013377 err = alc861_auto_fill_dac_nids(spec, &spec->autocfg);
13378 if (err < 0)
13379 return err;
13380 err = alc861_auto_create_multi_out_ctls(spec, &spec->autocfg);
13381 if (err < 0)
13382 return err;
13383 err = alc861_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
13384 if (err < 0)
13385 return err;
13386 err = alc861_auto_create_analog_input_ctls(spec, &spec->autocfg);
13387 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010013388 return err;
13389
13390 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
13391
13392 if (spec->autocfg.dig_out_pin)
13393 spec->multiout.dig_out_nid = ALC861_DIGOUT_NID;
13394
Takashi Iwai603c4012008-07-30 15:01:44 +020013395 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010013396 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +010013397
Takashi Iwaid88897e2008-10-31 15:01:37 +010013398 add_verb(spec, alc861_auto_init_verbs);
Kailang Yangdf694da2005-12-05 19:42:22 +010013399
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020013400 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +010013401 spec->input_mux = &spec->private_imux;
13402
13403 spec->adc_nids = alc861_adc_nids;
13404 spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids);
Takashi Iwaid88897e2008-10-31 15:01:37 +010013405 add_mixer(spec, alc861_capture_mixer);
Kailang Yangdf694da2005-12-05 19:42:22 +010013406
Takashi Iwaie044c392008-10-27 16:56:24 +010013407 store_pin_configs(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010013408 return 1;
13409}
13410
Takashi Iwaiae6b8132006-03-03 16:47:17 +010013411/* additional initialization for auto-configuration model */
13412static void alc861_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010013413{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013414 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010013415 alc861_auto_init_multi_out(codec);
13416 alc861_auto_init_hp_out(codec);
13417 alc861_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013418 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020013419 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010013420}
13421
Takashi Iwaicb53c622007-08-10 17:21:45 +020013422#ifdef CONFIG_SND_HDA_POWER_SAVE
13423static struct hda_amp_list alc861_loopbacks[] = {
13424 { 0x15, HDA_INPUT, 0 },
13425 { 0x15, HDA_INPUT, 1 },
13426 { 0x15, HDA_INPUT, 2 },
13427 { 0x15, HDA_INPUT, 3 },
13428 { } /* end */
13429};
13430#endif
13431
Kailang Yangdf694da2005-12-05 19:42:22 +010013432
13433/*
13434 * configuration and preset
13435 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010013436static const char *alc861_models[ALC861_MODEL_LAST] = {
13437 [ALC861_3ST] = "3stack",
13438 [ALC660_3ST] = "3stack-660",
13439 [ALC861_3ST_DIG] = "3stack-dig",
13440 [ALC861_6ST_DIG] = "6stack-dig",
13441 [ALC861_UNIWILL_M31] = "uniwill-m31",
13442 [ALC861_TOSHIBA] = "toshiba",
13443 [ALC861_ASUS] = "asus",
13444 [ALC861_ASUS_LAPTOP] = "asus-laptop",
13445 [ALC861_AUTO] = "auto",
13446};
13447
13448static struct snd_pci_quirk alc861_cfg_tbl[] = {
Takashi Iwai687a47b2007-01-10 11:25:58 +010013449 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010013450 SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP),
13451 SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP),
13452 SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013453 SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP),
Kailang Yang83c34212007-07-05 11:43:05 +020013454 SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS P1-AH2", ALC861_3ST_DIG),
Tobin Davisad5e7732007-01-08 10:57:32 +010013455 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA),
Takashi Iwai341d4eb2007-07-09 17:53:18 +020013456 /* FIXME: the entry below breaks Toshiba A100 (model=auto works!)
13457 * Any other models that need this preset?
13458 */
13459 /* SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), */
Claudio Matsuokaef64adb2007-07-14 00:26:16 +020013460 SND_PCI_QUIRK(0x1462, 0x7254, "HP dx2200 (MSI MS-7254)", ALC861_3ST),
13461 SND_PCI_QUIRK(0x1462, 0x7297, "HP dx2250 (MSI MS-7297)", ALC861_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013462 SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31),
13463 SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31),
13464 SND_PCI_QUIRK(0x1584, 0x9075, "Airis Praxis N1212", ALC861_ASUS_LAPTOP),
13465 /* FIXME: the below seems conflict */
13466 /* SND_PCI_QUIRK(0x1584, 0x9075, "Uniwill", ALC861_UNIWILL_M31), */
13467 SND_PCI_QUIRK(0x1849, 0x0660, "Asrock 939SLI32", ALC660_3ST),
13468 SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST),
Kailang Yangdf694da2005-12-05 19:42:22 +010013469 {}
13470};
13471
13472static struct alc_config_preset alc861_presets[] = {
13473 [ALC861_3ST] = {
13474 .mixers = { alc861_3ST_mixer },
13475 .init_verbs = { alc861_threestack_init_verbs },
13476 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
13477 .dac_nids = alc861_dac_nids,
13478 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
13479 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020013480 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010013481 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13482 .adc_nids = alc861_adc_nids,
13483 .input_mux = &alc861_capture_source,
13484 },
13485 [ALC861_3ST_DIG] = {
13486 .mixers = { alc861_base_mixer },
13487 .init_verbs = { alc861_threestack_init_verbs },
13488 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
13489 .dac_nids = alc861_dac_nids,
13490 .dig_out_nid = ALC861_DIGOUT_NID,
13491 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
13492 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020013493 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010013494 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13495 .adc_nids = alc861_adc_nids,
13496 .input_mux = &alc861_capture_source,
13497 },
13498 [ALC861_6ST_DIG] = {
13499 .mixers = { alc861_base_mixer },
13500 .init_verbs = { alc861_base_init_verbs },
13501 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
13502 .dac_nids = alc861_dac_nids,
13503 .dig_out_nid = ALC861_DIGOUT_NID,
13504 .num_channel_mode = ARRAY_SIZE(alc861_8ch_modes),
13505 .channel_mode = alc861_8ch_modes,
13506 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13507 .adc_nids = alc861_adc_nids,
13508 .input_mux = &alc861_capture_source,
13509 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013510 [ALC660_3ST] = {
13511 .mixers = { alc861_3ST_mixer },
13512 .init_verbs = { alc861_threestack_init_verbs },
13513 .num_dacs = ARRAY_SIZE(alc660_dac_nids),
13514 .dac_nids = alc660_dac_nids,
13515 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
13516 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020013517 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013518 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13519 .adc_nids = alc861_adc_nids,
13520 .input_mux = &alc861_capture_source,
13521 },
Takashi Iwai22309c32006-08-09 16:57:28 +020013522 [ALC861_UNIWILL_M31] = {
13523 .mixers = { alc861_uniwill_m31_mixer },
13524 .init_verbs = { alc861_uniwill_m31_init_verbs },
13525 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
13526 .dac_nids = alc861_dac_nids,
13527 .dig_out_nid = ALC861_DIGOUT_NID,
13528 .num_channel_mode = ARRAY_SIZE(alc861_uniwill_m31_modes),
13529 .channel_mode = alc861_uniwill_m31_modes,
13530 .need_dac_fix = 1,
13531 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13532 .adc_nids = alc861_adc_nids,
13533 .input_mux = &alc861_capture_source,
13534 },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013535 [ALC861_TOSHIBA] = {
13536 .mixers = { alc861_toshiba_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013537 .init_verbs = { alc861_base_init_verbs,
13538 alc861_toshiba_init_verbs },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020013539 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
13540 .dac_nids = alc861_dac_nids,
13541 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
13542 .channel_mode = alc883_3ST_2ch_modes,
13543 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13544 .adc_nids = alc861_adc_nids,
13545 .input_mux = &alc861_capture_source,
13546 .unsol_event = alc861_toshiba_unsol_event,
13547 .init_hook = alc861_toshiba_automute,
13548 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013549 [ALC861_ASUS] = {
13550 .mixers = { alc861_asus_mixer },
13551 .init_verbs = { alc861_asus_init_verbs },
13552 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
13553 .dac_nids = alc861_dac_nids,
13554 .dig_out_nid = ALC861_DIGOUT_NID,
13555 .num_channel_mode = ARRAY_SIZE(alc861_asus_modes),
13556 .channel_mode = alc861_asus_modes,
13557 .need_dac_fix = 1,
13558 .hp_nid = 0x06,
13559 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13560 .adc_nids = alc861_adc_nids,
13561 .input_mux = &alc861_capture_source,
13562 },
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010013563 [ALC861_ASUS_LAPTOP] = {
13564 .mixers = { alc861_toshiba_mixer, alc861_asus_laptop_mixer },
13565 .init_verbs = { alc861_asus_init_verbs,
13566 alc861_asus_laptop_init_verbs },
13567 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
13568 .dac_nids = alc861_dac_nids,
13569 .dig_out_nid = ALC861_DIGOUT_NID,
13570 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
13571 .channel_mode = alc883_3ST_2ch_modes,
13572 .need_dac_fix = 1,
13573 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
13574 .adc_nids = alc861_adc_nids,
13575 .input_mux = &alc861_capture_source,
13576 },
13577};
Kailang Yangdf694da2005-12-05 19:42:22 +010013578
13579
13580static int patch_alc861(struct hda_codec *codec)
13581{
13582 struct alc_spec *spec;
13583 int board_config;
13584 int err;
13585
Robert P. J. Daydc041e02006-12-19 14:44:15 +010013586 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010013587 if (spec == NULL)
13588 return -ENOMEM;
13589
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013590 codec->spec = spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010013591
Takashi Iwaif5fcc132006-11-24 17:07:44 +010013592 board_config = snd_hda_check_board_config(codec, ALC861_MODEL_LAST,
13593 alc861_models,
13594 alc861_cfg_tbl);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013595
Takashi Iwaif5fcc132006-11-24 17:07:44 +010013596 if (board_config < 0) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013597 printk(KERN_INFO "hda_codec: Unknown model for ALC861, "
13598 "trying auto-probe from BIOS...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010013599 board_config = ALC861_AUTO;
13600 }
13601
13602 if (board_config == ALC861_AUTO) {
13603 /* automatic parse from the BIOS config */
13604 err = alc861_parse_auto_config(codec);
13605 if (err < 0) {
13606 alc_free(codec);
13607 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013608 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013609 printk(KERN_INFO
13610 "hda_codec: Cannot set up configuration "
13611 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010013612 board_config = ALC861_3ST_DIG;
13613 }
13614 }
13615
13616 if (board_config != ALC861_AUTO)
13617 setup_preset(spec, &alc861_presets[board_config]);
13618
13619 spec->stream_name_analog = "ALC861 Analog";
13620 spec->stream_analog_playback = &alc861_pcm_analog_playback;
13621 spec->stream_analog_capture = &alc861_pcm_analog_capture;
13622
13623 spec->stream_name_digital = "ALC861 Digital";
13624 spec->stream_digital_playback = &alc861_pcm_digital_playback;
13625 spec->stream_digital_capture = &alc861_pcm_digital_capture;
13626
Takashi Iwai2134ea42008-01-10 16:53:55 +010013627 spec->vmaster_nid = 0x03;
13628
Kailang Yangdf694da2005-12-05 19:42:22 +010013629 codec->patch_ops = alc_patch_ops;
13630 if (board_config == ALC861_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +010013631 spec->init_hook = alc861_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020013632#ifdef CONFIG_SND_HDA_POWER_SAVE
13633 if (!spec->loopback.amplist)
13634 spec->loopback.amplist = alc861_loopbacks;
13635#endif
Kailang Yangea1fb292008-08-26 12:58:38 +020013636
Kailang Yangdf694da2005-12-05 19:42:22 +010013637 return 0;
13638}
13639
13640/*
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013641 * ALC861-VD support
13642 *
13643 * Based on ALC882
13644 *
13645 * In addition, an independent DAC
13646 */
13647#define ALC861VD_DIGOUT_NID 0x06
13648
13649static hda_nid_t alc861vd_dac_nids[4] = {
13650 /* front, surr, clfe, side surr */
13651 0x02, 0x03, 0x04, 0x05
13652};
13653
13654/* dac_nids for ALC660vd are in a different order - according to
13655 * Realtek's driver.
13656 * This should probably tesult in a different mixer for 6stack models
13657 * of ALC660vd codecs, but for now there is only 3stack mixer
13658 * - and it is the same as in 861vd.
13659 * adc_nids in ALC660vd are (is) the same as in 861vd
13660 */
13661static hda_nid_t alc660vd_dac_nids[3] = {
13662 /* front, rear, clfe, rear_surr */
13663 0x02, 0x04, 0x03
13664};
13665
13666static hda_nid_t alc861vd_adc_nids[1] = {
13667 /* ADC0 */
13668 0x09,
13669};
13670
Takashi Iwaie1406342008-02-11 18:32:32 +010013671static hda_nid_t alc861vd_capsrc_nids[1] = { 0x22 };
13672
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013673/* input MUX */
13674/* FIXME: should be a matrix-type input source selection */
13675static struct hda_input_mux alc861vd_capture_source = {
13676 .num_items = 4,
13677 .items = {
13678 { "Mic", 0x0 },
13679 { "Front Mic", 0x1 },
13680 { "Line", 0x2 },
13681 { "CD", 0x4 },
13682 },
13683};
13684
Kailang Yang272a5272007-05-14 11:00:38 +020013685static struct hda_input_mux alc861vd_dallas_capture_source = {
Tobin Davisb419f342008-03-07 11:57:51 +010013686 .num_items = 2,
Kailang Yang272a5272007-05-14 11:00:38 +020013687 .items = {
Tobin Davisb419f342008-03-07 11:57:51 +010013688 { "Ext Mic", 0x0 },
13689 { "Int Mic", 0x1 },
Kailang Yang272a5272007-05-14 11:00:38 +020013690 },
13691};
13692
Kailang Yangd1a991a2007-08-15 16:21:59 +020013693static struct hda_input_mux alc861vd_hp_capture_source = {
13694 .num_items = 2,
13695 .items = {
13696 { "Front Mic", 0x0 },
13697 { "ATAPI Mic", 0x1 },
13698 },
13699};
13700
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013701#define alc861vd_mux_enum_info alc_mux_enum_info
13702#define alc861vd_mux_enum_get alc_mux_enum_get
Takashi Iwaie1406342008-02-11 18:32:32 +010013703/* ALC861VD has the ALC882-type input selection (but has only one ADC) */
13704#define alc861vd_mux_enum_put alc882_mux_enum_put
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013705
13706/*
13707 * 2ch mode
13708 */
13709static struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = {
13710 { 2, NULL }
13711};
13712
13713/*
13714 * 6ch mode
13715 */
13716static struct hda_verb alc861vd_6stack_ch6_init[] = {
13717 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
13718 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
13719 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
13720 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
13721 { } /* end */
13722};
13723
13724/*
13725 * 8ch mode
13726 */
13727static struct hda_verb alc861vd_6stack_ch8_init[] = {
13728 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
13729 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
13730 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
13731 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
13732 { } /* end */
13733};
13734
13735static struct hda_channel_mode alc861vd_6stack_modes[2] = {
13736 { 6, alc861vd_6stack_ch6_init },
13737 { 8, alc861vd_6stack_ch8_init },
13738};
13739
13740static struct snd_kcontrol_new alc861vd_chmode_mixer[] = {
13741 {
13742 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13743 .name = "Channel Mode",
13744 .info = alc_ch_mode_info,
13745 .get = alc_ch_mode_get,
13746 .put = alc_ch_mode_put,
13747 },
13748 { } /* end */
13749};
13750
13751static struct snd_kcontrol_new alc861vd_capture_mixer[] = {
13752 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
13753 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
13754
13755 {
13756 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13757 /* The multiple "Capture Source" controls confuse alsamixer
13758 * So call somewhat different..
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013759 */
13760 /* .name = "Capture Source", */
13761 .name = "Input Source",
13762 .count = 1,
13763 .info = alc861vd_mux_enum_info,
13764 .get = alc861vd_mux_enum_get,
13765 .put = alc861vd_mux_enum_put,
13766 },
13767 { } /* end */
13768};
13769
13770/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
13771 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
13772 */
13773static struct snd_kcontrol_new alc861vd_6st_mixer[] = {
13774 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13775 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
13776
13777 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
13778 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
13779
13780 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0,
13781 HDA_OUTPUT),
13782 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0,
13783 HDA_OUTPUT),
13784 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
13785 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
13786
13787 HDA_CODEC_VOLUME("Side Playback Volume", 0x05, 0x0, HDA_OUTPUT),
13788 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
13789
13790 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
13791
13792 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13793 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13794 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13795
13796 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
13797 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
13798 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
13799
13800 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
13801 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
13802
13803 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
13804 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
13805
13806 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
13807 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
13808
13809 { } /* end */
13810};
13811
13812static struct snd_kcontrol_new alc861vd_3st_mixer[] = {
13813 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13814 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
13815
13816 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
13817
13818 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13819 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13820 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13821
13822 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
13823 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
13824 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
13825
13826 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
13827 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
13828
13829 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
13830 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
13831
13832 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
13833 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
13834
13835 { } /* end */
13836};
13837
Kailang Yangbdd148a2007-05-08 15:19:08 +020013838static struct snd_kcontrol_new alc861vd_lenovo_mixer[] = {
13839 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13840 /*HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),*/
13841 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
13842
13843 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
13844
13845 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13846 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13847 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13848
13849 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
13850 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
13851 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
13852
13853 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
13854 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
13855
13856 { } /* end */
13857};
13858
Tobin Davisb419f342008-03-07 11:57:51 +010013859/* Pin assignment: Speaker=0x14, HP = 0x15,
13860 * Ext Mic=0x18, Int Mic = 0x19, CD = 0x1c, PC Beep = 0x1d
Kailang Yang272a5272007-05-14 11:00:38 +020013861 */
13862static struct snd_kcontrol_new alc861vd_dallas_mixer[] = {
Tobin Davisb419f342008-03-07 11:57:51 +010013863 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13864 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020013865 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
13866 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
Tobin Davisb419f342008-03-07 11:57:51 +010013867 HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
13868 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13869 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13870 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
13871 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
13872 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
13873 HDA_CODEC_VOLUME("PC Beep Volume", 0x0b, 0x05, HDA_INPUT),
13874 HDA_CODEC_MUTE("PC Beep Switch", 0x0b, 0x05, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020013875 { } /* end */
13876};
13877
Kailang Yangd1a991a2007-08-15 16:21:59 +020013878/* Pin assignment: Speaker=0x14, Line-out = 0x15,
13879 * Front Mic=0x18, ATAPI Mic = 0x19,
13880 */
13881static struct snd_kcontrol_new alc861vd_hp_mixer[] = {
13882 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13883 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
13884 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
13885 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
13886 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13887 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13888 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
13889 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangea1fb292008-08-26 12:58:38 +020013890
Kailang Yangd1a991a2007-08-15 16:21:59 +020013891 { } /* end */
13892};
13893
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013894/*
13895 * generic initialization of ADC, input mixers and output mixers
13896 */
13897static struct hda_verb alc861vd_volume_init_verbs[] = {
13898 /*
13899 * Unmute ADC0 and set the default input to mic-in
13900 */
13901 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
13902 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13903
13904 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of
13905 * the analog-loopback mixer widget
13906 */
13907 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020013908 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13909 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13910 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
13911 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
13912 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013913
13914 /* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yangbdd148a2007-05-08 15:19:08 +020013915 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13916 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13917 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013918 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010013919
13920 /*
13921 * Set up output mixers (0x02 - 0x05)
13922 */
13923 /* set vol=0 to output mixers */
13924 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13925 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13926 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13927 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13928
13929 /* set up input amps for analog loopback */
13930 /* Amp Indices: DAC = 0, mixer = 1 */
13931 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13932 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13933 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13934 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13935 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13936 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13937 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13938 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13939
13940 { }
13941};
13942
13943/*
13944 * 3-stack pin configuration:
13945 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
13946 */
13947static struct hda_verb alc861vd_3stack_init_verbs[] = {
13948 /*
13949 * Set pin mode and muting
13950 */
13951 /* set front pin widgets 0x14 for output */
13952 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13953 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13954 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
13955
13956 /* Mic (rear) pin: input vref at 80% */
13957 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
13958 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13959 /* Front Mic pin: input vref at 80% */
13960 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
13961 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13962 /* Line In pin: input */
13963 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13964 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13965 /* Line-2 In: Headphone output (output 0 - 0x0c) */
13966 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13967 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13968 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
13969 /* CD pin widget for input */
13970 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13971
13972 { }
13973};
13974
13975/*
13976 * 6-stack pin configuration:
13977 */
13978static struct hda_verb alc861vd_6stack_init_verbs[] = {
13979 /*
13980 * Set pin mode and muting
13981 */
13982 /* set front pin widgets 0x14 for output */
13983 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13984 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13985 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
13986
13987 /* Rear Pin: output 1 (0x0d) */
13988 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13989 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13990 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
13991 /* CLFE Pin: output 2 (0x0e) */
13992 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13993 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13994 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
13995 /* Side Pin: output 3 (0x0f) */
13996 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13997 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13998 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
13999
14000 /* Mic (rear) pin: input vref at 80% */
14001 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14002 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14003 /* Front Mic pin: input vref at 80% */
14004 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14005 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14006 /* Line In pin: input */
14007 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14008 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14009 /* Line-2 In: Headphone output (output 0 - 0x0c) */
14010 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14011 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14012 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
14013 /* CD pin widget for input */
14014 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14015
14016 { }
14017};
14018
Kailang Yangbdd148a2007-05-08 15:19:08 +020014019static struct hda_verb alc861vd_eapd_verbs[] = {
14020 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
14021 { }
14022};
14023
Kailang Yangf9423e72008-05-27 12:32:25 +020014024static struct hda_verb alc660vd_eapd_verbs[] = {
14025 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
14026 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
14027 { }
14028};
14029
Kailang Yangbdd148a2007-05-08 15:19:08 +020014030static struct hda_verb alc861vd_lenovo_unsol_verbs[] = {
14031 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14032 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14033 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
14034 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Kailang Yangea1fb292008-08-26 12:58:38 +020014035 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
Kailang Yangbdd148a2007-05-08 15:19:08 +020014036 {}
14037};
14038
14039/* toggle speaker-output according to the hp-jack state */
14040static void alc861vd_lenovo_hp_automute(struct hda_codec *codec)
14041{
14042 unsigned int present;
14043 unsigned char bits;
14044
14045 present = snd_hda_codec_read(codec, 0x1b, 0,
14046 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020014047 bits = present ? HDA_AMP_MUTE : 0;
14048 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
14049 HDA_AMP_MUTE, bits);
Kailang Yangbdd148a2007-05-08 15:19:08 +020014050}
14051
14052static void alc861vd_lenovo_mic_automute(struct hda_codec *codec)
14053{
14054 unsigned int present;
14055 unsigned char bits;
14056
14057 present = snd_hda_codec_read(codec, 0x18, 0,
14058 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020014059 bits = present ? HDA_AMP_MUTE : 0;
14060 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
14061 HDA_AMP_MUTE, bits);
Kailang Yangbdd148a2007-05-08 15:19:08 +020014062}
14063
14064static void alc861vd_lenovo_automute(struct hda_codec *codec)
14065{
14066 alc861vd_lenovo_hp_automute(codec);
14067 alc861vd_lenovo_mic_automute(codec);
14068}
14069
14070static void alc861vd_lenovo_unsol_event(struct hda_codec *codec,
14071 unsigned int res)
14072{
14073 switch (res >> 26) {
14074 case ALC880_HP_EVENT:
14075 alc861vd_lenovo_hp_automute(codec);
14076 break;
14077 case ALC880_MIC_EVENT:
14078 alc861vd_lenovo_mic_automute(codec);
14079 break;
14080 }
14081}
14082
Kailang Yang272a5272007-05-14 11:00:38 +020014083static struct hda_verb alc861vd_dallas_verbs[] = {
14084 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14085 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14086 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14087 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14088
14089 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14090 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14091 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14092 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
14093 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14094 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
14095 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14096 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020014097
Kailang Yang272a5272007-05-14 11:00:38 +020014098 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14099 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14100 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14101 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14102 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14103 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14104 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14105 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14106
14107 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
14108 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14109 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
14110 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14111 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14112 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14113 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14114 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14115
14116 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14117 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
14118 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
14119 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
14120
14121 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020014122 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yang272a5272007-05-14 11:00:38 +020014123 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14124
14125 { } /* end */
14126};
14127
14128/* toggle speaker-output according to the hp-jack state */
14129static void alc861vd_dallas_automute(struct hda_codec *codec)
14130{
14131 unsigned int present;
14132
14133 present = snd_hda_codec_read(codec, 0x15, 0,
14134 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020014135 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
14136 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +020014137}
14138
14139static void alc861vd_dallas_unsol_event(struct hda_codec *codec, unsigned int res)
14140{
14141 if ((res >> 26) == ALC880_HP_EVENT)
14142 alc861vd_dallas_automute(codec);
14143}
14144
Takashi Iwaicb53c622007-08-10 17:21:45 +020014145#ifdef CONFIG_SND_HDA_POWER_SAVE
14146#define alc861vd_loopbacks alc880_loopbacks
14147#endif
14148
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014149/* pcm configuration: identiacal with ALC880 */
14150#define alc861vd_pcm_analog_playback alc880_pcm_analog_playback
14151#define alc861vd_pcm_analog_capture alc880_pcm_analog_capture
14152#define alc861vd_pcm_digital_playback alc880_pcm_digital_playback
14153#define alc861vd_pcm_digital_capture alc880_pcm_digital_capture
14154
14155/*
14156 * configuration and preset
14157 */
14158static const char *alc861vd_models[ALC861VD_MODEL_LAST] = {
14159 [ALC660VD_3ST] = "3stack-660",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020014160 [ALC660VD_3ST_DIG] = "3stack-660-digout",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014161 [ALC861VD_3ST] = "3stack",
14162 [ALC861VD_3ST_DIG] = "3stack-digout",
14163 [ALC861VD_6ST_DIG] = "6stack-digout",
Kailang Yangbdd148a2007-05-08 15:19:08 +020014164 [ALC861VD_LENOVO] = "lenovo",
Kailang Yang272a5272007-05-14 11:00:38 +020014165 [ALC861VD_DALLAS] = "dallas",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020014166 [ALC861VD_HP] = "hp",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014167 [ALC861VD_AUTO] = "auto",
14168};
14169
14170static struct snd_pci_quirk alc861vd_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +010014171 SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST),
14172 SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP),
Takashi Iwai07e038b2007-02-15 18:23:41 +010014173 SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014174 SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),
Alexander Holler2522d732008-07-17 23:36:15 +020014175 SND_PCI_QUIRK(0x1043, 0x1633, "Asus V1Sn", ALC861VD_LENOVO),
Mike Crash6963f842007-06-25 12:12:51 +020014176 SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014177 SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010014178 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO),
Takashi Iwai38baf5a2007-08-16 17:52:43 +020014179 /*SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS),*/ /*lenovo*/
Kailang Yang272a5272007-05-14 11:00:38 +020014180 SND_PCI_QUIRK(0x1179, 0xff01, "DALLAS", ALC861VD_DALLAS),
Takashi Iwai542d7c62007-08-16 18:57:30 +020014181 SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO),
Tobin Davisb419f342008-03-07 11:57:51 +010014182 SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_DALLAS),
Takashi Iwai39c5d412007-08-15 16:24:17 +020014183 SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010014184 SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo", ALC861VD_LENOVO),
14185 SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo 3000 C200", ALC861VD_LENOVO),
Takashi Iwaibe321a82008-07-07 16:04:04 +020014186 SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 N200", ALC861VD_LENOVO),
Tobin Davis625dc0b2007-07-30 21:42:10 +020014187 SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014188 {}
14189};
14190
14191static struct alc_config_preset alc861vd_presets[] = {
14192 [ALC660VD_3ST] = {
14193 .mixers = { alc861vd_3st_mixer },
14194 .init_verbs = { alc861vd_volume_init_verbs,
14195 alc861vd_3stack_init_verbs },
14196 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
14197 .dac_nids = alc660vd_dac_nids,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014198 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14199 .channel_mode = alc861vd_3stack_2ch_modes,
14200 .input_mux = &alc861vd_capture_source,
14201 },
Mike Crash6963f842007-06-25 12:12:51 +020014202 [ALC660VD_3ST_DIG] = {
14203 .mixers = { alc861vd_3st_mixer },
14204 .init_verbs = { alc861vd_volume_init_verbs,
14205 alc861vd_3stack_init_verbs },
14206 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
14207 .dac_nids = alc660vd_dac_nids,
14208 .dig_out_nid = ALC861VD_DIGOUT_NID,
Mike Crash6963f842007-06-25 12:12:51 +020014209 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14210 .channel_mode = alc861vd_3stack_2ch_modes,
14211 .input_mux = &alc861vd_capture_source,
14212 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014213 [ALC861VD_3ST] = {
14214 .mixers = { alc861vd_3st_mixer },
14215 .init_verbs = { alc861vd_volume_init_verbs,
14216 alc861vd_3stack_init_verbs },
14217 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
14218 .dac_nids = alc861vd_dac_nids,
14219 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14220 .channel_mode = alc861vd_3stack_2ch_modes,
14221 .input_mux = &alc861vd_capture_source,
14222 },
14223 [ALC861VD_3ST_DIG] = {
14224 .mixers = { alc861vd_3st_mixer },
14225 .init_verbs = { alc861vd_volume_init_verbs,
14226 alc861vd_3stack_init_verbs },
14227 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
14228 .dac_nids = alc861vd_dac_nids,
14229 .dig_out_nid = ALC861VD_DIGOUT_NID,
14230 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14231 .channel_mode = alc861vd_3stack_2ch_modes,
14232 .input_mux = &alc861vd_capture_source,
14233 },
14234 [ALC861VD_6ST_DIG] = {
14235 .mixers = { alc861vd_6st_mixer, alc861vd_chmode_mixer },
14236 .init_verbs = { alc861vd_volume_init_verbs,
14237 alc861vd_6stack_init_verbs },
14238 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
14239 .dac_nids = alc861vd_dac_nids,
14240 .dig_out_nid = ALC861VD_DIGOUT_NID,
14241 .num_channel_mode = ARRAY_SIZE(alc861vd_6stack_modes),
14242 .channel_mode = alc861vd_6stack_modes,
14243 .input_mux = &alc861vd_capture_source,
14244 },
Kailang Yangbdd148a2007-05-08 15:19:08 +020014245 [ALC861VD_LENOVO] = {
14246 .mixers = { alc861vd_lenovo_mixer },
14247 .init_verbs = { alc861vd_volume_init_verbs,
14248 alc861vd_3stack_init_verbs,
14249 alc861vd_eapd_verbs,
14250 alc861vd_lenovo_unsol_verbs },
14251 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
14252 .dac_nids = alc660vd_dac_nids,
Kailang Yangbdd148a2007-05-08 15:19:08 +020014253 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14254 .channel_mode = alc861vd_3stack_2ch_modes,
14255 .input_mux = &alc861vd_capture_source,
14256 .unsol_event = alc861vd_lenovo_unsol_event,
14257 .init_hook = alc861vd_lenovo_automute,
14258 },
Kailang Yang272a5272007-05-14 11:00:38 +020014259 [ALC861VD_DALLAS] = {
14260 .mixers = { alc861vd_dallas_mixer },
14261 .init_verbs = { alc861vd_dallas_verbs },
14262 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
14263 .dac_nids = alc861vd_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +020014264 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14265 .channel_mode = alc861vd_3stack_2ch_modes,
14266 .input_mux = &alc861vd_dallas_capture_source,
14267 .unsol_event = alc861vd_dallas_unsol_event,
14268 .init_hook = alc861vd_dallas_automute,
Kailang Yangd1a991a2007-08-15 16:21:59 +020014269 },
14270 [ALC861VD_HP] = {
14271 .mixers = { alc861vd_hp_mixer },
14272 .init_verbs = { alc861vd_dallas_verbs, alc861vd_eapd_verbs },
14273 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
14274 .dac_nids = alc861vd_dac_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020014275 .dig_out_nid = ALC861VD_DIGOUT_NID,
Kailang Yangd1a991a2007-08-15 16:21:59 +020014276 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
14277 .channel_mode = alc861vd_3stack_2ch_modes,
14278 .input_mux = &alc861vd_hp_capture_source,
14279 .unsol_event = alc861vd_dallas_unsol_event,
14280 .init_hook = alc861vd_dallas_automute,
Kailang Yangea1fb292008-08-26 12:58:38 +020014281 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014282};
14283
14284/*
14285 * BIOS auto configuration
14286 */
14287static void alc861vd_auto_set_output_and_unmute(struct hda_codec *codec,
14288 hda_nid_t nid, int pin_type, int dac_idx)
14289{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014290 alc_set_pin_output(codec, nid, pin_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014291}
14292
14293static void alc861vd_auto_init_multi_out(struct hda_codec *codec)
14294{
14295 struct alc_spec *spec = codec->spec;
14296 int i;
14297
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014298 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014299 for (i = 0; i <= HDA_SIDE; i++) {
14300 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020014301 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014302 if (nid)
14303 alc861vd_auto_set_output_and_unmute(codec, nid,
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020014304 pin_type, i);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014305 }
14306}
14307
14308
14309static void alc861vd_auto_init_hp_out(struct hda_codec *codec)
14310{
14311 struct alc_spec *spec = codec->spec;
14312 hda_nid_t pin;
14313
14314 pin = spec->autocfg.hp_pins[0];
14315 if (pin) /* connect to front and use dac 0 */
14316 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014317 pin = spec->autocfg.speaker_pins[0];
14318 if (pin)
14319 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014320}
14321
14322#define alc861vd_is_input_pin(nid) alc880_is_input_pin(nid)
14323#define ALC861VD_PIN_CD_NID ALC880_PIN_CD_NID
14324
14325static void alc861vd_auto_init_analog_input(struct hda_codec *codec)
14326{
14327 struct alc_spec *spec = codec->spec;
14328 int i;
14329
14330 for (i = 0; i < AUTO_PIN_LAST; i++) {
14331 hda_nid_t nid = spec->autocfg.input_pins[i];
14332 if (alc861vd_is_input_pin(nid)) {
14333 snd_hda_codec_write(codec, nid, 0,
14334 AC_VERB_SET_PIN_WIDGET_CONTROL,
14335 i <= AUTO_PIN_FRONT_MIC ?
14336 PIN_VREF80 : PIN_IN);
14337 if (nid != ALC861VD_PIN_CD_NID)
14338 snd_hda_codec_write(codec, nid, 0,
14339 AC_VERB_SET_AMP_GAIN_MUTE,
14340 AMP_OUT_MUTE);
14341 }
14342 }
14343}
14344
Takashi Iwaif511b012008-08-15 16:46:42 +020014345#define alc861vd_auto_init_input_src alc882_auto_init_input_src
14346
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014347#define alc861vd_idx_to_mixer_vol(nid) ((nid) + 0x02)
14348#define alc861vd_idx_to_mixer_switch(nid) ((nid) + 0x0c)
14349
14350/* add playback controls from the parsed DAC table */
14351/* Based on ALC880 version. But ALC861VD has separate,
14352 * different NIDs for mute/unmute switch and volume control */
14353static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
14354 const struct auto_pin_cfg *cfg)
14355{
14356 char name[32];
14357 static const char *chname[4] = {"Front", "Surround", "CLFE", "Side"};
14358 hda_nid_t nid_v, nid_s;
14359 int i, err;
14360
14361 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014362 if (!spec->multiout.dac_nids[i])
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014363 continue;
14364 nid_v = alc861vd_idx_to_mixer_vol(
14365 alc880_dac_to_idx(
14366 spec->multiout.dac_nids[i]));
14367 nid_s = alc861vd_idx_to_mixer_switch(
14368 alc880_dac_to_idx(
14369 spec->multiout.dac_nids[i]));
14370
14371 if (i == 2) {
14372 /* Center/LFE */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014373 err = add_control(spec, ALC_CTL_WIDGET_VOL,
14374 "Center Playback Volume",
14375 HDA_COMPOSE_AMP_VAL(nid_v, 1, 0,
14376 HDA_OUTPUT));
14377 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014378 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014379 err = add_control(spec, ALC_CTL_WIDGET_VOL,
14380 "LFE Playback Volume",
14381 HDA_COMPOSE_AMP_VAL(nid_v, 2, 0,
14382 HDA_OUTPUT));
14383 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014384 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014385 err = add_control(spec, ALC_CTL_BIND_MUTE,
14386 "Center Playback Switch",
14387 HDA_COMPOSE_AMP_VAL(nid_s, 1, 2,
14388 HDA_INPUT));
14389 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014390 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014391 err = add_control(spec, ALC_CTL_BIND_MUTE,
14392 "LFE Playback Switch",
14393 HDA_COMPOSE_AMP_VAL(nid_s, 2, 2,
14394 HDA_INPUT));
14395 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014396 return err;
14397 } else {
14398 sprintf(name, "%s Playback Volume", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014399 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
14400 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0,
14401 HDA_OUTPUT));
14402 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014403 return err;
14404 sprintf(name, "%s Playback Switch", chname[i]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014405 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
Kailang Yangbdd148a2007-05-08 15:19:08 +020014406 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014407 HDA_INPUT));
14408 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014409 return err;
14410 }
14411 }
14412 return 0;
14413}
14414
14415/* add playback controls for speaker and HP outputs */
14416/* Based on ALC880 version. But ALC861VD has separate,
14417 * different NIDs for mute/unmute switch and volume control */
14418static int alc861vd_auto_create_extra_out(struct alc_spec *spec,
14419 hda_nid_t pin, const char *pfx)
14420{
14421 hda_nid_t nid_v, nid_s;
14422 int err;
14423 char name[32];
14424
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014425 if (!pin)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014426 return 0;
14427
14428 if (alc880_is_fixed_pin(pin)) {
14429 nid_v = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
14430 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014431 if (!spec->multiout.hp_nid)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014432 spec->multiout.hp_nid = nid_v;
14433 else
14434 spec->multiout.extra_out_nid[0] = nid_v;
14435 /* control HP volume/switch on the output mixer amp */
14436 nid_v = alc861vd_idx_to_mixer_vol(
14437 alc880_fixed_pin_idx(pin));
14438 nid_s = alc861vd_idx_to_mixer_switch(
14439 alc880_fixed_pin_idx(pin));
14440
14441 sprintf(name, "%s Playback Volume", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014442 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
14443 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0, HDA_OUTPUT));
14444 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014445 return err;
14446 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014447 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
14448 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2, HDA_INPUT));
14449 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014450 return err;
14451 } else if (alc880_is_multi_pin(pin)) {
14452 /* set manual connection */
14453 /* we have only a switch on HP-out PIN */
14454 sprintf(name, "%s Playback Switch", pfx);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014455 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
14456 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
14457 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014458 return err;
14459 }
14460 return 0;
14461}
14462
14463/* parse the BIOS configuration and set up the alc_spec
14464 * return 1 if successful, 0 if the proper config is not found,
14465 * or a negative error code
14466 * Based on ALC880 version - had to change it to override
14467 * alc880_auto_create_extra_out and alc880_auto_create_multi_out_ctls */
14468static int alc861vd_parse_auto_config(struct hda_codec *codec)
14469{
14470 struct alc_spec *spec = codec->spec;
14471 int err;
14472 static hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
14473
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014474 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
14475 alc861vd_ignore);
14476 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014477 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014478 if (!spec->autocfg.line_outs)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014479 return 0; /* can't find valid BIOS pin config */
14480
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014481 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
14482 if (err < 0)
14483 return err;
14484 err = alc861vd_auto_create_multi_out_ctls(spec, &spec->autocfg);
14485 if (err < 0)
14486 return err;
14487 err = alc861vd_auto_create_extra_out(spec,
14488 spec->autocfg.speaker_pins[0],
14489 "Speaker");
14490 if (err < 0)
14491 return err;
14492 err = alc861vd_auto_create_extra_out(spec,
14493 spec->autocfg.hp_pins[0],
14494 "Headphone");
14495 if (err < 0)
14496 return err;
14497 err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg);
14498 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014499 return err;
14500
14501 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
14502
14503 if (spec->autocfg.dig_out_pin)
14504 spec->multiout.dig_out_nid = ALC861VD_DIGOUT_NID;
14505
Takashi Iwai603c4012008-07-30 15:01:44 +020014506 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010014507 add_mixer(spec, spec->kctls.list);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014508
Takashi Iwaid88897e2008-10-31 15:01:37 +010014509 add_verb(spec, alc861vd_volume_init_verbs);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014510
14511 spec->num_mux_defs = 1;
14512 spec->input_mux = &spec->private_imux;
14513
Takashi Iwai776e1842007-08-29 15:07:11 +020014514 err = alc_auto_add_mic_boost(codec);
14515 if (err < 0)
14516 return err;
14517
Takashi Iwaie044c392008-10-27 16:56:24 +010014518 store_pin_configs(codec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014519 return 1;
14520}
14521
14522/* additional initialization for auto-configuration model */
14523static void alc861vd_auto_init(struct hda_codec *codec)
14524{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014525 struct alc_spec *spec = codec->spec;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014526 alc861vd_auto_init_multi_out(codec);
14527 alc861vd_auto_init_hp_out(codec);
14528 alc861vd_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020014529 alc861vd_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014530 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020014531 alc_inithook(codec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014532}
14533
14534static int patch_alc861vd(struct hda_codec *codec)
14535{
14536 struct alc_spec *spec;
14537 int err, board_config;
14538
14539 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
14540 if (spec == NULL)
14541 return -ENOMEM;
14542
14543 codec->spec = spec;
14544
14545 board_config = snd_hda_check_board_config(codec, ALC861VD_MODEL_LAST,
14546 alc861vd_models,
14547 alc861vd_cfg_tbl);
14548
14549 if (board_config < 0 || board_config >= ALC861VD_MODEL_LAST) {
14550 printk(KERN_INFO "hda_codec: Unknown model for ALC660VD/"
14551 "ALC861VD, trying auto-probe from BIOS...\n");
14552 board_config = ALC861VD_AUTO;
14553 }
14554
14555 if (board_config == ALC861VD_AUTO) {
14556 /* automatic parse from the BIOS config */
14557 err = alc861vd_parse_auto_config(codec);
14558 if (err < 0) {
14559 alc_free(codec);
14560 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014561 } else if (!err) {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014562 printk(KERN_INFO
14563 "hda_codec: Cannot set up configuration "
14564 "from BIOS. Using base mode...\n");
14565 board_config = ALC861VD_3ST;
14566 }
14567 }
14568
14569 if (board_config != ALC861VD_AUTO)
14570 setup_preset(spec, &alc861vd_presets[board_config]);
14571
Kailang Yang2f893282008-05-27 12:14:47 +020014572 if (codec->vendor_id == 0x10ec0660) {
14573 spec->stream_name_analog = "ALC660-VD Analog";
14574 spec->stream_name_digital = "ALC660-VD Digital";
Kailang Yangf9423e72008-05-27 12:32:25 +020014575 /* always turn on EAPD */
Takashi Iwaid88897e2008-10-31 15:01:37 +010014576 add_verb(spec, alc660vd_eapd_verbs);
Kailang Yang2f893282008-05-27 12:14:47 +020014577 } else {
14578 spec->stream_name_analog = "ALC861VD Analog";
14579 spec->stream_name_digital = "ALC861VD Digital";
14580 }
14581
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014582 spec->stream_analog_playback = &alc861vd_pcm_analog_playback;
14583 spec->stream_analog_capture = &alc861vd_pcm_analog_capture;
14584
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014585 spec->stream_digital_playback = &alc861vd_pcm_digital_playback;
14586 spec->stream_digital_capture = &alc861vd_pcm_digital_capture;
14587
14588 spec->adc_nids = alc861vd_adc_nids;
14589 spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids);
Takashi Iwaie1406342008-02-11 18:32:32 +010014590 spec->capsrc_nids = alc861vd_capsrc_nids;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014591
Takashi Iwaid88897e2008-10-31 15:01:37 +010014592 add_mixer(spec, alc861vd_capture_mixer);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014593
Takashi Iwai2134ea42008-01-10 16:53:55 +010014594 spec->vmaster_nid = 0x02;
14595
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014596 codec->patch_ops = alc_patch_ops;
14597
14598 if (board_config == ALC861VD_AUTO)
14599 spec->init_hook = alc861vd_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020014600#ifdef CONFIG_SND_HDA_POWER_SAVE
14601 if (!spec->loopback.amplist)
14602 spec->loopback.amplist = alc861vd_loopbacks;
14603#endif
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014604
14605 return 0;
14606}
14607
14608/*
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014609 * ALC662 support
14610 *
14611 * ALC662 is almost identical with ALC880 but has cleaner and more flexible
14612 * configuration. Each pin widget can choose any input DACs and a mixer.
14613 * Each ADC is connected from a mixer of all inputs. This makes possible
14614 * 6-channel independent captures.
14615 *
14616 * In addition, an independent DAC for the multi-playback (not used in this
14617 * driver yet).
14618 */
14619#define ALC662_DIGOUT_NID 0x06
14620#define ALC662_DIGIN_NID 0x0a
14621
14622static hda_nid_t alc662_dac_nids[4] = {
14623 /* front, rear, clfe, rear_surr */
14624 0x02, 0x03, 0x04
14625};
14626
14627static hda_nid_t alc662_adc_nids[1] = {
14628 /* ADC1-2 */
14629 0x09,
14630};
Takashi Iwaie1406342008-02-11 18:32:32 +010014631
Kailang Yang77a261b2008-02-19 11:38:05 +010014632static hda_nid_t alc662_capsrc_nids[1] = { 0x22 };
Takashi Iwaie1406342008-02-11 18:32:32 +010014633
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014634/* input MUX */
14635/* FIXME: should be a matrix-type input source selection */
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014636static struct hda_input_mux alc662_capture_source = {
14637 .num_items = 4,
14638 .items = {
14639 { "Mic", 0x0 },
14640 { "Front Mic", 0x1 },
14641 { "Line", 0x2 },
14642 { "CD", 0x4 },
14643 },
14644};
14645
14646static struct hda_input_mux alc662_lenovo_101e_capture_source = {
14647 .num_items = 2,
14648 .items = {
14649 { "Mic", 0x1 },
14650 { "Line", 0x2 },
14651 },
14652};
Kailang Yang291702f2007-10-16 14:28:03 +020014653
14654static struct hda_input_mux alc662_eeepc_capture_source = {
14655 .num_items = 2,
14656 .items = {
14657 { "i-Mic", 0x1 },
14658 { "e-Mic", 0x0 },
14659 },
14660};
14661
Kailang Yang6dda9f42008-05-27 12:05:31 +020014662static struct hda_input_mux alc663_capture_source = {
14663 .num_items = 3,
14664 .items = {
14665 { "Mic", 0x0 },
14666 { "Front Mic", 0x1 },
14667 { "Line", 0x2 },
14668 },
14669};
14670
14671static struct hda_input_mux alc663_m51va_capture_source = {
14672 .num_items = 2,
14673 .items = {
14674 { "Ext-Mic", 0x0 },
14675 { "D-Mic", 0x9 },
14676 },
14677};
14678
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014679#define alc662_mux_enum_info alc_mux_enum_info
14680#define alc662_mux_enum_get alc_mux_enum_get
Takashi Iwaie1406342008-02-11 18:32:32 +010014681#define alc662_mux_enum_put alc882_mux_enum_put
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014682
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014683/*
14684 * 2ch mode
14685 */
14686static struct hda_channel_mode alc662_3ST_2ch_modes[1] = {
14687 { 2, NULL }
14688};
14689
14690/*
14691 * 2ch mode
14692 */
14693static struct hda_verb alc662_3ST_ch2_init[] = {
14694 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
14695 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
14696 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
14697 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
14698 { } /* end */
14699};
14700
14701/*
14702 * 6ch mode
14703 */
14704static struct hda_verb alc662_3ST_ch6_init[] = {
14705 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14706 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
14707 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
14708 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14709 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
14710 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
14711 { } /* end */
14712};
14713
14714static struct hda_channel_mode alc662_3ST_6ch_modes[2] = {
14715 { 2, alc662_3ST_ch2_init },
14716 { 6, alc662_3ST_ch6_init },
14717};
14718
14719/*
14720 * 2ch mode
14721 */
14722static struct hda_verb alc662_sixstack_ch6_init[] = {
14723 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
14724 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
14725 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14726 { } /* end */
14727};
14728
14729/*
14730 * 6ch mode
14731 */
14732static struct hda_verb alc662_sixstack_ch8_init[] = {
14733 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14734 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14735 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
14736 { } /* end */
14737};
14738
14739static struct hda_channel_mode alc662_5stack_modes[2] = {
14740 { 2, alc662_sixstack_ch6_init },
14741 { 6, alc662_sixstack_ch8_init },
14742};
14743
14744/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
14745 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
14746 */
14747
14748static struct snd_kcontrol_new alc662_base_mixer[] = {
14749 /* output mixer control */
14750 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010014751 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014752 HDA_CODEC_VOLUME("Surround Playback Volume", 0x3, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010014753 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014754 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
14755 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010014756 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
14757 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014758 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
14759
14760 /*Input mixer control */
14761 HDA_CODEC_VOLUME("CD Playback Volume", 0xb, 0x4, HDA_INPUT),
14762 HDA_CODEC_MUTE("CD Playback Switch", 0xb, 0x4, HDA_INPUT),
14763 HDA_CODEC_VOLUME("Line Playback Volume", 0xb, 0x02, HDA_INPUT),
14764 HDA_CODEC_MUTE("Line Playback Switch", 0xb, 0x02, HDA_INPUT),
14765 HDA_CODEC_VOLUME("Mic Playback Volume", 0xb, 0x0, HDA_INPUT),
14766 HDA_CODEC_MUTE("Mic Playback Switch", 0xb, 0x0, HDA_INPUT),
14767 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0xb, 0x01, HDA_INPUT),
14768 HDA_CODEC_MUTE("Front Mic Playback Switch", 0xb, 0x01, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014769 { } /* end */
14770};
14771
14772static struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = {
14773 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010014774 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014775 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
14776 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
14777 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
14778 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
14779 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
14780 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14781 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14782 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14783 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14784 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
14785 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014786 { } /* end */
14787};
14788
14789static struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = {
14790 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010014791 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014792 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010014793 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014794 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
14795 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010014796 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
14797 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014798 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
14799 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
14800 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
14801 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
14802 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
14803 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14804 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14805 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14806 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14807 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
14808 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014809 { } /* end */
14810};
14811
14812static struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = {
14813 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14814 HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010014815 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x03, 0x0, HDA_OUTPUT),
14816 HDA_BIND_MUTE("Speaker Playback Switch", 0x03, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014817 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
14818 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
14819 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
14820 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14821 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020014822 { } /* end */
14823};
14824
Kailang Yang291702f2007-10-16 14:28:03 +020014825static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = {
Takashi Iwai86cd9292008-01-28 18:09:56 +010014826 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang291702f2007-10-16 14:28:03 +020014827
Herton Ronaldo Krzesinskib4818492008-02-23 11:34:12 +010014828 HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14829 HDA_CODEC_MUTE("Line-Out Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yang291702f2007-10-16 14:28:03 +020014830
14831 HDA_CODEC_VOLUME("e-Mic Boost", 0x18, 0, HDA_INPUT),
14832 HDA_CODEC_VOLUME("e-Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14833 HDA_CODEC_MUTE("e-Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14834
14835 HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT),
14836 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14837 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14838 { } /* end */
14839};
14840
Kailang Yang8c427222008-01-10 13:03:59 +010014841static struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = {
Takashi Iwai31bffaa2008-02-27 16:10:44 +010014842 HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14843 HDA_CODEC_MUTE("Line-Out Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010014844 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
14845 HDA_BIND_MUTE("Surround Playback Switch", 0x03, 2, HDA_INPUT),
14846 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
14847 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
14848 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x04, 1, 2, HDA_INPUT),
14849 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x04, 2, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010014850 HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010014851 HDA_BIND_MUTE("MuteCtrl Playback Switch", 0x0c, 2, HDA_INPUT),
14852 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
14853 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
14854 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14855 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14856 { } /* end */
14857};
14858
Kailang Yangf1d4e282008-08-26 14:03:29 +020014859static struct hda_bind_ctls alc663_asus_bind_master_vol = {
14860 .ops = &snd_hda_bind_vol,
14861 .values = {
14862 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
14863 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
14864 0
14865 },
14866};
14867
14868static struct hda_bind_ctls alc663_asus_one_bind_switch = {
14869 .ops = &snd_hda_bind_sw,
14870 .values = {
14871 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
14872 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
14873 0
14874 },
14875};
14876
Kailang Yang6dda9f42008-05-27 12:05:31 +020014877static struct snd_kcontrol_new alc663_m51va_mixer[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020014878 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
14879 HDA_BIND_SW("Master Playback Switch", &alc663_asus_one_bind_switch),
14880 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14881 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14882 { } /* end */
14883};
14884
14885static struct hda_bind_ctls alc663_asus_tree_bind_switch = {
14886 .ops = &snd_hda_bind_sw,
14887 .values = {
14888 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
14889 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
14890 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
14891 0
14892 },
14893};
14894
14895static struct snd_kcontrol_new alc663_two_hp_m1_mixer[] = {
14896 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
14897 HDA_BIND_SW("Master Playback Switch", &alc663_asus_tree_bind_switch),
14898 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14899 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14900 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14901 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14902
14903 { } /* end */
14904};
14905
14906static struct hda_bind_ctls alc663_asus_four_bind_switch = {
14907 .ops = &snd_hda_bind_sw,
14908 .values = {
14909 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
14910 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
14911 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
14912 0
14913 },
14914};
14915
14916static struct snd_kcontrol_new alc663_two_hp_m2_mixer[] = {
14917 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
14918 HDA_BIND_SW("Master Playback Switch", &alc663_asus_four_bind_switch),
14919 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14920 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14921 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14922 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14923 { } /* end */
14924};
14925
14926static struct snd_kcontrol_new alc662_1bjd_mixer[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020014927 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14928 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020014929 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
14930 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14931 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14932 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14933 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14934 { } /* end */
14935};
14936
14937static struct hda_bind_ctls alc663_asus_two_bind_master_vol = {
14938 .ops = &snd_hda_bind_vol,
14939 .values = {
14940 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
14941 HDA_COMPOSE_AMP_VAL(0x04, 3, 0, HDA_OUTPUT),
14942 0
14943 },
14944};
14945
14946static struct hda_bind_ctls alc663_asus_two_bind_switch = {
14947 .ops = &snd_hda_bind_sw,
14948 .values = {
14949 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
14950 HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT),
14951 0
14952 },
14953};
14954
14955static struct snd_kcontrol_new alc663_asus_21jd_clfe_mixer[] = {
14956 HDA_BIND_VOL("Master Playback Volume",
14957 &alc663_asus_two_bind_master_vol),
14958 HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
14959 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020014960 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
14961 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14962 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020014963 { } /* end */
14964};
14965
14966static struct snd_kcontrol_new alc663_asus_15jd_clfe_mixer[] = {
14967 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
14968 HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
14969 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
14970 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
14971 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14972 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020014973 { } /* end */
14974};
14975
14976static struct snd_kcontrol_new alc663_g71v_mixer[] = {
14977 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14978 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
14979 HDA_CODEC_VOLUME("Front Playback Volume", 0x03, 0x0, HDA_OUTPUT),
14980 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
14981 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
14982
14983 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14984 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14985 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14986 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14987 { } /* end */
14988};
14989
14990static struct snd_kcontrol_new alc663_g50v_mixer[] = {
14991 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14992 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
14993 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
14994
14995 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14996 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
14997 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
14998 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
14999 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
15000 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
15001 { } /* end */
15002};
15003
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015004static struct snd_kcontrol_new alc662_chmode_mixer[] = {
15005 {
15006 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
15007 .name = "Channel Mode",
15008 .info = alc_ch_mode_info,
15009 .get = alc_ch_mode_get,
15010 .put = alc_ch_mode_put,
15011 },
15012 { } /* end */
15013};
15014
15015static struct hda_verb alc662_init_verbs[] = {
15016 /* ADC: mute amp left and right */
15017 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15018 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
15019 /* Front mixer: unmute input/output amp left and right (volume = 0) */
15020
Takashi Iwaicb53c622007-08-10 17:21:45 +020015021 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15022 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15023 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
15024 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
15025 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015026
Kailang Yangb60dd392007-09-20 12:50:29 +020015027 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15028 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15029 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15030 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15031 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15032 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015033
15034 /* Front Pin: output 0 (0x0c) */
15035 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
15036 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15037
15038 /* Rear Pin: output 1 (0x0d) */
15039 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
15040 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15041
15042 /* CLFE Pin: output 2 (0x0e) */
15043 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
15044 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15045
15046 /* Mic (rear) pin: input vref at 80% */
15047 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
15048 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15049 /* Front Mic pin: input vref at 80% */
15050 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
15051 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15052 /* Line In pin: input */
15053 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15054 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15055 /* Line-2 In: Headphone output (output 0 - 0x0c) */
15056 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15057 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15058 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
15059 /* CD pin widget for input */
15060 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15061
15062 /* FIXME: use matrix-type input source selection */
15063 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
15064 /* Input mixer */
15065 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15066 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15067 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15068 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Kailang Yang291702f2007-10-16 14:28:03 +020015069
15070 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15071 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15072 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15073 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Kailang Yang6dda9f42008-05-27 12:05:31 +020015074
15075 /* always trun on EAPD */
15076 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
15077 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
15078
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015079 { }
15080};
15081
15082static struct hda_verb alc662_sue_init_verbs[] = {
15083 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
15084 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
Kailang Yang291702f2007-10-16 14:28:03 +020015085 {}
15086};
15087
15088static struct hda_verb alc662_eeepc_sue_init_verbs[] = {
15089 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15090 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15091 {}
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015092};
15093
Kailang Yang8c427222008-01-10 13:03:59 +010015094/* Set Unsolicited Event*/
15095static struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = {
15096 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
15097 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15098 {}
15099};
15100
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015101/*
15102 * generic initialization of ADC, input mixers and output mixers
15103 */
15104static struct hda_verb alc662_auto_init_verbs[] = {
15105 /*
15106 * Unmute ADC and set the default input to mic-in
15107 */
15108 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
15109 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15110
15111 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
15112 * mixer widget
15113 * Note: PASD motherboards uses the Line In 2 as the input for front
15114 * panel mic (mic 2)
15115 */
15116 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020015117 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15118 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15119 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
15120 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
15121 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015122
15123 /*
15124 * Set up output mixers (0x0c - 0x0f)
15125 */
15126 /* set vol=0 to output mixers */
15127 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
15128 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
15129 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
15130
15131 /* set up input amps for analog loopback */
15132 /* Amp Indices: DAC = 0, mixer = 1 */
Kailang Yangb60dd392007-09-20 12:50:29 +020015133 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15134 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15135 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15136 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15137 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15138 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015139
15140
15141 /* FIXME: use matrix-type input source selection */
15142 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
15143 /* Input mixer */
15144 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangd1a991a2007-08-15 16:21:59 +020015145 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015146 { }
15147};
15148
Takashi Iwai24fb9172008-09-02 14:48:20 +020015149/* additional verbs for ALC663 */
15150static struct hda_verb alc663_auto_init_verbs[] = {
15151 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15152 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15153 { }
15154};
15155
Kailang Yang6dda9f42008-05-27 12:05:31 +020015156static struct hda_verb alc663_m51va_init_verbs[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020015157 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15158 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yang6dda9f42008-05-27 12:05:31 +020015159 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15160 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangf1d4e282008-08-26 14:03:29 +020015161 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
15162 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15163 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
Kailang Yang6dda9f42008-05-27 12:05:31 +020015164 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15165 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15166 {}
15167};
15168
Kailang Yangf1d4e282008-08-26 14:03:29 +020015169static struct hda_verb alc663_21jd_amic_init_verbs[] = {
15170 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15171 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15172 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
15173 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15174 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15175 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15176 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15177 {}
15178};
15179
15180static struct hda_verb alc662_1bjd_amic_init_verbs[] = {
15181 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15182 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15183 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15184 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
15185 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15186 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15187 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15188 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15189 {}
15190};
15191
15192static struct hda_verb alc663_15jd_amic_init_verbs[] = {
15193 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15194 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15195 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
15196 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15197 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15198 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15199 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15200 {}
15201};
15202
15203static struct hda_verb alc663_two_hp_amic_m1_init_verbs[] = {
15204 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15205 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15206 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15207 {0x21, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */
15208 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15209 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15210 {0x15, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */
15211 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15212 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15213 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15214 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15215 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15216 {}
15217};
15218
15219static struct hda_verb alc663_two_hp_amic_m2_init_verbs[] = {
15220 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15221 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15222 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15223 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
15224 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15225 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15226 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
15227 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15228 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15229 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15230 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15231 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15232 {}
15233};
15234
Kailang Yang6dda9f42008-05-27 12:05:31 +020015235static struct hda_verb alc663_g71v_init_verbs[] = {
15236 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15237 /* {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
15238 /* {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, */ /* Headphone */
15239
15240 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15241 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15242 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
15243
15244 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
15245 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_MIC_EVENT},
15246 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
15247 {}
15248};
15249
15250static struct hda_verb alc663_g50v_init_verbs[] = {
15251 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15252 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15253 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
15254
15255 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15256 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15257 {}
15258};
15259
Kailang Yangf1d4e282008-08-26 14:03:29 +020015260static struct hda_verb alc662_ecs_init_verbs[] = {
15261 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
15262 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15263 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
15264 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15265 {}
15266};
15267
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015268/* capture mixer elements */
15269static struct snd_kcontrol_new alc662_capture_mixer[] = {
15270 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
15271 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
15272 {
15273 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
15274 /* The multiple "Capture Source" controls confuse alsamixer
15275 * So call somewhat different..
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015276 */
15277 /* .name = "Capture Source", */
15278 .name = "Input Source",
15279 .count = 1,
Herton Ronaldo Krzesinski6e7939b2007-12-19 17:49:02 +010015280 .info = alc662_mux_enum_info,
15281 .get = alc662_mux_enum_get,
15282 .put = alc662_mux_enum_put,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015283 },
15284 { } /* end */
15285};
15286
Kailang Yangf1d4e282008-08-26 14:03:29 +020015287static struct snd_kcontrol_new alc662_auto_capture_mixer[] = {
15288 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
15289 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
15290 { } /* end */
15291};
15292
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015293static void alc662_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
15294{
15295 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015296 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015297
15298 present = snd_hda_codec_read(codec, 0x14, 0,
15299 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020015300 bits = present ? HDA_AMP_MUTE : 0;
15301 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
15302 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015303}
15304
15305static void alc662_lenovo_101e_all_automute(struct hda_codec *codec)
15306{
15307 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015308 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015309
15310 present = snd_hda_codec_read(codec, 0x1b, 0,
15311 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
Takashi Iwai47fd8302007-08-10 17:11:07 +020015312 bits = present ? HDA_AMP_MUTE : 0;
15313 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
15314 HDA_AMP_MUTE, bits);
15315 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
15316 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015317}
15318
15319static void alc662_lenovo_101e_unsol_event(struct hda_codec *codec,
15320 unsigned int res)
15321{
15322 if ((res >> 26) == ALC880_HP_EVENT)
15323 alc662_lenovo_101e_all_automute(codec);
15324 if ((res >> 26) == ALC880_FRONT_EVENT)
15325 alc662_lenovo_101e_ispeaker_automute(codec);
15326}
15327
Kailang Yang291702f2007-10-16 14:28:03 +020015328static void alc662_eeepc_mic_automute(struct hda_codec *codec)
15329{
15330 unsigned int present;
15331
15332 present = snd_hda_codec_read(codec, 0x18, 0,
15333 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
15334 snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
15335 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
15336 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
15337 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
15338 snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
15339 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
15340 snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
15341 0x7000 | (0x01 << 8) | (present ? 0x80 : 0));
15342}
15343
15344/* unsolicited event for HP jack sensing */
15345static void alc662_eeepc_unsol_event(struct hda_codec *codec,
15346 unsigned int res)
15347{
15348 if ((res >> 26) == ALC880_HP_EVENT)
15349 alc262_hippo1_automute( codec );
15350
15351 if ((res >> 26) == ALC880_MIC_EVENT)
15352 alc662_eeepc_mic_automute(codec);
15353}
15354
15355static void alc662_eeepc_inithook(struct hda_codec *codec)
15356{
15357 alc262_hippo1_automute( codec );
15358 alc662_eeepc_mic_automute(codec);
15359}
15360
Kailang Yang8c427222008-01-10 13:03:59 +010015361static void alc662_eeepc_ep20_automute(struct hda_codec *codec)
15362{
15363 unsigned int mute;
15364 unsigned int present;
15365
15366 snd_hda_codec_read(codec, 0x14, 0, AC_VERB_SET_PIN_SENSE, 0);
15367 present = snd_hda_codec_read(codec, 0x14, 0,
15368 AC_VERB_GET_PIN_SENSE, 0);
15369 present = (present & 0x80000000) != 0;
15370 if (present) {
15371 /* mute internal speaker */
15372 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +020015373 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yang8c427222008-01-10 13:03:59 +010015374 } else {
15375 /* unmute internal speaker if necessary */
15376 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
15377 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +020015378 HDA_AMP_MUTE, mute);
Kailang Yang8c427222008-01-10 13:03:59 +010015379 }
15380}
15381
15382/* unsolicited event for HP jack sensing */
15383static void alc662_eeepc_ep20_unsol_event(struct hda_codec *codec,
15384 unsigned int res)
15385{
15386 if ((res >> 26) == ALC880_HP_EVENT)
15387 alc662_eeepc_ep20_automute(codec);
15388}
15389
15390static void alc662_eeepc_ep20_inithook(struct hda_codec *codec)
15391{
15392 alc662_eeepc_ep20_automute(codec);
15393}
15394
Kailang Yang6dda9f42008-05-27 12:05:31 +020015395static void alc663_m51va_speaker_automute(struct hda_codec *codec)
15396{
15397 unsigned int present;
15398 unsigned char bits;
15399
15400 present = snd_hda_codec_read(codec, 0x21, 0,
Kailang Yangf1d4e282008-08-26 14:03:29 +020015401 AC_VERB_GET_PIN_SENSE, 0)
15402 & AC_PINSENSE_PRESENCE;
Kailang Yang6dda9f42008-05-27 12:05:31 +020015403 bits = present ? HDA_AMP_MUTE : 0;
Kailang Yangf1d4e282008-08-26 14:03:29 +020015404 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
15405 AMP_IN_MUTE(0), bits);
15406 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
15407 AMP_IN_MUTE(0), bits);
15408}
15409
15410static void alc663_21jd_two_speaker_automute(struct hda_codec *codec)
15411{
15412 unsigned int present;
15413 unsigned char bits;
15414
15415 present = snd_hda_codec_read(codec, 0x21, 0,
15416 AC_VERB_GET_PIN_SENSE, 0)
15417 & AC_PINSENSE_PRESENCE;
15418 bits = present ? HDA_AMP_MUTE : 0;
15419 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
15420 AMP_IN_MUTE(0), bits);
15421 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
15422 AMP_IN_MUTE(0), bits);
15423 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0,
15424 AMP_IN_MUTE(0), bits);
15425 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1,
15426 AMP_IN_MUTE(0), bits);
15427}
15428
15429static void alc663_15jd_two_speaker_automute(struct hda_codec *codec)
15430{
15431 unsigned int present;
15432 unsigned char bits;
15433
15434 present = snd_hda_codec_read(codec, 0x15, 0,
15435 AC_VERB_GET_PIN_SENSE, 0)
15436 & AC_PINSENSE_PRESENCE;
15437 bits = present ? HDA_AMP_MUTE : 0;
15438 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
15439 AMP_IN_MUTE(0), bits);
15440 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
15441 AMP_IN_MUTE(0), bits);
15442 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0,
15443 AMP_IN_MUTE(0), bits);
15444 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1,
15445 AMP_IN_MUTE(0), bits);
15446}
15447
15448static void alc662_f5z_speaker_automute(struct hda_codec *codec)
15449{
15450 unsigned int present;
15451 unsigned char bits;
15452
15453 present = snd_hda_codec_read(codec, 0x1b, 0,
15454 AC_VERB_GET_PIN_SENSE, 0)
15455 & AC_PINSENSE_PRESENCE;
15456 bits = present ? 0 : PIN_OUT;
15457 snd_hda_codec_write(codec, 0x14, 0,
15458 AC_VERB_SET_PIN_WIDGET_CONTROL, bits);
15459}
15460
15461static void alc663_two_hp_m1_speaker_automute(struct hda_codec *codec)
15462{
15463 unsigned int present1, present2;
15464
15465 present1 = snd_hda_codec_read(codec, 0x21, 0,
15466 AC_VERB_GET_PIN_SENSE, 0)
15467 & AC_PINSENSE_PRESENCE;
15468 present2 = snd_hda_codec_read(codec, 0x15, 0,
15469 AC_VERB_GET_PIN_SENSE, 0)
15470 & AC_PINSENSE_PRESENCE;
15471
15472 if (present1 || present2) {
15473 snd_hda_codec_write_cache(codec, 0x14, 0,
15474 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
15475 } else {
15476 snd_hda_codec_write_cache(codec, 0x14, 0,
15477 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
15478 }
15479}
15480
15481static void alc663_two_hp_m2_speaker_automute(struct hda_codec *codec)
15482{
15483 unsigned int present1, present2;
15484
15485 present1 = snd_hda_codec_read(codec, 0x1b, 0,
15486 AC_VERB_GET_PIN_SENSE, 0)
15487 & AC_PINSENSE_PRESENCE;
15488 present2 = snd_hda_codec_read(codec, 0x15, 0,
15489 AC_VERB_GET_PIN_SENSE, 0)
15490 & AC_PINSENSE_PRESENCE;
15491
15492 if (present1 || present2) {
15493 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
15494 AMP_IN_MUTE(0), AMP_IN_MUTE(0));
15495 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
15496 AMP_IN_MUTE(0), AMP_IN_MUTE(0));
15497 } else {
15498 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
15499 AMP_IN_MUTE(0), 0);
15500 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
15501 AMP_IN_MUTE(0), 0);
15502 }
Kailang Yang6dda9f42008-05-27 12:05:31 +020015503}
15504
15505static void alc663_m51va_mic_automute(struct hda_codec *codec)
15506{
15507 unsigned int present;
15508
15509 present = snd_hda_codec_read(codec, 0x18, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +020015510 AC_VERB_GET_PIN_SENSE, 0)
15511 & AC_PINSENSE_PRESENCE;
Kailang Yang6dda9f42008-05-27 12:05:31 +020015512 snd_hda_codec_write_cache(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangea1fb292008-08-26 12:58:38 +020015513 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
Kailang Yang6dda9f42008-05-27 12:05:31 +020015514 snd_hda_codec_write_cache(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangea1fb292008-08-26 12:58:38 +020015515 0x7000 | (0x00 << 8) | (present ? 0 : 0x80));
Kailang Yang6dda9f42008-05-27 12:05:31 +020015516 snd_hda_codec_write_cache(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangea1fb292008-08-26 12:58:38 +020015517 0x7000 | (0x09 << 8) | (present ? 0x80 : 0));
Kailang Yang6dda9f42008-05-27 12:05:31 +020015518 snd_hda_codec_write_cache(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangea1fb292008-08-26 12:58:38 +020015519 0x7000 | (0x09 << 8) | (present ? 0x80 : 0));
Kailang Yang6dda9f42008-05-27 12:05:31 +020015520}
15521
15522static void alc663_m51va_unsol_event(struct hda_codec *codec,
15523 unsigned int res)
15524{
15525 switch (res >> 26) {
15526 case ALC880_HP_EVENT:
15527 alc663_m51va_speaker_automute(codec);
15528 break;
15529 case ALC880_MIC_EVENT:
15530 alc663_m51va_mic_automute(codec);
15531 break;
15532 }
15533}
15534
15535static void alc663_m51va_inithook(struct hda_codec *codec)
15536{
15537 alc663_m51va_speaker_automute(codec);
15538 alc663_m51va_mic_automute(codec);
15539}
15540
Kailang Yangf1d4e282008-08-26 14:03:29 +020015541/* ***************** Mode1 ******************************/
15542static void alc663_mode1_unsol_event(struct hda_codec *codec,
15543 unsigned int res)
15544{
15545 switch (res >> 26) {
15546 case ALC880_HP_EVENT:
15547 alc663_m51va_speaker_automute(codec);
15548 break;
15549 case ALC880_MIC_EVENT:
15550 alc662_eeepc_mic_automute(codec);
15551 break;
15552 }
15553}
15554
15555static void alc663_mode1_inithook(struct hda_codec *codec)
15556{
15557 alc663_m51va_speaker_automute(codec);
15558 alc662_eeepc_mic_automute(codec);
15559}
15560/* ***************** Mode2 ******************************/
15561static void alc662_mode2_unsol_event(struct hda_codec *codec,
15562 unsigned int res)
15563{
15564 switch (res >> 26) {
15565 case ALC880_HP_EVENT:
15566 alc662_f5z_speaker_automute(codec);
15567 break;
15568 case ALC880_MIC_EVENT:
15569 alc662_eeepc_mic_automute(codec);
15570 break;
15571 }
15572}
15573
15574static void alc662_mode2_inithook(struct hda_codec *codec)
15575{
15576 alc662_f5z_speaker_automute(codec);
15577 alc662_eeepc_mic_automute(codec);
15578}
15579/* ***************** Mode3 ******************************/
15580static void alc663_mode3_unsol_event(struct hda_codec *codec,
15581 unsigned int res)
15582{
15583 switch (res >> 26) {
15584 case ALC880_HP_EVENT:
15585 alc663_two_hp_m1_speaker_automute(codec);
15586 break;
15587 case ALC880_MIC_EVENT:
15588 alc662_eeepc_mic_automute(codec);
15589 break;
15590 }
15591}
15592
15593static void alc663_mode3_inithook(struct hda_codec *codec)
15594{
15595 alc663_two_hp_m1_speaker_automute(codec);
15596 alc662_eeepc_mic_automute(codec);
15597}
15598/* ***************** Mode4 ******************************/
15599static void alc663_mode4_unsol_event(struct hda_codec *codec,
15600 unsigned int res)
15601{
15602 switch (res >> 26) {
15603 case ALC880_HP_EVENT:
15604 alc663_21jd_two_speaker_automute(codec);
15605 break;
15606 case ALC880_MIC_EVENT:
15607 alc662_eeepc_mic_automute(codec);
15608 break;
15609 }
15610}
15611
15612static void alc663_mode4_inithook(struct hda_codec *codec)
15613{
15614 alc663_21jd_two_speaker_automute(codec);
15615 alc662_eeepc_mic_automute(codec);
15616}
15617/* ***************** Mode5 ******************************/
15618static void alc663_mode5_unsol_event(struct hda_codec *codec,
15619 unsigned int res)
15620{
15621 switch (res >> 26) {
15622 case ALC880_HP_EVENT:
15623 alc663_15jd_two_speaker_automute(codec);
15624 break;
15625 case ALC880_MIC_EVENT:
15626 alc662_eeepc_mic_automute(codec);
15627 break;
15628 }
15629}
15630
15631static void alc663_mode5_inithook(struct hda_codec *codec)
15632{
15633 alc663_15jd_two_speaker_automute(codec);
15634 alc662_eeepc_mic_automute(codec);
15635}
15636/* ***************** Mode6 ******************************/
15637static void alc663_mode6_unsol_event(struct hda_codec *codec,
15638 unsigned int res)
15639{
15640 switch (res >> 26) {
15641 case ALC880_HP_EVENT:
15642 alc663_two_hp_m2_speaker_automute(codec);
15643 break;
15644 case ALC880_MIC_EVENT:
15645 alc662_eeepc_mic_automute(codec);
15646 break;
15647 }
15648}
15649
15650static void alc663_mode6_inithook(struct hda_codec *codec)
15651{
15652 alc663_two_hp_m2_speaker_automute(codec);
15653 alc662_eeepc_mic_automute(codec);
15654}
15655
Kailang Yang6dda9f42008-05-27 12:05:31 +020015656static void alc663_g71v_hp_automute(struct hda_codec *codec)
15657{
15658 unsigned int present;
15659 unsigned char bits;
15660
15661 present = snd_hda_codec_read(codec, 0x21, 0,
15662 AC_VERB_GET_PIN_SENSE, 0)
15663 & AC_PINSENSE_PRESENCE;
15664 bits = present ? HDA_AMP_MUTE : 0;
15665 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
15666 HDA_AMP_MUTE, bits);
15667 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
15668 HDA_AMP_MUTE, bits);
15669}
15670
15671static void alc663_g71v_front_automute(struct hda_codec *codec)
15672{
15673 unsigned int present;
15674 unsigned char bits;
15675
15676 present = snd_hda_codec_read(codec, 0x15, 0,
15677 AC_VERB_GET_PIN_SENSE, 0)
15678 & AC_PINSENSE_PRESENCE;
15679 bits = present ? HDA_AMP_MUTE : 0;
15680 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
15681 HDA_AMP_MUTE, bits);
15682}
15683
15684static void alc663_g71v_unsol_event(struct hda_codec *codec,
15685 unsigned int res)
15686{
15687 switch (res >> 26) {
15688 case ALC880_HP_EVENT:
15689 alc663_g71v_hp_automute(codec);
15690 break;
15691 case ALC880_FRONT_EVENT:
15692 alc663_g71v_front_automute(codec);
15693 break;
15694 case ALC880_MIC_EVENT:
15695 alc662_eeepc_mic_automute(codec);
15696 break;
15697 }
15698}
15699
15700static void alc663_g71v_inithook(struct hda_codec *codec)
15701{
15702 alc663_g71v_front_automute(codec);
15703 alc663_g71v_hp_automute(codec);
15704 alc662_eeepc_mic_automute(codec);
15705}
15706
15707static void alc663_g50v_unsol_event(struct hda_codec *codec,
15708 unsigned int res)
15709{
15710 switch (res >> 26) {
15711 case ALC880_HP_EVENT:
15712 alc663_m51va_speaker_automute(codec);
15713 break;
15714 case ALC880_MIC_EVENT:
15715 alc662_eeepc_mic_automute(codec);
15716 break;
15717 }
15718}
15719
15720static void alc663_g50v_inithook(struct hda_codec *codec)
15721{
15722 alc663_m51va_speaker_automute(codec);
15723 alc662_eeepc_mic_automute(codec);
15724}
15725
Kailang Yangf1d4e282008-08-26 14:03:29 +020015726/* bind hp and internal speaker mute (with plug check) */
15727static int alc662_ecs_master_sw_put(struct snd_kcontrol *kcontrol,
15728 struct snd_ctl_elem_value *ucontrol)
15729{
15730 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
15731 long *valp = ucontrol->value.integer.value;
15732 int change;
15733
15734 change = snd_hda_codec_amp_update(codec, 0x1b, 0, HDA_OUTPUT, 0,
15735 HDA_AMP_MUTE,
15736 valp[0] ? 0 : HDA_AMP_MUTE);
15737 change |= snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0,
15738 HDA_AMP_MUTE,
15739 valp[1] ? 0 : HDA_AMP_MUTE);
15740 if (change)
15741 alc262_hippo1_automute(codec);
15742 return change;
15743}
15744
15745static struct snd_kcontrol_new alc662_ecs_mixer[] = {
15746 HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15747 {
15748 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
15749 .name = "Master Playback Switch",
15750 .info = snd_hda_mixer_amp_switch_info,
15751 .get = snd_hda_mixer_amp_switch_get,
15752 .put = alc662_ecs_master_sw_put,
15753 .private_value = HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
15754 },
15755
15756 HDA_CODEC_VOLUME("e-Mic/LineIn Boost", 0x18, 0, HDA_INPUT),
15757 HDA_CODEC_VOLUME("e-Mic/LineIn Playback Volume", 0x0b, 0x0, HDA_INPUT),
15758 HDA_CODEC_MUTE("e-Mic/LineIn Playback Switch", 0x0b, 0x0, HDA_INPUT),
15759
15760 HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT),
15761 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15762 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
15763 { } /* end */
15764};
15765
Takashi Iwaicb53c622007-08-10 17:21:45 +020015766#ifdef CONFIG_SND_HDA_POWER_SAVE
15767#define alc662_loopbacks alc880_loopbacks
15768#endif
15769
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015770
15771/* pcm configuration: identiacal with ALC880 */
15772#define alc662_pcm_analog_playback alc880_pcm_analog_playback
15773#define alc662_pcm_analog_capture alc880_pcm_analog_capture
15774#define alc662_pcm_digital_playback alc880_pcm_digital_playback
15775#define alc662_pcm_digital_capture alc880_pcm_digital_capture
15776
15777/*
15778 * configuration and preset
15779 */
15780static const char *alc662_models[ALC662_MODEL_LAST] = {
15781 [ALC662_3ST_2ch_DIG] = "3stack-dig",
15782 [ALC662_3ST_6ch_DIG] = "3stack-6ch-dig",
15783 [ALC662_3ST_6ch] = "3stack-6ch",
15784 [ALC662_5ST_DIG] = "6stack-dig",
15785 [ALC662_LENOVO_101E] = "lenovo-101e",
Takashi Iwaib995d762007-10-17 10:41:06 +020015786 [ALC662_ASUS_EEEPC_P701] = "eeepc-p701",
Kailang Yang8c427222008-01-10 13:03:59 +010015787 [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20",
Kailang Yangf1d4e282008-08-26 14:03:29 +020015788 [ALC662_ECS] = "ecs",
Kailang Yang6dda9f42008-05-27 12:05:31 +020015789 [ALC663_ASUS_M51VA] = "m51va",
15790 [ALC663_ASUS_G71V] = "g71v",
15791 [ALC663_ASUS_H13] = "h13",
15792 [ALC663_ASUS_G50V] = "g50v",
Kailang Yangf1d4e282008-08-26 14:03:29 +020015793 [ALC663_ASUS_MODE1] = "asus-mode1",
15794 [ALC662_ASUS_MODE2] = "asus-mode2",
15795 [ALC663_ASUS_MODE3] = "asus-mode3",
15796 [ALC663_ASUS_MODE4] = "asus-mode4",
15797 [ALC663_ASUS_MODE5] = "asus-mode5",
15798 [ALC663_ASUS_MODE6] = "asus-mode6",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015799 [ALC662_AUTO] = "auto",
15800};
15801
15802static struct snd_pci_quirk alc662_cfg_tbl[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020015803 SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M51VA", ALC663_ASUS_M51VA),
Kailang Yang80ffe862008-10-15 11:23:27 +020015804 SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS G50V", ALC663_ASUS_G50V),
Herton Ronaldo Krzesinski3da23ca2008-03-14 12:52:59 +010015805 SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG),
Kailang Yang291702f2007-10-16 14:28:03 +020015806 SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701),
Kailang Yang8c427222008-01-10 13:03:59 +010015807 SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20),
Kailang Yangf1d4e282008-08-26 14:03:29 +020015808 SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC663_ASUS_MODE1),
15809 SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M50Vr", ALC663_ASUS_MODE1),
15810 SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC663_ASUS_MODE1),
15811 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC663_ASUS_MODE1),
15812 SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC663_ASUS_MODE1),
15813 SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS NB", ALC663_ASUS_MODE1),
15814 SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC663_ASUS_MODE1),
15815 SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC663_ASUS_MODE1),
15816 SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC663_ASUS_MODE1),
Kailang Yang80ffe862008-10-15 11:23:27 +020015817 SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC663_ASUS_MODE1),
Kailang Yangf1d4e282008-08-26 14:03:29 +020015818 SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_ASUS_MODE2),
15819 SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_ASUS_MODE2),
15820 SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_ASUS_MODE2),
15821 SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_ASUS_MODE2),
15822 SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_ASUS_MODE2),
15823 SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_ASUS_MODE2),
15824 SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_ASUS_MODE2),
15825 SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_ASUS_MODE2),
15826 SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_ASUS_MODE2),
15827 SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_ASUS_MODE2),
15828 SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_ASUS_MODE2),
15829 SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_ASUS_MODE2),
15830 SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC663_ASUS_MODE3),
15831 SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC663_ASUS_MODE3),
15832 SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC663_ASUS_MODE3),
15833 SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC663_ASUS_MODE3),
15834 SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC663_ASUS_MODE3),
15835 SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC663_ASUS_MODE4),
15836 SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC663_ASUS_MODE5),
15837 SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC663_ASUS_MODE6),
15838 SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC663_ASUS_MODE6),
15839 SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC663_ASUS_MODE6),
Herton Ronaldo Krzesinski95fe5f22008-09-26 23:48:45 -030015840 SND_PCI_QUIRK(0x105b, 0x0d47, "Foxconn 45CMX/45GMX/45CMX-K",
15841 ALC662_3ST_6ch_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010015842 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E),
Kailang Yangf1d4e282008-08-26 14:03:29 +020015843 SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_ECS),
15844 SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS),
Herton Ronaldo Krzesinskicb559742008-09-26 23:47:45 -030015845 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L",
15846 ALC662_3ST_6ch_DIG),
Vedran Miletic19c009a2008-09-29 20:29:25 +020015847 SND_PCI_QUIRK(0x1565, 0x820f, "Biostar TA780G M2+", ALC662_3ST_6ch_DIG),
Takashi Iwai238713d2008-10-05 10:57:39 +020015848 SND_PCI_QUIRK(0x1849, 0x3662, "ASROCK K10N78FullHD-hSLI R3.0",
Vedran Miletic19c009a2008-09-29 20:29:25 +020015849 ALC662_3ST_6ch_DIG),
Kailang Yang6dda9f42008-05-27 12:05:31 +020015850 SND_PCI_QUIRK(0x1854, 0x2000, "ASUS H13-2000", ALC663_ASUS_H13),
15851 SND_PCI_QUIRK(0x1854, 0x2001, "ASUS H13-2001", ALC663_ASUS_H13),
15852 SND_PCI_QUIRK(0x1854, 0x2002, "ASUS H13-2002", ALC663_ASUS_H13),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015853 {}
15854};
15855
15856static struct alc_config_preset alc662_presets[] = {
15857 [ALC662_3ST_2ch_DIG] = {
Kailang Yang291702f2007-10-16 14:28:03 +020015858 .mixers = { alc662_3ST_2ch_mixer, alc662_capture_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015859 .init_verbs = { alc662_init_verbs },
15860 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15861 .dac_nids = alc662_dac_nids,
15862 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015863 .dig_in_nid = ALC662_DIGIN_NID,
15864 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15865 .channel_mode = alc662_3ST_2ch_modes,
15866 .input_mux = &alc662_capture_source,
15867 },
15868 [ALC662_3ST_6ch_DIG] = {
Kailang Yang291702f2007-10-16 14:28:03 +020015869 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer,
15870 alc662_capture_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015871 .init_verbs = { alc662_init_verbs },
15872 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15873 .dac_nids = alc662_dac_nids,
15874 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015875 .dig_in_nid = ALC662_DIGIN_NID,
15876 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
15877 .channel_mode = alc662_3ST_6ch_modes,
15878 .need_dac_fix = 1,
15879 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015880 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015881 [ALC662_3ST_6ch] = {
Kailang Yang291702f2007-10-16 14:28:03 +020015882 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer,
15883 alc662_capture_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015884 .init_verbs = { alc662_init_verbs },
15885 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15886 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015887 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
15888 .channel_mode = alc662_3ST_6ch_modes,
15889 .need_dac_fix = 1,
15890 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015891 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015892 [ALC662_5ST_DIG] = {
Kailang Yang291702f2007-10-16 14:28:03 +020015893 .mixers = { alc662_base_mixer, alc662_chmode_mixer,
15894 alc662_capture_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015895 .init_verbs = { alc662_init_verbs },
15896 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15897 .dac_nids = alc662_dac_nids,
15898 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015899 .dig_in_nid = ALC662_DIGIN_NID,
15900 .num_channel_mode = ARRAY_SIZE(alc662_5stack_modes),
15901 .channel_mode = alc662_5stack_modes,
15902 .input_mux = &alc662_capture_source,
15903 },
15904 [ALC662_LENOVO_101E] = {
Kailang Yang291702f2007-10-16 14:28:03 +020015905 .mixers = { alc662_lenovo_101e_mixer, alc662_capture_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015906 .init_verbs = { alc662_init_verbs, alc662_sue_init_verbs },
15907 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15908 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015909 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15910 .channel_mode = alc662_3ST_2ch_modes,
15911 .input_mux = &alc662_lenovo_101e_capture_source,
15912 .unsol_event = alc662_lenovo_101e_unsol_event,
15913 .init_hook = alc662_lenovo_101e_all_automute,
15914 },
Kailang Yang291702f2007-10-16 14:28:03 +020015915 [ALC662_ASUS_EEEPC_P701] = {
15916 .mixers = { alc662_eeepc_p701_mixer, alc662_capture_mixer },
15917 .init_verbs = { alc662_init_verbs,
15918 alc662_eeepc_sue_init_verbs },
15919 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15920 .dac_nids = alc662_dac_nids,
Kailang Yang291702f2007-10-16 14:28:03 +020015921 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15922 .channel_mode = alc662_3ST_2ch_modes,
15923 .input_mux = &alc662_eeepc_capture_source,
15924 .unsol_event = alc662_eeepc_unsol_event,
15925 .init_hook = alc662_eeepc_inithook,
15926 },
Kailang Yang8c427222008-01-10 13:03:59 +010015927 [ALC662_ASUS_EEEPC_EP20] = {
15928 .mixers = { alc662_eeepc_ep20_mixer, alc662_capture_mixer,
15929 alc662_chmode_mixer },
15930 .init_verbs = { alc662_init_verbs,
15931 alc662_eeepc_ep20_sue_init_verbs },
15932 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15933 .dac_nids = alc662_dac_nids,
Kailang Yang8c427222008-01-10 13:03:59 +010015934 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
15935 .channel_mode = alc662_3ST_6ch_modes,
15936 .input_mux = &alc662_lenovo_101e_capture_source,
15937 .unsol_event = alc662_eeepc_ep20_unsol_event,
15938 .init_hook = alc662_eeepc_ep20_inithook,
15939 },
Kailang Yangf1d4e282008-08-26 14:03:29 +020015940 [ALC662_ECS] = {
15941 .mixers = { alc662_ecs_mixer, alc662_capture_mixer },
15942 .init_verbs = { alc662_init_verbs,
15943 alc662_ecs_init_verbs },
15944 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15945 .dac_nids = alc662_dac_nids,
15946 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15947 .channel_mode = alc662_3ST_2ch_modes,
15948 .input_mux = &alc662_eeepc_capture_source,
15949 .unsol_event = alc662_eeepc_unsol_event,
15950 .init_hook = alc662_eeepc_inithook,
15951 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020015952 [ALC663_ASUS_M51VA] = {
15953 .mixers = { alc663_m51va_mixer, alc662_capture_mixer},
15954 .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
15955 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15956 .dac_nids = alc662_dac_nids,
15957 .dig_out_nid = ALC662_DIGOUT_NID,
15958 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15959 .channel_mode = alc662_3ST_2ch_modes,
15960 .input_mux = &alc663_m51va_capture_source,
15961 .unsol_event = alc663_m51va_unsol_event,
15962 .init_hook = alc663_m51va_inithook,
15963 },
15964 [ALC663_ASUS_G71V] = {
15965 .mixers = { alc663_g71v_mixer, alc662_capture_mixer},
15966 .init_verbs = { alc662_init_verbs, alc663_g71v_init_verbs },
15967 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15968 .dac_nids = alc662_dac_nids,
15969 .dig_out_nid = ALC662_DIGOUT_NID,
15970 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15971 .channel_mode = alc662_3ST_2ch_modes,
15972 .input_mux = &alc662_eeepc_capture_source,
15973 .unsol_event = alc663_g71v_unsol_event,
15974 .init_hook = alc663_g71v_inithook,
15975 },
15976 [ALC663_ASUS_H13] = {
15977 .mixers = { alc663_m51va_mixer, alc662_capture_mixer},
15978 .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
15979 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15980 .dac_nids = alc662_dac_nids,
15981 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
15982 .channel_mode = alc662_3ST_2ch_modes,
15983 .input_mux = &alc663_m51va_capture_source,
15984 .unsol_event = alc663_m51va_unsol_event,
15985 .init_hook = alc663_m51va_inithook,
15986 },
15987 [ALC663_ASUS_G50V] = {
15988 .mixers = { alc663_g50v_mixer, alc662_capture_mixer},
15989 .init_verbs = { alc662_init_verbs, alc663_g50v_init_verbs },
15990 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
15991 .dac_nids = alc662_dac_nids,
15992 .dig_out_nid = ALC662_DIGOUT_NID,
15993 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
15994 .channel_mode = alc662_3ST_6ch_modes,
15995 .input_mux = &alc663_capture_source,
15996 .unsol_event = alc663_g50v_unsol_event,
15997 .init_hook = alc663_g50v_inithook,
15998 },
Kailang Yangf1d4e282008-08-26 14:03:29 +020015999 [ALC663_ASUS_MODE1] = {
16000 .mixers = { alc663_m51va_mixer, alc662_auto_capture_mixer },
16001 .init_verbs = { alc662_init_verbs,
16002 alc663_21jd_amic_init_verbs },
16003 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16004 .hp_nid = 0x03,
16005 .dac_nids = alc662_dac_nids,
16006 .dig_out_nid = ALC662_DIGOUT_NID,
16007 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16008 .channel_mode = alc662_3ST_2ch_modes,
16009 .input_mux = &alc662_eeepc_capture_source,
16010 .unsol_event = alc663_mode1_unsol_event,
16011 .init_hook = alc663_mode1_inithook,
16012 },
16013 [ALC662_ASUS_MODE2] = {
16014 .mixers = { alc662_1bjd_mixer, alc662_auto_capture_mixer },
16015 .init_verbs = { alc662_init_verbs,
16016 alc662_1bjd_amic_init_verbs },
16017 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16018 .dac_nids = alc662_dac_nids,
16019 .dig_out_nid = ALC662_DIGOUT_NID,
16020 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16021 .channel_mode = alc662_3ST_2ch_modes,
16022 .input_mux = &alc662_eeepc_capture_source,
16023 .unsol_event = alc662_mode2_unsol_event,
16024 .init_hook = alc662_mode2_inithook,
16025 },
16026 [ALC663_ASUS_MODE3] = {
16027 .mixers = { alc663_two_hp_m1_mixer, alc662_auto_capture_mixer },
16028 .init_verbs = { alc662_init_verbs,
16029 alc663_two_hp_amic_m1_init_verbs },
16030 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16031 .hp_nid = 0x03,
16032 .dac_nids = alc662_dac_nids,
16033 .dig_out_nid = ALC662_DIGOUT_NID,
16034 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16035 .channel_mode = alc662_3ST_2ch_modes,
16036 .input_mux = &alc662_eeepc_capture_source,
16037 .unsol_event = alc663_mode3_unsol_event,
16038 .init_hook = alc663_mode3_inithook,
16039 },
16040 [ALC663_ASUS_MODE4] = {
16041 .mixers = { alc663_asus_21jd_clfe_mixer,
16042 alc662_auto_capture_mixer},
16043 .init_verbs = { alc662_init_verbs,
16044 alc663_21jd_amic_init_verbs},
16045 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16046 .hp_nid = 0x03,
16047 .dac_nids = alc662_dac_nids,
16048 .dig_out_nid = ALC662_DIGOUT_NID,
16049 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16050 .channel_mode = alc662_3ST_2ch_modes,
16051 .input_mux = &alc662_eeepc_capture_source,
16052 .unsol_event = alc663_mode4_unsol_event,
16053 .init_hook = alc663_mode4_inithook,
16054 },
16055 [ALC663_ASUS_MODE5] = {
16056 .mixers = { alc663_asus_15jd_clfe_mixer,
16057 alc662_auto_capture_mixer },
16058 .init_verbs = { alc662_init_verbs,
16059 alc663_15jd_amic_init_verbs },
16060 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16061 .hp_nid = 0x03,
16062 .dac_nids = alc662_dac_nids,
16063 .dig_out_nid = ALC662_DIGOUT_NID,
16064 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16065 .channel_mode = alc662_3ST_2ch_modes,
16066 .input_mux = &alc662_eeepc_capture_source,
16067 .unsol_event = alc663_mode5_unsol_event,
16068 .init_hook = alc663_mode5_inithook,
16069 },
16070 [ALC663_ASUS_MODE6] = {
16071 .mixers = { alc663_two_hp_m2_mixer, alc662_auto_capture_mixer },
16072 .init_verbs = { alc662_init_verbs,
16073 alc663_two_hp_amic_m2_init_verbs },
16074 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
16075 .hp_nid = 0x03,
16076 .dac_nids = alc662_dac_nids,
16077 .dig_out_nid = ALC662_DIGOUT_NID,
16078 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
16079 .channel_mode = alc662_3ST_2ch_modes,
16080 .input_mux = &alc662_eeepc_capture_source,
16081 .unsol_event = alc663_mode6_unsol_event,
16082 .init_hook = alc663_mode6_inithook,
16083 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016084};
16085
16086
16087/*
16088 * BIOS auto configuration
16089 */
16090
16091/* add playback controls from the parsed DAC table */
16092static int alc662_auto_create_multi_out_ctls(struct alc_spec *spec,
16093 const struct auto_pin_cfg *cfg)
16094{
16095 char name[32];
16096 static const char *chname[4] = {
16097 "Front", "Surround", NULL /*CLFE*/, "Side"
16098 };
16099 hda_nid_t nid;
16100 int i, err;
16101
16102 for (i = 0; i < cfg->line_outs; i++) {
16103 if (!spec->multiout.dac_nids[i])
16104 continue;
Kailang Yangb60dd392007-09-20 12:50:29 +020016105 nid = alc880_idx_to_dac(i);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016106 if (i == 2) {
16107 /* Center/LFE */
16108 err = add_control(spec, ALC_CTL_WIDGET_VOL,
16109 "Center Playback Volume",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016110 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
16111 HDA_OUTPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016112 if (err < 0)
16113 return err;
16114 err = add_control(spec, ALC_CTL_WIDGET_VOL,
16115 "LFE Playback Volume",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016116 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
16117 HDA_OUTPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016118 if (err < 0)
16119 return err;
Herton Ronaldo Krzesinskib69ce012008-09-18 16:41:49 -030016120 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016121 "Center Playback Switch",
Herton Ronaldo Krzesinskib69ce012008-09-18 16:41:49 -030016122 HDA_COMPOSE_AMP_VAL(0x0e, 1, 0,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016123 HDA_INPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016124 if (err < 0)
16125 return err;
Herton Ronaldo Krzesinskib69ce012008-09-18 16:41:49 -030016126 err = add_control(spec, ALC_CTL_WIDGET_MUTE,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016127 "LFE Playback Switch",
Herton Ronaldo Krzesinskib69ce012008-09-18 16:41:49 -030016128 HDA_COMPOSE_AMP_VAL(0x0e, 2, 0,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016129 HDA_INPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016130 if (err < 0)
16131 return err;
16132 } else {
16133 sprintf(name, "%s Playback Volume", chname[i]);
16134 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016135 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
16136 HDA_OUTPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016137 if (err < 0)
16138 return err;
16139 sprintf(name, "%s Playback Switch", chname[i]);
Herton Ronaldo Krzesinskib69ce012008-09-18 16:41:49 -030016140 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
16141 HDA_COMPOSE_AMP_VAL(alc880_idx_to_mixer(i),
16142 3, 0, HDA_INPUT));
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016143 if (err < 0)
16144 return err;
16145 }
16146 }
16147 return 0;
16148}
16149
16150/* add playback controls for speaker and HP outputs */
16151static int alc662_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
16152 const char *pfx)
16153{
16154 hda_nid_t nid;
16155 int err;
16156 char name[32];
16157
16158 if (!pin)
16159 return 0;
16160
Takashi Iwai24fb9172008-09-02 14:48:20 +020016161 if (pin == 0x17) {
16162 /* ALC663 has a mono output pin on 0x17 */
16163 sprintf(name, "%s Playback Switch", pfx);
16164 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
16165 HDA_COMPOSE_AMP_VAL(pin, 2, 0, HDA_OUTPUT));
16166 return err;
16167 }
16168
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016169 if (alc880_is_fixed_pin(pin)) {
16170 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
16171 /* printk("DAC nid=%x\n",nid); */
16172 /* specify the DAC as the extra output */
16173 if (!spec->multiout.hp_nid)
16174 spec->multiout.hp_nid = nid;
16175 else
16176 spec->multiout.extra_out_nid[0] = nid;
16177 /* control HP volume/switch on the output mixer amp */
16178 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
16179 sprintf(name, "%s Playback Volume", pfx);
16180 err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
16181 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
16182 if (err < 0)
16183 return err;
16184 sprintf(name, "%s Playback Switch", pfx);
16185 err = add_control(spec, ALC_CTL_BIND_MUTE, name,
16186 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
16187 if (err < 0)
16188 return err;
16189 } else if (alc880_is_multi_pin(pin)) {
16190 /* set manual connection */
16191 /* we have only a switch on HP-out PIN */
16192 sprintf(name, "%s Playback Switch", pfx);
16193 err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
16194 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
16195 if (err < 0)
16196 return err;
16197 }
16198 return 0;
16199}
16200
16201/* create playback/capture controls for input pins */
16202static int alc662_auto_create_analog_input_ctls(struct alc_spec *spec,
16203 const struct auto_pin_cfg *cfg)
16204{
16205 struct hda_input_mux *imux = &spec->private_imux;
16206 int i, err, idx;
16207
16208 for (i = 0; i < AUTO_PIN_LAST; i++) {
16209 if (alc880_is_input_pin(cfg->input_pins[i])) {
16210 idx = alc880_input_pin_idx(cfg->input_pins[i]);
16211 err = new_analog_input(spec, cfg->input_pins[i],
16212 auto_pin_cfg_labels[i],
16213 idx, 0x0b);
16214 if (err < 0)
16215 return err;
16216 imux->items[imux->num_items].label =
16217 auto_pin_cfg_labels[i];
16218 imux->items[imux->num_items].index =
16219 alc880_input_pin_idx(cfg->input_pins[i]);
16220 imux->num_items++;
16221 }
16222 }
16223 return 0;
16224}
16225
16226static void alc662_auto_set_output_and_unmute(struct hda_codec *codec,
16227 hda_nid_t nid, int pin_type,
16228 int dac_idx)
16229{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016230 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016231 /* need the manual connection? */
16232 if (alc880_is_multi_pin(nid)) {
16233 struct alc_spec *spec = codec->spec;
16234 int idx = alc880_multi_pin_idx(nid);
16235 snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
16236 AC_VERB_SET_CONNECT_SEL,
16237 alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
16238 }
16239}
16240
16241static void alc662_auto_init_multi_out(struct hda_codec *codec)
16242{
16243 struct alc_spec *spec = codec->spec;
16244 int i;
16245
Kailang Yang8c427222008-01-10 13:03:59 +010016246 alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016247 for (i = 0; i <= HDA_SIDE; i++) {
16248 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020016249 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016250 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020016251 alc662_auto_set_output_and_unmute(codec, nid, pin_type,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016252 i);
16253 }
16254}
16255
16256static void alc662_auto_init_hp_out(struct hda_codec *codec)
16257{
16258 struct alc_spec *spec = codec->spec;
16259 hda_nid_t pin;
16260
16261 pin = spec->autocfg.hp_pins[0];
16262 if (pin) /* connect to front */
16263 /* use dac 0 */
16264 alc662_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016265 pin = spec->autocfg.speaker_pins[0];
16266 if (pin)
16267 alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016268}
16269
16270#define alc662_is_input_pin(nid) alc880_is_input_pin(nid)
16271#define ALC662_PIN_CD_NID ALC880_PIN_CD_NID
16272
16273static void alc662_auto_init_analog_input(struct hda_codec *codec)
16274{
16275 struct alc_spec *spec = codec->spec;
16276 int i;
16277
16278 for (i = 0; i < AUTO_PIN_LAST; i++) {
16279 hda_nid_t nid = spec->autocfg.input_pins[i];
16280 if (alc662_is_input_pin(nid)) {
16281 snd_hda_codec_write(codec, nid, 0,
16282 AC_VERB_SET_PIN_WIDGET_CONTROL,
16283 (i <= AUTO_PIN_FRONT_MIC ?
16284 PIN_VREF80 : PIN_IN));
16285 if (nid != ALC662_PIN_CD_NID)
16286 snd_hda_codec_write(codec, nid, 0,
16287 AC_VERB_SET_AMP_GAIN_MUTE,
16288 AMP_OUT_MUTE);
16289 }
16290 }
16291}
16292
Takashi Iwaif511b012008-08-15 16:46:42 +020016293#define alc662_auto_init_input_src alc882_auto_init_input_src
16294
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016295static int alc662_parse_auto_config(struct hda_codec *codec)
16296{
16297 struct alc_spec *spec = codec->spec;
16298 int err;
16299 static hda_nid_t alc662_ignore[] = { 0x1d, 0 };
16300
16301 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
16302 alc662_ignore);
16303 if (err < 0)
16304 return err;
16305 if (!spec->autocfg.line_outs)
16306 return 0; /* can't find valid BIOS pin config */
16307
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016308 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
16309 if (err < 0)
16310 return err;
16311 err = alc662_auto_create_multi_out_ctls(spec, &spec->autocfg);
16312 if (err < 0)
16313 return err;
16314 err = alc662_auto_create_extra_out(spec,
16315 spec->autocfg.speaker_pins[0],
16316 "Speaker");
16317 if (err < 0)
16318 return err;
16319 err = alc662_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
16320 "Headphone");
16321 if (err < 0)
16322 return err;
16323 err = alc662_auto_create_analog_input_ctls(spec, &spec->autocfg);
16324 if (err < 0)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016325 return err;
16326
16327 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
16328
16329 if (spec->autocfg.dig_out_pin)
16330 spec->multiout.dig_out_nid = ALC880_DIGOUT_NID;
16331
Takashi Iwai603c4012008-07-30 15:01:44 +020016332 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010016333 add_mixer(spec, spec->kctls.list);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016334
16335 spec->num_mux_defs = 1;
16336 spec->input_mux = &spec->private_imux;
Kailang Yangea1fb292008-08-26 12:58:38 +020016337
Takashi Iwaid88897e2008-10-31 15:01:37 +010016338 add_verb(spec, alc662_auto_init_verbs);
Takashi Iwai24fb9172008-09-02 14:48:20 +020016339 if (codec->vendor_id == 0x10ec0663)
Takashi Iwaid88897e2008-10-31 15:01:37 +010016340 add_verb(spec, alc663_auto_init_verbs);
Takashi Iwaiee979a142008-09-02 15:42:20 +020016341
16342 err = alc_auto_add_mic_boost(codec);
16343 if (err < 0)
16344 return err;
16345
Takashi Iwaid88897e2008-10-31 15:01:37 +010016346 add_mixer(spec, alc662_capture_mixer);
Takashi Iwaie044c392008-10-27 16:56:24 +010016347
16348 store_pin_configs(codec);
Takashi Iwai8c872862007-06-19 12:11:16 +020016349 return 1;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016350}
16351
16352/* additional initialization for auto-configuration model */
16353static void alc662_auto_init(struct hda_codec *codec)
16354{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016355 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016356 alc662_auto_init_multi_out(codec);
16357 alc662_auto_init_hp_out(codec);
16358 alc662_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020016359 alc662_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016360 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020016361 alc_inithook(codec);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016362}
16363
16364static int patch_alc662(struct hda_codec *codec)
16365{
16366 struct alc_spec *spec;
16367 int err, board_config;
16368
16369 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
16370 if (!spec)
16371 return -ENOMEM;
16372
16373 codec->spec = spec;
16374
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020016375 alc_fix_pll_init(codec, 0x20, 0x04, 15);
16376
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016377 board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST,
16378 alc662_models,
16379 alc662_cfg_tbl);
16380 if (board_config < 0) {
16381 printk(KERN_INFO "hda_codec: Unknown model for ALC662, "
16382 "trying auto-probe from BIOS...\n");
16383 board_config = ALC662_AUTO;
16384 }
16385
16386 if (board_config == ALC662_AUTO) {
16387 /* automatic parse from the BIOS config */
16388 err = alc662_parse_auto_config(codec);
16389 if (err < 0) {
16390 alc_free(codec);
16391 return err;
Takashi Iwai8c872862007-06-19 12:11:16 +020016392 } else if (!err) {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016393 printk(KERN_INFO
16394 "hda_codec: Cannot set up configuration "
16395 "from BIOS. Using base mode...\n");
16396 board_config = ALC662_3ST_2ch_DIG;
16397 }
16398 }
16399
16400 if (board_config != ALC662_AUTO)
16401 setup_preset(spec, &alc662_presets[board_config]);
16402
Kailang Yang6dda9f42008-05-27 12:05:31 +020016403 if (codec->vendor_id == 0x10ec0663) {
16404 spec->stream_name_analog = "ALC663 Analog";
16405 spec->stream_name_digital = "ALC663 Digital";
Kailang Yang01afd412008-10-15 11:22:09 +020016406 } else if (codec->vendor_id == 0x10ec0272) {
16407 spec->stream_name_analog = "ALC272 Analog";
16408 spec->stream_name_digital = "ALC272 Digital";
Kailang Yang6dda9f42008-05-27 12:05:31 +020016409 } else {
16410 spec->stream_name_analog = "ALC662 Analog";
16411 spec->stream_name_digital = "ALC662 Digital";
16412 }
16413
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016414 spec->stream_analog_playback = &alc662_pcm_analog_playback;
16415 spec->stream_analog_capture = &alc662_pcm_analog_capture;
16416
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016417 spec->stream_digital_playback = &alc662_pcm_digital_playback;
16418 spec->stream_digital_capture = &alc662_pcm_digital_capture;
16419
Takashi Iwaie1406342008-02-11 18:32:32 +010016420 spec->adc_nids = alc662_adc_nids;
16421 spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids);
16422 spec->capsrc_nids = alc662_capsrc_nids;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016423
Takashi Iwai2134ea42008-01-10 16:53:55 +010016424 spec->vmaster_nid = 0x02;
16425
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016426 codec->patch_ops = alc_patch_ops;
16427 if (board_config == ALC662_AUTO)
16428 spec->init_hook = alc662_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020016429#ifdef CONFIG_SND_HDA_POWER_SAVE
16430 if (!spec->loopback.amplist)
16431 spec->loopback.amplist = alc662_loopbacks;
16432#endif
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016433
16434 return 0;
16435}
16436
16437/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070016438 * patch entries
16439 */
16440struct hda_codec_preset snd_hda_preset_realtek[] = {
16441 { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
Kailang Yangdf694da2005-12-05 19:42:22 +010016442 { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
Kailang Yangf6a92242007-12-13 16:52:54 +010016443 { .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 },
Kailang Yanga361d842007-06-05 12:30:55 +020016444 { .id = 0x10ec0268, .name = "ALC268", .patch = patch_alc268 },
Kailang Yangf6a92242007-12-13 16:52:54 +010016445 { .id = 0x10ec0269, .name = "ALC269", .patch = patch_alc269 },
Kailang Yang01afd412008-10-15 11:22:09 +020016446 { .id = 0x10ec0272, .name = "ALC272", .patch = patch_alc662 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016447 { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016448 .patch = patch_alc861 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016449 { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
16450 { .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 },
16451 { .id = 0x10ec0862, .name = "ALC861-VD", .patch = patch_alc861vd },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016452 { .id = 0x10ec0662, .rev = 0x100002, .name = "ALC662 rev2",
16453 .patch = patch_alc883 },
16454 { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1",
16455 .patch = patch_alc662 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020016456 { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016457 { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070016458 { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020016459 { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc883 },
Clive Messer669faba2008-09-30 15:49:13 +020016460 { .id = 0x10ec0885, .rev = 0x100101, .name = "ALC889A",
16461 .patch = patch_alc882 }, /* should be patch_alc883() in future */
Takashi Iwaicb308f92008-04-16 14:13:29 +020016462 { .id = 0x10ec0885, .rev = 0x100103, .name = "ALC889A",
Takashi Iwai7943a8a2008-04-16 17:29:09 +020016463 .patch = patch_alc882 }, /* should be patch_alc883() in future */
Kailang Yangdf694da2005-12-05 19:42:22 +010016464 { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
Kailang Yanga385a522008-10-15 11:20:21 +020016465 { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc883 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020016466 { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc883 },
Kailang Yang44426082008-10-15 11:18:05 +020016467 { .id = 0x10ec0888, .rev = 0x100101, .name = "ALC1200",
16468 .patch = patch_alc883 },
Kailang Yangf6a92242007-12-13 16:52:54 +010016469 { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc883 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070016470 {} /* terminator */
16471};