blob: a45199014986b9c264590c59365791de8ca30b83 [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"
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090033#include "hda_beep.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,
Michael Schwingencc959482009-02-22 18:58:45 +010081 ALC260_FAVORIT100,
Jonathan Woithe7cf51e42006-02-09 12:01:26 +010082#ifdef CONFIG_SND_DEBUG
83 ALC260_TEST,
84#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010085 ALC260_AUTO,
Takashi Iwai16ded522005-06-10 19:58:24 +020086 ALC260_MODEL_LAST /* last tag */
Linus Torvalds1da177e2005-04-16 15:20:36 -070087};
88
Kailang Yangdf694da2005-12-05 19:42:22 +010089/* ALC262 models */
90enum {
91 ALC262_BASIC,
Kailang Yangccc656c2006-10-17 12:32:26 +020092 ALC262_HIPPO,
93 ALC262_HIPPO_1,
Takashi Iwai834be882006-03-01 14:16:17 +010094 ALC262_FUJITSU,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020095 ALC262_HP_BPC,
Kailang Yangcd7509a2007-01-26 18:33:17 +010096 ALC262_HP_BPC_D7000_WL,
97 ALC262_HP_BPC_D7000_WF,
Kailang Yang66d2a9d2007-11-14 12:06:21 +010098 ALC262_HP_TC_T5735,
Kailang Yang8c427222008-01-10 13:03:59 +010099 ALC262_HP_RP5700,
Takashi Iwai304dcaa2006-07-25 14:51:16 +0200100 ALC262_BENQ_ED8,
Kailang Yang272a5272007-05-14 11:00:38 +0200101 ALC262_SONY_ASSAMD,
Kailang Yang83c34212007-07-05 11:43:05 +0200102 ALC262_BENQ_T31,
Tobin Davisf651b502007-10-26 12:40:47 +0200103 ALC262_ULTRA,
Jiang zhe0e31daf2008-03-20 12:12:39 +0100104 ALC262_LENOVO_3000,
Pascal Terjane8f9ae22008-08-04 14:36:05 +0200105 ALC262_NEC,
Kailang Yang4e555fe2008-08-26 13:05:55 +0200106 ALC262_TOSHIBA_S06,
Hiroshi Miura9f99a632008-08-28 16:09:06 +0200107 ALC262_TOSHIBA_RX1,
Tony Vroonba340e82009-02-02 19:01:30 +0000108 ALC262_TYAN,
Kailang Yangdf694da2005-12-05 19:42:22 +0100109 ALC262_AUTO,
110 ALC262_MODEL_LAST /* last tag */
111};
112
Kailang Yanga361d842007-06-05 12:30:55 +0200113/* ALC268 models */
114enum {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +0200115 ALC267_QUANTA_IL1,
Kailang Yanga361d842007-06-05 12:30:55 +0200116 ALC268_3ST,
Kailang Yangd1a991a2007-08-15 16:21:59 +0200117 ALC268_TOSHIBA,
Takashi Iwaid2738092007-08-16 14:59:45 +0200118 ALC268_ACER,
Takashi Iwaic238b4f2008-11-05 14:57:20 +0100119 ALC268_ACER_DMIC,
Kailang Yang8ef355d2008-08-26 13:10:22 +0200120 ALC268_ACER_ASPIRE_ONE,
Takashi Iwai3866f0b2008-01-15 12:37:42 +0100121 ALC268_DELL,
Mirco Tischlerf12462c2008-02-04 12:33:59 +0100122 ALC268_ZEPTO,
Jonathan Woithe86c53bd2008-01-08 12:33:19 +0100123#ifdef CONFIG_SND_DEBUG
124 ALC268_TEST,
125#endif
Kailang Yanga361d842007-06-05 12:30:55 +0200126 ALC268_AUTO,
127 ALC268_MODEL_LAST /* last tag */
128};
129
Kailang Yangf6a92242007-12-13 16:52:54 +0100130/* ALC269 models */
131enum {
132 ALC269_BASIC,
Kailang Yang60db6b52008-08-26 13:13:00 +0200133 ALC269_QUANTA_FL1,
Kailang Yangebb83ee2009-12-17 12:23:00 +0100134 ALC269_ASUS_AMIC,
135 ALC269_ASUS_DMIC,
Takashi Iwai26f5df22008-11-03 17:39:46 +0100136 ALC269_FUJITSU,
Tony Vroon64154832008-11-06 15:08:49 +0000137 ALC269_LIFEBOOK,
Kailang Yangf6a92242007-12-13 16:52:54 +0100138 ALC269_AUTO,
139 ALC269_MODEL_LAST /* last tag */
140};
141
Kailang Yangdf694da2005-12-05 19:42:22 +0100142/* ALC861 models */
143enum {
144 ALC861_3ST,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200145 ALC660_3ST,
Kailang Yangdf694da2005-12-05 19:42:22 +0100146 ALC861_3ST_DIG,
147 ALC861_6ST_DIG,
Takashi Iwai22309c32006-08-09 16:57:28 +0200148 ALC861_UNIWILL_M31,
Tobin Davisa53d1ae2006-10-17 12:00:28 +0200149 ALC861_TOSHIBA,
Mariusz Domanski7cdbff92006-10-23 13:42:56 +0200150 ALC861_ASUS,
Takashi Iwai56bb0ca2006-11-22 11:52:52 +0100151 ALC861_ASUS_LAPTOP,
Kailang Yangdf694da2005-12-05 19:42:22 +0100152 ALC861_AUTO,
153 ALC861_MODEL_LAST,
154};
155
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100156/* ALC861-VD models */
157enum {
158 ALC660VD_3ST,
Mike Crash6963f842007-06-25 12:12:51 +0200159 ALC660VD_3ST_DIG,
Takashi Iwai13c94742008-11-05 08:06:08 +0100160 ALC660VD_ASUS_V1S,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100161 ALC861VD_3ST,
162 ALC861VD_3ST_DIG,
163 ALC861VD_6ST_DIG,
Kailang Yangbdd148a2007-05-08 15:19:08 +0200164 ALC861VD_LENOVO,
Kailang Yang272a5272007-05-14 11:00:38 +0200165 ALC861VD_DALLAS,
Kailang Yangd1a991a2007-08-15 16:21:59 +0200166 ALC861VD_HP,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100167 ALC861VD_AUTO,
168 ALC861VD_MODEL_LAST,
169};
170
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200171/* ALC662 models */
172enum {
173 ALC662_3ST_2ch_DIG,
174 ALC662_3ST_6ch_DIG,
175 ALC662_3ST_6ch,
176 ALC662_5ST_DIG,
177 ALC662_LENOVO_101E,
Kailang Yang291702f2007-10-16 14:28:03 +0200178 ALC662_ASUS_EEEPC_P701,
Kailang Yang8c427222008-01-10 13:03:59 +0100179 ALC662_ASUS_EEEPC_EP20,
Kailang Yang6dda9f42008-05-27 12:05:31 +0200180 ALC663_ASUS_M51VA,
181 ALC663_ASUS_G71V,
182 ALC663_ASUS_H13,
183 ALC663_ASUS_G50V,
Kailang Yangf1d4e282008-08-26 14:03:29 +0200184 ALC662_ECS,
185 ALC663_ASUS_MODE1,
186 ALC662_ASUS_MODE2,
187 ALC663_ASUS_MODE3,
188 ALC663_ASUS_MODE4,
189 ALC663_ASUS_MODE5,
190 ALC663_ASUS_MODE6,
Kailang Yangebb83ee2009-12-17 12:23:00 +0100191 ALC663_ASUS_MODE7,
192 ALC663_ASUS_MODE8,
Kailang Yang622e84c2009-04-21 07:39:04 +0200193 ALC272_DELL,
194 ALC272_DELL_ZM1,
Chris Pockelé9541ba12009-05-12 08:08:53 +0200195 ALC272_SAMSUNG_NC10,
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200196 ALC662_AUTO,
197 ALC662_MODEL_LAST,
198};
199
Kailang Yangdf694da2005-12-05 19:42:22 +0100200/* ALC882 models */
201enum {
202 ALC882_3ST_DIG,
203 ALC882_6ST_DIG,
Takashi Iwai4b146cb2006-07-28 14:42:36 +0200204 ALC882_ARIMA,
Kailang Yangbdd148a2007-05-08 15:19:08 +0200205 ALC882_W2JC,
Kailang Yang272a5272007-05-14 11:00:38 +0200206 ALC882_TARGA,
207 ALC882_ASUS_A7J,
Takashi Iwai914759b2007-09-06 14:52:04 +0200208 ALC882_ASUS_A7M,
Tobin Davis9102cd12006-12-15 10:02:12 +0100209 ALC885_MACPRO,
Takashi Iwai87350ad2007-08-16 18:19:38 +0200210 ALC885_MBP3,
Kacper Szczesniak41d55452009-05-07 12:47:43 +0200211 ALC885_MB5,
Nicola Fagnanic54728d2007-07-19 23:28:52 +0200212 ALC885_IMAC24,
Justin P. Mattock4b7e1802009-12-07 15:07:46 -0800213 ALC885_IMAC91,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200214 ALC883_3ST_2ch_DIG,
215 ALC883_3ST_6ch_DIG,
216 ALC883_3ST_6ch,
217 ALC883_6ST_DIG,
Kailang Yangccc656c2006-10-17 12:32:26 +0200218 ALC883_TARGA_DIG,
219 ALC883_TARGA_2ch_DIG,
David Heidelberger64a8be72009-06-08 16:15:18 +0200220 ALC883_TARGA_8ch_DIG,
Vladimir Avdoninbab282b2006-08-22 13:31:58 +0200221 ALC883_ACER,
Tobin Davis2880a862007-08-07 11:50:26 +0200222 ALC883_ACER_ASPIRE,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +0800223 ALC888_ACER_ASPIRE_4930G,
Tony Vroond2fd4b02009-06-21 00:40:10 +0100224 ALC888_ACER_ASPIRE_6530G,
Hector Martin3b315d72009-06-02 10:54:19 +0200225 ALC888_ACER_ASPIRE_8930G,
Denis Kuplyakovfc86f952009-08-25 18:15:59 +0200226 ALC888_ACER_ASPIRE_7730G,
Tobin Davisc07584c2006-10-13 12:32:16 +0200227 ALC883_MEDION,
Kailang Yangea1fb292008-08-26 12:58:38 +0200228 ALC883_MEDION_MD2,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +0100229 ALC883_LAPTOP_EAPD,
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200230 ALC883_LENOVO_101E_2ch,
Kailang Yang272a5272007-05-14 11:00:38 +0200231 ALC883_LENOVO_NB0763,
Kailang Yang189609a2007-08-20 11:31:23 +0200232 ALC888_LENOVO_MS7195_DIG,
Kailang Yange2757d52008-08-26 13:17:46 +0200233 ALC888_LENOVO_SKY,
Kailang Yangea1fb292008-08-26 12:58:38 +0200234 ALC883_HAIER_W66,
Claudio Matsuoka4723c022007-07-13 14:36:19 +0200235 ALC888_3ST_HP,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +0100236 ALC888_6ST_DELL,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +0100237 ALC883_MITAC,
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -0430238 ALC883_CLEVO_M540R,
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +0100239 ALC883_CLEVO_M720,
Jiang zhefb97dc62008-03-06 11:07:11 +0100240 ALC883_FUJITSU_PI2515,
Vincent Petryef8ef5f2008-11-23 11:31:41 +0800241 ALC888_FUJITSU_XA3530,
Jiang zhe17bba1b2008-06-04 12:11:07 +0200242 ALC883_3ST_6ch_INTEL,
Jaroslav Kysela87a8c372009-07-23 10:58:29 +0200243 ALC889A_INTEL,
244 ALC889_INTEL,
Kailang Yange2757d52008-08-26 13:17:46 +0200245 ALC888_ASUS_M90V,
246 ALC888_ASUS_EEE1601,
Torben Schulzeb4c41d2009-05-18 15:02:35 +0200247 ALC889A_MB31,
Wu Fengguang3ab90932008-11-17 09:51:09 +0100248 ALC1200_ASUS_P5Q,
Guido Günther3e1647c2009-06-05 00:47:26 +0200249 ALC883_SONY_VAIO_TT,
Takashi Iwai4953550a2009-06-30 15:28:30 +0200250 ALC882_AUTO,
251 ALC882_MODEL_LAST,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200252};
253
Kailang Yangdf694da2005-12-05 19:42:22 +0100254/* for GPIO Poll */
255#define GPIO_MASK 0x03
256
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200257/* extra amp-initialization sequence types */
258enum {
259 ALC_INIT_NONE,
260 ALC_INIT_DEFAULT,
261 ALC_INIT_GPIO1,
262 ALC_INIT_GPIO2,
263 ALC_INIT_GPIO3,
264};
265
Takashi Iwai6c819492009-08-10 18:47:44 +0200266struct alc_mic_route {
267 hda_nid_t pin;
268 unsigned char mux_idx;
269 unsigned char amix_idx;
270};
271
272#define MUX_IDX_UNDEF ((unsigned char)-1)
273
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274struct alc_spec {
275 /* codec parameterization */
Kailang Yangdf694da2005-12-05 19:42:22 +0100276 struct snd_kcontrol_new *mixers[5]; /* mixer arrays */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 unsigned int num_mixers;
Takashi Iwaif9e336f2008-10-31 16:37:07 +0100278 struct snd_kcontrol_new *cap_mixer; /* capture mixer */
Takashi Iwai45bdd1c2009-02-06 16:11:25 +0100279 unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280
Takashi Iwai2d9c6482009-10-13 08:06:55 +0200281 const struct hda_verb *init_verbs[10]; /* initialization verbs
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200282 * don't forget NULL
283 * termination!
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200284 */
285 unsigned int num_init_verbs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286
Takashi Iwaiaa563af2009-07-31 10:05:11 +0200287 char stream_name_analog[32]; /* analog PCM stream */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 struct hda_pcm_stream *stream_analog_playback;
289 struct hda_pcm_stream *stream_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +0100290 struct hda_pcm_stream *stream_analog_alt_playback;
291 struct hda_pcm_stream *stream_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292
Takashi Iwaiaa563af2009-07-31 10:05:11 +0200293 char stream_name_digital[32]; /* digital PCM stream */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 struct hda_pcm_stream *stream_digital_playback;
295 struct hda_pcm_stream *stream_digital_capture;
296
297 /* playback */
Takashi Iwai16ded522005-06-10 19:58:24 +0200298 struct hda_multi_out multiout; /* playback set-up
299 * max_channels, dacs must be set
300 * dig_out_nid and hp_nid are optional
301 */
Takashi Iwai63300792008-01-24 15:31:36 +0100302 hda_nid_t alt_dac_nid;
Takashi Iwai6a05ac42009-02-13 11:19:09 +0100303 hda_nid_t slave_dig_outs[3]; /* optional - for auto-parsing */
Takashi Iwai8c441982009-01-20 18:30:20 +0100304 int dig_out_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305
306 /* capture */
307 unsigned int num_adc_nids;
308 hda_nid_t *adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100309 hda_nid_t *capsrc_nids;
Takashi Iwai16ded522005-06-10 19:58:24 +0200310 hda_nid_t dig_in_nid; /* digital-in NID; optional */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311
312 /* capture source */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200313 unsigned int num_mux_defs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 const struct hda_input_mux *input_mux;
315 unsigned int cur_mux[3];
Takashi Iwai6c819492009-08-10 18:47:44 +0200316 struct alc_mic_route ext_mic;
317 struct alc_mic_route int_mic;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318
319 /* channel model */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100320 const struct hda_channel_mode *channel_mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 int num_channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200322 int need_dac_fix;
Hector Martin3b315d72009-06-02 10:54:19 +0200323 int const_channel_count;
324 int ext_channel_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325
326 /* PCM information */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100327 struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */
Takashi Iwai41e41f12005-06-08 14:48:49 +0200328
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200329 /* dynamic controls, init_verbs and input_mux */
330 struct auto_pin_cfg autocfg;
Takashi Iwai603c4012008-07-30 15:01:44 +0200331 struct snd_array kctls;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -0200332 struct hda_input_mux private_imux[3];
Takashi Iwai41923e42007-10-22 17:20:10 +0200333 hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
Takashi Iwai4953550a2009-06-30 15:28:30 +0200334 hda_nid_t private_adc_nids[AUTO_CFG_MAX_OUTS];
335 hda_nid_t private_capsrc_nids[AUTO_CFG_MAX_OUTS];
Takashi Iwai834be882006-03-01 14:16:17 +0100336
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100337 /* hooks */
338 void (*init_hook)(struct hda_codec *codec);
339 void (*unsol_event)(struct hda_codec *codec, unsigned int res);
Hector Martinf5de24b2009-12-20 22:51:31 +0100340#ifdef CONFIG_SND_HDA_POWER_SAVE
341 void (*power_hook)(struct hda_codec *codec, int power);
342#endif
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100343
Takashi Iwai834be882006-03-01 14:16:17 +0100344 /* for pin sensing */
345 unsigned int sense_updated: 1;
346 unsigned int jack_present: 1;
Takashi Iwaibec15c32008-01-28 18:16:30 +0100347 unsigned int master_sw: 1;
Takashi Iwai6c819492009-08-10 18:47:44 +0200348 unsigned int auto_mic:1;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200349
Takashi Iwaie64f14f2009-01-20 18:32:55 +0100350 /* other flags */
351 unsigned int no_analog :1; /* digital I/O only */
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200352 int init_amp;
Takashi Iwaie64f14f2009-01-20 18:32:55 +0100353
Takashi Iwai2134ea42008-01-10 16:53:55 +0100354 /* for virtual master */
355 hda_nid_t vmaster_nid;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200356#ifdef CONFIG_SND_HDA_POWER_SAVE
357 struct hda_loopback_check loopback;
358#endif
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +0200359
360 /* for PLL fix */
361 hda_nid_t pll_nid;
362 unsigned int pll_coef_idx, pll_coef_bit;
Kailang Yangdf694da2005-12-05 19:42:22 +0100363};
364
365/*
366 * configuration template - to be copied to the spec instance
367 */
368struct alc_config_preset {
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200369 struct snd_kcontrol_new *mixers[5]; /* should be identical size
370 * with spec
371 */
Takashi Iwaif9e336f2008-10-31 16:37:07 +0100372 struct snd_kcontrol_new *cap_mixer; /* capture mixer */
Kailang Yangdf694da2005-12-05 19:42:22 +0100373 const struct hda_verb *init_verbs[5];
374 unsigned int num_dacs;
375 hda_nid_t *dac_nids;
376 hda_nid_t dig_out_nid; /* optional */
377 hda_nid_t hp_nid; /* optional */
Wu Fengguangb25c9da2009-02-06 15:02:27 +0800378 hda_nid_t *slave_dig_outs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100379 unsigned int num_adc_nids;
380 hda_nid_t *adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100381 hda_nid_t *capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +0100382 hda_nid_t dig_in_nid;
383 unsigned int num_channel_mode;
384 const struct hda_channel_mode *channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200385 int need_dac_fix;
Hector Martin3b315d72009-06-02 10:54:19 +0200386 int const_channel_count;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200387 unsigned int num_mux_defs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100388 const struct hda_input_mux *input_mux;
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100389 void (*unsol_event)(struct hda_codec *, unsigned int);
Takashi Iwaie9c364c2009-08-11 17:16:13 +0200390 void (*setup)(struct hda_codec *);
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100391 void (*init_hook)(struct hda_codec *);
Takashi Iwaicb53c622007-08-10 17:21:45 +0200392#ifdef CONFIG_SND_HDA_POWER_SAVE
393 struct hda_amp_list *loopbacks;
Hector Martinf5de24b2009-12-20 22:51:31 +0100394 void (*power_hook)(struct hda_codec *codec, int power);
Takashi Iwaicb53c622007-08-10 17:21:45 +0200395#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396};
397
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398
399/*
400 * input MUX handling
401 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200402static int alc_mux_enum_info(struct snd_kcontrol *kcontrol,
403 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404{
405 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
406 struct alc_spec *spec = codec->spec;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200407 unsigned int mux_idx = snd_ctl_get_ioffidx(kcontrol, &uinfo->id);
408 if (mux_idx >= spec->num_mux_defs)
409 mux_idx = 0;
410 return snd_hda_input_mux_info(&spec->input_mux[mux_idx], uinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411}
412
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200413static int alc_mux_enum_get(struct snd_kcontrol *kcontrol,
414 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415{
416 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
417 struct alc_spec *spec = codec->spec;
418 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
419
420 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
421 return 0;
422}
423
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200424static int alc_mux_enum_put(struct snd_kcontrol *kcontrol,
425 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426{
427 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
428 struct alc_spec *spec = codec->spec;
Takashi Iwaicd896c32008-11-18 12:36:33 +0100429 const struct hda_input_mux *imux;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Takashi Iwaicd896c32008-11-18 12:36:33 +0100431 unsigned int mux_idx;
Takashi Iwaie1406342008-02-11 18:32:32 +0100432 hda_nid_t nid = spec->capsrc_nids ?
433 spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx];
Takashi Iwai0169b6b2009-06-22 10:50:19 +0200434 unsigned int type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435
Takashi Iwaicd896c32008-11-18 12:36:33 +0100436 mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx;
437 imux = &spec->input_mux[mux_idx];
438
Takashi Iwaia22d5432009-07-27 12:54:26 +0200439 type = get_wcaps_type(get_wcaps(codec, nid));
Takashi Iwai0169b6b2009-06-22 10:50:19 +0200440 if (type == AC_WID_AUD_MIX) {
Takashi Iwai54cbc9a2008-10-31 15:24:04 +0100441 /* Matrix-mixer style (e.g. ALC882) */
442 unsigned int *cur_val = &spec->cur_mux[adc_idx];
443 unsigned int i, idx;
444
445 idx = ucontrol->value.enumerated.item[0];
446 if (idx >= imux->num_items)
447 idx = imux->num_items - 1;
448 if (*cur_val == idx)
449 return 0;
450 for (i = 0; i < imux->num_items; i++) {
451 unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE;
452 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT,
453 imux->items[i].index,
454 HDA_AMP_MUTE, v);
455 }
456 *cur_val = idx;
457 return 1;
458 } else {
459 /* MUX style (e.g. ALC880) */
Takashi Iwaicd896c32008-11-18 12:36:33 +0100460 return snd_hda_input_mux_put(codec, imux, ucontrol, nid,
Takashi Iwai54cbc9a2008-10-31 15:24:04 +0100461 &spec->cur_mux[adc_idx]);
462 }
463}
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200464
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465/*
466 * channel mode setting
467 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200468static int alc_ch_mode_info(struct snd_kcontrol *kcontrol,
469 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470{
471 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
472 struct alc_spec *spec = codec->spec;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100473 return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode,
474 spec->num_channel_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475}
476
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200477static int alc_ch_mode_get(struct snd_kcontrol *kcontrol,
478 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479{
480 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
481 struct alc_spec *spec = codec->spec;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100482 return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200483 spec->num_channel_mode,
Hector Martin3b315d72009-06-02 10:54:19 +0200484 spec->ext_channel_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485}
486
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200487static int alc_ch_mode_put(struct snd_kcontrol *kcontrol,
488 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489{
490 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
491 struct alc_spec *spec = codec->spec;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200492 int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
493 spec->num_channel_mode,
Hector Martin3b315d72009-06-02 10:54:19 +0200494 &spec->ext_channel_count);
495 if (err >= 0 && !spec->const_channel_count) {
496 spec->multiout.max_channels = spec->ext_channel_count;
497 if (spec->need_dac_fix)
498 spec->multiout.num_dacs = spec->multiout.max_channels / 2;
499 }
Takashi Iwai4e195a72006-07-28 14:47:34 +0200500 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501}
502
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503/*
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100504 * Control the mode of pin widget settings via the mixer. "pc" is used
Kailang Yangea1fb292008-08-26 12:58:38 +0200505 * instead of "%" to avoid consequences of accidently treating the % as
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100506 * being part of a format specifier. Maximum allowed length of a value is
507 * 63 characters plus NULL terminator.
Jonathan Woithe7cf51e42006-02-09 12:01:26 +0100508 *
509 * Note: some retasking pin complexes seem to ignore requests for input
510 * states other than HiZ (eg: PIN_VREFxx) and revert to HiZ if any of these
511 * are requested. Therefore order this list so that this behaviour will not
512 * cause problems when mixer clients move through the enum sequentially.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200513 * NIDs 0x0f and 0x10 have been observed to have this behaviour as of
514 * March 2006.
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200515 */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100516static char *alc_pin_mode_names[] = {
Jonathan Woithe7cf51e42006-02-09 12:01:26 +0100517 "Mic 50pc bias", "Mic 80pc bias",
518 "Line in", "Line out", "Headphone out",
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100519};
520static unsigned char alc_pin_mode_values[] = {
Jonathan Woithe7cf51e42006-02-09 12:01:26 +0100521 PIN_VREF50, PIN_VREF80, PIN_IN, PIN_OUT, PIN_HP,
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100522};
523/* The control can present all 5 options, or it can limit the options based
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200524 * in the pin being assumed to be exclusively an input or an output pin. In
525 * addition, "input" pins may or may not process the mic bias option
526 * depending on actual widget capability (NIDs 0x0f and 0x10 don't seem to
527 * accept requests for bias as of chip versions up to March 2006) and/or
528 * wiring in the computer.
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100529 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200530#define ALC_PIN_DIR_IN 0x00
531#define ALC_PIN_DIR_OUT 0x01
532#define ALC_PIN_DIR_INOUT 0x02
533#define ALC_PIN_DIR_IN_NOMICBIAS 0x03
534#define ALC_PIN_DIR_INOUT_NOMICBIAS 0x04
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100535
Kailang Yangea1fb292008-08-26 12:58:38 +0200536/* Info about the pin modes supported by the different pin direction modes.
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100537 * For each direction the minimum and maximum values are given.
538 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200539static signed char alc_pin_mode_dir_info[5][2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100540 { 0, 2 }, /* ALC_PIN_DIR_IN */
541 { 3, 4 }, /* ALC_PIN_DIR_OUT */
542 { 0, 4 }, /* ALC_PIN_DIR_INOUT */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200543 { 2, 2 }, /* ALC_PIN_DIR_IN_NOMICBIAS */
544 { 2, 4 }, /* ALC_PIN_DIR_INOUT_NOMICBIAS */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100545};
546#define alc_pin_mode_min(_dir) (alc_pin_mode_dir_info[_dir][0])
547#define alc_pin_mode_max(_dir) (alc_pin_mode_dir_info[_dir][1])
548#define alc_pin_mode_n_items(_dir) \
549 (alc_pin_mode_max(_dir)-alc_pin_mode_min(_dir)+1)
550
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200551static int alc_pin_mode_info(struct snd_kcontrol *kcontrol,
552 struct snd_ctl_elem_info *uinfo)
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200553{
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100554 unsigned int item_num = uinfo->value.enumerated.item;
555 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
556
557 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200558 uinfo->count = 1;
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100559 uinfo->value.enumerated.items = alc_pin_mode_n_items(dir);
560
561 if (item_num<alc_pin_mode_min(dir) || item_num>alc_pin_mode_max(dir))
562 item_num = alc_pin_mode_min(dir);
563 strcpy(uinfo->value.enumerated.name, alc_pin_mode_names[item_num]);
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200564 return 0;
565}
566
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200567static int alc_pin_mode_get(struct snd_kcontrol *kcontrol,
568 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200569{
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100570 unsigned int i;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200571 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
572 hda_nid_t nid = kcontrol->private_value & 0xffff;
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100573 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200574 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200575 unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
576 AC_VERB_GET_PIN_WIDGET_CONTROL,
577 0x00);
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200578
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100579 /* Find enumerated value for current pinctl setting */
580 i = alc_pin_mode_min(dir);
Roel Kluin4b35d2c2009-08-02 13:30:45 +0200581 while (i <= alc_pin_mode_max(dir) && alc_pin_mode_values[i] != pinctl)
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100582 i++;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200583 *valp = i <= alc_pin_mode_max(dir) ? i: alc_pin_mode_min(dir);
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100584 return 0;
585}
586
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200587static int alc_pin_mode_put(struct snd_kcontrol *kcontrol,
588 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100589{
590 signed int change;
591 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
592 hda_nid_t nid = kcontrol->private_value & 0xffff;
593 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
594 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200595 unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
596 AC_VERB_GET_PIN_WIDGET_CONTROL,
597 0x00);
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100598
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200599 if (val < alc_pin_mode_min(dir) || val > alc_pin_mode_max(dir))
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100600 val = alc_pin_mode_min(dir);
601
602 change = pinctl != alc_pin_mode_values[val];
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100603 if (change) {
604 /* Set pin mode to that requested */
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200605 snd_hda_codec_write_cache(codec, nid, 0,
606 AC_VERB_SET_PIN_WIDGET_CONTROL,
607 alc_pin_mode_values[val]);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100608
Kailang Yangea1fb292008-08-26 12:58:38 +0200609 /* Also enable the retasking pin's input/output as required
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100610 * for the requested pin mode. Enum values of 2 or less are
611 * input modes.
612 *
613 * Dynamically switching the input/output buffers probably
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200614 * reduces noise slightly (particularly on input) so we'll
615 * do it. However, having both input and output buffers
616 * enabled simultaneously doesn't seem to be problematic if
617 * this turns out to be necessary in the future.
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100618 */
619 if (val <= 2) {
Takashi Iwai47fd8302007-08-10 17:11:07 +0200620 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
621 HDA_AMP_MUTE, HDA_AMP_MUTE);
622 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
623 HDA_AMP_MUTE, 0);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100624 } else {
Takashi Iwai47fd8302007-08-10 17:11:07 +0200625 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
626 HDA_AMP_MUTE, HDA_AMP_MUTE);
627 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
628 HDA_AMP_MUTE, 0);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100629 }
630 }
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200631 return change;
632}
633
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100634#define ALC_PIN_MODE(xname, nid, dir) \
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200635 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +0100636 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100637 .info = alc_pin_mode_info, \
638 .get = alc_pin_mode_get, \
639 .put = alc_pin_mode_put, \
640 .private_value = nid | (dir<<16) }
Kailang Yangdf694da2005-12-05 19:42:22 +0100641
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100642/* A switch control for ALC260 GPIO pins. Multiple GPIOs can be ganged
643 * together using a mask with more than one bit set. This control is
644 * currently used only by the ALC260 test model. At this stage they are not
645 * needed for any "production" models.
646 */
647#ifdef CONFIG_SND_DEBUG
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200648#define alc_gpio_data_info snd_ctl_boolean_mono_info
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200649
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200650static int alc_gpio_data_get(struct snd_kcontrol *kcontrol,
651 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100652{
653 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
654 hda_nid_t nid = kcontrol->private_value & 0xffff;
655 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
656 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200657 unsigned int val = snd_hda_codec_read(codec, nid, 0,
658 AC_VERB_GET_GPIO_DATA, 0x00);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100659
660 *valp = (val & mask) != 0;
661 return 0;
662}
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200663static int alc_gpio_data_put(struct snd_kcontrol *kcontrol,
664 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100665{
666 signed int change;
667 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
668 hda_nid_t nid = kcontrol->private_value & 0xffff;
669 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
670 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200671 unsigned int gpio_data = snd_hda_codec_read(codec, nid, 0,
672 AC_VERB_GET_GPIO_DATA,
673 0x00);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100674
675 /* Set/unset the masked GPIO bit(s) as needed */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200676 change = (val == 0 ? 0 : mask) != (gpio_data & mask);
677 if (val == 0)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100678 gpio_data &= ~mask;
679 else
680 gpio_data |= mask;
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200681 snd_hda_codec_write_cache(codec, nid, 0,
682 AC_VERB_SET_GPIO_DATA, gpio_data);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100683
684 return change;
685}
686#define ALC_GPIO_DATA_SWITCH(xname, nid, mask) \
687 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +0100688 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100689 .info = alc_gpio_data_info, \
690 .get = alc_gpio_data_get, \
691 .put = alc_gpio_data_put, \
692 .private_value = nid | (mask<<16) }
693#endif /* CONFIG_SND_DEBUG */
694
Jonathan Woithe92621f12006-02-28 11:47:47 +0100695/* A switch control to allow the enabling of the digital IO pins on the
696 * ALC260. This is incredibly simplistic; the intention of this control is
697 * to provide something in the test model allowing digital outputs to be
698 * identified if present. If models are found which can utilise these
699 * outputs a more complete mixer control can be devised for those models if
700 * necessary.
701 */
702#ifdef CONFIG_SND_DEBUG
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200703#define alc_spdif_ctrl_info snd_ctl_boolean_mono_info
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200704
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200705static int alc_spdif_ctrl_get(struct snd_kcontrol *kcontrol,
706 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe92621f12006-02-28 11:47:47 +0100707{
708 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
709 hda_nid_t nid = kcontrol->private_value & 0xffff;
710 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
711 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200712 unsigned int val = snd_hda_codec_read(codec, nid, 0,
Andrew Paprocki3982d172007-12-19 12:13:44 +0100713 AC_VERB_GET_DIGI_CONVERT_1, 0x00);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100714
715 *valp = (val & mask) != 0;
716 return 0;
717}
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200718static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol,
719 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe92621f12006-02-28 11:47:47 +0100720{
721 signed int change;
722 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
723 hda_nid_t nid = kcontrol->private_value & 0xffff;
724 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
725 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200726 unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
Andrew Paprocki3982d172007-12-19 12:13:44 +0100727 AC_VERB_GET_DIGI_CONVERT_1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200728 0x00);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100729
730 /* Set/unset the masked control bit(s) as needed */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200731 change = (val == 0 ? 0 : mask) != (ctrl_data & mask);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100732 if (val==0)
733 ctrl_data &= ~mask;
734 else
735 ctrl_data |= mask;
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200736 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
737 ctrl_data);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100738
739 return change;
740}
741#define ALC_SPDIF_CTRL_SWITCH(xname, nid, mask) \
742 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +0100743 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Jonathan Woithe92621f12006-02-28 11:47:47 +0100744 .info = alc_spdif_ctrl_info, \
745 .get = alc_spdif_ctrl_get, \
746 .put = alc_spdif_ctrl_put, \
747 .private_value = nid | (mask<<16) }
748#endif /* CONFIG_SND_DEBUG */
749
Jonathan Woithef8225f62008-01-08 12:16:54 +0100750/* A switch control to allow the enabling EAPD digital outputs on the ALC26x.
751 * Again, this is only used in the ALC26x test models to help identify when
752 * the EAPD line must be asserted for features to work.
753 */
754#ifdef CONFIG_SND_DEBUG
755#define alc_eapd_ctrl_info snd_ctl_boolean_mono_info
756
757static int alc_eapd_ctrl_get(struct snd_kcontrol *kcontrol,
758 struct snd_ctl_elem_value *ucontrol)
759{
760 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
761 hda_nid_t nid = kcontrol->private_value & 0xffff;
762 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
763 long *valp = ucontrol->value.integer.value;
764 unsigned int val = snd_hda_codec_read(codec, nid, 0,
765 AC_VERB_GET_EAPD_BTLENABLE, 0x00);
766
767 *valp = (val & mask) != 0;
768 return 0;
769}
770
771static int alc_eapd_ctrl_put(struct snd_kcontrol *kcontrol,
772 struct snd_ctl_elem_value *ucontrol)
773{
774 int change;
775 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
776 hda_nid_t nid = kcontrol->private_value & 0xffff;
777 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
778 long val = *ucontrol->value.integer.value;
779 unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
780 AC_VERB_GET_EAPD_BTLENABLE,
781 0x00);
782
783 /* Set/unset the masked control bit(s) as needed */
784 change = (!val ? 0 : mask) != (ctrl_data & mask);
785 if (!val)
786 ctrl_data &= ~mask;
787 else
788 ctrl_data |= mask;
789 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
790 ctrl_data);
791
792 return change;
793}
794
795#define ALC_EAPD_CTRL_SWITCH(xname, nid, mask) \
796 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +0100797 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Jonathan Woithef8225f62008-01-08 12:16:54 +0100798 .info = alc_eapd_ctrl_info, \
799 .get = alc_eapd_ctrl_get, \
800 .put = alc_eapd_ctrl_put, \
801 .private_value = nid | (mask<<16) }
802#endif /* CONFIG_SND_DEBUG */
803
Kailang Yangdf694da2005-12-05 19:42:22 +0100804/*
Takashi Iwai23f0c042009-02-26 13:03:58 +0100805 * set up the input pin config (depending on the given auto-pin type)
806 */
807static void alc_set_input_pin(struct hda_codec *codec, hda_nid_t nid,
808 int auto_pin_type)
809{
810 unsigned int val = PIN_IN;
811
812 if (auto_pin_type <= AUTO_PIN_FRONT_MIC) {
813 unsigned int pincap;
Takashi Iwai1327a322009-03-23 13:07:47 +0100814 pincap = snd_hda_query_pin_caps(codec, nid);
Takashi Iwai23f0c042009-02-26 13:03:58 +0100815 pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
816 if (pincap & AC_PINCAP_VREF_80)
817 val = PIN_VREF80;
Takashi Iwai461c6c32009-05-25 08:06:02 +0200818 else if (pincap & AC_PINCAP_VREF_50)
819 val = PIN_VREF50;
820 else if (pincap & AC_PINCAP_VREF_100)
821 val = PIN_VREF100;
822 else if (pincap & AC_PINCAP_VREF_GRD)
823 val = PIN_VREFGRD;
Takashi Iwai23f0c042009-02-26 13:03:58 +0100824 }
825 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, val);
826}
827
828/*
Takashi Iwaid88897e2008-10-31 15:01:37 +0100829 */
830static void add_mixer(struct alc_spec *spec, struct snd_kcontrol_new *mix)
831{
832 if (snd_BUG_ON(spec->num_mixers >= ARRAY_SIZE(spec->mixers)))
833 return;
834 spec->mixers[spec->num_mixers++] = mix;
835}
836
837static void add_verb(struct alc_spec *spec, const struct hda_verb *verb)
838{
839 if (snd_BUG_ON(spec->num_init_verbs >= ARRAY_SIZE(spec->init_verbs)))
840 return;
841 spec->init_verbs[spec->num_init_verbs++] = verb;
842}
843
Takashi Iwaidaead532008-11-28 12:55:36 +0100844#ifdef CONFIG_PROC_FS
845/*
846 * hook for proc
847 */
848static void print_realtek_coef(struct snd_info_buffer *buffer,
849 struct hda_codec *codec, hda_nid_t nid)
850{
851 int coeff;
852
853 if (nid != 0x20)
854 return;
855 coeff = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PROC_COEF, 0);
856 snd_iprintf(buffer, " Processing Coefficient: 0x%02x\n", coeff);
857 coeff = snd_hda_codec_read(codec, nid, 0,
858 AC_VERB_GET_COEF_INDEX, 0);
859 snd_iprintf(buffer, " Coefficient Index: 0x%02x\n", coeff);
860}
861#else
862#define print_realtek_coef NULL
863#endif
864
Takashi Iwaid88897e2008-10-31 15:01:37 +0100865/*
Kailang Yangdf694da2005-12-05 19:42:22 +0100866 * set up from the preset table
867 */
Takashi Iwaie9c364c2009-08-11 17:16:13 +0200868static void setup_preset(struct hda_codec *codec,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200869 const struct alc_config_preset *preset)
Kailang Yangdf694da2005-12-05 19:42:22 +0100870{
Takashi Iwaie9c364c2009-08-11 17:16:13 +0200871 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +0100872 int i;
873
874 for (i = 0; i < ARRAY_SIZE(preset->mixers) && preset->mixers[i]; i++)
Takashi Iwaid88897e2008-10-31 15:01:37 +0100875 add_mixer(spec, preset->mixers[i]);
Takashi Iwaif9e336f2008-10-31 16:37:07 +0100876 spec->cap_mixer = preset->cap_mixer;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200877 for (i = 0; i < ARRAY_SIZE(preset->init_verbs) && preset->init_verbs[i];
878 i++)
Takashi Iwaid88897e2008-10-31 15:01:37 +0100879 add_verb(spec, preset->init_verbs[i]);
Kailang Yangea1fb292008-08-26 12:58:38 +0200880
Kailang Yangdf694da2005-12-05 19:42:22 +0100881 spec->channel_mode = preset->channel_mode;
882 spec->num_channel_mode = preset->num_channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200883 spec->need_dac_fix = preset->need_dac_fix;
Hector Martin3b315d72009-06-02 10:54:19 +0200884 spec->const_channel_count = preset->const_channel_count;
Kailang Yangdf694da2005-12-05 19:42:22 +0100885
Hector Martin3b315d72009-06-02 10:54:19 +0200886 if (preset->const_channel_count)
887 spec->multiout.max_channels = preset->const_channel_count;
888 else
889 spec->multiout.max_channels = spec->channel_mode[0].channels;
890 spec->ext_channel_count = spec->channel_mode[0].channels;
Kailang Yangdf694da2005-12-05 19:42:22 +0100891
892 spec->multiout.num_dacs = preset->num_dacs;
893 spec->multiout.dac_nids = preset->dac_nids;
894 spec->multiout.dig_out_nid = preset->dig_out_nid;
Wu Fengguangb25c9da2009-02-06 15:02:27 +0800895 spec->multiout.slave_dig_outs = preset->slave_dig_outs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100896 spec->multiout.hp_nid = preset->hp_nid;
Kailang Yangea1fb292008-08-26 12:58:38 +0200897
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200898 spec->num_mux_defs = preset->num_mux_defs;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200899 if (!spec->num_mux_defs)
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200900 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +0100901 spec->input_mux = preset->input_mux;
902
903 spec->num_adc_nids = preset->num_adc_nids;
904 spec->adc_nids = preset->adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100905 spec->capsrc_nids = preset->capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +0100906 spec->dig_in_nid = preset->dig_in_nid;
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100907
908 spec->unsol_event = preset->unsol_event;
909 spec->init_hook = preset->init_hook;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200910#ifdef CONFIG_SND_HDA_POWER_SAVE
Hector Martinf5de24b2009-12-20 22:51:31 +0100911 spec->power_hook = preset->power_hook;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200912 spec->loopback.amplist = preset->loopbacks;
913#endif
Takashi Iwaie9c364c2009-08-11 17:16:13 +0200914
915 if (preset->setup)
916 preset->setup(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +0100917}
918
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200919/* Enable GPIO mask and set output */
920static struct hda_verb alc_gpio1_init_verbs[] = {
921 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
922 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
923 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
924 { }
925};
926
927static struct hda_verb alc_gpio2_init_verbs[] = {
928 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
929 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
930 {0x01, AC_VERB_SET_GPIO_DATA, 0x02},
931 { }
932};
933
Kailang Yangbdd148a2007-05-08 15:19:08 +0200934static struct hda_verb alc_gpio3_init_verbs[] = {
935 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
936 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
937 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
938 { }
939};
940
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +0200941/*
942 * Fix hardware PLL issue
943 * On some codecs, the analog PLL gating control must be off while
944 * the default value is 1.
945 */
946static void alc_fix_pll(struct hda_codec *codec)
947{
948 struct alc_spec *spec = codec->spec;
949 unsigned int val;
950
951 if (!spec->pll_nid)
952 return;
953 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
954 spec->pll_coef_idx);
955 val = snd_hda_codec_read(codec, spec->pll_nid, 0,
956 AC_VERB_GET_PROC_COEF, 0);
957 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
958 spec->pll_coef_idx);
959 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_PROC_COEF,
960 val & ~(1 << spec->pll_coef_bit));
961}
962
963static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
964 unsigned int coef_idx, unsigned int coef_bit)
965{
966 struct alc_spec *spec = codec->spec;
967 spec->pll_nid = nid;
968 spec->pll_coef_idx = coef_idx;
969 spec->pll_coef_bit = coef_bit;
970 alc_fix_pll(codec);
971}
972
Takashi Iwaia9fd4f32009-05-08 15:57:59 +0200973static void alc_automute_pin(struct hda_codec *codec)
Kailang Yangc9b58002007-10-16 14:30:01 +0200974{
975 struct alc_spec *spec = codec->spec;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +0200976 unsigned int nid = spec->autocfg.hp_pins[0];
977 int i;
Kailang Yangc9b58002007-10-16 14:30:01 +0200978
Takashi Iwaiad87c642009-11-02 14:23:15 +0100979 if (!nid)
980 return;
Wu Fengguang864f92b2009-11-18 12:38:02 +0800981 spec->jack_present = snd_hda_jack_detect(codec, nid);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +0200982 for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) {
983 nid = spec->autocfg.speaker_pins[i];
984 if (!nid)
985 break;
986 snd_hda_codec_write(codec, nid, 0,
987 AC_VERB_SET_PIN_WIDGET_CONTROL,
988 spec->jack_present ? 0 : PIN_OUT);
989 }
Kailang Yangc9b58002007-10-16 14:30:01 +0200990}
991
Takashi Iwai6c819492009-08-10 18:47:44 +0200992static int get_connection_index(struct hda_codec *codec, hda_nid_t mux,
993 hda_nid_t nid)
994{
995 hda_nid_t conn[HDA_MAX_NUM_INPUTS];
996 int i, nums;
997
998 nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn));
999 for (i = 0; i < nums; i++)
1000 if (conn[i] == nid)
1001 return i;
1002 return -1;
1003}
1004
Kailang Yang7fb0d782008-10-15 11:12:35 +02001005static void alc_mic_automute(struct hda_codec *codec)
1006{
1007 struct alc_spec *spec = codec->spec;
Takashi Iwai6c819492009-08-10 18:47:44 +02001008 struct alc_mic_route *dead, *alive;
1009 unsigned int present, type;
1010 hda_nid_t cap_nid;
Kailang Yang7fb0d782008-10-15 11:12:35 +02001011
Takashi Iwaib59bdf32009-08-11 09:47:30 +02001012 if (!spec->auto_mic)
1013 return;
Takashi Iwai6c819492009-08-10 18:47:44 +02001014 if (!spec->int_mic.pin || !spec->ext_mic.pin)
1015 return;
1016 if (snd_BUG_ON(!spec->adc_nids))
1017 return;
1018
1019 cap_nid = spec->capsrc_nids ? spec->capsrc_nids[0] : spec->adc_nids[0];
1020
Wu Fengguang864f92b2009-11-18 12:38:02 +08001021 present = snd_hda_jack_detect(codec, spec->ext_mic.pin);
Takashi Iwai6c819492009-08-10 18:47:44 +02001022 if (present) {
1023 alive = &spec->ext_mic;
1024 dead = &spec->int_mic;
1025 } else {
1026 alive = &spec->int_mic;
1027 dead = &spec->ext_mic;
1028 }
1029
Takashi Iwai6c819492009-08-10 18:47:44 +02001030 type = get_wcaps_type(get_wcaps(codec, cap_nid));
1031 if (type == AC_WID_AUD_MIX) {
1032 /* Matrix-mixer style (e.g. ALC882) */
1033 snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT,
1034 alive->mux_idx,
1035 HDA_AMP_MUTE, 0);
1036 snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT,
1037 dead->mux_idx,
1038 HDA_AMP_MUTE, HDA_AMP_MUTE);
1039 } else {
1040 /* MUX style (e.g. ALC880) */
1041 snd_hda_codec_write_cache(codec, cap_nid, 0,
1042 AC_VERB_SET_CONNECT_SEL,
1043 alive->mux_idx);
1044 }
1045
1046 /* FIXME: analog mixer */
Kailang Yang7fb0d782008-10-15 11:12:35 +02001047}
1048
Kailang Yangc9b58002007-10-16 14:30:01 +02001049/* unsolicited event for HP jack sensing */
1050static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res)
1051{
1052 if (codec->vendor_id == 0x10ec0880)
1053 res >>= 28;
1054 else
1055 res >>= 26;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001056 switch (res) {
1057 case ALC880_HP_EVENT:
1058 alc_automute_pin(codec);
1059 break;
1060 case ALC880_MIC_EVENT:
Kailang Yang7fb0d782008-10-15 11:12:35 +02001061 alc_mic_automute(codec);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001062 break;
1063 }
Kailang Yang7fb0d782008-10-15 11:12:35 +02001064}
1065
1066static void alc_inithook(struct hda_codec *codec)
1067{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001068 alc_automute_pin(codec);
Kailang Yang7fb0d782008-10-15 11:12:35 +02001069 alc_mic_automute(codec);
Kailang Yangc9b58002007-10-16 14:30:01 +02001070}
1071
Kailang Yangf9423e72008-05-27 12:32:25 +02001072/* additional initialization for ALC888 variants */
1073static void alc888_coef_init(struct hda_codec *codec)
1074{
1075 unsigned int tmp;
1076
1077 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0);
1078 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
1079 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
Takashi Iwai37db6232009-03-05 09:40:16 +01001080 if ((tmp & 0xf0) == 0x20)
Kailang Yangf9423e72008-05-27 12:32:25 +02001081 /* alc888S-VC */
1082 snd_hda_codec_read(codec, 0x20, 0,
1083 AC_VERB_SET_PROC_COEF, 0x830);
1084 else
1085 /* alc888-VB */
1086 snd_hda_codec_read(codec, 0x20, 0,
1087 AC_VERB_SET_PROC_COEF, 0x3030);
1088}
1089
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02001090static void alc889_coef_init(struct hda_codec *codec)
1091{
1092 unsigned int tmp;
1093
1094 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
1095 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
1096 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
1097 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF, tmp|0x2010);
1098}
1099
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001100static void alc_auto_init_amp(struct hda_codec *codec, int type)
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001101{
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001102 unsigned int tmp;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001103
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001104 switch (type) {
1105 case ALC_INIT_GPIO1:
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001106 snd_hda_sequence_write(codec, alc_gpio1_init_verbs);
1107 break;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001108 case ALC_INIT_GPIO2:
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001109 snd_hda_sequence_write(codec, alc_gpio2_init_verbs);
1110 break;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001111 case ALC_INIT_GPIO3:
Kailang Yangbdd148a2007-05-08 15:19:08 +02001112 snd_hda_sequence_write(codec, alc_gpio3_init_verbs);
1113 break;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001114 case ALC_INIT_DEFAULT:
Kailang Yangbdd148a2007-05-08 15:19:08 +02001115 switch (codec->vendor_id) {
Kailang Yangc9b58002007-10-16 14:30:01 +02001116 case 0x10ec0260:
1117 snd_hda_codec_write(codec, 0x0f, 0,
1118 AC_VERB_SET_EAPD_BTLENABLE, 2);
1119 snd_hda_codec_write(codec, 0x10, 0,
1120 AC_VERB_SET_EAPD_BTLENABLE, 2);
1121 break;
1122 case 0x10ec0262:
Kailang Yangbdd148a2007-05-08 15:19:08 +02001123 case 0x10ec0267:
1124 case 0x10ec0268:
Kailang Yangc9b58002007-10-16 14:30:01 +02001125 case 0x10ec0269:
Takashi Iwaic6e8f2d2009-02-06 12:45:52 +01001126 case 0x10ec0272:
Kailang Yangf9423e72008-05-27 12:32:25 +02001127 case 0x10ec0660:
1128 case 0x10ec0662:
1129 case 0x10ec0663:
Kailang Yangc9b58002007-10-16 14:30:01 +02001130 case 0x10ec0862:
Takashi Iwai20a3a052008-05-23 17:52:53 +02001131 case 0x10ec0889:
Kailang Yangbdd148a2007-05-08 15:19:08 +02001132 snd_hda_codec_write(codec, 0x14, 0,
1133 AC_VERB_SET_EAPD_BTLENABLE, 2);
1134 snd_hda_codec_write(codec, 0x15, 0,
1135 AC_VERB_SET_EAPD_BTLENABLE, 2);
Kailang Yangc9b58002007-10-16 14:30:01 +02001136 break;
Kailang Yangbdd148a2007-05-08 15:19:08 +02001137 }
Kailang Yangc9b58002007-10-16 14:30:01 +02001138 switch (codec->vendor_id) {
1139 case 0x10ec0260:
1140 snd_hda_codec_write(codec, 0x1a, 0,
1141 AC_VERB_SET_COEF_INDEX, 7);
1142 tmp = snd_hda_codec_read(codec, 0x1a, 0,
1143 AC_VERB_GET_PROC_COEF, 0);
1144 snd_hda_codec_write(codec, 0x1a, 0,
1145 AC_VERB_SET_COEF_INDEX, 7);
1146 snd_hda_codec_write(codec, 0x1a, 0,
1147 AC_VERB_SET_PROC_COEF,
1148 tmp | 0x2010);
1149 break;
1150 case 0x10ec0262:
1151 case 0x10ec0880:
1152 case 0x10ec0882:
1153 case 0x10ec0883:
1154 case 0x10ec0885:
Takashi Iwai4a5a4c52009-02-06 12:46:59 +01001155 case 0x10ec0887:
Takashi Iwai20a3a052008-05-23 17:52:53 +02001156 case 0x10ec0889:
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02001157 alc889_coef_init(codec);
Kailang Yangc9b58002007-10-16 14:30:01 +02001158 break;
Kailang Yangf9423e72008-05-27 12:32:25 +02001159 case 0x10ec0888:
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001160 alc888_coef_init(codec);
Kailang Yangf9423e72008-05-27 12:32:25 +02001161 break;
Kailang Yangc9b58002007-10-16 14:30:01 +02001162 case 0x10ec0267:
1163 case 0x10ec0268:
1164 snd_hda_codec_write(codec, 0x20, 0,
1165 AC_VERB_SET_COEF_INDEX, 7);
1166 tmp = snd_hda_codec_read(codec, 0x20, 0,
1167 AC_VERB_GET_PROC_COEF, 0);
1168 snd_hda_codec_write(codec, 0x20, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +02001169 AC_VERB_SET_COEF_INDEX, 7);
Kailang Yangc9b58002007-10-16 14:30:01 +02001170 snd_hda_codec_write(codec, 0x20, 0,
1171 AC_VERB_SET_PROC_COEF,
1172 tmp | 0x3000);
1173 break;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001174 }
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001175 break;
1176 }
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001177}
Kailang Yangea1fb292008-08-26 12:58:38 +02001178
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001179static void alc_init_auto_hp(struct hda_codec *codec)
1180{
1181 struct alc_spec *spec = codec->spec;
1182
1183 if (!spec->autocfg.hp_pins[0])
Kailang Yangc9b58002007-10-16 14:30:01 +02001184 return;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001185
Kailang Yangc9b58002007-10-16 14:30:01 +02001186 if (!spec->autocfg.speaker_pins[0]) {
Takashi Iwai2a2ed0d2009-04-28 13:01:26 +02001187 if (spec->autocfg.line_out_pins[0] &&
1188 spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT)
Kailang Yangc9b58002007-10-16 14:30:01 +02001189 spec->autocfg.speaker_pins[0] =
Kailang Yang8c427222008-01-10 13:03:59 +01001190 spec->autocfg.line_out_pins[0];
Kailang Yangc9b58002007-10-16 14:30:01 +02001191 else
1192 return;
1193 }
1194
Takashi Iwai2a2ed0d2009-04-28 13:01:26 +02001195 snd_printdd("realtek: Enable HP auto-muting on NID 0x%x\n",
1196 spec->autocfg.hp_pins[0]);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001197 snd_hda_codec_write_cache(codec, spec->autocfg.hp_pins[0], 0,
1198 AC_VERB_SET_UNSOLICITED_ENABLE,
1199 AC_USRSP_EN | ALC880_HP_EVENT);
1200 spec->unsol_event = alc_sku_unsol_event;
1201}
1202
Takashi Iwai6c819492009-08-10 18:47:44 +02001203static void alc_init_auto_mic(struct hda_codec *codec)
1204{
1205 struct alc_spec *spec = codec->spec;
1206 struct auto_pin_cfg *cfg = &spec->autocfg;
1207 hda_nid_t fixed, ext;
1208 int i;
1209
1210 /* there must be only two mic inputs exclusively */
1211 for (i = AUTO_PIN_LINE; i < AUTO_PIN_LAST; i++)
1212 if (cfg->input_pins[i])
1213 return;
1214
1215 fixed = ext = 0;
1216 for (i = AUTO_PIN_MIC; i <= AUTO_PIN_FRONT_MIC; i++) {
1217 hda_nid_t nid = cfg->input_pins[i];
1218 unsigned int defcfg;
1219 if (!nid)
1220 return;
1221 defcfg = snd_hda_codec_get_pincfg(codec, nid);
1222 switch (get_defcfg_connect(defcfg)) {
1223 case AC_JACK_PORT_FIXED:
1224 if (fixed)
1225 return; /* already occupied */
1226 fixed = nid;
1227 break;
1228 case AC_JACK_PORT_COMPLEX:
1229 if (ext)
1230 return; /* already occupied */
1231 ext = nid;
1232 break;
1233 default:
1234 return; /* invalid entry */
1235 }
1236 }
1237 if (!(get_wcaps(codec, ext) & AC_WCAP_UNSOL_CAP))
1238 return; /* no unsol support */
1239 snd_printdd("realtek: Enable auto-mic switch on NID 0x%x/0x%x\n",
1240 ext, fixed);
1241 spec->ext_mic.pin = ext;
1242 spec->int_mic.pin = fixed;
1243 spec->ext_mic.mux_idx = MUX_IDX_UNDEF; /* set later */
1244 spec->int_mic.mux_idx = MUX_IDX_UNDEF; /* set later */
1245 spec->auto_mic = 1;
1246 snd_hda_codec_write_cache(codec, spec->ext_mic.pin, 0,
1247 AC_VERB_SET_UNSOLICITED_ENABLE,
1248 AC_USRSP_EN | ALC880_MIC_EVENT);
1249 spec->unsol_event = alc_sku_unsol_event;
1250}
1251
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001252/* check subsystem ID and set up device-specific initialization;
1253 * return 1 if initialized, 0 if invalid SSID
1254 */
1255/* 32-bit subsystem ID for BIOS loading in HD Audio codec.
1256 * 31 ~ 16 : Manufacture ID
1257 * 15 ~ 8 : SKU ID
1258 * 7 ~ 0 : Assembly ID
1259 * port-A --> pin 39/41, port-E --> pin 14/15, port-D --> pin 35/36
1260 */
1261static int alc_subsystem_id(struct hda_codec *codec,
1262 hda_nid_t porta, hda_nid_t porte,
1263 hda_nid_t portd)
1264{
1265 unsigned int ass, tmp, i;
1266 unsigned nid;
1267 struct alc_spec *spec = codec->spec;
1268
1269 ass = codec->subsystem_id & 0xffff;
1270 if ((ass != codec->bus->pci->subsystem_device) && (ass & 1))
1271 goto do_sku;
1272
1273 /* invalid SSID, check the special NID pin defcfg instead */
1274 /*
Sasha Alexandrdef319f2009-06-16 16:00:15 -04001275 * 31~30 : port connectivity
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001276 * 29~21 : reserve
1277 * 20 : PCBEEP input
1278 * 19~16 : Check sum (15:1)
1279 * 15~1 : Custom
1280 * 0 : override
1281 */
1282 nid = 0x1d;
1283 if (codec->vendor_id == 0x10ec0260)
1284 nid = 0x17;
1285 ass = snd_hda_codec_get_pincfg(codec, nid);
1286 snd_printd("realtek: No valid SSID, "
1287 "checking pincfg 0x%08x for NID 0x%x\n",
Takashi Iwaicb6605c2009-04-28 13:03:19 +02001288 ass, nid);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001289 if (!(ass & 1) && !(ass & 0x100000))
1290 return 0;
1291 if ((ass >> 30) != 1) /* no physical connection */
1292 return 0;
1293
1294 /* check sum */
1295 tmp = 0;
1296 for (i = 1; i < 16; i++) {
1297 if ((ass >> i) & 1)
1298 tmp++;
1299 }
1300 if (((ass >> 16) & 0xf) != tmp)
1301 return 0;
1302do_sku:
1303 snd_printd("realtek: Enabling init ASM_ID=0x%04x CODEC_ID=%08x\n",
1304 ass & 0xffff, codec->vendor_id);
1305 /*
1306 * 0 : override
1307 * 1 : Swap Jack
1308 * 2 : 0 --> Desktop, 1 --> Laptop
1309 * 3~5 : External Amplifier control
1310 * 7~6 : Reserved
1311 */
1312 tmp = (ass & 0x38) >> 3; /* external Amp control */
1313 switch (tmp) {
1314 case 1:
1315 spec->init_amp = ALC_INIT_GPIO1;
1316 break;
1317 case 3:
1318 spec->init_amp = ALC_INIT_GPIO2;
1319 break;
1320 case 7:
1321 spec->init_amp = ALC_INIT_GPIO3;
1322 break;
1323 case 5:
1324 spec->init_amp = ALC_INIT_DEFAULT;
1325 break;
1326 }
1327
1328 /* is laptop or Desktop and enable the function "Mute internal speaker
1329 * when the external headphone out jack is plugged"
1330 */
1331 if (!(ass & 0x8000))
1332 return 1;
1333 /*
1334 * 10~8 : Jack location
1335 * 12~11: Headphone out -> 00: PortA, 01: PortE, 02: PortD, 03: Resvered
1336 * 14~13: Resvered
1337 * 15 : 1 --> enable the function "Mute internal speaker
1338 * when the external headphone out jack is plugged"
1339 */
Kailang Yangc9b58002007-10-16 14:30:01 +02001340 if (!spec->autocfg.hp_pins[0]) {
Takashi Iwai01d48252009-10-06 13:21:54 +02001341 hda_nid_t nid;
Kailang Yangc9b58002007-10-16 14:30:01 +02001342 tmp = (ass >> 11) & 0x3; /* HP to chassis */
1343 if (tmp == 0)
Takashi Iwai01d48252009-10-06 13:21:54 +02001344 nid = porta;
Kailang Yangc9b58002007-10-16 14:30:01 +02001345 else if (tmp == 1)
Takashi Iwai01d48252009-10-06 13:21:54 +02001346 nid = porte;
Kailang Yangc9b58002007-10-16 14:30:01 +02001347 else if (tmp == 2)
Takashi Iwai01d48252009-10-06 13:21:54 +02001348 nid = portd;
Kailang Yangc9b58002007-10-16 14:30:01 +02001349 else
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001350 return 1;
Takashi Iwai01d48252009-10-06 13:21:54 +02001351 for (i = 0; i < spec->autocfg.line_outs; i++)
1352 if (spec->autocfg.line_out_pins[i] == nid)
1353 return 1;
1354 spec->autocfg.hp_pins[0] = nid;
Kailang Yangc9b58002007-10-16 14:30:01 +02001355 }
1356
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001357 alc_init_auto_hp(codec);
Takashi Iwai6c819492009-08-10 18:47:44 +02001358 alc_init_auto_mic(codec);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001359 return 1;
1360}
Kailang Yangea1fb292008-08-26 12:58:38 +02001361
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001362static void alc_ssid_check(struct hda_codec *codec,
1363 hda_nid_t porta, hda_nid_t porte, hda_nid_t portd)
1364{
1365 if (!alc_subsystem_id(codec, porta, porte, portd)) {
1366 struct alc_spec *spec = codec->spec;
1367 snd_printd("realtek: "
1368 "Enable default setup for auto mode as fallback\n");
1369 spec->init_amp = ALC_INIT_DEFAULT;
1370 alc_init_auto_hp(codec);
Takashi Iwai6c819492009-08-10 18:47:44 +02001371 alc_init_auto_mic(codec);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001372 }
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001373}
1374
Takashi Iwai41e41f12005-06-08 14:48:49 +02001375/*
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02001376 * Fix-up pin default configurations and add default verbs
Takashi Iwaif95474e2007-07-10 00:47:43 +02001377 */
1378
1379struct alc_pincfg {
1380 hda_nid_t nid;
1381 u32 val;
1382};
1383
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02001384struct alc_fixup {
1385 const struct alc_pincfg *pins;
1386 const struct hda_verb *verbs;
1387};
1388
1389static void alc_pick_fixup(struct hda_codec *codec,
Takashi Iwaif95474e2007-07-10 00:47:43 +02001390 const struct snd_pci_quirk *quirk,
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02001391 const struct alc_fixup *fix)
Takashi Iwaif95474e2007-07-10 00:47:43 +02001392{
1393 const struct alc_pincfg *cfg;
1394
1395 quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk);
1396 if (!quirk)
1397 return;
1398
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02001399 fix += quirk->value;
1400 cfg = fix->pins;
1401 if (cfg) {
1402 for (; cfg->nid; cfg++)
1403 snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val);
1404 }
1405 if (fix->verbs)
1406 add_verb(codec->spec, fix->verbs);
Takashi Iwaif95474e2007-07-10 00:47:43 +02001407}
1408
Kailang Yang274693f2009-12-03 10:07:50 +01001409static int alc_read_coef_idx(struct hda_codec *codec,
1410 unsigned int coef_idx)
1411{
1412 unsigned int val;
1413 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX,
1414 coef_idx);
1415 val = snd_hda_codec_read(codec, 0x20, 0,
1416 AC_VERB_GET_PROC_COEF, 0);
1417 return val;
1418}
1419
Takashi Iwaif95474e2007-07-10 00:47:43 +02001420/*
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001421 * ALC888
1422 */
1423
1424/*
1425 * 2ch mode
1426 */
1427static struct hda_verb alc888_4ST_ch2_intel_init[] = {
1428/* Mic-in jack as mic in */
1429 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1430 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1431/* Line-in jack as Line in */
1432 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
1433 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1434/* Line-Out as Front */
1435 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00},
1436 { } /* end */
1437};
1438
1439/*
1440 * 4ch mode
1441 */
1442static struct hda_verb alc888_4ST_ch4_intel_init[] = {
1443/* Mic-in jack as mic in */
1444 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1445 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1446/* Line-in jack as Surround */
1447 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1448 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1449/* Line-Out as Front */
1450 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00},
1451 { } /* end */
1452};
1453
1454/*
1455 * 6ch mode
1456 */
1457static struct hda_verb alc888_4ST_ch6_intel_init[] = {
1458/* Mic-in jack as CLFE */
1459 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1460 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1461/* Line-in jack as Surround */
1462 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1463 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1464/* Line-Out as CLFE (workaround because Mic-in is not loud enough) */
1465 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
1466 { } /* end */
1467};
1468
1469/*
1470 * 8ch mode
1471 */
1472static struct hda_verb alc888_4ST_ch8_intel_init[] = {
1473/* Mic-in jack as CLFE */
1474 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1475 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1476/* Line-in jack as Surround */
1477 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1478 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1479/* Line-Out as Side */
1480 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
1481 { } /* end */
1482};
1483
1484static struct hda_channel_mode alc888_4ST_8ch_intel_modes[4] = {
1485 { 2, alc888_4ST_ch2_intel_init },
1486 { 4, alc888_4ST_ch4_intel_init },
1487 { 6, alc888_4ST_ch6_intel_init },
1488 { 8, alc888_4ST_ch8_intel_init },
1489};
1490
1491/*
1492 * ALC888 Fujitsu Siemens Amillo xa3530
1493 */
1494
1495static struct hda_verb alc888_fujitsu_xa3530_verbs[] = {
1496/* Front Mic: set to PIN_IN (empty by default) */
1497 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1498/* Connect Internal HP to Front */
1499 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1500 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1501 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
1502/* Connect Bass HP to Front */
1503 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1504 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1505 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
1506/* Connect Line-Out side jack (SPDIF) to Side */
1507 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1508 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1509 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
1510/* Connect Mic jack to CLFE */
1511 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1512 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1513 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02},
1514/* Connect Line-in jack to Surround */
1515 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1516 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1517 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
1518/* Connect HP out jack to Front */
1519 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1520 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1521 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
1522/* Enable unsolicited event for HP jack and Line-out jack */
1523 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
1524 {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
1525 {}
1526};
1527
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001528static void alc_automute_amp(struct hda_codec *codec)
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001529{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001530 struct alc_spec *spec = codec->spec;
Wu Fengguang864f92b2009-11-18 12:38:02 +08001531 unsigned int mute;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001532 hda_nid_t nid;
1533 int i;
1534
1535 spec->jack_present = 0;
1536 for (i = 0; i < ARRAY_SIZE(spec->autocfg.hp_pins); i++) {
1537 nid = spec->autocfg.hp_pins[i];
1538 if (!nid)
1539 break;
Wu Fengguang864f92b2009-11-18 12:38:02 +08001540 if (snd_hda_jack_detect(codec, nid)) {
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001541 spec->jack_present = 1;
1542 break;
1543 }
1544 }
1545
1546 mute = spec->jack_present ? HDA_AMP_MUTE : 0;
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001547 /* Toggle internal speakers muting */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001548 for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) {
1549 nid = spec->autocfg.speaker_pins[i];
1550 if (!nid)
1551 break;
1552 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
1553 HDA_AMP_MUTE, mute);
1554 }
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001555}
1556
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001557static void alc_automute_amp_unsol_event(struct hda_codec *codec,
1558 unsigned int res)
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001559{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001560 if (codec->vendor_id == 0x10ec0880)
1561 res >>= 28;
1562 else
1563 res >>= 26;
1564 if (res == ALC880_HP_EVENT)
1565 alc_automute_amp(codec);
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001566}
1567
Takashi Iwai4f5d17062009-08-11 18:17:46 +02001568static void alc889_automute_setup(struct hda_codec *codec)
Wu Fengguang6732bd02009-07-30 09:19:14 +02001569{
1570 struct alc_spec *spec = codec->spec;
1571
1572 spec->autocfg.hp_pins[0] = 0x15;
1573 spec->autocfg.speaker_pins[0] = 0x14;
1574 spec->autocfg.speaker_pins[1] = 0x16;
1575 spec->autocfg.speaker_pins[2] = 0x17;
1576 spec->autocfg.speaker_pins[3] = 0x19;
1577 spec->autocfg.speaker_pins[4] = 0x1a;
Wu Fengguang6732bd02009-07-30 09:19:14 +02001578}
1579
1580static void alc889_intel_init_hook(struct hda_codec *codec)
1581{
1582 alc889_coef_init(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +02001583 alc_automute_amp(codec);
Wu Fengguang6732bd02009-07-30 09:19:14 +02001584}
1585
Takashi Iwai4f5d17062009-08-11 18:17:46 +02001586static void alc888_fujitsu_xa3530_setup(struct hda_codec *codec)
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001587{
1588 struct alc_spec *spec = codec->spec;
1589
1590 spec->autocfg.hp_pins[0] = 0x17; /* line-out */
1591 spec->autocfg.hp_pins[1] = 0x1b; /* hp */
1592 spec->autocfg.speaker_pins[0] = 0x14; /* speaker */
1593 spec->autocfg.speaker_pins[1] = 0x15; /* bass */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001594}
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001595
1596/*
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001597 * ALC888 Acer Aspire 4930G model
1598 */
1599
1600static struct hda_verb alc888_acer_aspire_4930g_verbs[] = {
1601/* Front Mic: set to PIN_IN (empty by default) */
1602 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1603/* Unselect Front Mic by default in input mixer 3 */
1604 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001605/* Enable unsolicited event for HP jack */
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001606 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
1607/* Connect Internal HP to front */
1608 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1609 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1610 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
1611/* Connect HP out to front */
1612 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1613 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1614 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
1615 { }
1616};
1617
Hector Martin3b315d72009-06-02 10:54:19 +02001618/*
Tony Vroond2fd4b02009-06-21 00:40:10 +01001619 * ALC888 Acer Aspire 6530G model
1620 */
1621
1622static struct hda_verb alc888_acer_aspire_6530g_verbs[] = {
1623/* Bias voltage on for external mic port */
1624 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN | PIN_VREF80},
Emilio López320d5922009-06-25 08:18:44 +02001625/* Front Mic: set to PIN_IN (empty by default) */
1626 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1627/* Unselect Front Mic by default in input mixer 3 */
1628 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
Tony Vroond2fd4b02009-06-21 00:40:10 +01001629/* Enable unsolicited event for HP jack */
1630 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
1631/* Enable speaker output */
1632 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1633 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1634/* Enable headphone output */
1635 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP},
1636 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1637 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
1638 { }
1639};
1640
1641/*
Hector Martin018df412009-06-04 00:13:40 +02001642 * ALC889 Acer Aspire 8930G model
Hector Martin3b315d72009-06-02 10:54:19 +02001643 */
1644
Hector Martin018df412009-06-04 00:13:40 +02001645static struct hda_verb alc889_acer_aspire_8930g_verbs[] = {
Hector Martin3b315d72009-06-02 10:54:19 +02001646/* Front Mic: set to PIN_IN (empty by default) */
1647 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1648/* Unselect Front Mic by default in input mixer 3 */
1649 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
1650/* Enable unsolicited event for HP jack */
1651 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
1652/* Connect Internal Front to Front */
1653 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1654 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1655 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
1656/* Connect Internal Rear to Rear */
1657 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1658 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1659 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01},
1660/* Connect Internal CLFE to CLFE */
1661 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1662 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1663 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
1664/* Connect HP out to Front */
Hector Martin018df412009-06-04 00:13:40 +02001665 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP},
Hector Martin3b315d72009-06-02 10:54:19 +02001666 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1667 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
1668/* Enable all DACs */
1669/* DAC DISABLE/MUTE 1? */
1670/* setting bits 1-5 disables DAC nids 0x02-0x06 apparently. Init=0x38 */
1671 {0x20, AC_VERB_SET_COEF_INDEX, 0x03},
1672 {0x20, AC_VERB_SET_PROC_COEF, 0x0000},
1673/* DAC DISABLE/MUTE 2? */
1674/* some bit here disables the other DACs. Init=0x4900 */
1675 {0x20, AC_VERB_SET_COEF_INDEX, 0x08},
1676 {0x20, AC_VERB_SET_PROC_COEF, 0x0000},
Hector Martin018df412009-06-04 00:13:40 +02001677/* DMIC fix
1678 * This laptop has a stereo digital microphone. The mics are only 1cm apart
1679 * which makes the stereo useless. However, either the mic or the ALC889
1680 * makes the signal become a difference/sum signal instead of standard
1681 * stereo, which is annoying. So instead we flip this bit which makes the
1682 * codec replicate the sum signal to both channels, turning it into a
1683 * normal mono mic.
1684 */
1685/* DMIC_CONTROL? Init value = 0x0001 */
1686 {0x20, AC_VERB_SET_COEF_INDEX, 0x0b},
1687 {0x20, AC_VERB_SET_PROC_COEF, 0x0003},
Hector Martin3b315d72009-06-02 10:54:19 +02001688 { }
1689};
1690
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001691static struct hda_input_mux alc888_2_capture_sources[2] = {
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001692 /* Front mic only available on one ADC */
1693 {
1694 .num_items = 4,
1695 .items = {
1696 { "Mic", 0x0 },
1697 { "Line", 0x2 },
1698 { "CD", 0x4 },
1699 { "Front Mic", 0xb },
1700 },
1701 },
1702 {
1703 .num_items = 3,
1704 .items = {
1705 { "Mic", 0x0 },
1706 { "Line", 0x2 },
1707 { "CD", 0x4 },
1708 },
1709 }
1710};
1711
Tony Vroond2fd4b02009-06-21 00:40:10 +01001712static struct hda_input_mux alc888_acer_aspire_6530_sources[2] = {
1713 /* Interal mic only available on one ADC */
1714 {
Tony Vroon684a8842009-06-26 09:27:50 +01001715 .num_items = 5,
Tony Vroond2fd4b02009-06-21 00:40:10 +01001716 .items = {
1717 { "Ext Mic", 0x0 },
Tony Vroon684a8842009-06-26 09:27:50 +01001718 { "Line In", 0x2 },
Tony Vroond2fd4b02009-06-21 00:40:10 +01001719 { "CD", 0x4 },
Tony Vroon684a8842009-06-26 09:27:50 +01001720 { "Input Mix", 0xa },
Tony Vroond2fd4b02009-06-21 00:40:10 +01001721 { "Int Mic", 0xb },
1722 },
1723 },
1724 {
Tony Vroon684a8842009-06-26 09:27:50 +01001725 .num_items = 4,
Tony Vroond2fd4b02009-06-21 00:40:10 +01001726 .items = {
1727 { "Ext Mic", 0x0 },
Tony Vroon684a8842009-06-26 09:27:50 +01001728 { "Line In", 0x2 },
Tony Vroond2fd4b02009-06-21 00:40:10 +01001729 { "CD", 0x4 },
Tony Vroon684a8842009-06-26 09:27:50 +01001730 { "Input Mix", 0xa },
Tony Vroond2fd4b02009-06-21 00:40:10 +01001731 },
1732 }
1733};
1734
Hector Martin018df412009-06-04 00:13:40 +02001735static struct hda_input_mux alc889_capture_sources[3] = {
1736 /* Digital mic only available on first "ADC" */
1737 {
1738 .num_items = 5,
1739 .items = {
1740 { "Mic", 0x0 },
1741 { "Line", 0x2 },
1742 { "CD", 0x4 },
1743 { "Front Mic", 0xb },
1744 { "Input Mix", 0xa },
1745 },
1746 },
1747 {
1748 .num_items = 4,
1749 .items = {
1750 { "Mic", 0x0 },
1751 { "Line", 0x2 },
1752 { "CD", 0x4 },
1753 { "Input Mix", 0xa },
1754 },
1755 },
1756 {
1757 .num_items = 4,
1758 .items = {
1759 { "Mic", 0x0 },
1760 { "Line", 0x2 },
1761 { "CD", 0x4 },
1762 { "Input Mix", 0xa },
1763 },
1764 }
1765};
1766
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001767static struct snd_kcontrol_new alc888_base_mixer[] = {
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001768 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1769 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
1770 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1771 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
1772 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
1773 HDA_OUTPUT),
1774 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
1775 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1776 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
1777 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
1778 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
1779 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1780 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1781 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1782 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1783 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1784 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
1785 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001786 { } /* end */
1787};
1788
Hector Martin556eea92009-12-20 22:51:23 +01001789static struct snd_kcontrol_new alc889_acer_aspire_8930g_mixer[] = {
1790 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
1791 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
1792 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
1793 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
1794 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
1795 HDA_OUTPUT),
1796 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
1797 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1798 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
1799 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1800 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1801 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1802 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
1803 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1804 { } /* end */
1805};
1806
1807
Takashi Iwai4f5d17062009-08-11 18:17:46 +02001808static void alc888_acer_aspire_4930g_setup(struct hda_codec *codec)
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001809{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001810 struct alc_spec *spec = codec->spec;
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001811
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001812 spec->autocfg.hp_pins[0] = 0x15;
1813 spec->autocfg.speaker_pins[0] = 0x14;
Łukasz Wojniłowicz7cef4cf2009-11-20 12:14:35 +01001814 spec->autocfg.speaker_pins[1] = 0x16;
1815 spec->autocfg.speaker_pins[2] = 0x17;
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001816}
1817
Takashi Iwai4f5d17062009-08-11 18:17:46 +02001818static void alc888_acer_aspire_6530g_setup(struct hda_codec *codec)
Emilio López320d5922009-06-25 08:18:44 +02001819{
1820 struct alc_spec *spec = codec->spec;
1821
1822 spec->autocfg.hp_pins[0] = 0x15;
1823 spec->autocfg.speaker_pins[0] = 0x14;
1824 spec->autocfg.speaker_pins[1] = 0x16;
1825 spec->autocfg.speaker_pins[2] = 0x17;
Emilio López320d5922009-06-25 08:18:44 +02001826}
1827
Takashi Iwai4f5d17062009-08-11 18:17:46 +02001828static void alc889_acer_aspire_8930g_setup(struct hda_codec *codec)
Hector Martin3b315d72009-06-02 10:54:19 +02001829{
1830 struct alc_spec *spec = codec->spec;
1831
1832 spec->autocfg.hp_pins[0] = 0x15;
1833 spec->autocfg.speaker_pins[0] = 0x14;
1834 spec->autocfg.speaker_pins[1] = 0x16;
1835 spec->autocfg.speaker_pins[2] = 0x1b;
Hector Martin3b315d72009-06-02 10:54:19 +02001836}
1837
Hector Martinf5de24b2009-12-20 22:51:31 +01001838#ifdef CONFIG_SND_HDA_POWER_SAVE
1839static void alc889_power_eapd(struct hda_codec *codec, int power)
1840{
1841 snd_hda_codec_write(codec, 0x14, 0,
1842 AC_VERB_SET_EAPD_BTLENABLE, power ? 2 : 0);
1843 snd_hda_codec_write(codec, 0x15, 0,
1844 AC_VERB_SET_EAPD_BTLENABLE, power ? 2 : 0);
1845}
1846#endif
1847
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08001848/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001849 * ALC880 3-stack model
1850 *
1851 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0e)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001852 * Pin assignment: Front = 0x14, Line-In/Surr = 0x1a, Mic/CLFE = 0x18,
1853 * F-Mic = 0x1b, HP = 0x19
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854 */
1855
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001856static hda_nid_t alc880_dac_nids[4] = {
1857 /* front, rear, clfe, rear_surr */
1858 0x02, 0x05, 0x04, 0x03
1859};
1860
1861static hda_nid_t alc880_adc_nids[3] = {
1862 /* ADC0-2 */
1863 0x07, 0x08, 0x09,
1864};
1865
1866/* The datasheet says the node 0x07 is connected from inputs,
1867 * but it shows zero connection in the real implementation on some devices.
Kailang Yangdf694da2005-12-05 19:42:22 +01001868 * Note: this is a 915GAV bug, fixed on 915GLV
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001870static hda_nid_t alc880_adc_nids_alt[2] = {
1871 /* ADC1-2 */
1872 0x08, 0x09,
1873};
1874
1875#define ALC880_DIGOUT_NID 0x06
1876#define ALC880_DIGIN_NID 0x0a
1877
1878static struct hda_input_mux alc880_capture_source = {
1879 .num_items = 4,
1880 .items = {
1881 { "Mic", 0x0 },
1882 { "Front Mic", 0x3 },
1883 { "Line", 0x2 },
1884 { "CD", 0x4 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885 },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001886};
1887
1888/* channel source setting (2/6 channel selection for 3-stack) */
1889/* 2ch mode */
1890static struct hda_verb alc880_threestack_ch2_init[] = {
1891 /* set line-in to input, mute it */
1892 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
1893 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1894 /* set mic-in to input vref 80%, mute it */
1895 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1896 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897 { } /* end */
1898};
1899
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001900/* 6ch mode */
1901static struct hda_verb alc880_threestack_ch6_init[] = {
1902 /* set line-in to output, unmute it */
1903 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1904 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1905 /* set mic-in to output, unmute it */
1906 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1907 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1908 { } /* end */
1909};
1910
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01001911static struct hda_channel_mode alc880_threestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001912 { 2, alc880_threestack_ch2_init },
1913 { 6, alc880_threestack_ch6_init },
1914};
1915
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001916static struct snd_kcontrol_new alc880_three_stack_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02001917 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001918 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02001919 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001920 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02001921 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
1922 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01001923 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
1924 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
1926 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
1927 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
1928 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
1929 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
1930 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
1931 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
1932 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001934 {
1935 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1936 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01001937 .info = alc_ch_mode_info,
1938 .get = alc_ch_mode_get,
1939 .put = alc_ch_mode_put,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001940 },
1941 { } /* end */
1942};
1943
1944/* capture mixer elements */
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001945static int alc_cap_vol_info(struct snd_kcontrol *kcontrol,
1946 struct snd_ctl_elem_info *uinfo)
1947{
1948 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1949 struct alc_spec *spec = codec->spec;
1950 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001951
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001952 mutex_lock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001953 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0,
1954 HDA_INPUT);
1955 err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001956 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001957 return err;
1958}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001960static int alc_cap_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
1961 unsigned int size, unsigned int __user *tlv)
1962{
1963 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1964 struct alc_spec *spec = codec->spec;
1965 int err;
1966
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001967 mutex_lock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001968 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0,
1969 HDA_INPUT);
1970 err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001971 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001972 return err;
1973}
1974
1975typedef int (*getput_call_t)(struct snd_kcontrol *kcontrol,
1976 struct snd_ctl_elem_value *ucontrol);
1977
1978static int alc_cap_getput_caller(struct snd_kcontrol *kcontrol,
1979 struct snd_ctl_elem_value *ucontrol,
1980 getput_call_t func)
1981{
1982 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1983 struct alc_spec *spec = codec->spec;
1984 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1985 int err;
1986
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001987 mutex_lock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001988 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[adc_idx],
1989 3, 0, HDA_INPUT);
1990 err = func(kcontrol, ucontrol);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001991 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001992 return err;
1993}
1994
1995static int alc_cap_vol_get(struct snd_kcontrol *kcontrol,
1996 struct snd_ctl_elem_value *ucontrol)
1997{
1998 return alc_cap_getput_caller(kcontrol, ucontrol,
1999 snd_hda_mixer_amp_volume_get);
2000}
2001
2002static int alc_cap_vol_put(struct snd_kcontrol *kcontrol,
2003 struct snd_ctl_elem_value *ucontrol)
2004{
2005 return alc_cap_getput_caller(kcontrol, ucontrol,
2006 snd_hda_mixer_amp_volume_put);
2007}
2008
2009/* capture mixer elements */
2010#define alc_cap_sw_info snd_ctl_boolean_stereo_info
2011
2012static int alc_cap_sw_get(struct snd_kcontrol *kcontrol,
2013 struct snd_ctl_elem_value *ucontrol)
2014{
2015 return alc_cap_getput_caller(kcontrol, ucontrol,
2016 snd_hda_mixer_amp_switch_get);
2017}
2018
2019static int alc_cap_sw_put(struct snd_kcontrol *kcontrol,
2020 struct snd_ctl_elem_value *ucontrol)
2021{
2022 return alc_cap_getput_caller(kcontrol, ucontrol,
2023 snd_hda_mixer_amp_switch_put);
2024}
2025
Takashi Iwaia23b6882009-03-23 15:21:36 +01002026#define _DEFINE_CAPMIX(num) \
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002027 { \
2028 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2029 .name = "Capture Switch", \
2030 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
2031 .count = num, \
2032 .info = alc_cap_sw_info, \
2033 .get = alc_cap_sw_get, \
2034 .put = alc_cap_sw_put, \
2035 }, \
2036 { \
2037 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2038 .name = "Capture Volume", \
2039 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | \
2040 SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
2041 SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK), \
2042 .count = num, \
2043 .info = alc_cap_vol_info, \
2044 .get = alc_cap_vol_get, \
2045 .put = alc_cap_vol_put, \
2046 .tlv = { .c = alc_cap_vol_tlv }, \
Takashi Iwaia23b6882009-03-23 15:21:36 +01002047 }
2048
2049#define _DEFINE_CAPSRC(num) \
Takashi Iwai3c3e9892008-10-31 17:48:56 +01002050 { \
2051 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2052 /* .name = "Capture Source", */ \
2053 .name = "Input Source", \
2054 .count = num, \
2055 .info = alc_mux_enum_info, \
2056 .get = alc_mux_enum_get, \
2057 .put = alc_mux_enum_put, \
Takashi Iwaia23b6882009-03-23 15:21:36 +01002058 }
2059
2060#define DEFINE_CAPMIX(num) \
2061static struct snd_kcontrol_new alc_capture_mixer ## num[] = { \
2062 _DEFINE_CAPMIX(num), \
2063 _DEFINE_CAPSRC(num), \
2064 { } /* end */ \
2065}
2066
2067#define DEFINE_CAPMIX_NOSRC(num) \
2068static struct snd_kcontrol_new alc_capture_mixer_nosrc ## num[] = { \
2069 _DEFINE_CAPMIX(num), \
2070 { } /* end */ \
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002071}
2072
2073/* up to three ADCs */
2074DEFINE_CAPMIX(1);
2075DEFINE_CAPMIX(2);
2076DEFINE_CAPMIX(3);
Takashi Iwaia23b6882009-03-23 15:21:36 +01002077DEFINE_CAPMIX_NOSRC(1);
2078DEFINE_CAPMIX_NOSRC(2);
2079DEFINE_CAPMIX_NOSRC(3);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002080
2081/*
2082 * ALC880 5-stack model
2083 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002084 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0d),
2085 * Side = 0x02 (0xd)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002086 * Pin assignment: Front = 0x14, Surr = 0x17, CLFE = 0x16
2087 * Line-In/Side = 0x1a, Mic = 0x18, F-Mic = 0x1b, HP = 0x19
2088 */
2089
2090/* additional mixers to alc880_three_stack_mixer */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002091static struct snd_kcontrol_new alc880_five_stack_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002092 HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002093 HDA_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094 { } /* end */
2095};
2096
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002097/* channel source setting (6/8 channel selection for 5-stack) */
2098/* 6ch mode */
2099static struct hda_verb alc880_fivestack_ch6_init[] = {
2100 /* set line-in to input, mute it */
2101 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2102 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02002103 { } /* end */
2104};
2105
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002106/* 8ch mode */
2107static struct hda_verb alc880_fivestack_ch8_init[] = {
2108 /* set line-in to output, unmute it */
2109 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2110 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2111 { } /* end */
2112};
2113
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002114static struct hda_channel_mode alc880_fivestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002115 { 6, alc880_fivestack_ch6_init },
2116 { 8, alc880_fivestack_ch8_init },
2117};
2118
2119
2120/*
2121 * ALC880 6-stack model
2122 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002123 * DAC: Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e),
2124 * Side = 0x05 (0x0f)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002125 * Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, Side = 0x17,
2126 * Mic = 0x18, F-Mic = 0x19, Line = 0x1a, HP = 0x1b
2127 */
2128
2129static hda_nid_t alc880_6st_dac_nids[4] = {
2130 /* front, rear, clfe, rear_surr */
2131 0x02, 0x03, 0x04, 0x05
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002132};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002133
2134static struct hda_input_mux alc880_6stack_capture_source = {
2135 .num_items = 4,
2136 .items = {
2137 { "Mic", 0x0 },
2138 { "Front Mic", 0x1 },
2139 { "Line", 0x2 },
2140 { "CD", 0x4 },
2141 },
2142};
2143
2144/* fixed 8-channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002145static struct hda_channel_mode alc880_sixstack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002146 { 8, NULL },
2147};
2148
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002149static struct snd_kcontrol_new alc880_six_stack_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02002150 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002151 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002152 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002153 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002154 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2155 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002156 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2157 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002158 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002159 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002160 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2161 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2162 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2163 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2164 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2165 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2166 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2167 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002168 {
2169 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2170 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01002171 .info = alc_ch_mode_info,
2172 .get = alc_ch_mode_get,
2173 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02002174 },
2175 { } /* end */
2176};
2177
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002178
2179/*
2180 * ALC880 W810 model
2181 *
2182 * W810 has rear IO for:
2183 * Front (DAC 02)
2184 * Surround (DAC 03)
2185 * Center/LFE (DAC 04)
2186 * Digital out (06)
2187 *
2188 * The system also has a pair of internal speakers, and a headphone jack.
2189 * These are both connected to Line2 on the codec, hence to DAC 02.
Kailang Yangea1fb292008-08-26 12:58:38 +02002190 *
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002191 * There is a variable resistor to control the speaker or headphone
2192 * volume. This is a hardware-only device without a software API.
2193 *
2194 * Plugging headphones in will disable the internal speakers. This is
2195 * implemented in hardware, not via the driver using jack sense. In
2196 * a similar fashion, plugging into the rear socket marked "front" will
2197 * disable both the speakers and headphones.
2198 *
2199 * For input, there's a microphone jack, and an "audio in" jack.
2200 * These may not do anything useful with this driver yet, because I
2201 * haven't setup any initialization verbs for these yet...
2202 */
2203
2204static hda_nid_t alc880_w810_dac_nids[3] = {
2205 /* front, rear/surround, clfe */
2206 0x02, 0x03, 0x04
2207};
2208
2209/* fixed 6 channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002210static struct hda_channel_mode alc880_w810_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002211 { 6, NULL }
2212};
2213
2214/* Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, HP = 0x1b */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002215static struct snd_kcontrol_new alc880_w810_base_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002216 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002217 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002218 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002219 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002220 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2221 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002222 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2223 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002224 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
2225 { } /* end */
2226};
2227
2228
2229/*
2230 * Z710V model
2231 *
2232 * DAC: Front = 0x02 (0x0c), HP = 0x03 (0x0d)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002233 * Pin assignment: Front = 0x14, HP = 0x15, Mic = 0x18, Mic2 = 0x19(?),
2234 * Line = 0x1a
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002235 */
2236
2237static hda_nid_t alc880_z71v_dac_nids[1] = {
2238 0x02
2239};
2240#define ALC880_Z71V_HP_DAC 0x03
2241
2242/* fixed 2 channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002243static struct hda_channel_mode alc880_2_jack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002244 { 2, NULL }
2245};
2246
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002247static struct snd_kcontrol_new alc880_z71v_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002248 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002249 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002250 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002251 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002252 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2253 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2254 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2255 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2256 { } /* end */
2257};
2258
2259
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002260/*
2261 * ALC880 F1734 model
2262 *
2263 * DAC: HP = 0x02 (0x0c), Front = 0x03 (0x0d)
2264 * Pin assignment: HP = 0x14, Front = 0x15, Mic = 0x18
2265 */
2266
2267static hda_nid_t alc880_f1734_dac_nids[1] = {
2268 0x03
2269};
2270#define ALC880_F1734_HP_DAC 0x02
2271
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002272static struct snd_kcontrol_new alc880_f1734_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02002273 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002274 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01002275 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2276 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002277 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2278 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Takashi Iwai937b4162008-02-11 14:52:36 +01002279 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2280 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002281 { } /* end */
2282};
2283
Takashi Iwai937b4162008-02-11 14:52:36 +01002284static struct hda_input_mux alc880_f1734_capture_source = {
2285 .num_items = 2,
2286 .items = {
2287 { "Mic", 0x1 },
2288 { "CD", 0x4 },
2289 },
2290};
2291
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002292
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002293/*
2294 * ALC880 ASUS model
2295 *
2296 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
2297 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
2298 * Mic = 0x18, Line = 0x1a
2299 */
2300
2301#define alc880_asus_dac_nids alc880_w810_dac_nids /* identical with w810 */
2302#define alc880_asus_modes alc880_threestack_modes /* 2/6 channel mode */
2303
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002304static struct snd_kcontrol_new alc880_asus_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02002305 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002306 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002307 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002308 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002309 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2310 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002311 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2312 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002313 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2314 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2315 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2316 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2317 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2318 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002319 {
2320 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2321 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01002322 .info = alc_ch_mode_info,
2323 .get = alc_ch_mode_get,
2324 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02002325 },
2326 { } /* end */
2327};
2328
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002329/*
2330 * ALC880 ASUS W1V model
2331 *
2332 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
2333 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
2334 * Mic = 0x18, Line = 0x1a, Line2 = 0x1b
2335 */
2336
2337/* additional mixers to alc880_asus_mixer */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002338static struct snd_kcontrol_new alc880_asus_w1v_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02002339 HDA_CODEC_VOLUME("Line2 Playback Volume", 0x0b, 0x03, HDA_INPUT),
2340 HDA_CODEC_MUTE("Line2 Playback Switch", 0x0b, 0x03, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002341 { } /* end */
2342};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002343
Kailang Yangdf694da2005-12-05 19:42:22 +01002344/* TCL S700 */
2345static struct snd_kcontrol_new alc880_tcl_s700_mixer[] = {
2346 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2347 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
2348 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
2349 HDA_CODEC_VOLUME("CD Playback Volume", 0x0B, 0x04, HDA_INPUT),
2350 HDA_CODEC_MUTE("CD Playback Switch", 0x0B, 0x04, HDA_INPUT),
2351 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0B, 0x0, HDA_INPUT),
2352 HDA_CODEC_MUTE("Mic Playback Switch", 0x0B, 0x0, HDA_INPUT),
2353 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
2354 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01002355 { } /* end */
2356};
2357
Kailang Yangccc656c2006-10-17 12:32:26 +02002358/* Uniwill */
2359static struct snd_kcontrol_new alc880_uniwill_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01002360 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2361 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
2362 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2363 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02002364 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2365 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
2366 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2367 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
2368 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2369 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2370 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2371 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2372 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2373 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2374 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2375 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02002376 {
2377 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2378 .name = "Channel Mode",
2379 .info = alc_ch_mode_info,
2380 .get = alc_ch_mode_get,
2381 .put = alc_ch_mode_put,
2382 },
2383 { } /* end */
2384};
2385
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01002386static struct snd_kcontrol_new alc880_fujitsu_mixer[] = {
2387 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2388 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
2389 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2390 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
2391 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2392 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2393 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2394 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2395 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2396 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
2397 { } /* end */
2398};
2399
Kailang Yangccc656c2006-10-17 12:32:26 +02002400static struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01002401 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2402 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
2403 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2404 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02002405 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2406 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2407 { } /* end */
2408};
2409
Linus Torvalds1da177e2005-04-16 15:20:36 -07002410/*
Takashi Iwai2134ea42008-01-10 16:53:55 +01002411 * virtual master controls
2412 */
2413
2414/*
2415 * slave controls for virtual master
2416 */
2417static const char *alc_slave_vols[] = {
2418 "Front Playback Volume",
2419 "Surround Playback Volume",
2420 "Center Playback Volume",
2421 "LFE Playback Volume",
2422 "Side Playback Volume",
2423 "Headphone Playback Volume",
2424 "Speaker Playback Volume",
2425 "Mono Playback Volume",
Takashi Iwai2134ea42008-01-10 16:53:55 +01002426 "Line-Out Playback Volume",
Takashi Iwai26f5df22008-11-03 17:39:46 +01002427 "PCM Playback Volume",
Takashi Iwai2134ea42008-01-10 16:53:55 +01002428 NULL,
2429};
2430
2431static const char *alc_slave_sws[] = {
2432 "Front Playback Switch",
2433 "Surround Playback Switch",
2434 "Center Playback Switch",
2435 "LFE Playback Switch",
2436 "Side Playback Switch",
2437 "Headphone Playback Switch",
2438 "Speaker Playback Switch",
2439 "Mono Playback Switch",
Takashi Iwaiedb54a52008-01-29 12:47:02 +01002440 "IEC958 Playback Switch",
Takashi Iwai23033b22009-12-08 12:36:52 +01002441 "Line-Out Playback Switch",
2442 "PCM Playback Switch",
Takashi Iwai2134ea42008-01-10 16:53:55 +01002443 NULL,
2444};
2445
2446/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002447 * build control elements
Linus Torvalds1da177e2005-04-16 15:20:36 -07002448 */
Takashi Iwai603c4012008-07-30 15:01:44 +02002449
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01002450#define NID_MAPPING (-1)
2451
2452#define SUBDEV_SPEAKER_ (0 << 6)
2453#define SUBDEV_HP_ (1 << 6)
2454#define SUBDEV_LINE_ (2 << 6)
2455#define SUBDEV_SPEAKER(x) (SUBDEV_SPEAKER_ | ((x) & 0x3f))
2456#define SUBDEV_HP(x) (SUBDEV_HP_ | ((x) & 0x3f))
2457#define SUBDEV_LINE(x) (SUBDEV_LINE_ | ((x) & 0x3f))
2458
Takashi Iwai603c4012008-07-30 15:01:44 +02002459static void alc_free_kctls(struct hda_codec *codec);
2460
Takashi Iwai67d634c2009-11-16 15:35:59 +01002461#ifdef CONFIG_SND_HDA_INPUT_BEEP
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002462/* additional beep mixers; the actual parameters are overwritten at build */
2463static struct snd_kcontrol_new alc_beep_mixer[] = {
2464 HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_INPUT),
Jaroslav Kysela123c07a2009-10-21 14:48:23 +02002465 HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002466 { } /* end */
2467};
Takashi Iwai67d634c2009-11-16 15:35:59 +01002468#endif
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002469
Linus Torvalds1da177e2005-04-16 15:20:36 -07002470static int alc_build_controls(struct hda_codec *codec)
2471{
2472 struct alc_spec *spec = codec->spec;
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01002473 struct snd_kcontrol *kctl;
2474 struct snd_kcontrol_new *knew;
2475 int i, j, err;
2476 unsigned int u;
2477 hda_nid_t nid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002478
2479 for (i = 0; i < spec->num_mixers; i++) {
2480 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
2481 if (err < 0)
2482 return err;
2483 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002484 if (spec->cap_mixer) {
2485 err = snd_hda_add_new_ctls(codec, spec->cap_mixer);
2486 if (err < 0)
2487 return err;
2488 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002489 if (spec->multiout.dig_out_nid) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002490 err = snd_hda_create_spdif_out_ctls(codec,
2491 spec->multiout.dig_out_nid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492 if (err < 0)
2493 return err;
Takashi Iwaie64f14f2009-01-20 18:32:55 +01002494 if (!spec->no_analog) {
2495 err = snd_hda_create_spdif_share_sw(codec,
2496 &spec->multiout);
2497 if (err < 0)
2498 return err;
2499 spec->multiout.share_spdif = 1;
2500 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002501 }
2502 if (spec->dig_in_nid) {
2503 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
2504 if (err < 0)
2505 return err;
2506 }
Takashi Iwai2134ea42008-01-10 16:53:55 +01002507
Takashi Iwai67d634c2009-11-16 15:35:59 +01002508#ifdef CONFIG_SND_HDA_INPUT_BEEP
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002509 /* create beep controls if needed */
2510 if (spec->beep_amp) {
2511 struct snd_kcontrol_new *knew;
2512 for (knew = alc_beep_mixer; knew->name; knew++) {
2513 struct snd_kcontrol *kctl;
2514 kctl = snd_ctl_new1(knew, codec);
2515 if (!kctl)
2516 return -ENOMEM;
2517 kctl->private_value = spec->beep_amp;
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +01002518 err = snd_hda_ctl_add(codec, 0, kctl);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002519 if (err < 0)
2520 return err;
2521 }
2522 }
Takashi Iwai67d634c2009-11-16 15:35:59 +01002523#endif
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002524
Takashi Iwai2134ea42008-01-10 16:53:55 +01002525 /* if we have no master control, let's create it */
Takashi Iwaie64f14f2009-01-20 18:32:55 +01002526 if (!spec->no_analog &&
2527 !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
Takashi Iwai1c82ed12008-02-18 13:05:50 +01002528 unsigned int vmaster_tlv[4];
Takashi Iwai2134ea42008-01-10 16:53:55 +01002529 snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
Takashi Iwai1c82ed12008-02-18 13:05:50 +01002530 HDA_OUTPUT, vmaster_tlv);
Takashi Iwai2134ea42008-01-10 16:53:55 +01002531 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
Takashi Iwai1c82ed12008-02-18 13:05:50 +01002532 vmaster_tlv, alc_slave_vols);
Takashi Iwai2134ea42008-01-10 16:53:55 +01002533 if (err < 0)
2534 return err;
2535 }
Takashi Iwaie64f14f2009-01-20 18:32:55 +01002536 if (!spec->no_analog &&
2537 !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
Takashi Iwai2134ea42008-01-10 16:53:55 +01002538 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
2539 NULL, alc_slave_sws);
2540 if (err < 0)
2541 return err;
2542 }
2543
Takashi Iwai603c4012008-07-30 15:01:44 +02002544 alc_free_kctls(codec); /* no longer needed */
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01002545
2546 /* assign Capture Source enums to NID */
2547 kctl = snd_hda_find_mixer_ctl(codec, "Capture Source");
2548 if (!kctl)
2549 kctl = snd_hda_find_mixer_ctl(codec, "Input Source");
2550 for (i = 0; kctl && i < kctl->count; i++) {
Takashi Iwaid1409ae2009-12-17 15:01:31 +01002551 hda_nid_t *nids = spec->capsrc_nids;
2552 if (!nids)
2553 nids = spec->adc_nids;
Takashi Iwai21949f02009-12-23 08:31:59 +01002554 err = snd_hda_add_nid(codec, kctl, i, nids[i]);
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01002555 if (err < 0)
2556 return err;
2557 }
2558 if (spec->cap_mixer) {
2559 const char *kname = kctl ? kctl->id.name : NULL;
2560 for (knew = spec->cap_mixer; knew->name; knew++) {
2561 if (kname && strcmp(knew->name, kname) == 0)
2562 continue;
2563 kctl = snd_hda_find_mixer_ctl(codec, knew->name);
2564 for (i = 0; kctl && i < kctl->count; i++) {
2565 err = snd_hda_add_nid(codec, kctl, i,
2566 spec->adc_nids[i]);
2567 if (err < 0)
2568 return err;
2569 }
2570 }
2571 }
2572
2573 /* other nid->control mapping */
2574 for (i = 0; i < spec->num_mixers; i++) {
2575 for (knew = spec->mixers[i]; knew->name; knew++) {
2576 if (knew->iface != NID_MAPPING)
2577 continue;
2578 kctl = snd_hda_find_mixer_ctl(codec, knew->name);
2579 if (kctl == NULL)
2580 continue;
2581 u = knew->subdevice;
2582 for (j = 0; j < 4; j++, u >>= 8) {
2583 nid = u & 0x3f;
2584 if (nid == 0)
2585 continue;
2586 switch (u & 0xc0) {
2587 case SUBDEV_SPEAKER_:
2588 nid = spec->autocfg.speaker_pins[nid];
2589 break;
2590 case SUBDEV_LINE_:
2591 nid = spec->autocfg.line_out_pins[nid];
2592 break;
2593 case SUBDEV_HP_:
2594 nid = spec->autocfg.hp_pins[nid];
2595 break;
2596 default:
2597 continue;
2598 }
2599 err = snd_hda_add_nid(codec, kctl, 0, nid);
2600 if (err < 0)
2601 return err;
2602 }
2603 u = knew->private_value;
2604 for (j = 0; j < 4; j++, u >>= 8) {
2605 nid = u & 0xff;
2606 if (nid == 0)
2607 continue;
2608 err = snd_hda_add_nid(codec, kctl, 0, nid);
2609 if (err < 0)
2610 return err;
2611 }
2612 }
2613 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614 return 0;
2615}
2616
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002617
Linus Torvalds1da177e2005-04-16 15:20:36 -07002618/*
2619 * initialize the codec volumes, etc
2620 */
2621
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002622/*
2623 * generic initialization of ADC, input mixers and output mixers
2624 */
2625static struct hda_verb alc880_volume_init_verbs[] = {
2626 /*
2627 * Unmute ADC0-2 and set the default input to mic-in
2628 */
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002629 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002630 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002631 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002632 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02002633 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002634 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002636 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
2637 * mixer widget
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002638 * Note: PASD motherboards uses the Line In 2 as the input for front
2639 * panel mic (mic 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002641 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02002642 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2643 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2644 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
2645 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2646 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
2647 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
2648 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002649
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002650 /*
2651 * Set up output mixers (0x0c - 0x0f)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002653 /* set vol=0 to output mixers */
2654 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2655 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2656 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2657 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2658 /* set up input amps for analog loopback */
2659 /* Amp Indices: DAC = 0, mixer = 1 */
Takashi Iwai05acb862005-06-10 19:50:25 +02002660 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2661 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02002662 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2663 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02002664 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2665 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02002666 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2667 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002668
2669 { }
2670};
2671
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002672/*
2673 * 3-stack pin configuration:
2674 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
2675 */
2676static struct hda_verb alc880_pin_3stack_init_verbs[] = {
2677 /*
2678 * preset connection lists of input pins
2679 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
2680 */
2681 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
2682 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2683 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
2684
2685 /*
2686 * Set pin mode and muting
2687 */
2688 /* set front pin widgets 0x14 for output */
2689 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2690 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2691 /* Mic1 (rear panel) pin widget for input and vref at 80% */
2692 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2693 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2694 /* Mic2 (as headphone out) for HP output */
2695 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2696 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2697 /* Line In pin widget for input */
2698 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2699 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2700 /* Line2 (as front mic) pin widget for input and vref at 80% */
2701 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2702 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2703 /* CD pin widget for input */
2704 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2705
2706 { }
2707};
2708
2709/*
2710 * 5-stack pin configuration:
2711 * front = 0x14, surround = 0x17, clfe = 0x16, mic = 0x18, HP = 0x19,
2712 * line-in/side = 0x1a, f-mic = 0x1b
2713 */
2714static struct hda_verb alc880_pin_5stack_init_verbs[] = {
2715 /*
2716 * preset connection lists of input pins
2717 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
2718 */
2719 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2720 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/side */
2721
2722 /*
2723 * Set pin mode and muting
2724 */
2725 /* set pin widgets 0x14-0x17 for output */
Takashi Iwai05acb862005-06-10 19:50:25 +02002726 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2727 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2728 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2729 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002730 /* unmute pins for output (no gain on this amp) */
2731 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2732 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2733 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2734 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2735
Linus Torvalds1da177e2005-04-16 15:20:36 -07002736 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02002737 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002738 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2739 /* Mic2 (as headphone out) for HP output */
2740 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02002741 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002742 /* Line In pin widget for input */
2743 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2744 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2745 /* Line2 (as front mic) pin widget for input and vref at 80% */
2746 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2747 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2748 /* CD pin widget for input */
2749 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750
2751 { }
2752};
2753
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002754/*
2755 * W810 pin configuration:
2756 * front = 0x14, surround = 0x15, clfe = 0x16, HP = 0x1b
2757 */
2758static struct hda_verb alc880_pin_w810_init_verbs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759 /* hphone/speaker input selector: front DAC */
2760 {0x13, AC_VERB_SET_CONNECT_SEL, 0x0},
2761
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002762 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2763 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2764 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2765 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2766 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2767 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2768
2769 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02002770 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772 { }
2773};
2774
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002775/*
2776 * Z71V pin configuration:
2777 * Speaker-out = 0x14, HP = 0x15, Mic = 0x18, Line-in = 0x1a, Mic2 = 0x1b (?)
2778 */
2779static struct hda_verb alc880_pin_z71v_init_verbs[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02002780 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002781 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai05acb862005-06-10 19:50:25 +02002782 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002783 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02002784
Takashi Iwai16ded522005-06-10 19:58:24 +02002785 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002786 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02002787 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002788 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02002789
2790 { }
2791};
2792
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002793/*
2794 * 6-stack pin configuration:
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002795 * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18,
2796 * f-mic = 0x19, line = 0x1a, HP = 0x1b
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002797 */
2798static struct hda_verb alc880_pin_6stack_init_verbs[] = {
2799 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2800
Takashi Iwai16ded522005-06-10 19:58:24 +02002801 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002802 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002803 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002804 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002805 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002806 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002807 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002808 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2809
Takashi Iwai16ded522005-06-10 19:58:24 +02002810 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002811 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002812 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002813 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002814 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002815 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002816 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai16ded522005-06-10 19:58:24 +02002817 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02002818 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangea1fb292008-08-26 12:58:38 +02002819
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002820 { }
2821};
Takashi Iwai16ded522005-06-10 19:58:24 +02002822
Kailang Yangccc656c2006-10-17 12:32:26 +02002823/*
2824 * Uniwill pin configuration:
2825 * HP = 0x14, InternalSpeaker = 0x15, mic = 0x18, internal mic = 0x19,
2826 * line = 0x1a
2827 */
2828static struct hda_verb alc880_uniwill_init_verbs[] = {
2829 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2830
2831 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2832 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2833 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2834 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2835 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2836 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2837 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2838 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2839 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2840 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2841 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2842 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2843 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2844 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2845
2846 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2847 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2848 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2849 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2850 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2851 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2852 /* {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, */
2853 /* {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
2854 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2855
2856 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
2857 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
2858
2859 { }
2860};
2861
2862/*
2863* Uniwill P53
Kailang Yangea1fb292008-08-26 12:58:38 +02002864* HP = 0x14, InternalSpeaker = 0x15, mic = 0x19,
Kailang Yangccc656c2006-10-17 12:32:26 +02002865 */
2866static struct hda_verb alc880_uniwill_p53_init_verbs[] = {
2867 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
2868
2869 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2870 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2871 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2872 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2873 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2874 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2875 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2876 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2877 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2878 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2879 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
2880 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
2881
2882 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2883 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2884 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2885 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2886 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2887 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2888
2889 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
2890 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_DCVOL_EVENT},
2891
2892 { }
2893};
2894
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01002895static struct hda_verb alc880_beep_init_verbs[] = {
2896 { 0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) },
2897 { }
2898};
2899
Takashi Iwai458a4fa2007-05-05 12:18:40 +02002900/* auto-toggle front mic */
2901static void alc880_uniwill_mic_automute(struct hda_codec *codec)
2902{
2903 unsigned int present;
2904 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02002905
Wu Fengguang864f92b2009-11-18 12:38:02 +08002906 present = snd_hda_jack_detect(codec, 0x18);
Takashi Iwai47fd8302007-08-10 17:11:07 +02002907 bits = present ? HDA_AMP_MUTE : 0;
2908 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02002909}
2910
Takashi Iwai4f5d17062009-08-11 18:17:46 +02002911static void alc880_uniwill_setup(struct hda_codec *codec)
Takashi Iwai458a4fa2007-05-05 12:18:40 +02002912{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002913 struct alc_spec *spec = codec->spec;
2914
2915 spec->autocfg.hp_pins[0] = 0x14;
2916 spec->autocfg.speaker_pins[0] = 0x15;
2917 spec->autocfg.speaker_pins[0] = 0x16;
Takashi Iwai4f5d17062009-08-11 18:17:46 +02002918}
2919
2920static void alc880_uniwill_init_hook(struct hda_codec *codec)
2921{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002922 alc_automute_amp(codec);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02002923 alc880_uniwill_mic_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02002924}
2925
2926static void alc880_uniwill_unsol_event(struct hda_codec *codec,
2927 unsigned int res)
2928{
2929 /* Looks like the unsol event is incompatible with the standard
2930 * definition. 4bit tag is placed at 28 bit!
2931 */
Takashi Iwai458a4fa2007-05-05 12:18:40 +02002932 switch (res >> 28) {
Takashi Iwai458a4fa2007-05-05 12:18:40 +02002933 case ALC880_MIC_EVENT:
2934 alc880_uniwill_mic_automute(codec);
2935 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002936 default:
2937 alc_automute_amp_unsol_event(codec, res);
2938 break;
Takashi Iwai458a4fa2007-05-05 12:18:40 +02002939 }
Kailang Yangccc656c2006-10-17 12:32:26 +02002940}
2941
Takashi Iwai4f5d17062009-08-11 18:17:46 +02002942static void alc880_uniwill_p53_setup(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02002943{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002944 struct alc_spec *spec = codec->spec;
Kailang Yangccc656c2006-10-17 12:32:26 +02002945
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002946 spec->autocfg.hp_pins[0] = 0x14;
2947 spec->autocfg.speaker_pins[0] = 0x15;
Kailang Yangccc656c2006-10-17 12:32:26 +02002948}
2949
2950static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec)
2951{
2952 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02002953
Kailang Yangccc656c2006-10-17 12:32:26 +02002954 present = snd_hda_codec_read(codec, 0x21, 0,
Takashi Iwai47fd8302007-08-10 17:11:07 +02002955 AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
2956 present &= HDA_AMP_VOLMASK;
2957 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0,
2958 HDA_AMP_VOLMASK, present);
2959 snd_hda_codec_amp_stereo(codec, 0x0d, HDA_OUTPUT, 0,
2960 HDA_AMP_VOLMASK, present);
Kailang Yangccc656c2006-10-17 12:32:26 +02002961}
Takashi Iwai47fd8302007-08-10 17:11:07 +02002962
Kailang Yangccc656c2006-10-17 12:32:26 +02002963static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec,
2964 unsigned int res)
2965{
2966 /* Looks like the unsol event is incompatible with the standard
2967 * definition. 4bit tag is placed at 28 bit!
2968 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002969 if ((res >> 28) == ALC880_DCVOL_EVENT)
Kailang Yangccc656c2006-10-17 12:32:26 +02002970 alc880_uniwill_p53_dcvol_automute(codec);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002971 else
2972 alc_automute_amp_unsol_event(codec, res);
Kailang Yangccc656c2006-10-17 12:32:26 +02002973}
2974
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002975/*
2976 * F1734 pin configuration:
2977 * HP = 0x14, speaker-out = 0x15, mic = 0x18
2978 */
2979static struct hda_verb alc880_pin_f1734_init_verbs[] = {
Michael Gruberee7a9c72008-03-10 11:30:59 +01002980 {0x07, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002981 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
2982 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
2983 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
2984 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
2985
2986 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2987 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2988 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2989 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2990
2991 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2992 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Michael Gruberee7a9c72008-03-10 11:30:59 +01002993 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002994 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2995 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2996 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2997 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2998 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2999 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02003000
Takashi Iwai937b4162008-02-11 14:52:36 +01003001 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
3002 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_DCVOL_EVENT},
3003
Takashi Iwai16ded522005-06-10 19:58:24 +02003004 { }
3005};
3006
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003007/*
3008 * ASUS pin configuration:
3009 * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a
3010 */
3011static struct hda_verb alc880_pin_asus_init_verbs[] = {
3012 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
3013 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
3014 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
3015 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
3016
3017 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3018 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3019 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3020 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3021 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3022 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3023 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3024 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3025
3026 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3027 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3028 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3029 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3030 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3031 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3032 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3033 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3034 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangea1fb292008-08-26 12:58:38 +02003035
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003036 { }
3037};
3038
3039/* Enable GPIO mask and set output */
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003040#define alc880_gpio1_init_verbs alc_gpio1_init_verbs
3041#define alc880_gpio2_init_verbs alc_gpio2_init_verbs
David Heidelberger64a8be72009-06-08 16:15:18 +02003042#define alc880_gpio3_init_verbs alc_gpio3_init_verbs
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003043
Kailang Yangdf694da2005-12-05 19:42:22 +01003044/* Clevo m520g init */
3045static struct hda_verb alc880_pin_clevo_init_verbs[] = {
3046 /* headphone output */
3047 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
3048 /* line-out */
3049 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3050 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3051 /* Line-in */
3052 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3053 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3054 /* CD */
3055 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3056 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3057 /* Mic1 (rear panel) */
3058 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3059 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3060 /* Mic2 (front panel) */
3061 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3062 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3063 /* headphone */
3064 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3065 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3066 /* change to EAPD mode */
3067 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
3068 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
3069
3070 { }
3071};
3072
3073static struct hda_verb alc880_pin_tcl_S700_init_verbs[] = {
Takashi Iwai4b146cb2006-07-28 14:42:36 +02003074 /* change to EAPD mode */
3075 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
3076 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
3077
Kailang Yangdf694da2005-12-05 19:42:22 +01003078 /* Headphone output */
3079 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3080 /* Front output*/
3081 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3082 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
3083
3084 /* Line In pin widget for input */
3085 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3086 /* CD pin widget for input */
3087 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3088 /* Mic1 (rear panel) pin widget for input and vref at 80% */
3089 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3090
3091 /* change to EAPD mode */
3092 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
3093 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
3094
3095 { }
3096};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003097
3098/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003099 * LG m1 express dual
3100 *
3101 * Pin assignment:
3102 * Rear Line-In/Out (blue): 0x14
3103 * Build-in Mic-In: 0x15
3104 * Speaker-out: 0x17
3105 * HP-Out (green): 0x1b
3106 * Mic-In/Out (red): 0x19
3107 * SPDIF-Out: 0x1e
3108 */
3109
3110/* To make 5.1 output working (green=Front, blue=Surr, red=CLFE) */
3111static hda_nid_t alc880_lg_dac_nids[3] = {
3112 0x05, 0x02, 0x03
3113};
3114
3115/* seems analog CD is not working */
3116static struct hda_input_mux alc880_lg_capture_source = {
3117 .num_items = 3,
3118 .items = {
3119 { "Mic", 0x1 },
3120 { "Line", 0x5 },
3121 { "Internal Mic", 0x6 },
3122 },
3123};
3124
3125/* 2,4,6 channel modes */
3126static struct hda_verb alc880_lg_ch2_init[] = {
3127 /* set line-in and mic-in to input */
3128 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
3129 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
3130 { }
3131};
3132
3133static struct hda_verb alc880_lg_ch4_init[] = {
3134 /* set line-in to out and mic-in to input */
3135 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
3136 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
3137 { }
3138};
3139
3140static struct hda_verb alc880_lg_ch6_init[] = {
3141 /* set line-in and mic-in to output */
3142 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
3143 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
3144 { }
3145};
3146
3147static struct hda_channel_mode alc880_lg_ch_modes[3] = {
3148 { 2, alc880_lg_ch2_init },
3149 { 4, alc880_lg_ch4_init },
3150 { 6, alc880_lg_ch6_init },
3151};
3152
3153static struct snd_kcontrol_new alc880_lg_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01003154 HDA_CODEC_VOLUME("Front Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
3155 HDA_BIND_MUTE("Front Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003156 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3157 HDA_BIND_MUTE("Surround Playback Switch", 0x0c, 2, HDA_INPUT),
3158 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
3159 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
3160 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
3161 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
3162 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
3163 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
3164 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x06, HDA_INPUT),
3165 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x06, HDA_INPUT),
3166 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x07, HDA_INPUT),
3167 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x07, HDA_INPUT),
3168 {
3169 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3170 .name = "Channel Mode",
3171 .info = alc_ch_mode_info,
3172 .get = alc_ch_mode_get,
3173 .put = alc_ch_mode_put,
3174 },
3175 { } /* end */
3176};
3177
3178static struct hda_verb alc880_lg_init_verbs[] = {
3179 /* set capture source to mic-in */
3180 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3181 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3182 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3183 /* mute all amp mixer inputs */
3184 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02003185 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
3186 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003187 /* line-in to input */
3188 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3189 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3190 /* built-in mic */
3191 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3192 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3193 /* speaker-out */
3194 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3195 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3196 /* mic-in to input */
3197 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
3198 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3199 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3200 /* HP-out */
3201 {0x13, AC_VERB_SET_CONNECT_SEL, 0x03},
3202 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3203 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3204 /* jack sense */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003205 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003206 { }
3207};
3208
3209/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003210static void alc880_lg_setup(struct hda_codec *codec)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003211{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003212 struct alc_spec *spec = codec->spec;
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003213
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003214 spec->autocfg.hp_pins[0] = 0x1b;
3215 spec->autocfg.speaker_pins[0] = 0x17;
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003216}
3217
3218/*
Takashi Iwaid6815182006-03-23 16:06:23 +01003219 * LG LW20
3220 *
3221 * Pin assignment:
3222 * Speaker-out: 0x14
3223 * Mic-In: 0x18
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02003224 * Built-in Mic-In: 0x19
3225 * Line-In: 0x1b
3226 * HP-Out: 0x1a
Takashi Iwaid6815182006-03-23 16:06:23 +01003227 * SPDIF-Out: 0x1e
3228 */
3229
Takashi Iwaid6815182006-03-23 16:06:23 +01003230static struct hda_input_mux alc880_lg_lw_capture_source = {
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02003231 .num_items = 3,
Takashi Iwaid6815182006-03-23 16:06:23 +01003232 .items = {
3233 { "Mic", 0x0 },
3234 { "Internal Mic", 0x1 },
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02003235 { "Line In", 0x2 },
Takashi Iwaid6815182006-03-23 16:06:23 +01003236 },
3237};
3238
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003239#define alc880_lg_lw_modes alc880_threestack_modes
3240
Takashi Iwaid6815182006-03-23 16:06:23 +01003241static struct snd_kcontrol_new alc880_lg_lw_mixer[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003242 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3243 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
3244 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
3245 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
3246 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
3247 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
3248 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
3249 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
3250 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
3251 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaid6815182006-03-23 16:06:23 +01003252 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
3253 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
3254 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
3255 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003256 {
3257 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3258 .name = "Channel Mode",
3259 .info = alc_ch_mode_info,
3260 .get = alc_ch_mode_get,
3261 .put = alc_ch_mode_put,
3262 },
Takashi Iwaid6815182006-03-23 16:06:23 +01003263 { } /* end */
3264};
3265
3266static struct hda_verb alc880_lg_lw_init_verbs[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003267 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3268 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
3269 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
3270
Takashi Iwaid6815182006-03-23 16:06:23 +01003271 /* set capture source to mic-in */
3272 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3273 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3274 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02003275 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaid6815182006-03-23 16:06:23 +01003276 /* speaker-out */
3277 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3278 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3279 /* HP-out */
Takashi Iwaid6815182006-03-23 16:06:23 +01003280 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3281 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3282 /* mic-in to input */
3283 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3284 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3285 /* built-in mic */
3286 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3287 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3288 /* jack sense */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003289 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaid6815182006-03-23 16:06:23 +01003290 { }
3291};
3292
3293/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003294static void alc880_lg_lw_setup(struct hda_codec *codec)
Takashi Iwaid6815182006-03-23 16:06:23 +01003295{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003296 struct alc_spec *spec = codec->spec;
Takashi Iwaid6815182006-03-23 16:06:23 +01003297
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003298 spec->autocfg.hp_pins[0] = 0x1b;
3299 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwaid6815182006-03-23 16:06:23 +01003300}
3301
Takashi Iwaidf99cd32008-04-25 15:25:04 +02003302static struct snd_kcontrol_new alc880_medion_rim_mixer[] = {
3303 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3304 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
3305 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
3306 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
3307 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
3308 HDA_CODEC_MUTE("Internal Playback Switch", 0x0b, 0x1, HDA_INPUT),
3309 { } /* end */
3310};
3311
3312static struct hda_input_mux alc880_medion_rim_capture_source = {
3313 .num_items = 2,
3314 .items = {
3315 { "Mic", 0x0 },
3316 { "Internal Mic", 0x1 },
3317 },
3318};
3319
3320static struct hda_verb alc880_medion_rim_init_verbs[] = {
3321 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3322
3323 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3324 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3325
3326 /* Mic1 (rear panel) pin widget for input and vref at 80% */
3327 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3328 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3329 /* Mic2 (as headphone out) for HP output */
3330 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3331 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3332 /* Internal Speaker */
3333 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3334 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3335
3336 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
3337 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
3338
3339 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
3340 { }
3341};
3342
3343/* toggle speaker-output according to the hp-jack state */
3344static void alc880_medion_rim_automute(struct hda_codec *codec)
3345{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003346 struct alc_spec *spec = codec->spec;
3347 alc_automute_amp(codec);
3348 /* toggle EAPD */
3349 if (spec->jack_present)
Takashi Iwaidf99cd32008-04-25 15:25:04 +02003350 snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0);
3351 else
3352 snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 2);
3353}
3354
3355static void alc880_medion_rim_unsol_event(struct hda_codec *codec,
3356 unsigned int res)
3357{
3358 /* Looks like the unsol event is incompatible with the standard
3359 * definition. 4bit tag is placed at 28 bit!
3360 */
3361 if ((res >> 28) == ALC880_HP_EVENT)
3362 alc880_medion_rim_automute(codec);
3363}
3364
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003365static void alc880_medion_rim_setup(struct hda_codec *codec)
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003366{
3367 struct alc_spec *spec = codec->spec;
3368
3369 spec->autocfg.hp_pins[0] = 0x14;
3370 spec->autocfg.speaker_pins[0] = 0x1b;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003371}
3372
Takashi Iwaicb53c622007-08-10 17:21:45 +02003373#ifdef CONFIG_SND_HDA_POWER_SAVE
3374static struct hda_amp_list alc880_loopbacks[] = {
3375 { 0x0b, HDA_INPUT, 0 },
3376 { 0x0b, HDA_INPUT, 1 },
3377 { 0x0b, HDA_INPUT, 2 },
3378 { 0x0b, HDA_INPUT, 3 },
3379 { 0x0b, HDA_INPUT, 4 },
3380 { } /* end */
3381};
3382
3383static struct hda_amp_list alc880_lg_loopbacks[] = {
3384 { 0x0b, HDA_INPUT, 1 },
3385 { 0x0b, HDA_INPUT, 6 },
3386 { 0x0b, HDA_INPUT, 7 },
3387 { } /* end */
3388};
3389#endif
3390
Takashi Iwaid6815182006-03-23 16:06:23 +01003391/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003392 * Common callbacks
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003393 */
Takashi Iwai16ded522005-06-10 19:58:24 +02003394
Linus Torvalds1da177e2005-04-16 15:20:36 -07003395static int alc_init(struct hda_codec *codec)
3396{
3397 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003398 unsigned int i;
3399
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02003400 alc_fix_pll(codec);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02003401 alc_auto_init_amp(codec, spec->init_amp);
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02003402
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003403 for (i = 0; i < spec->num_init_verbs; i++)
3404 snd_hda_sequence_write(codec, spec->init_verbs[i]);
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003405
3406 if (spec->init_hook)
3407 spec->init_hook(codec);
3408
Linus Torvalds1da177e2005-04-16 15:20:36 -07003409 return 0;
3410}
3411
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003412static void alc_unsol_event(struct hda_codec *codec, unsigned int res)
3413{
3414 struct alc_spec *spec = codec->spec;
3415
3416 if (spec->unsol_event)
3417 spec->unsol_event(codec, res);
3418}
3419
Takashi Iwaicb53c622007-08-10 17:21:45 +02003420#ifdef CONFIG_SND_HDA_POWER_SAVE
3421static int alc_check_power_status(struct hda_codec *codec, hda_nid_t nid)
3422{
3423 struct alc_spec *spec = codec->spec;
3424 return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
3425}
3426#endif
3427
Linus Torvalds1da177e2005-04-16 15:20:36 -07003428/*
3429 * Analog playback callbacks
3430 */
3431static int alc880_playback_pcm_open(struct hda_pcm_stream *hinfo,
3432 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003433 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003434{
3435 struct alc_spec *spec = codec->spec;
Takashi Iwai9a081602008-02-12 18:37:26 +01003436 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
3437 hinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003438}
3439
3440static int alc880_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
3441 struct hda_codec *codec,
3442 unsigned int stream_tag,
3443 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003444 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003445{
3446 struct alc_spec *spec = codec->spec;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003447 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
3448 stream_tag, format, substream);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003449}
3450
3451static int alc880_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
3452 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003453 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003454{
3455 struct alc_spec *spec = codec->spec;
3456 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
3457}
3458
3459/*
3460 * Digital out
3461 */
3462static int alc880_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
3463 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003464 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003465{
3466 struct alc_spec *spec = codec->spec;
3467 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
3468}
3469
Takashi Iwai6b97eb42007-04-05 14:51:48 +02003470static int alc880_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
3471 struct hda_codec *codec,
3472 unsigned int stream_tag,
3473 unsigned int format,
3474 struct snd_pcm_substream *substream)
3475{
3476 struct alc_spec *spec = codec->spec;
3477 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
3478 stream_tag, format, substream);
3479}
3480
Takashi Iwai9b5f12e2009-02-13 11:47:37 +01003481static int alc880_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
3482 struct hda_codec *codec,
3483 struct snd_pcm_substream *substream)
3484{
3485 struct alc_spec *spec = codec->spec;
3486 return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
3487}
3488
Linus Torvalds1da177e2005-04-16 15:20:36 -07003489static int alc880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
3490 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003491 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003492{
3493 struct alc_spec *spec = codec->spec;
3494 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
3495}
3496
3497/*
3498 * Analog capture
3499 */
Takashi Iwai63300792008-01-24 15:31:36 +01003500static int alc880_alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003501 struct hda_codec *codec,
3502 unsigned int stream_tag,
3503 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003504 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003505{
3506 struct alc_spec *spec = codec->spec;
3507
Takashi Iwai63300792008-01-24 15:31:36 +01003508 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1],
Linus Torvalds1da177e2005-04-16 15:20:36 -07003509 stream_tag, 0, format);
3510 return 0;
3511}
3512
Takashi Iwai63300792008-01-24 15:31:36 +01003513static int alc880_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003514 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003515 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003516{
3517 struct alc_spec *spec = codec->spec;
3518
Takashi Iwai888afa12008-03-18 09:57:50 +01003519 snd_hda_codec_cleanup_stream(codec,
3520 spec->adc_nids[substream->number + 1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003521 return 0;
3522}
3523
3524
3525/*
3526 */
3527static struct hda_pcm_stream alc880_pcm_analog_playback = {
3528 .substreams = 1,
3529 .channels_min = 2,
3530 .channels_max = 8,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003531 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003532 .ops = {
3533 .open = alc880_playback_pcm_open,
3534 .prepare = alc880_playback_pcm_prepare,
3535 .cleanup = alc880_playback_pcm_cleanup
3536 },
3537};
3538
3539static struct hda_pcm_stream alc880_pcm_analog_capture = {
Takashi Iwai63300792008-01-24 15:31:36 +01003540 .substreams = 1,
3541 .channels_min = 2,
3542 .channels_max = 2,
3543 /* NID is set in alc_build_pcms */
3544};
3545
3546static struct hda_pcm_stream alc880_pcm_analog_alt_playback = {
3547 .substreams = 1,
3548 .channels_min = 2,
3549 .channels_max = 2,
3550 /* NID is set in alc_build_pcms */
3551};
3552
3553static struct hda_pcm_stream alc880_pcm_analog_alt_capture = {
3554 .substreams = 2, /* can be overridden */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003555 .channels_min = 2,
3556 .channels_max = 2,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003557 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003558 .ops = {
Takashi Iwai63300792008-01-24 15:31:36 +01003559 .prepare = alc880_alt_capture_pcm_prepare,
3560 .cleanup = alc880_alt_capture_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07003561 },
3562};
3563
3564static struct hda_pcm_stream alc880_pcm_digital_playback = {
3565 .substreams = 1,
3566 .channels_min = 2,
3567 .channels_max = 2,
3568 /* NID is set in alc_build_pcms */
3569 .ops = {
3570 .open = alc880_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02003571 .close = alc880_dig_playback_pcm_close,
Takashi Iwai9b5f12e2009-02-13 11:47:37 +01003572 .prepare = alc880_dig_playback_pcm_prepare,
3573 .cleanup = alc880_dig_playback_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07003574 },
3575};
3576
3577static struct hda_pcm_stream alc880_pcm_digital_capture = {
3578 .substreams = 1,
3579 .channels_min = 2,
3580 .channels_max = 2,
3581 /* NID is set in alc_build_pcms */
3582};
3583
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01003584/* Used by alc_build_pcms to flag that a PCM has no playback stream */
Takashi Iwai63300792008-01-24 15:31:36 +01003585static struct hda_pcm_stream alc_pcm_null_stream = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01003586 .substreams = 0,
3587 .channels_min = 0,
3588 .channels_max = 0,
3589};
3590
Linus Torvalds1da177e2005-04-16 15:20:36 -07003591static int alc_build_pcms(struct hda_codec *codec)
3592{
3593 struct alc_spec *spec = codec->spec;
3594 struct hda_pcm *info = spec->pcm_rec;
3595 int i;
3596
3597 codec->num_pcms = 1;
3598 codec->pcm_info = info;
3599
Takashi Iwaie64f14f2009-01-20 18:32:55 +01003600 if (spec->no_analog)
3601 goto skip_analog;
3602
Takashi Iwai812a2cc2009-05-16 10:00:49 +02003603 snprintf(spec->stream_name_analog, sizeof(spec->stream_name_analog),
3604 "%s Analog", codec->chip_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003605 info->name = spec->stream_name_analog;
Kailang Yang274693f2009-12-03 10:07:50 +01003606
Takashi Iwai4a471b72005-12-07 13:56:29 +01003607 if (spec->stream_analog_playback) {
Takashi Iwaida3cec32008-08-08 17:12:14 +02003608 if (snd_BUG_ON(!spec->multiout.dac_nids))
3609 return -EINVAL;
Takashi Iwai4a471b72005-12-07 13:56:29 +01003610 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
3611 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
3612 }
3613 if (spec->stream_analog_capture) {
Takashi Iwaida3cec32008-08-08 17:12:14 +02003614 if (snd_BUG_ON(!spec->adc_nids))
3615 return -EINVAL;
Takashi Iwai4a471b72005-12-07 13:56:29 +01003616 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
3617 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
3618 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003619
Takashi Iwai4a471b72005-12-07 13:56:29 +01003620 if (spec->channel_mode) {
3621 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0;
3622 for (i = 0; i < spec->num_channel_mode; i++) {
3623 if (spec->channel_mode[i].channels > info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max) {
3624 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->channel_mode[i].channels;
3625 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003626 }
3627 }
3628
Takashi Iwaie64f14f2009-01-20 18:32:55 +01003629 skip_analog:
Takashi Iwaie08a0072006-09-07 17:52:14 +02003630 /* SPDIF for stream index #1 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003631 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
Takashi Iwai812a2cc2009-05-16 10:00:49 +02003632 snprintf(spec->stream_name_digital,
3633 sizeof(spec->stream_name_digital),
3634 "%s Digital", codec->chip_name);
Takashi Iwaie08a0072006-09-07 17:52:14 +02003635 codec->num_pcms = 2;
Wu Fengguangb25c9da2009-02-06 15:02:27 +08003636 codec->slave_dig_outs = spec->multiout.slave_dig_outs;
Takashi Iwaic06134d2006-10-11 18:49:13 +02003637 info = spec->pcm_rec + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003638 info->name = spec->stream_name_digital;
Takashi Iwai8c441982009-01-20 18:30:20 +01003639 if (spec->dig_out_type)
3640 info->pcm_type = spec->dig_out_type;
3641 else
3642 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Takashi Iwai4a471b72005-12-07 13:56:29 +01003643 if (spec->multiout.dig_out_nid &&
3644 spec->stream_digital_playback) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003645 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_digital_playback);
3646 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
3647 }
Takashi Iwai4a471b72005-12-07 13:56:29 +01003648 if (spec->dig_in_nid &&
3649 spec->stream_digital_capture) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003650 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_digital_capture);
3651 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
3652 }
Takashi Iwai963f8032008-08-11 10:04:40 +02003653 /* FIXME: do we need this for all Realtek codec models? */
3654 codec->spdif_status_reset = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003655 }
3656
Takashi Iwaie64f14f2009-01-20 18:32:55 +01003657 if (spec->no_analog)
3658 return 0;
3659
Takashi Iwaie08a0072006-09-07 17:52:14 +02003660 /* If the use of more than one ADC is requested for the current
3661 * model, configure a second analog capture-only PCM.
3662 */
3663 /* Additional Analaog capture for index #2 */
Takashi Iwai63300792008-01-24 15:31:36 +01003664 if ((spec->alt_dac_nid && spec->stream_analog_alt_playback) ||
3665 (spec->num_adc_nids > 1 && spec->stream_analog_alt_capture)) {
Takashi Iwaie08a0072006-09-07 17:52:14 +02003666 codec->num_pcms = 3;
Takashi Iwaic06134d2006-10-11 18:49:13 +02003667 info = spec->pcm_rec + 2;
Takashi Iwaie08a0072006-09-07 17:52:14 +02003668 info->name = spec->stream_name_analog;
Takashi Iwai63300792008-01-24 15:31:36 +01003669 if (spec->alt_dac_nid) {
3670 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
3671 *spec->stream_analog_alt_playback;
3672 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
3673 spec->alt_dac_nid;
3674 } else {
3675 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
3676 alc_pcm_null_stream;
3677 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
3678 }
3679 if (spec->num_adc_nids > 1) {
3680 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
3681 *spec->stream_analog_alt_capture;
3682 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
3683 spec->adc_nids[1];
3684 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams =
3685 spec->num_adc_nids - 1;
3686 } else {
3687 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
3688 alc_pcm_null_stream;
3689 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0;
Takashi Iwaie08a0072006-09-07 17:52:14 +02003690 }
3691 }
3692
Linus Torvalds1da177e2005-04-16 15:20:36 -07003693 return 0;
3694}
3695
Takashi Iwai603c4012008-07-30 15:01:44 +02003696static void alc_free_kctls(struct hda_codec *codec)
3697{
3698 struct alc_spec *spec = codec->spec;
3699
3700 if (spec->kctls.list) {
3701 struct snd_kcontrol_new *kctl = spec->kctls.list;
3702 int i;
3703 for (i = 0; i < spec->kctls.used; i++)
3704 kfree(kctl[i].name);
3705 }
3706 snd_array_free(&spec->kctls);
3707}
3708
Linus Torvalds1da177e2005-04-16 15:20:36 -07003709static void alc_free(struct hda_codec *codec)
3710{
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003711 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003712
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003713 if (!spec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003714 return;
3715
Takashi Iwai603c4012008-07-30 15:01:44 +02003716 alc_free_kctls(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003717 kfree(spec);
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09003718 snd_hda_detach_beep_device(codec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003719}
3720
Hector Martinf5de24b2009-12-20 22:51:31 +01003721#ifdef CONFIG_SND_HDA_POWER_SAVE
3722static int alc_suspend(struct hda_codec *codec, pm_message_t state)
3723{
3724 struct alc_spec *spec = codec->spec;
3725 if (spec && spec->power_hook)
3726 spec->power_hook(codec, 0);
3727 return 0;
3728}
3729#endif
3730
Takashi Iwaie044c392008-10-27 16:56:24 +01003731#ifdef SND_HDA_NEEDS_RESUME
Takashi Iwaie044c392008-10-27 16:56:24 +01003732static int alc_resume(struct hda_codec *codec)
3733{
Hector Martinf5de24b2009-12-20 22:51:31 +01003734#ifdef CONFIG_SND_HDA_POWER_SAVE
3735 struct alc_spec *spec = codec->spec;
3736#endif
Takashi Iwaie044c392008-10-27 16:56:24 +01003737 codec->patch_ops.init(codec);
3738 snd_hda_codec_resume_amp(codec);
3739 snd_hda_codec_resume_cache(codec);
Hector Martinf5de24b2009-12-20 22:51:31 +01003740#ifdef CONFIG_SND_HDA_POWER_SAVE
3741 if (spec && spec->power_hook)
3742 spec->power_hook(codec, 1);
3743#endif
Takashi Iwaie044c392008-10-27 16:56:24 +01003744 return 0;
3745}
Takashi Iwaie044c392008-10-27 16:56:24 +01003746#endif
3747
Linus Torvalds1da177e2005-04-16 15:20:36 -07003748/*
3749 */
3750static struct hda_codec_ops alc_patch_ops = {
3751 .build_controls = alc_build_controls,
3752 .build_pcms = alc_build_pcms,
3753 .init = alc_init,
3754 .free = alc_free,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003755 .unsol_event = alc_unsol_event,
Takashi Iwaie044c392008-10-27 16:56:24 +01003756#ifdef SND_HDA_NEEDS_RESUME
3757 .resume = alc_resume,
3758#endif
Takashi Iwaicb53c622007-08-10 17:21:45 +02003759#ifdef CONFIG_SND_HDA_POWER_SAVE
Hector Martinf5de24b2009-12-20 22:51:31 +01003760 .suspend = alc_suspend,
Takashi Iwaicb53c622007-08-10 17:21:45 +02003761 .check_power_status = alc_check_power_status,
3762#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07003763};
3764
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003765
3766/*
3767 * Test configuration for debugging
3768 *
3769 * Almost all inputs/outputs are enabled. I/O pins can be configured via
3770 * enum controls.
3771 */
3772#ifdef CONFIG_SND_DEBUG
3773static hda_nid_t alc880_test_dac_nids[4] = {
3774 0x02, 0x03, 0x04, 0x05
3775};
3776
3777static struct hda_input_mux alc880_test_capture_source = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003778 .num_items = 7,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003779 .items = {
3780 { "In-1", 0x0 },
3781 { "In-2", 0x1 },
3782 { "In-3", 0x2 },
3783 { "In-4", 0x3 },
3784 { "CD", 0x4 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003785 { "Front", 0x5 },
3786 { "Surround", 0x6 },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003787 },
3788};
3789
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01003790static struct hda_channel_mode alc880_test_modes[4] = {
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003791 { 2, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02003792 { 4, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003793 { 6, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02003794 { 8, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003795};
3796
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003797static int alc_test_pin_ctl_info(struct snd_kcontrol *kcontrol,
3798 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003799{
3800 static char *texts[] = {
3801 "N/A", "Line Out", "HP Out",
3802 "In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%"
3803 };
3804 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
3805 uinfo->count = 1;
3806 uinfo->value.enumerated.items = 8;
3807 if (uinfo->value.enumerated.item >= 8)
3808 uinfo->value.enumerated.item = 7;
3809 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
3810 return 0;
3811}
3812
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003813static int alc_test_pin_ctl_get(struct snd_kcontrol *kcontrol,
3814 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003815{
3816 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3817 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
3818 unsigned int pin_ctl, item = 0;
3819
3820 pin_ctl = snd_hda_codec_read(codec, nid, 0,
3821 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
3822 if (pin_ctl & AC_PINCTL_OUT_EN) {
3823 if (pin_ctl & AC_PINCTL_HP_EN)
3824 item = 2;
3825 else
3826 item = 1;
3827 } else if (pin_ctl & AC_PINCTL_IN_EN) {
3828 switch (pin_ctl & AC_PINCTL_VREFEN) {
3829 case AC_PINCTL_VREF_HIZ: item = 3; break;
3830 case AC_PINCTL_VREF_50: item = 4; break;
3831 case AC_PINCTL_VREF_GRD: item = 5; break;
3832 case AC_PINCTL_VREF_80: item = 6; break;
3833 case AC_PINCTL_VREF_100: item = 7; break;
3834 }
3835 }
3836 ucontrol->value.enumerated.item[0] = item;
3837 return 0;
3838}
3839
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003840static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol,
3841 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003842{
3843 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3844 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
3845 static unsigned int ctls[] = {
3846 0, AC_PINCTL_OUT_EN, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN,
3847 AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ,
3848 AC_PINCTL_IN_EN | AC_PINCTL_VREF_50,
3849 AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD,
3850 AC_PINCTL_IN_EN | AC_PINCTL_VREF_80,
3851 AC_PINCTL_IN_EN | AC_PINCTL_VREF_100,
3852 };
3853 unsigned int old_ctl, new_ctl;
3854
3855 old_ctl = snd_hda_codec_read(codec, nid, 0,
3856 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
3857 new_ctl = ctls[ucontrol->value.enumerated.item[0]];
3858 if (old_ctl != new_ctl) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003859 int val;
3860 snd_hda_codec_write_cache(codec, nid, 0,
3861 AC_VERB_SET_PIN_WIDGET_CONTROL,
3862 new_ctl);
Takashi Iwai47fd8302007-08-10 17:11:07 +02003863 val = ucontrol->value.enumerated.item[0] >= 3 ?
3864 HDA_AMP_MUTE : 0;
3865 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
3866 HDA_AMP_MUTE, val);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003867 return 1;
3868 }
3869 return 0;
3870}
3871
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003872static int alc_test_pin_src_info(struct snd_kcontrol *kcontrol,
3873 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003874{
3875 static char *texts[] = {
3876 "Front", "Surround", "CLFE", "Side"
3877 };
3878 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
3879 uinfo->count = 1;
3880 uinfo->value.enumerated.items = 4;
3881 if (uinfo->value.enumerated.item >= 4)
3882 uinfo->value.enumerated.item = 3;
3883 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
3884 return 0;
3885}
3886
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003887static int alc_test_pin_src_get(struct snd_kcontrol *kcontrol,
3888 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003889{
3890 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3891 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
3892 unsigned int sel;
3893
3894 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0);
3895 ucontrol->value.enumerated.item[0] = sel & 3;
3896 return 0;
3897}
3898
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003899static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol,
3900 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003901{
3902 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3903 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
3904 unsigned int sel;
3905
3906 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3;
3907 if (ucontrol->value.enumerated.item[0] != sel) {
3908 sel = ucontrol->value.enumerated.item[0] & 3;
Takashi Iwai82beb8f2007-08-10 17:09:26 +02003909 snd_hda_codec_write_cache(codec, nid, 0,
3910 AC_VERB_SET_CONNECT_SEL, sel);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003911 return 1;
3912 }
3913 return 0;
3914}
3915
3916#define PIN_CTL_TEST(xname,nid) { \
3917 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
3918 .name = xname, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01003919 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003920 .info = alc_test_pin_ctl_info, \
3921 .get = alc_test_pin_ctl_get, \
3922 .put = alc_test_pin_ctl_put, \
3923 .private_value = nid \
3924 }
3925
3926#define PIN_SRC_TEST(xname,nid) { \
3927 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
3928 .name = xname, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01003929 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003930 .info = alc_test_pin_src_info, \
3931 .get = alc_test_pin_src_get, \
3932 .put = alc_test_pin_src_put, \
3933 .private_value = nid \
3934 }
3935
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01003936static struct snd_kcontrol_new alc880_test_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02003937 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3938 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
3939 HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
3940 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003941 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
3942 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
3943 HDA_BIND_MUTE("CLFE Playback Switch", 0x0e, 2, HDA_INPUT),
3944 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003945 PIN_CTL_TEST("Front Pin Mode", 0x14),
3946 PIN_CTL_TEST("Surround Pin Mode", 0x15),
3947 PIN_CTL_TEST("CLFE Pin Mode", 0x16),
3948 PIN_CTL_TEST("Side Pin Mode", 0x17),
3949 PIN_CTL_TEST("In-1 Pin Mode", 0x18),
3950 PIN_CTL_TEST("In-2 Pin Mode", 0x19),
3951 PIN_CTL_TEST("In-3 Pin Mode", 0x1a),
3952 PIN_CTL_TEST("In-4 Pin Mode", 0x1b),
3953 PIN_SRC_TEST("In-1 Pin Source", 0x18),
3954 PIN_SRC_TEST("In-2 Pin Source", 0x19),
3955 PIN_SRC_TEST("In-3 Pin Source", 0x1a),
3956 PIN_SRC_TEST("In-4 Pin Source", 0x1b),
3957 HDA_CODEC_VOLUME("In-1 Playback Volume", 0x0b, 0x0, HDA_INPUT),
3958 HDA_CODEC_MUTE("In-1 Playback Switch", 0x0b, 0x0, HDA_INPUT),
3959 HDA_CODEC_VOLUME("In-2 Playback Volume", 0x0b, 0x1, HDA_INPUT),
3960 HDA_CODEC_MUTE("In-2 Playback Switch", 0x0b, 0x1, HDA_INPUT),
3961 HDA_CODEC_VOLUME("In-3 Playback Volume", 0x0b, 0x2, HDA_INPUT),
3962 HDA_CODEC_MUTE("In-3 Playback Switch", 0x0b, 0x2, HDA_INPUT),
3963 HDA_CODEC_VOLUME("In-4 Playback Volume", 0x0b, 0x3, HDA_INPUT),
3964 HDA_CODEC_MUTE("In-4 Playback Switch", 0x0b, 0x3, HDA_INPUT),
3965 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x4, HDA_INPUT),
3966 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x4, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003967 {
3968 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3969 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01003970 .info = alc_ch_mode_info,
3971 .get = alc_ch_mode_get,
3972 .put = alc_ch_mode_put,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003973 },
3974 { } /* end */
3975};
3976
3977static struct hda_verb alc880_test_init_verbs[] = {
3978 /* Unmute inputs of 0x0c - 0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02003979 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3980 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3981 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3982 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3983 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3984 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3985 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3986 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003987 /* Vol output for 0x0c-0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02003988 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3989 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3990 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3991 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003992 /* Set output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02003993 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3994 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3995 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3996 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02003997 /* Unmute output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02003998 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3999 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4000 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4001 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004002 /* Set input pins 0x18-0x1c */
Takashi Iwai16ded522005-06-10 19:58:24 +02004003 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4004 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwai05acb862005-06-10 19:50:25 +02004005 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4006 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4007 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004008 /* Mute input pins 0x18-0x1b */
Takashi Iwai05acb862005-06-10 19:50:25 +02004009 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4010 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4011 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4012 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02004013 /* ADC set up */
Takashi Iwai05acb862005-06-10 19:50:25 +02004014 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02004015 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02004016 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02004017 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02004018 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02004019 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02004020 /* Analog input/passthru */
4021 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4022 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4023 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4024 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4025 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004026 { }
4027};
4028#endif
4029
Linus Torvalds1da177e2005-04-16 15:20:36 -07004030/*
4031 */
4032
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004033static const char *alc880_models[ALC880_MODEL_LAST] = {
4034 [ALC880_3ST] = "3stack",
4035 [ALC880_TCL_S700] = "tcl",
4036 [ALC880_3ST_DIG] = "3stack-digout",
4037 [ALC880_CLEVO] = "clevo",
4038 [ALC880_5ST] = "5stack",
4039 [ALC880_5ST_DIG] = "5stack-digout",
4040 [ALC880_W810] = "w810",
4041 [ALC880_Z71V] = "z71v",
4042 [ALC880_6ST] = "6stack",
4043 [ALC880_6ST_DIG] = "6stack-digout",
4044 [ALC880_ASUS] = "asus",
4045 [ALC880_ASUS_W1V] = "asus-w1v",
4046 [ALC880_ASUS_DIG] = "asus-dig",
4047 [ALC880_ASUS_DIG2] = "asus-dig2",
4048 [ALC880_UNIWILL_DIG] = "uniwill",
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004049 [ALC880_UNIWILL_P53] = "uniwill-p53",
4050 [ALC880_FUJITSU] = "fujitsu",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004051 [ALC880_F1734] = "F1734",
4052 [ALC880_LG] = "lg",
4053 [ALC880_LG_LW] = "lg-lw",
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004054 [ALC880_MEDION_RIM] = "medion",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004055#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004056 [ALC880_TEST] = "test",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004057#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004058 [ALC880_AUTO] = "auto",
4059};
4060
4061static struct snd_pci_quirk alc880_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004062 SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004063 SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG),
4064 SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST),
4065 SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_3ST_DIG),
4066 SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_6ST_DIG),
4067 SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_6ST_DIG),
4068 SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_6ST_DIG),
4069 SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_3ST_DIG),
4070 SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004071 SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_6ST_DIG),
4072 SND_PCI_QUIRK(0x103c, 0x2a09, "HP", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004073 SND_PCI_QUIRK(0x1043, 0x10b3, "ASUS W1V", ALC880_ASUS_W1V),
4074 SND_PCI_QUIRK(0x1043, 0x10c2, "ASUS W6A", ALC880_ASUS_DIG),
4075 SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS Wxx", ALC880_ASUS_DIG),
4076 SND_PCI_QUIRK(0x1043, 0x1113, "ASUS", ALC880_ASUS_DIG),
4077 SND_PCI_QUIRK(0x1043, 0x1123, "ASUS", ALC880_ASUS_DIG),
4078 SND_PCI_QUIRK(0x1043, 0x1173, "ASUS", ALC880_ASUS_DIG),
4079 SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_Z71V),
4080 /* SND_PCI_QUIRK(0x1043, 0x1964, "ASUS", ALC880_ASUS_DIG), */
4081 SND_PCI_QUIRK(0x1043, 0x1973, "ASUS", ALC880_ASUS_DIG),
4082 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS", ALC880_ASUS_DIG),
Travis Place186c3112008-05-20 11:54:41 +02004083 SND_PCI_QUIRK(0x1043, 0x814e, "ASUS P5GD1 w/SPDIF", ALC880_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004084 SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG),
4085 SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST),
4086 SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST),
Takashi Iwaidea0a502009-02-09 17:14:52 +01004087 SND_PCI_QUIRK_VENDOR(0x1043, "ASUS", ALC880_ASUS), /* default ASUS */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004088 SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004089 SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST),
4090 SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004091 SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_5ST),
4092 SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004093 SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_6ST_DIG),
4094 SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_6ST_DIG),
4095 SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_6ST_DIG),
4096 SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004097 SND_PCI_QUIRK(0x1558, 0x0520, "Clevo m520G", ALC880_CLEVO),
4098 SND_PCI_QUIRK(0x1558, 0x0660, "Clevo m655n", ALC880_CLEVO),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004099 SND_PCI_QUIRK(0x1558, 0x5401, "ASUS", ALC880_ASUS_DIG2),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004100 SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004101 SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_UNIWILL_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004102 SND_PCI_QUIRK(0x1584, 0x9054, "Uniwlll", ALC880_F1734),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004103 SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL),
4104 SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004105 SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810),
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004106 SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_MEDION_RIM),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004107 SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004108 SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004109 SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734),
Travis Place1d116042008-06-23 11:42:30 +02004110 SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FUJITSU),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004111 SND_PCI_QUIRK(0x1734, 0x10ac, "FSC", ALC880_UNIWILL),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004112 SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004113 SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004114 SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG),
4115 SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004116 SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004117 SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700),
4118 SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG), /* broken BIOS */
4119 SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG),
4120 SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004121 SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_5ST_DIG),
4122 SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004123 SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004124 SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004125 SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_3ST_DIG),
4126 SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004127 SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_5ST_DIG),
4128 SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_5ST_DIG),
4129 SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +01004130 /* default Intel */
4131 SND_PCI_QUIRK_VENDOR(0x8086, "Intel mobo", ALC880_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004132 SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG),
4133 SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004134 {}
4135};
4136
Takashi Iwai16ded522005-06-10 19:58:24 +02004137/*
Kailang Yangdf694da2005-12-05 19:42:22 +01004138 * ALC880 codec presets
Takashi Iwai16ded522005-06-10 19:58:24 +02004139 */
Takashi Iwai16ded522005-06-10 19:58:24 +02004140static struct alc_config_preset alc880_presets[] = {
4141 [ALC880_3ST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004142 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004143 .init_verbs = { alc880_volume_init_verbs,
4144 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004145 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02004146 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02004147 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
4148 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004149 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004150 .input_mux = &alc880_capture_source,
4151 },
4152 [ALC880_3ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004153 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004154 .init_verbs = { alc880_volume_init_verbs,
4155 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004156 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02004157 .dac_nids = alc880_dac_nids,
4158 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02004159 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
4160 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004161 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004162 .input_mux = &alc880_capture_source,
4163 },
Kailang Yangdf694da2005-12-05 19:42:22 +01004164 [ALC880_TCL_S700] = {
4165 .mixers = { alc880_tcl_s700_mixer },
4166 .init_verbs = { alc880_volume_init_verbs,
4167 alc880_pin_tcl_S700_init_verbs,
4168 alc880_gpio2_init_verbs },
4169 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4170 .dac_nids = alc880_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01004171 .adc_nids = alc880_adc_nids_alt, /* FIXME: correct? */
4172 .num_adc_nids = 1, /* single ADC */
Kailang Yangdf694da2005-12-05 19:42:22 +01004173 .hp_nid = 0x03,
4174 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
4175 .channel_mode = alc880_2_jack_modes,
4176 .input_mux = &alc880_capture_source,
4177 },
Takashi Iwai16ded522005-06-10 19:58:24 +02004178 [ALC880_5ST] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004179 .mixers = { alc880_three_stack_mixer,
4180 alc880_five_stack_mixer},
4181 .init_verbs = { alc880_volume_init_verbs,
4182 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004183 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4184 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02004185 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
4186 .channel_mode = alc880_fivestack_modes,
4187 .input_mux = &alc880_capture_source,
4188 },
4189 [ALC880_5ST_DIG] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004190 .mixers = { alc880_three_stack_mixer,
4191 alc880_five_stack_mixer },
4192 .init_verbs = { alc880_volume_init_verbs,
4193 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004194 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4195 .dac_nids = alc880_dac_nids,
4196 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02004197 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
4198 .channel_mode = alc880_fivestack_modes,
4199 .input_mux = &alc880_capture_source,
4200 },
Takashi Iwaib6482d42005-06-27 15:32:43 +02004201 [ALC880_6ST] = {
4202 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004203 .init_verbs = { alc880_volume_init_verbs,
4204 alc880_pin_6stack_init_verbs },
Takashi Iwaib6482d42005-06-27 15:32:43 +02004205 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
4206 .dac_nids = alc880_6st_dac_nids,
4207 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
4208 .channel_mode = alc880_sixstack_modes,
4209 .input_mux = &alc880_6stack_capture_source,
4210 },
Takashi Iwai16ded522005-06-10 19:58:24 +02004211 [ALC880_6ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004212 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004213 .init_verbs = { alc880_volume_init_verbs,
4214 alc880_pin_6stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004215 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
4216 .dac_nids = alc880_6st_dac_nids,
4217 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02004218 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
4219 .channel_mode = alc880_sixstack_modes,
4220 .input_mux = &alc880_6stack_capture_source,
4221 },
4222 [ALC880_W810] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004223 .mixers = { alc880_w810_base_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004224 .init_verbs = { alc880_volume_init_verbs,
4225 alc880_pin_w810_init_verbs,
Takashi Iwaib0af0de2005-06-21 14:49:19 +02004226 alc880_gpio2_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004227 .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids),
4228 .dac_nids = alc880_w810_dac_nids,
4229 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02004230 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
4231 .channel_mode = alc880_w810_modes,
4232 .input_mux = &alc880_capture_source,
4233 },
4234 [ALC880_Z71V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004235 .mixers = { alc880_z71v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004236 .init_verbs = { alc880_volume_init_verbs,
4237 alc880_pin_z71v_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004238 .num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids),
4239 .dac_nids = alc880_z71v_dac_nids,
4240 .dig_out_nid = ALC880_DIGOUT_NID,
4241 .hp_nid = 0x03,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004242 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
4243 .channel_mode = alc880_2_jack_modes,
Takashi Iwai16ded522005-06-10 19:58:24 +02004244 .input_mux = &alc880_capture_source,
4245 },
4246 [ALC880_F1734] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004247 .mixers = { alc880_f1734_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004248 .init_verbs = { alc880_volume_init_verbs,
4249 alc880_pin_f1734_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004250 .num_dacs = ARRAY_SIZE(alc880_f1734_dac_nids),
4251 .dac_nids = alc880_f1734_dac_nids,
4252 .hp_nid = 0x02,
4253 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
4254 .channel_mode = alc880_2_jack_modes,
Takashi Iwai937b4162008-02-11 14:52:36 +01004255 .input_mux = &alc880_f1734_capture_source,
4256 .unsol_event = alc880_uniwill_p53_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004257 .setup = alc880_uniwill_p53_setup,
4258 .init_hook = alc_automute_amp,
Takashi Iwai16ded522005-06-10 19:58:24 +02004259 },
4260 [ALC880_ASUS] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004261 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004262 .init_verbs = { alc880_volume_init_verbs,
4263 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004264 alc880_gpio1_init_verbs },
4265 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4266 .dac_nids = alc880_asus_dac_nids,
4267 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
4268 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004269 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004270 .input_mux = &alc880_capture_source,
4271 },
4272 [ALC880_ASUS_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004273 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004274 .init_verbs = { alc880_volume_init_verbs,
4275 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004276 alc880_gpio1_init_verbs },
4277 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4278 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02004279 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004280 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
4281 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004282 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004283 .input_mux = &alc880_capture_source,
4284 },
Kailang Yangdf694da2005-12-05 19:42:22 +01004285 [ALC880_ASUS_DIG2] = {
4286 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004287 .init_verbs = { alc880_volume_init_verbs,
4288 alc880_pin_asus_init_verbs,
Kailang Yangdf694da2005-12-05 19:42:22 +01004289 alc880_gpio2_init_verbs }, /* use GPIO2 */
4290 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4291 .dac_nids = alc880_asus_dac_nids,
4292 .dig_out_nid = ALC880_DIGOUT_NID,
4293 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
4294 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004295 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01004296 .input_mux = &alc880_capture_source,
4297 },
Takashi Iwai16ded522005-06-10 19:58:24 +02004298 [ALC880_ASUS_W1V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004299 .mixers = { alc880_asus_mixer, alc880_asus_w1v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004300 .init_verbs = { alc880_volume_init_verbs,
4301 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004302 alc880_gpio1_init_verbs },
4303 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4304 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02004305 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004306 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
4307 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004308 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004309 .input_mux = &alc880_capture_source,
4310 },
4311 [ALC880_UNIWILL_DIG] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01004312 .mixers = { alc880_asus_mixer },
Kailang Yangccc656c2006-10-17 12:32:26 +02004313 .init_verbs = { alc880_volume_init_verbs,
4314 alc880_pin_asus_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004315 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4316 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02004317 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004318 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
4319 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004320 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004321 .input_mux = &alc880_capture_source,
4322 },
Kailang Yangccc656c2006-10-17 12:32:26 +02004323 [ALC880_UNIWILL] = {
4324 .mixers = { alc880_uniwill_mixer },
4325 .init_verbs = { alc880_volume_init_verbs,
4326 alc880_uniwill_init_verbs },
4327 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4328 .dac_nids = alc880_asus_dac_nids,
4329 .dig_out_nid = ALC880_DIGOUT_NID,
4330 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
4331 .channel_mode = alc880_threestack_modes,
4332 .need_dac_fix = 1,
4333 .input_mux = &alc880_capture_source,
4334 .unsol_event = alc880_uniwill_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004335 .setup = alc880_uniwill_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004336 .init_hook = alc880_uniwill_init_hook,
Kailang Yangccc656c2006-10-17 12:32:26 +02004337 },
4338 [ALC880_UNIWILL_P53] = {
4339 .mixers = { alc880_uniwill_p53_mixer },
4340 .init_verbs = { alc880_volume_init_verbs,
4341 alc880_uniwill_p53_init_verbs },
4342 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4343 .dac_nids = alc880_asus_dac_nids,
4344 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004345 .channel_mode = alc880_threestack_modes,
4346 .input_mux = &alc880_capture_source,
4347 .unsol_event = alc880_uniwill_p53_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004348 .setup = alc880_uniwill_p53_setup,
4349 .init_hook = alc_automute_amp,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004350 },
4351 [ALC880_FUJITSU] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01004352 .mixers = { alc880_fujitsu_mixer },
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004353 .init_verbs = { alc880_volume_init_verbs,
4354 alc880_uniwill_p53_init_verbs,
4355 alc880_beep_init_verbs },
4356 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4357 .dac_nids = alc880_dac_nids,
Takashi Iwaid53d7d92007-08-20 15:20:02 +02004358 .dig_out_nid = ALC880_DIGOUT_NID,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004359 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
4360 .channel_mode = alc880_2_jack_modes,
Kailang Yangccc656c2006-10-17 12:32:26 +02004361 .input_mux = &alc880_capture_source,
4362 .unsol_event = alc880_uniwill_p53_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004363 .setup = alc880_uniwill_p53_setup,
4364 .init_hook = alc_automute_amp,
Kailang Yangccc656c2006-10-17 12:32:26 +02004365 },
Kailang Yangdf694da2005-12-05 19:42:22 +01004366 [ALC880_CLEVO] = {
4367 .mixers = { alc880_three_stack_mixer },
4368 .init_verbs = { alc880_volume_init_verbs,
4369 alc880_pin_clevo_init_verbs },
4370 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4371 .dac_nids = alc880_dac_nids,
4372 .hp_nid = 0x03,
4373 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
4374 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004375 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01004376 .input_mux = &alc880_capture_source,
4377 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004378 [ALC880_LG] = {
4379 .mixers = { alc880_lg_mixer },
4380 .init_verbs = { alc880_volume_init_verbs,
4381 alc880_lg_init_verbs },
4382 .num_dacs = ARRAY_SIZE(alc880_lg_dac_nids),
4383 .dac_nids = alc880_lg_dac_nids,
4384 .dig_out_nid = ALC880_DIGOUT_NID,
4385 .num_channel_mode = ARRAY_SIZE(alc880_lg_ch_modes),
4386 .channel_mode = alc880_lg_ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004387 .need_dac_fix = 1,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004388 .input_mux = &alc880_lg_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004389 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004390 .setup = alc880_lg_setup,
4391 .init_hook = alc_automute_amp,
Takashi Iwaicb53c622007-08-10 17:21:45 +02004392#ifdef CONFIG_SND_HDA_POWER_SAVE
4393 .loopbacks = alc880_lg_loopbacks,
4394#endif
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004395 },
Takashi Iwaid6815182006-03-23 16:06:23 +01004396 [ALC880_LG_LW] = {
4397 .mixers = { alc880_lg_lw_mixer },
4398 .init_verbs = { alc880_volume_init_verbs,
4399 alc880_lg_lw_init_verbs },
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02004400 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwaid6815182006-03-23 16:06:23 +01004401 .dac_nids = alc880_dac_nids,
4402 .dig_out_nid = ALC880_DIGOUT_NID,
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02004403 .num_channel_mode = ARRAY_SIZE(alc880_lg_lw_modes),
4404 .channel_mode = alc880_lg_lw_modes,
Takashi Iwaid6815182006-03-23 16:06:23 +01004405 .input_mux = &alc880_lg_lw_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004406 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004407 .setup = alc880_lg_lw_setup,
4408 .init_hook = alc_automute_amp,
Takashi Iwaid6815182006-03-23 16:06:23 +01004409 },
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004410 [ALC880_MEDION_RIM] = {
4411 .mixers = { alc880_medion_rim_mixer },
4412 .init_verbs = { alc880_volume_init_verbs,
4413 alc880_medion_rim_init_verbs,
4414 alc_gpio2_init_verbs },
4415 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4416 .dac_nids = alc880_dac_nids,
4417 .dig_out_nid = ALC880_DIGOUT_NID,
4418 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
4419 .channel_mode = alc880_2_jack_modes,
4420 .input_mux = &alc880_medion_rim_capture_source,
4421 .unsol_event = alc880_medion_rim_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004422 .setup = alc880_medion_rim_setup,
4423 .init_hook = alc880_medion_rim_automute,
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004424 },
Takashi Iwai16ded522005-06-10 19:58:24 +02004425#ifdef CONFIG_SND_DEBUG
4426 [ALC880_TEST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004427 .mixers = { alc880_test_mixer },
4428 .init_verbs = { alc880_test_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004429 .num_dacs = ARRAY_SIZE(alc880_test_dac_nids),
4430 .dac_nids = alc880_test_dac_nids,
4431 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02004432 .num_channel_mode = ARRAY_SIZE(alc880_test_modes),
4433 .channel_mode = alc880_test_modes,
4434 .input_mux = &alc880_test_capture_source,
4435 },
4436#endif
4437};
4438
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004439/*
4440 * Automatic parse of I/O pins from the BIOS configuration
4441 */
4442
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004443enum {
4444 ALC_CTL_WIDGET_VOL,
4445 ALC_CTL_WIDGET_MUTE,
4446 ALC_CTL_BIND_MUTE,
4447};
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01004448static struct snd_kcontrol_new alc880_control_templates[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004449 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
4450 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Takashi Iwai985be542005-11-02 18:26:49 +01004451 HDA_BIND_MUTE(NULL, 0, 0, 0),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004452};
4453
4454/* add dynamic controls */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004455static int add_control(struct alc_spec *spec, int type, const char *name,
4456 unsigned long val)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004457{
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01004458 struct snd_kcontrol_new *knew;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004459
Takashi Iwai603c4012008-07-30 15:01:44 +02004460 snd_array_init(&spec->kctls, sizeof(*knew), 32);
4461 knew = snd_array_new(&spec->kctls);
4462 if (!knew)
4463 return -ENOMEM;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004464 *knew = alc880_control_templates[type];
Paulo Marques543537b2005-06-23 00:09:02 -07004465 knew->name = kstrdup(name, GFP_KERNEL);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004466 if (!knew->name)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004467 return -ENOMEM;
Jaroslav Kysela4d02d1b2009-11-12 10:15:48 +01004468 if (get_amp_nid_(val))
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +01004469 knew->subdevice = HDA_SUBDEV_AMP_FLAG;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004470 knew->private_value = val;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004471 return 0;
4472}
4473
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004474static int add_control_with_pfx(struct alc_spec *spec, int type,
4475 const char *pfx, const char *dir,
4476 const char *sfx, unsigned long val)
4477{
4478 char name[32];
4479 snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx);
4480 return add_control(spec, type, name, val);
4481}
4482
4483#define add_pb_vol_ctrl(spec, type, pfx, val) \
4484 add_control_with_pfx(spec, type, pfx, "Playback", "Volume", val)
4485#define add_pb_sw_ctrl(spec, type, pfx, val) \
4486 add_control_with_pfx(spec, type, pfx, "Playback", "Switch", val)
4487
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004488#define alc880_is_fixed_pin(nid) ((nid) >= 0x14 && (nid) <= 0x17)
4489#define alc880_fixed_pin_idx(nid) ((nid) - 0x14)
4490#define alc880_is_multi_pin(nid) ((nid) >= 0x18)
4491#define alc880_multi_pin_idx(nid) ((nid) - 0x18)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004492#define alc880_idx_to_dac(nid) ((nid) + 0x02)
4493#define alc880_dac_to_idx(nid) ((nid) - 0x02)
4494#define alc880_idx_to_mixer(nid) ((nid) + 0x0c)
4495#define alc880_idx_to_selector(nid) ((nid) + 0x10)
4496#define ALC880_PIN_CD_NID 0x1c
4497
4498/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004499static int alc880_auto_fill_dac_nids(struct alc_spec *spec,
4500 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004501{
4502 hda_nid_t nid;
4503 int assigned[4];
4504 int i, j;
4505
4506 memset(assigned, 0, sizeof(assigned));
Takashi Iwaib0af0de2005-06-21 14:49:19 +02004507 spec->multiout.dac_nids = spec->private_dac_nids;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004508
4509 /* check the pins hardwired to audio widget */
4510 for (i = 0; i < cfg->line_outs; i++) {
4511 nid = cfg->line_out_pins[i];
4512 if (alc880_is_fixed_pin(nid)) {
4513 int idx = alc880_fixed_pin_idx(nid);
Libin Yang5014f192005-11-23 15:48:36 +01004514 spec->multiout.dac_nids[i] = alc880_idx_to_dac(idx);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004515 assigned[idx] = 1;
4516 }
4517 }
4518 /* left pins can be connect to any audio widget */
4519 for (i = 0; i < cfg->line_outs; i++) {
4520 nid = cfg->line_out_pins[i];
4521 if (alc880_is_fixed_pin(nid))
4522 continue;
4523 /* search for an empty channel */
4524 for (j = 0; j < cfg->line_outs; j++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004525 if (!assigned[j]) {
4526 spec->multiout.dac_nids[i] =
4527 alc880_idx_to_dac(j);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004528 assigned[j] = 1;
4529 break;
4530 }
4531 }
4532 }
4533 spec->multiout.num_dacs = cfg->line_outs;
4534 return 0;
4535}
4536
4537/* add playback controls from the parsed DAC table */
Kailang Yangdf694da2005-12-05 19:42:22 +01004538static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
4539 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004540{
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004541 static const char *chname[4] = {
4542 "Front", "Surround", NULL /*CLFE*/, "Side"
4543 };
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004544 hda_nid_t nid;
4545 int i, err;
4546
4547 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004548 if (!spec->multiout.dac_nids[i])
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004549 continue;
4550 nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i]));
4551 if (i == 2) {
4552 /* Center/LFE */
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004553 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
4554 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004555 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
4556 HDA_OUTPUT));
4557 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004558 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004559 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
4560 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004561 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
4562 HDA_OUTPUT));
4563 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004564 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004565 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
4566 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004567 HDA_COMPOSE_AMP_VAL(nid, 1, 2,
4568 HDA_INPUT));
4569 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004570 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004571 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
4572 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004573 HDA_COMPOSE_AMP_VAL(nid, 2, 2,
4574 HDA_INPUT));
4575 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004576 return err;
4577 } else {
Takashi Iwaicb162b62009-08-25 16:05:03 +02004578 const char *pfx;
4579 if (cfg->line_outs == 1 &&
4580 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
4581 pfx = "Speaker";
4582 else
4583 pfx = chname[i];
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004584 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004585 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
4586 HDA_OUTPUT));
4587 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004588 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004589 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004590 HDA_COMPOSE_AMP_VAL(nid, 3, 2,
4591 HDA_INPUT));
4592 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004593 return err;
4594 }
4595 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004596 return 0;
4597}
4598
Takashi Iwai8d88bc32005-11-17 11:09:23 +01004599/* add playback controls for speaker and HP outputs */
4600static int alc880_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
4601 const char *pfx)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004602{
4603 hda_nid_t nid;
4604 int err;
4605
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004606 if (!pin)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004607 return 0;
4608
4609 if (alc880_is_fixed_pin(pin)) {
4610 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
Takashi Iwai82bc9552006-03-21 11:24:42 +01004611 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004612 if (!spec->multiout.hp_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004613 spec->multiout.hp_nid = nid;
Takashi Iwai82bc9552006-03-21 11:24:42 +01004614 else
4615 spec->multiout.extra_out_nid[0] = nid;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004616 /* control HP volume/switch on the output mixer amp */
4617 nid = alc880_idx_to_mixer(alc880_fixed_pin_idx(pin));
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004618 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004619 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
4620 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004621 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004622 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004623 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
4624 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004625 return err;
4626 } else if (alc880_is_multi_pin(pin)) {
4627 /* set manual connection */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004628 /* we have only a switch on HP-out PIN */
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004629 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004630 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
4631 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004632 return err;
4633 }
4634 return 0;
4635}
4636
4637/* create input playback/capture controls for the given pin */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004638static int new_analog_input(struct alc_spec *spec, hda_nid_t pin,
4639 const char *ctlname,
Kailang Yangdf694da2005-12-05 19:42:22 +01004640 int idx, hda_nid_t mix_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004641{
Kailang Yangdf694da2005-12-05 19:42:22 +01004642 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004643
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004644 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004645 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
4646 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004647 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02004648 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004649 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
4650 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004651 return err;
4652 return 0;
4653}
4654
Takashi Iwai05f5f472009-08-25 13:10:18 +02004655static int alc_is_input_pin(struct hda_codec *codec, hda_nid_t nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004656{
Takashi Iwai05f5f472009-08-25 13:10:18 +02004657 unsigned int pincap = snd_hda_query_pin_caps(codec, nid);
4658 return (pincap & AC_PINCAP_IN) != 0;
4659}
4660
4661/* create playback/capture controls for input pins */
4662static int alc_auto_create_input_ctls(struct hda_codec *codec,
4663 const struct auto_pin_cfg *cfg,
4664 hda_nid_t mixer,
4665 hda_nid_t cap1, hda_nid_t cap2)
4666{
4667 struct alc_spec *spec = codec->spec;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02004668 struct hda_input_mux *imux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01004669 int i, err, idx;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004670
4671 for (i = 0; i < AUTO_PIN_LAST; i++) {
Takashi Iwai05f5f472009-08-25 13:10:18 +02004672 hda_nid_t pin;
4673
4674 pin = cfg->input_pins[i];
4675 if (!alc_is_input_pin(codec, pin))
4676 continue;
4677
4678 if (mixer) {
4679 idx = get_connection_index(codec, mixer, pin);
4680 if (idx >= 0) {
4681 err = new_analog_input(spec, pin,
4682 auto_pin_cfg_labels[i],
4683 idx, mixer);
4684 if (err < 0)
4685 return err;
4686 }
4687 }
4688
4689 if (!cap1)
4690 continue;
4691 idx = get_connection_index(codec, cap1, pin);
4692 if (idx < 0 && cap2)
4693 idx = get_connection_index(codec, cap2, pin);
4694 if (idx >= 0) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004695 imux->items[imux->num_items].label =
4696 auto_pin_cfg_labels[i];
Takashi Iwai05f5f472009-08-25 13:10:18 +02004697 imux->items[imux->num_items].index = idx;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004698 imux->num_items++;
4699 }
4700 }
4701 return 0;
4702}
4703
Takashi Iwai05f5f472009-08-25 13:10:18 +02004704static int alc880_auto_create_input_ctls(struct hda_codec *codec,
4705 const struct auto_pin_cfg *cfg)
4706{
4707 return alc_auto_create_input_ctls(codec, cfg, 0x0b, 0x08, 0x09);
4708}
4709
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004710static void alc_set_pin_output(struct hda_codec *codec, hda_nid_t nid,
4711 unsigned int pin_type)
4712{
4713 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
4714 pin_type);
4715 /* unmute pin */
Takashi Iwaid260cdf2008-02-13 17:19:35 +01004716 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
4717 AMP_OUT_UNMUTE);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004718}
4719
Kailang Yangdf694da2005-12-05 19:42:22 +01004720static void alc880_auto_set_output_and_unmute(struct hda_codec *codec,
4721 hda_nid_t nid, int pin_type,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004722 int dac_idx)
4723{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004724 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004725 /* need the manual connection? */
4726 if (alc880_is_multi_pin(nid)) {
4727 struct alc_spec *spec = codec->spec;
4728 int idx = alc880_multi_pin_idx(nid);
4729 snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
4730 AC_VERB_SET_CONNECT_SEL,
4731 alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
4732 }
4733}
4734
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02004735static int get_pin_type(int line_out_type)
4736{
4737 if (line_out_type == AUTO_PIN_HP_OUT)
4738 return PIN_HP;
4739 else
4740 return PIN_OUT;
4741}
4742
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004743static void alc880_auto_init_multi_out(struct hda_codec *codec)
4744{
4745 struct alc_spec *spec = codec->spec;
4746 int i;
Kailang Yangea1fb292008-08-26 12:58:38 +02004747
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004748 for (i = 0; i < spec->autocfg.line_outs; i++) {
4749 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02004750 int pin_type = get_pin_type(spec->autocfg.line_out_type);
4751 alc880_auto_set_output_and_unmute(codec, nid, pin_type, i);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004752 }
4753}
4754
Takashi Iwai8d88bc32005-11-17 11:09:23 +01004755static void alc880_auto_init_extra_out(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004756{
4757 struct alc_spec *spec = codec->spec;
4758 hda_nid_t pin;
4759
Takashi Iwai82bc9552006-03-21 11:24:42 +01004760 pin = spec->autocfg.speaker_pins[0];
Takashi Iwai8d88bc32005-11-17 11:09:23 +01004761 if (pin) /* connect to front */
4762 alc880_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02004763 pin = spec->autocfg.hp_pins[0];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004764 if (pin) /* connect to front */
4765 alc880_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
4766}
4767
4768static void alc880_auto_init_analog_input(struct hda_codec *codec)
4769{
4770 struct alc_spec *spec = codec->spec;
4771 int i;
4772
4773 for (i = 0; i < AUTO_PIN_LAST; i++) {
4774 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwai05f5f472009-08-25 13:10:18 +02004775 if (alc_is_input_pin(codec, nid)) {
Takashi Iwai23f0c042009-02-26 13:03:58 +01004776 alc_set_input_pin(codec, nid, i);
Takashi Iwaie82c0252009-03-23 15:17:38 +01004777 if (nid != ALC880_PIN_CD_NID &&
4778 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004779 snd_hda_codec_write(codec, nid, 0,
4780 AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004781 AMP_OUT_MUTE);
4782 }
4783 }
4784}
4785
4786/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004787/* return 1 if successful, 0 if the proper config is not found,
4788 * or a negative error code
4789 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004790static int alc880_parse_auto_config(struct hda_codec *codec)
4791{
4792 struct alc_spec *spec = codec->spec;
Takashi Iwai6a05ac42009-02-13 11:19:09 +01004793 int i, err;
Kailang Yangdf694da2005-12-05 19:42:22 +01004794 static hda_nid_t alc880_ignore[] = { 0x1d, 0 };
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004795
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004796 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
4797 alc880_ignore);
4798 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004799 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004800 if (!spec->autocfg.line_outs)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004801 return 0; /* can't find valid BIOS pin config */
Kailang Yangdf694da2005-12-05 19:42:22 +01004802
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004803 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
4804 if (err < 0)
4805 return err;
4806 err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
4807 if (err < 0)
4808 return err;
4809 err = alc880_auto_create_extra_out(spec,
4810 spec->autocfg.speaker_pins[0],
4811 "Speaker");
4812 if (err < 0)
4813 return err;
4814 err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
4815 "Headphone");
4816 if (err < 0)
4817 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +02004818 err = alc880_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004819 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004820 return err;
4821
4822 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
4823
Takashi Iwai6a05ac42009-02-13 11:19:09 +01004824 /* check multiple SPDIF-out (for recent codecs) */
4825 for (i = 0; i < spec->autocfg.dig_outs; i++) {
4826 hda_nid_t dig_nid;
4827 err = snd_hda_get_connections(codec,
4828 spec->autocfg.dig_out_pins[i],
4829 &dig_nid, 1);
4830 if (err < 0)
4831 continue;
4832 if (!i)
4833 spec->multiout.dig_out_nid = dig_nid;
4834 else {
4835 spec->multiout.slave_dig_outs = spec->slave_dig_outs;
Roel Kluin71121d9f2009-11-10 20:11:55 +01004836 if (i >= ARRAY_SIZE(spec->slave_dig_outs) - 1)
Takashi Iwai6a05ac42009-02-13 11:19:09 +01004837 break;
Roel Kluin71121d9f2009-11-10 20:11:55 +01004838 spec->slave_dig_outs[i - 1] = dig_nid;
Takashi Iwai6a05ac42009-02-13 11:19:09 +01004839 }
4840 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004841 if (spec->autocfg.dig_in_pin)
4842 spec->dig_in_nid = ALC880_DIGIN_NID;
4843
Takashi Iwai603c4012008-07-30 15:01:44 +02004844 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +01004845 add_mixer(spec, spec->kctls.list);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004846
Takashi Iwaid88897e2008-10-31 15:01:37 +01004847 add_verb(spec, alc880_volume_init_verbs);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004848
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02004849 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02004850 spec->input_mux = &spec->private_imux[0];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004851
Takashi Iwai4a79ba32009-04-22 16:31:35 +02004852 alc_ssid_check(codec, 0x15, 0x1b, 0x14);
4853
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004854 return 1;
4855}
4856
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004857/* additional initialization for auto-configuration model */
4858static void alc880_auto_init(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004859{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004860 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004861 alc880_auto_init_multi_out(codec);
Takashi Iwai8d88bc32005-11-17 11:09:23 +01004862 alc880_auto_init_extra_out(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004863 alc880_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01004864 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02004865 alc_inithook(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004866}
4867
Takashi Iwaib59bdf32009-08-11 09:47:30 +02004868/* check the ADC/MUX contains all input pins; some ADC/MUX contains only
4869 * one of two digital mic pins, e.g. on ALC272
4870 */
4871static void fixup_automic_adc(struct hda_codec *codec)
Takashi Iwaif9e336f2008-10-31 16:37:07 +01004872{
Takashi Iwaib59bdf32009-08-11 09:47:30 +02004873 struct alc_spec *spec = codec->spec;
4874 int i;
4875
4876 for (i = 0; i < spec->num_adc_nids; i++) {
4877 hda_nid_t cap = spec->capsrc_nids ?
4878 spec->capsrc_nids[i] : spec->adc_nids[i];
4879 int iidx, eidx;
4880
4881 iidx = get_connection_index(codec, cap, spec->int_mic.pin);
4882 if (iidx < 0)
4883 continue;
4884 eidx = get_connection_index(codec, cap, spec->ext_mic.pin);
4885 if (eidx < 0)
4886 continue;
4887 spec->int_mic.mux_idx = iidx;
4888 spec->ext_mic.mux_idx = eidx;
4889 if (spec->capsrc_nids)
4890 spec->capsrc_nids += i;
4891 spec->adc_nids += i;
4892 spec->num_adc_nids = 1;
4893 return;
4894 }
4895 snd_printd(KERN_INFO "hda_codec: %s: "
4896 "No ADC/MUX containing both 0x%x and 0x%x pins\n",
4897 codec->chip_name, spec->int_mic.pin, spec->ext_mic.pin);
4898 spec->auto_mic = 0; /* disable auto-mic to be sure */
4899}
4900
4901static void set_capture_mixer(struct hda_codec *codec)
4902{
4903 struct alc_spec *spec = codec->spec;
Takashi Iwaia23b6882009-03-23 15:21:36 +01004904 static struct snd_kcontrol_new *caps[2][3] = {
4905 { alc_capture_mixer_nosrc1,
4906 alc_capture_mixer_nosrc2,
4907 alc_capture_mixer_nosrc3 },
4908 { alc_capture_mixer1,
4909 alc_capture_mixer2,
4910 alc_capture_mixer3 },
Takashi Iwaif9e336f2008-10-31 16:37:07 +01004911 };
Takashi Iwaia23b6882009-03-23 15:21:36 +01004912 if (spec->num_adc_nids > 0 && spec->num_adc_nids <= 3) {
4913 int mux;
Takashi Iwai2a22d3f2009-08-10 18:54:38 +02004914 if (spec->auto_mic) {
4915 mux = 0;
Takashi Iwaib59bdf32009-08-11 09:47:30 +02004916 fixup_automic_adc(codec);
Takashi Iwai2a22d3f2009-08-10 18:54:38 +02004917 } else if (spec->input_mux && spec->input_mux->num_items > 1)
Takashi Iwaia23b6882009-03-23 15:21:36 +01004918 mux = 1;
4919 else
4920 mux = 0;
4921 spec->cap_mixer = caps[mux][spec->num_adc_nids - 1];
4922 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01004923}
4924
Takashi Iwai67d634c2009-11-16 15:35:59 +01004925#ifdef CONFIG_SND_HDA_INPUT_BEEP
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01004926#define set_beep_amp(spec, nid, idx, dir) \
4927 ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir))
Takashi Iwai67d634c2009-11-16 15:35:59 +01004928#else
4929#define set_beep_amp(spec, nid, idx, dir) /* NOP */
4930#endif
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01004931
4932/*
4933 * OK, here we have finally the patch for ALC880
4934 */
4935
Linus Torvalds1da177e2005-04-16 15:20:36 -07004936static int patch_alc880(struct hda_codec *codec)
4937{
4938 struct alc_spec *spec;
4939 int board_config;
Kailang Yangdf694da2005-12-05 19:42:22 +01004940 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004941
Takashi Iwaie560d8d2005-09-09 14:21:46 +02004942 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004943 if (spec == NULL)
4944 return -ENOMEM;
4945
4946 codec->spec = spec;
4947
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004948 board_config = snd_hda_check_board_config(codec, ALC880_MODEL_LAST,
4949 alc880_models,
4950 alc880_cfg_tbl);
4951 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +02004952 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
4953 codec->chip_name);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004954 board_config = ALC880_AUTO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004955 }
4956
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004957 if (board_config == ALC880_AUTO) {
4958 /* automatic parse from the BIOS config */
4959 err = alc880_parse_auto_config(codec);
4960 if (err < 0) {
4961 alc_free(codec);
4962 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004963 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004964 printk(KERN_INFO
4965 "hda_codec: Cannot set up configuration "
4966 "from BIOS. Using 3-stack mode...\n");
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004967 board_config = ALC880_3ST;
4968 }
4969 }
4970
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09004971 err = snd_hda_attach_beep_device(codec, 0x1);
4972 if (err < 0) {
4973 alc_free(codec);
4974 return err;
4975 }
4976
Kailang Yangdf694da2005-12-05 19:42:22 +01004977 if (board_config != ALC880_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +02004978 setup_preset(codec, &alc880_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004979
Linus Torvalds1da177e2005-04-16 15:20:36 -07004980 spec->stream_analog_playback = &alc880_pcm_analog_playback;
4981 spec->stream_analog_capture = &alc880_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01004982 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004983
Linus Torvalds1da177e2005-04-16 15:20:36 -07004984 spec->stream_digital_playback = &alc880_pcm_digital_playback;
4985 spec->stream_digital_capture = &alc880_pcm_digital_capture;
4986
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004987 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004988 /* check whether NID 0x07 is valid */
Takashi Iwai54d17402005-11-21 16:33:22 +01004989 unsigned int wcap = get_wcaps(codec, alc880_adc_nids[0]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004990 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +02004991 wcap = get_wcaps_type(wcap);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004992 if (wcap != AC_WID_AUD_IN) {
4993 spec->adc_nids = alc880_adc_nids_alt;
4994 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids_alt);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004995 } else {
4996 spec->adc_nids = alc880_adc_nids;
4997 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004998 }
4999 }
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005000 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01005001 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005002
Takashi Iwai2134ea42008-01-10 16:53:55 +01005003 spec->vmaster_nid = 0x0c;
5004
Linus Torvalds1da177e2005-04-16 15:20:36 -07005005 codec->patch_ops = alc_patch_ops;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005006 if (board_config == ALC880_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005007 spec->init_hook = alc880_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02005008#ifdef CONFIG_SND_HDA_POWER_SAVE
5009 if (!spec->loopback.amplist)
5010 spec->loopback.amplist = alc880_loopbacks;
5011#endif
Takashi Iwaidaead532008-11-28 12:55:36 +01005012 codec->proc_widget_hook = print_realtek_coef;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005013
5014 return 0;
5015}
5016
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005017
Linus Torvalds1da177e2005-04-16 15:20:36 -07005018/*
5019 * ALC260 support
5020 */
5021
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005022static hda_nid_t alc260_dac_nids[1] = {
5023 /* front */
5024 0x02,
5025};
5026
5027static hda_nid_t alc260_adc_nids[1] = {
5028 /* ADC0 */
5029 0x04,
5030};
5031
Kailang Yangdf694da2005-12-05 19:42:22 +01005032static hda_nid_t alc260_adc_nids_alt[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005033 /* ADC1 */
5034 0x05,
5035};
5036
Jonathan Woithed57fdac2006-02-28 11:38:35 +01005037/* NIDs used when simultaneous access to both ADCs makes sense. Note that
5038 * alc260_capture_mixer assumes ADC0 (nid 0x04) is the first ADC.
5039 */
5040static hda_nid_t alc260_dual_adc_nids[2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01005041 /* ADC0, ADC1 */
5042 0x04, 0x05
5043};
5044
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005045#define ALC260_DIGOUT_NID 0x03
5046#define ALC260_DIGIN_NID 0x06
5047
5048static struct hda_input_mux alc260_capture_source = {
5049 .num_items = 4,
5050 .items = {
5051 { "Mic", 0x0 },
5052 { "Front Mic", 0x1 },
5053 { "Line", 0x2 },
5054 { "CD", 0x4 },
5055 },
5056};
5057
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01005058/* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005059 * headphone jack and the internal CD lines since these are the only pins at
5060 * which audio can appear. For flexibility, also allow the option of
5061 * recording the mixer output on the second ADC (ADC0 doesn't have a
5062 * connection to the mixer output).
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005063 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005064static struct hda_input_mux alc260_fujitsu_capture_sources[2] = {
5065 {
5066 .num_items = 3,
5067 .items = {
5068 { "Mic/Line", 0x0 },
5069 { "CD", 0x4 },
5070 { "Headphone", 0x2 },
5071 },
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005072 },
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005073 {
5074 .num_items = 4,
5075 .items = {
5076 { "Mic/Line", 0x0 },
5077 { "CD", 0x4 },
5078 { "Headphone", 0x2 },
5079 { "Mixer", 0x5 },
5080 },
5081 },
5082
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005083};
5084
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005085/* Acer TravelMate(/Extensa/Aspire) notebooks have similar configuration to
5086 * the Fujitsu S702x, but jacks are marked differently.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005087 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005088static struct hda_input_mux alc260_acer_capture_sources[2] = {
5089 {
5090 .num_items = 4,
5091 .items = {
5092 { "Mic", 0x0 },
5093 { "Line", 0x2 },
5094 { "CD", 0x4 },
5095 { "Headphone", 0x5 },
5096 },
5097 },
5098 {
5099 .num_items = 5,
5100 .items = {
5101 { "Mic", 0x0 },
5102 { "Line", 0x2 },
5103 { "CD", 0x4 },
5104 { "Headphone", 0x6 },
5105 { "Mixer", 0x5 },
5106 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005107 },
5108};
Michael Schwingencc959482009-02-22 18:58:45 +01005109
5110/* Maxdata Favorit 100XS */
5111static struct hda_input_mux alc260_favorit100_capture_sources[2] = {
5112 {
5113 .num_items = 2,
5114 .items = {
5115 { "Line/Mic", 0x0 },
5116 { "CD", 0x4 },
5117 },
5118 },
5119 {
5120 .num_items = 3,
5121 .items = {
5122 { "Line/Mic", 0x0 },
5123 { "CD", 0x4 },
5124 { "Mixer", 0x5 },
5125 },
5126 },
5127};
5128
Linus Torvalds1da177e2005-04-16 15:20:36 -07005129/*
5130 * This is just place-holder, so there's something for alc_build_pcms to look
5131 * at when it calculates the maximum number of channels. ALC260 has no mixer
5132 * element which allows changing the channel mode, so the verb list is
5133 * never used.
5134 */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01005135static struct hda_channel_mode alc260_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005136 { 2, NULL },
5137};
5138
Kailang Yangdf694da2005-12-05 19:42:22 +01005139
5140/* Mixer combinations
5141 *
5142 * basic: base_output + input + pc_beep + capture
5143 * HP: base_output + input + capture_alt
5144 * HP_3013: hp_3013 + input + capture
5145 * fujitsu: fujitsu + capture
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005146 * acer: acer + capture
Kailang Yangdf694da2005-12-05 19:42:22 +01005147 */
5148
5149static struct snd_kcontrol_new alc260_base_output_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02005150 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005151 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01005152 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
5153 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
5154 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
5155 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
5156 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005157};
Kailang Yangdf694da2005-12-05 19:42:22 +01005158
5159static struct snd_kcontrol_new alc260_input_mixer[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005160 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
5161 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
5162 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
5163 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
5164 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
5165 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
5166 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT),
5167 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005168 { } /* end */
5169};
5170
Takashi Iwaibec15c32008-01-28 18:16:30 +01005171/* update HP, line and mono out pins according to the master switch */
5172static void alc260_hp_master_update(struct hda_codec *codec,
5173 hda_nid_t hp, hda_nid_t line,
5174 hda_nid_t mono)
5175{
5176 struct alc_spec *spec = codec->spec;
5177 unsigned int val = spec->master_sw ? PIN_HP : 0;
5178 /* change HP and line-out pins */
Takashi Iwai30cde0a2008-11-07 14:49:28 +01005179 snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005180 val);
Takashi Iwai30cde0a2008-11-07 14:49:28 +01005181 snd_hda_codec_write(codec, line, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005182 val);
5183 /* mono (speaker) depending on the HP jack sense */
5184 val = (val && !spec->jack_present) ? PIN_OUT : 0;
Takashi Iwai30cde0a2008-11-07 14:49:28 +01005185 snd_hda_codec_write(codec, mono, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005186 val);
5187}
5188
5189static int alc260_hp_master_sw_get(struct snd_kcontrol *kcontrol,
5190 struct snd_ctl_elem_value *ucontrol)
5191{
5192 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
5193 struct alc_spec *spec = codec->spec;
5194 *ucontrol->value.integer.value = spec->master_sw;
5195 return 0;
5196}
5197
5198static int alc260_hp_master_sw_put(struct snd_kcontrol *kcontrol,
5199 struct snd_ctl_elem_value *ucontrol)
5200{
5201 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
5202 struct alc_spec *spec = codec->spec;
5203 int val = !!*ucontrol->value.integer.value;
5204 hda_nid_t hp, line, mono;
5205
5206 if (val == spec->master_sw)
5207 return 0;
5208 spec->master_sw = val;
5209 hp = (kcontrol->private_value >> 16) & 0xff;
5210 line = (kcontrol->private_value >> 8) & 0xff;
5211 mono = kcontrol->private_value & 0xff;
5212 alc260_hp_master_update(codec, hp, line, mono);
5213 return 1;
5214}
5215
5216static struct snd_kcontrol_new alc260_hp_output_mixer[] = {
5217 {
5218 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5219 .name = "Master Playback Switch",
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01005220 .subdevice = HDA_SUBDEV_NID_FLAG | 0x11,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005221 .info = snd_ctl_boolean_mono_info,
5222 .get = alc260_hp_master_sw_get,
5223 .put = alc260_hp_master_sw_put,
5224 .private_value = (0x0f << 16) | (0x10 << 8) | 0x11
5225 },
5226 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5227 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
5228 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
5229 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
5230 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
5231 HDA_OUTPUT),
5232 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2, HDA_INPUT),
5233 { } /* end */
5234};
5235
5236static struct hda_verb alc260_hp_unsol_verbs[] = {
5237 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
5238 {},
5239};
5240
5241static void alc260_hp_automute(struct hda_codec *codec)
5242{
5243 struct alc_spec *spec = codec->spec;
Takashi Iwaibec15c32008-01-28 18:16:30 +01005244
Wu Fengguang864f92b2009-11-18 12:38:02 +08005245 spec->jack_present = snd_hda_jack_detect(codec, 0x10);
Takashi Iwaibec15c32008-01-28 18:16:30 +01005246 alc260_hp_master_update(codec, 0x0f, 0x10, 0x11);
5247}
5248
5249static void alc260_hp_unsol_event(struct hda_codec *codec, unsigned int res)
5250{
5251 if ((res >> 26) == ALC880_HP_EVENT)
5252 alc260_hp_automute(codec);
5253}
5254
Kailang Yangdf694da2005-12-05 19:42:22 +01005255static struct snd_kcontrol_new alc260_hp_3013_mixer[] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01005256 {
5257 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5258 .name = "Master Playback Switch",
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01005259 .subdevice = HDA_SUBDEV_NID_FLAG | 0x11,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005260 .info = snd_ctl_boolean_mono_info,
5261 .get = alc260_hp_master_sw_get,
5262 .put = alc260_hp_master_sw_put,
Takashi Iwai30cde0a2008-11-07 14:49:28 +01005263 .private_value = (0x15 << 16) | (0x10 << 8) | 0x11
Takashi Iwaibec15c32008-01-28 18:16:30 +01005264 },
Kailang Yangdf694da2005-12-05 19:42:22 +01005265 HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT),
5266 HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT),
5267 HDA_CODEC_VOLUME("Aux-In Playback Volume", 0x07, 0x06, HDA_INPUT),
5268 HDA_CODEC_MUTE("Aux-In Playback Switch", 0x07, 0x06, HDA_INPUT),
5269 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5270 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01005271 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
5272 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02005273 { } /* end */
5274};
5275
Kailang Yang3f878302008-08-26 13:02:23 +02005276static struct hda_bind_ctls alc260_dc7600_bind_master_vol = {
5277 .ops = &snd_hda_bind_vol,
5278 .values = {
5279 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_OUTPUT),
5280 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_OUTPUT),
5281 HDA_COMPOSE_AMP_VAL(0x0a, 3, 0, HDA_OUTPUT),
5282 0
5283 },
5284};
5285
5286static struct hda_bind_ctls alc260_dc7600_bind_switch = {
5287 .ops = &snd_hda_bind_sw,
5288 .values = {
5289 HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT),
5290 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
5291 0
5292 },
5293};
5294
5295static struct snd_kcontrol_new alc260_hp_dc7600_mixer[] = {
5296 HDA_BIND_VOL("Master Playback Volume", &alc260_dc7600_bind_master_vol),
5297 HDA_BIND_SW("LineOut Playback Switch", &alc260_dc7600_bind_switch),
5298 HDA_CODEC_MUTE("Speaker Playback Switch", 0x0f, 0x0, HDA_OUTPUT),
5299 HDA_CODEC_MUTE("Headphone Playback Switch", 0x10, 0x0, HDA_OUTPUT),
5300 { } /* end */
5301};
5302
Takashi Iwaibec15c32008-01-28 18:16:30 +01005303static struct hda_verb alc260_hp_3013_unsol_verbs[] = {
5304 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
5305 {},
5306};
5307
5308static void alc260_hp_3013_automute(struct hda_codec *codec)
5309{
5310 struct alc_spec *spec = codec->spec;
Takashi Iwaibec15c32008-01-28 18:16:30 +01005311
Wu Fengguang864f92b2009-11-18 12:38:02 +08005312 spec->jack_present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwai30cde0a2008-11-07 14:49:28 +01005313 alc260_hp_master_update(codec, 0x15, 0x10, 0x11);
Takashi Iwaibec15c32008-01-28 18:16:30 +01005314}
5315
5316static void alc260_hp_3013_unsol_event(struct hda_codec *codec,
5317 unsigned int res)
5318{
5319 if ((res >> 26) == ALC880_HP_EVENT)
5320 alc260_hp_3013_automute(codec);
5321}
5322
Kailang Yang3f878302008-08-26 13:02:23 +02005323static void alc260_hp_3012_automute(struct hda_codec *codec)
5324{
Wu Fengguang864f92b2009-11-18 12:38:02 +08005325 unsigned int bits = snd_hda_jack_detect(codec, 0x10) ? 0 : PIN_OUT;
Kailang Yang3f878302008-08-26 13:02:23 +02005326
Kailang Yang3f878302008-08-26 13:02:23 +02005327 snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
5328 bits);
5329 snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
5330 bits);
5331 snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
5332 bits);
5333}
5334
5335static void alc260_hp_3012_unsol_event(struct hda_codec *codec,
5336 unsigned int res)
5337{
5338 if ((res >> 26) == ALC880_HP_EVENT)
5339 alc260_hp_3012_automute(codec);
5340}
5341
5342/* Fujitsu S702x series laptops. ALC260 pin usage: Mic/Line jack = 0x12,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005343 * HP jack = 0x14, CD audio = 0x16, internal speaker = 0x10.
5344 */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01005345static struct snd_kcontrol_new alc260_fujitsu_mixer[] = {
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005346 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005347 HDA_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01005348 ALC_PIN_MODE("Headphone Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005349 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
5350 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
5351 HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT),
5352 HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01005353 ALC_PIN_MODE("Mic/Line Jack Mode", 0x12, ALC_PIN_DIR_IN),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01005354 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT),
5355 HDA_BIND_MUTE("Speaker Playback Switch", 0x09, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01005356 { } /* end */
5357};
5358
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005359/* Mixer for Acer TravelMate(/Extensa/Aspire) notebooks. Note that current
5360 * versions of the ALC260 don't act on requests to enable mic bias from NID
5361 * 0x0f (used to drive the headphone jack in these laptops). The ALC260
5362 * datasheet doesn't mention this restriction. At this stage it's not clear
5363 * whether this behaviour is intentional or is a hardware bug in chip
5364 * revisions available in early 2006. Therefore for now allow the
5365 * "Headphone Jack Mode" control to span all choices, but if it turns out
5366 * that the lack of mic bias for this NID is intentional we could change the
5367 * mode from ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
5368 *
5369 * In addition, Acer TravelMate(/Extensa/Aspire) notebooks in early 2006
5370 * don't appear to make the mic bias available from the "line" jack, even
5371 * though the NID used for this jack (0x14) can supply it. The theory is
5372 * that perhaps Acer have included blocking capacitors between the ALC260
5373 * and the output jack. If this turns out to be the case for all such
5374 * models the "Line Jack Mode" mode could be changed from ALC_PIN_DIR_INOUT
5375 * to ALC_PIN_DIR_INOUT_NOMICBIAS.
Jonathan Woithebd869482006-11-28 11:35:52 +01005376 *
5377 * The C20x Tablet series have a mono internal speaker which is controlled
5378 * via the chip's Mono sum widget and pin complex, so include the necessary
5379 * controls for such models. On models without a "mono speaker" the control
5380 * won't do anything.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005381 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005382static struct snd_kcontrol_new alc260_acer_mixer[] = {
5383 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5384 HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005385 ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01005386 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
Jonathan Woithebd869482006-11-28 11:35:52 +01005387 HDA_OUTPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01005388 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2,
Jonathan Woithebd869482006-11-28 11:35:52 +01005389 HDA_INPUT),
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005390 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
5391 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
5392 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
5393 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
5394 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
5395 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
5396 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
5397 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005398 { } /* end */
5399};
5400
Michael Schwingencc959482009-02-22 18:58:45 +01005401/* Maxdata Favorit 100XS: one output and one input (0x12) jack
5402 */
5403static struct snd_kcontrol_new alc260_favorit100_mixer[] = {
5404 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5405 HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
5406 ALC_PIN_MODE("Output Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
5407 HDA_CODEC_VOLUME("Line/Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
5408 HDA_CODEC_MUTE("Line/Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
5409 ALC_PIN_MODE("Line/Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
5410 { } /* end */
5411};
5412
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005413/* Packard bell V7900 ALC260 pin usage: HP = 0x0f, Mic jack = 0x12,
5414 * Line In jack = 0x14, CD audio = 0x16, pc beep = 0x17.
5415 */
5416static struct snd_kcontrol_new alc260_will_mixer[] = {
5417 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5418 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
5419 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
5420 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
5421 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
5422 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
5423 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
5424 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
5425 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
5426 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005427 { } /* end */
5428};
5429
5430/* Replacer 672V ALC260 pin usage: Mic jack = 0x12,
5431 * Line In jack = 0x14, ATAPI Mic = 0x13, speaker = 0x0f.
5432 */
5433static struct snd_kcontrol_new alc260_replacer_672v_mixer[] = {
5434 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5435 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
5436 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
5437 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
5438 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
5439 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x07, 0x1, HDA_INPUT),
5440 HDA_CODEC_MUTE("ATATI Mic Playback Switch", 0x07, 0x1, HDA_INPUT),
5441 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
5442 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
5443 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
5444 { } /* end */
5445};
5446
Kailang Yangdf694da2005-12-05 19:42:22 +01005447/*
5448 * initialization verbs
5449 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005450static struct hda_verb alc260_init_verbs[] = {
5451 /* Line In pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02005452 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005453 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02005454 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005455 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02005456 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005457 /* Mic2 (front panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02005458 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005459 /* LINE-2 is used for line-out in rear */
Takashi Iwai05acb862005-06-10 19:50:25 +02005460 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005461 /* select line-out */
Jonathan Woithefd56f2d2006-01-24 10:35:46 +01005462 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005463 /* LINE-OUT pin */
Takashi Iwai05acb862005-06-10 19:50:25 +02005464 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005465 /* enable HP */
Takashi Iwai05acb862005-06-10 19:50:25 +02005466 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005467 /* enable Mono */
Takashi Iwai05acb862005-06-10 19:50:25 +02005468 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5469 /* mute capture amp left and right */
Takashi Iwai16ded522005-06-10 19:58:24 +02005470 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005471 /* set connection select to line in (default select for this ADC) */
5472 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai16ded522005-06-10 19:58:24 +02005473 /* mute capture amp left and right */
5474 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5475 /* set connection select to line in (default select for this ADC) */
5476 {0x05, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai05acb862005-06-10 19:50:25 +02005477 /* set vol=0 Line-Out mixer amp left and right */
5478 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5479 /* unmute pin widget amp left and right (no gain on this amp) */
5480 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5481 /* set vol=0 HP mixer amp left and right */
5482 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5483 /* unmute pin widget amp left and right (no gain on this amp) */
5484 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5485 /* set vol=0 Mono mixer amp left and right */
5486 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5487 /* unmute pin widget amp left and right (no gain on this amp) */
5488 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5489 /* unmute LINE-2 out pin */
5490 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005491 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
5492 * Line In 2 = 0x03
5493 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02005494 /* mute analog inputs */
5495 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5496 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5497 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5498 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5499 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005500 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
Takashi Iwai05acb862005-06-10 19:50:25 +02005501 /* mute Front out path */
5502 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5503 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5504 /* mute Headphone out path */
5505 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5506 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5507 /* mute Mono out path */
5508 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5509 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07005510 { }
5511};
5512
Takashi Iwai474167d2006-05-17 17:17:43 +02005513#if 0 /* should be identical with alc260_init_verbs? */
Kailang Yangdf694da2005-12-05 19:42:22 +01005514static struct hda_verb alc260_hp_init_verbs[] = {
5515 /* Headphone and output */
5516 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
5517 /* mono output */
5518 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
5519 /* Mic1 (rear panel) pin widget for input and vref at 80% */
5520 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
5521 /* Mic2 (front panel) pin widget for input and vref at 80% */
5522 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
5523 /* Line In pin widget for input */
5524 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
5525 /* Line-2 pin widget for output */
5526 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
5527 /* CD pin widget for input */
5528 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
5529 /* unmute amp left and right */
5530 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
5531 /* set connection select to line in (default select for this ADC) */
5532 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
5533 /* unmute Line-Out mixer amp left and right (volume = 0) */
5534 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
5535 /* mute pin widget amp left and right (no gain on this amp) */
5536 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
5537 /* unmute HP mixer amp left and right (volume = 0) */
5538 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
5539 /* mute pin widget amp left and right (no gain on this amp) */
5540 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005541 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
5542 * Line In 2 = 0x03
5543 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02005544 /* mute analog inputs */
5545 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5546 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5547 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5548 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5549 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01005550 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
5551 /* Unmute Front out path */
5552 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5553 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
5554 /* Unmute Headphone out path */
5555 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5556 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
5557 /* Unmute Mono out path */
5558 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5559 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
5560 { }
5561};
Takashi Iwai474167d2006-05-17 17:17:43 +02005562#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01005563
5564static struct hda_verb alc260_hp_3013_init_verbs[] = {
5565 /* Line out and output */
5566 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
5567 /* mono output */
5568 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
5569 /* Mic1 (rear panel) pin widget for input and vref at 80% */
5570 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
5571 /* Mic2 (front panel) pin widget for input and vref at 80% */
5572 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
5573 /* Line In pin widget for input */
5574 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
5575 /* Headphone pin widget for output */
5576 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
5577 /* CD pin widget for input */
5578 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
5579 /* unmute amp left and right */
5580 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
5581 /* set connection select to line in (default select for this ADC) */
5582 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
5583 /* unmute Line-Out mixer amp left and right (volume = 0) */
5584 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
5585 /* mute pin widget amp left and right (no gain on this amp) */
5586 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
5587 /* unmute HP mixer amp left and right (volume = 0) */
5588 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
5589 /* mute pin widget amp left and right (no gain on this amp) */
5590 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005591 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
5592 * Line In 2 = 0x03
5593 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02005594 /* mute analog inputs */
5595 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5596 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5597 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5598 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5599 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01005600 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
5601 /* Unmute Front out path */
5602 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5603 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
5604 /* Unmute Headphone out path */
5605 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5606 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
5607 /* Unmute Mono out path */
5608 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
5609 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
5610 { }
5611};
5612
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005613/* Initialisation sequence for ALC260 as configured in Fujitsu S702x
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005614 * laptops. ALC260 pin usage: Mic/Line jack = 0x12, HP jack = 0x14, CD
5615 * audio = 0x16, internal speaker = 0x10.
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005616 */
5617static struct hda_verb alc260_fujitsu_init_verbs[] = {
5618 /* Disable all GPIOs */
5619 {0x01, AC_VERB_SET_GPIO_MASK, 0},
5620 /* Internal speaker is connected to headphone pin */
5621 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5622 /* Headphone/Line-out jack connects to Line1 pin; make it an output */
5623 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Jonathan Woithef7ace402006-02-28 11:46:14 +01005624 /* Mic/Line-in jack is connected to mic1 pin, so make it an input */
5625 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
5626 /* Ensure all other unused pins are disabled and muted. */
5627 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5628 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005629 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01005630 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005631 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01005632 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5633 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5634 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005635
Jonathan Woithef7ace402006-02-28 11:46:14 +01005636 /* Disable digital (SPDIF) pins */
5637 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
5638 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01005639
Kailang Yangea1fb292008-08-26 12:58:38 +02005640 /* Ensure Line1 pin widget takes its input from the OUT1 sum bus
Jonathan Woithef7ace402006-02-28 11:46:14 +01005641 * when acting as an output.
5642 */
5643 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
5644
5645 /* Start with output sum widgets muted and their output gains at min */
Takashi Iwai8b33a5a2006-02-09 11:57:01 +01005646 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5647 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5648 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5649 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5650 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5651 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5652 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5653 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5654 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005655
Jonathan Woithef7ace402006-02-28 11:46:14 +01005656 /* Unmute HP pin widget amp left and right (no equiv mixer ctrl) */
5657 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5658 /* Unmute Line1 pin widget output buffer since it starts as an output.
5659 * If the pin mode is changed by the user the pin mode control will
5660 * take care of enabling the pin's input/output buffers as needed.
5661 * Therefore there's no need to enable the input buffer at this
5662 * stage.
Jonathan Woithecdcd9262006-02-28 11:36:42 +01005663 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01005664 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +02005665 /* Unmute input buffer of pin widget used for Line-in (no equiv
Jonathan Woithecdcd9262006-02-28 11:36:42 +01005666 * mixer ctrl)
5667 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01005668 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005669
Jonathan Woithef7ace402006-02-28 11:46:14 +01005670 /* Mute capture amp left and right */
5671 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +02005672 /* Set ADC connection select to match default mixer setting - line
Jonathan Woithef7ace402006-02-28 11:46:14 +01005673 * in (on mic1 pin)
5674 */
5675 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005676
Jonathan Woithef7ace402006-02-28 11:46:14 +01005677 /* Do the same for the second ADC: mute capture input amp and
5678 * set ADC connection to line in (on mic1 pin)
5679 */
5680 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5681 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01005682
Jonathan Woithef7ace402006-02-28 11:46:14 +01005683 /* Mute all inputs to mixer widget (even unconnected ones) */
5684 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
5685 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
5686 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
5687 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
5688 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
5689 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
5690 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
5691 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
Takashi Iwai4a471b72005-12-07 13:56:29 +01005692
5693 { }
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005694};
5695
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005696/* Initialisation sequence for ALC260 as configured in Acer TravelMate and
5697 * similar laptops (adapted from Fujitsu init verbs).
5698 */
5699static struct hda_verb alc260_acer_init_verbs[] = {
5700 /* On TravelMate laptops, GPIO 0 enables the internal speaker and
5701 * the headphone jack. Turn this on and rely on the standard mute
5702 * methods whenever the user wants to turn these outputs off.
5703 */
5704 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
5705 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
5706 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
5707 /* Internal speaker/Headphone jack is connected to Line-out pin */
5708 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5709 /* Internal microphone/Mic jack is connected to Mic1 pin */
5710 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
5711 /* Line In jack is connected to Line1 pin */
5712 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Jonathan Woithebd869482006-11-28 11:35:52 +01005713 /* Some Acers (eg: C20x Tablets) use Mono pin for internal speaker */
5714 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005715 /* Ensure all other unused pins are disabled and muted. */
5716 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5717 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005718 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5719 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5720 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5721 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5722 /* Disable digital (SPDIF) pins */
5723 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
5724 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
5725
Kailang Yangea1fb292008-08-26 12:58:38 +02005726 /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005727 * bus when acting as outputs.
5728 */
5729 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
5730 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
5731
5732 /* Start with output sum widgets muted and their output gains at min */
5733 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5734 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5735 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5736 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5737 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5738 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5739 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5740 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5741 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5742
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005743 /* Unmute Line-out pin widget amp left and right
5744 * (no equiv mixer ctrl)
5745 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005746 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithebd869482006-11-28 11:35:52 +01005747 /* Unmute mono pin widget amp output (no equiv mixer ctrl) */
5748 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005749 /* Unmute Mic1 and Line1 pin widget input buffers since they start as
5750 * inputs. If the pin mode is changed by the user the pin mode control
5751 * will take care of enabling the pin's input/output buffers as needed.
5752 * Therefore there's no need to enable the input buffer at this
5753 * stage.
5754 */
5755 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5756 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5757
5758 /* Mute capture amp left and right */
5759 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5760 /* Set ADC connection select to match default mixer setting - mic
5761 * (on mic1 pin)
5762 */
5763 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
5764
5765 /* Do similar with the second ADC: mute capture input amp and
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005766 * set ADC connection to mic to match ALSA's default state.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005767 */
5768 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005769 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005770
5771 /* Mute all inputs to mixer widget (even unconnected ones) */
5772 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
5773 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
5774 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
5775 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
5776 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
5777 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
5778 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
5779 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
5780
5781 { }
5782};
5783
Michael Schwingencc959482009-02-22 18:58:45 +01005784/* Initialisation sequence for Maxdata Favorit 100XS
5785 * (adapted from Acer init verbs).
5786 */
5787static struct hda_verb alc260_favorit100_init_verbs[] = {
5788 /* GPIO 0 enables the output jack.
5789 * Turn this on and rely on the standard mute
5790 * methods whenever the user wants to turn these outputs off.
5791 */
5792 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
5793 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
5794 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
5795 /* Line/Mic input jack is connected to Mic1 pin */
5796 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
5797 /* Ensure all other unused pins are disabled and muted. */
5798 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5799 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5800 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5801 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5802 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5803 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5804 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5805 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5806 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
5807 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5808 /* Disable digital (SPDIF) pins */
5809 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
5810 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
5811
5812 /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
5813 * bus when acting as outputs.
5814 */
5815 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
5816 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
5817
5818 /* Start with output sum widgets muted and their output gains at min */
5819 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5820 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5821 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5822 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5823 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5824 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5825 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5826 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5827 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5828
5829 /* Unmute Line-out pin widget amp left and right
5830 * (no equiv mixer ctrl)
5831 */
5832 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
5833 /* Unmute Mic1 and Line1 pin widget input buffers since they start as
5834 * inputs. If the pin mode is changed by the user the pin mode control
5835 * will take care of enabling the pin's input/output buffers as needed.
5836 * Therefore there's no need to enable the input buffer at this
5837 * stage.
5838 */
5839 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5840
5841 /* Mute capture amp left and right */
5842 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5843 /* Set ADC connection select to match default mixer setting - mic
5844 * (on mic1 pin)
5845 */
5846 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
5847
5848 /* Do similar with the second ADC: mute capture input amp and
5849 * set ADC connection to mic to match ALSA's default state.
5850 */
5851 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5852 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
5853
5854 /* Mute all inputs to mixer widget (even unconnected ones) */
5855 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
5856 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
5857 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
5858 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
5859 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
5860 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
5861 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
5862 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
5863
5864 { }
5865};
5866
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005867static struct hda_verb alc260_will_verbs[] = {
5868 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5869 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x00},
5870 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
5871 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
5872 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
5873 {0x1a, AC_VERB_SET_PROC_COEF, 0x3040},
5874 {}
5875};
5876
5877static struct hda_verb alc260_replacer_672v_verbs[] = {
5878 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
5879 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
5880 {0x1a, AC_VERB_SET_PROC_COEF, 0x3050},
5881
5882 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
5883 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
5884 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
5885
5886 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
5887 {}
5888};
5889
5890/* toggle speaker-output according to the hp-jack state */
5891static void alc260_replacer_672v_automute(struct hda_codec *codec)
5892{
5893 unsigned int present;
5894
5895 /* speaker --> GPIO Data 0, hp or spdif --> GPIO data 1 */
Wu Fengguang864f92b2009-11-18 12:38:02 +08005896 present = snd_hda_jack_detect(codec, 0x0f);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005897 if (present) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02005898 snd_hda_codec_write_cache(codec, 0x01, 0,
5899 AC_VERB_SET_GPIO_DATA, 1);
5900 snd_hda_codec_write_cache(codec, 0x0f, 0,
5901 AC_VERB_SET_PIN_WIDGET_CONTROL,
5902 PIN_HP);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005903 } else {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02005904 snd_hda_codec_write_cache(codec, 0x01, 0,
5905 AC_VERB_SET_GPIO_DATA, 0);
5906 snd_hda_codec_write_cache(codec, 0x0f, 0,
5907 AC_VERB_SET_PIN_WIDGET_CONTROL,
5908 PIN_OUT);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005909 }
5910}
5911
5912static void alc260_replacer_672v_unsol_event(struct hda_codec *codec,
5913 unsigned int res)
5914{
5915 if ((res >> 26) == ALC880_HP_EVENT)
5916 alc260_replacer_672v_automute(codec);
5917}
5918
Kailang Yang3f878302008-08-26 13:02:23 +02005919static struct hda_verb alc260_hp_dc7600_verbs[] = {
5920 {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
5921 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
5922 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5923 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5924 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5925 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5926 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
5927 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
5928 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
5929 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
5930 {}
5931};
5932
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005933/* Test configuration for debugging, modelled after the ALC880 test
5934 * configuration.
5935 */
5936#ifdef CONFIG_SND_DEBUG
5937static hda_nid_t alc260_test_dac_nids[1] = {
5938 0x02,
5939};
5940static hda_nid_t alc260_test_adc_nids[2] = {
5941 0x04, 0x05,
5942};
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005943/* For testing the ALC260, each input MUX needs its own definition since
Kailang Yangea1fb292008-08-26 12:58:38 +02005944 * the signal assignments are different. This assumes that the first ADC
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005945 * is NID 0x04.
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01005946 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005947static struct hda_input_mux alc260_test_capture_sources[2] = {
5948 {
5949 .num_items = 7,
5950 .items = {
5951 { "MIC1 pin", 0x0 },
5952 { "MIC2 pin", 0x1 },
5953 { "LINE1 pin", 0x2 },
5954 { "LINE2 pin", 0x3 },
5955 { "CD pin", 0x4 },
5956 { "LINE-OUT pin", 0x5 },
5957 { "HP-OUT pin", 0x6 },
5958 },
5959 },
5960 {
5961 .num_items = 8,
5962 .items = {
5963 { "MIC1 pin", 0x0 },
5964 { "MIC2 pin", 0x1 },
5965 { "LINE1 pin", 0x2 },
5966 { "LINE2 pin", 0x3 },
5967 { "CD pin", 0x4 },
5968 { "Mixer", 0x5 },
5969 { "LINE-OUT pin", 0x6 },
5970 { "HP-OUT pin", 0x7 },
5971 },
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005972 },
5973};
5974static struct snd_kcontrol_new alc260_test_mixer[] = {
5975 /* Output driver widgets */
5976 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
5977 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
5978 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x09, 0x0, HDA_OUTPUT),
5979 HDA_BIND_MUTE("LOUT2 Playback Switch", 0x09, 2, HDA_INPUT),
5980 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5981 HDA_BIND_MUTE("LOUT1 Playback Switch", 0x08, 2, HDA_INPUT),
5982
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005983 /* Modes for retasking pin widgets
5984 * Note: the ALC260 doesn't seem to act on requests to enable mic
5985 * bias from NIDs 0x0f and 0x10. The ALC260 datasheet doesn't
5986 * mention this restriction. At this stage it's not clear whether
5987 * this behaviour is intentional or is a hardware bug in chip
5988 * revisions available at least up until early 2006. Therefore for
5989 * now allow the "HP-OUT" and "LINE-OUT" Mode controls to span all
5990 * choices, but if it turns out that the lack of mic bias for these
5991 * NIDs is intentional we could change their modes from
5992 * ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
5993 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01005994 ALC_PIN_MODE("HP-OUT pin mode", 0x10, ALC_PIN_DIR_INOUT),
5995 ALC_PIN_MODE("LINE-OUT pin mode", 0x0f, ALC_PIN_DIR_INOUT),
5996 ALC_PIN_MODE("LINE2 pin mode", 0x15, ALC_PIN_DIR_INOUT),
5997 ALC_PIN_MODE("LINE1 pin mode", 0x14, ALC_PIN_DIR_INOUT),
5998 ALC_PIN_MODE("MIC2 pin mode", 0x13, ALC_PIN_DIR_INOUT),
5999 ALC_PIN_MODE("MIC1 pin mode", 0x12, ALC_PIN_DIR_INOUT),
6000
6001 /* Loopback mixer controls */
6002 HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x07, 0x00, HDA_INPUT),
6003 HDA_CODEC_MUTE("MIC1 Playback Switch", 0x07, 0x00, HDA_INPUT),
6004 HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x07, 0x01, HDA_INPUT),
6005 HDA_CODEC_MUTE("MIC2 Playback Switch", 0x07, 0x01, HDA_INPUT),
6006 HDA_CODEC_VOLUME("LINE1 Playback Volume", 0x07, 0x02, HDA_INPUT),
6007 HDA_CODEC_MUTE("LINE1 Playback Switch", 0x07, 0x02, HDA_INPUT),
6008 HDA_CODEC_VOLUME("LINE2 Playback Volume", 0x07, 0x03, HDA_INPUT),
6009 HDA_CODEC_MUTE("LINE2 Playback Switch", 0x07, 0x03, HDA_INPUT),
6010 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
6011 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006012 HDA_CODEC_VOLUME("LINE-OUT loopback Playback Volume", 0x07, 0x06, HDA_INPUT),
6013 HDA_CODEC_MUTE("LINE-OUT loopback Playback Switch", 0x07, 0x06, HDA_INPUT),
6014 HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x07, 0x7, HDA_INPUT),
6015 HDA_CODEC_MUTE("HP-OUT loopback Playback Switch", 0x07, 0x7, HDA_INPUT),
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01006016
6017 /* Controls for GPIO pins, assuming they are configured as outputs */
6018 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
6019 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
6020 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
6021 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
6022
Jonathan Woithe92621f12006-02-28 11:47:47 +01006023 /* Switches to allow the digital IO pins to be enabled. The datasheet
6024 * is ambigious as to which NID is which; testing on laptops which
Kailang Yangea1fb292008-08-26 12:58:38 +02006025 * make this output available should provide clarification.
Jonathan Woithe92621f12006-02-28 11:47:47 +01006026 */
6027 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x03, 0x01),
6028 ALC_SPDIF_CTRL_SWITCH("SPDIF Capture Switch", 0x06, 0x01),
6029
Jonathan Woithef8225f62008-01-08 12:16:54 +01006030 /* A switch allowing EAPD to be enabled. Some laptops seem to use
6031 * this output to turn on an external amplifier.
6032 */
6033 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
6034 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
6035
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006036 { } /* end */
6037};
6038static struct hda_verb alc260_test_init_verbs[] = {
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01006039 /* Enable all GPIOs as outputs with an initial value of 0 */
6040 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f},
6041 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
6042 {0x01, AC_VERB_SET_GPIO_MASK, 0x0f},
6043
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006044 /* Enable retasking pins as output, initially without power amp */
6045 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6046 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6047 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6048 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6049 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6050 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6051
Jonathan Woithe92621f12006-02-28 11:47:47 +01006052 /* Disable digital (SPDIF) pins initially, but users can enable
6053 * them via a mixer switch. In the case of SPDIF-out, this initverb
6054 * payload also sets the generation to 0, output to be in "consumer"
6055 * PCM format, copyright asserted, no pre-emphasis and no validity
6056 * control.
6057 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006058 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
6059 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
6060
Kailang Yangea1fb292008-08-26 12:58:38 +02006061 /* Ensure mic1, mic2, line1 and line2 pin widgets take input from the
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006062 * OUT1 sum bus when acting as an output.
6063 */
6064 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
6065 {0x0c, AC_VERB_SET_CONNECT_SEL, 0},
6066 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
6067 {0x0e, AC_VERB_SET_CONNECT_SEL, 0},
6068
6069 /* Start with output sum widgets muted and their output gains at min */
6070 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6071 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6072 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6073 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6074 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6075 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6076 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6077 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6078 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6079
Jonathan Woithecdcd9262006-02-28 11:36:42 +01006080 /* Unmute retasking pin widget output buffers since the default
6081 * state appears to be output. As the pin mode is changed by the
6082 * user the pin mode control will take care of enabling the pin's
6083 * input/output buffers as needed.
6084 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006085 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6086 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6087 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6088 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6089 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6090 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6091 /* Also unmute the mono-out pin widget */
6092 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6093
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006094 /* Mute capture amp left and right */
6095 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithef7ace402006-02-28 11:46:14 +01006096 /* Set ADC connection select to match default mixer setting (mic1
6097 * pin)
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006098 */
6099 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
6100
6101 /* Do the same for the second ADC: mute capture input amp and
Jonathan Woithef7ace402006-02-28 11:46:14 +01006102 * set ADC connection to mic1 pin
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006103 */
6104 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6105 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
6106
6107 /* Mute all inputs to mixer widget (even unconnected ones) */
6108 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
6109 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
6110 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
6111 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
6112 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
6113 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
6114 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
6115 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
6116
6117 { }
6118};
6119#endif
6120
Takashi Iwai63300792008-01-24 15:31:36 +01006121#define alc260_pcm_analog_playback alc880_pcm_analog_alt_playback
6122#define alc260_pcm_analog_capture alc880_pcm_analog_capture
Linus Torvalds1da177e2005-04-16 15:20:36 -07006123
Takashi Iwaia3bcba32005-12-06 19:05:29 +01006124#define alc260_pcm_digital_playback alc880_pcm_digital_playback
6125#define alc260_pcm_digital_capture alc880_pcm_digital_capture
6126
Kailang Yangdf694da2005-12-05 19:42:22 +01006127/*
6128 * for BIOS auto-configuration
6129 */
6130
6131static int alc260_add_playback_controls(struct alc_spec *spec, hda_nid_t nid,
Takashi Iwai863b4512008-10-21 17:01:47 +02006132 const char *pfx, int *vol_bits)
Kailang Yangdf694da2005-12-05 19:42:22 +01006133{
6134 hda_nid_t nid_vol;
6135 unsigned long vol_val, sw_val;
Kailang Yangdf694da2005-12-05 19:42:22 +01006136 int err;
6137
6138 if (nid >= 0x0f && nid < 0x11) {
6139 nid_vol = nid - 0x7;
6140 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
6141 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
6142 } else if (nid == 0x11) {
6143 nid_vol = nid - 0x7;
6144 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT);
6145 sw_val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
6146 } else if (nid >= 0x12 && nid <= 0x15) {
6147 nid_vol = 0x08;
6148 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
6149 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
6150 } else
6151 return 0; /* N/A */
Kailang Yangea1fb292008-08-26 12:58:38 +02006152
Takashi Iwai863b4512008-10-21 17:01:47 +02006153 if (!(*vol_bits & (1 << nid_vol))) {
6154 /* first control for the volume widget */
Takashi Iwai0afe5f82009-10-02 09:20:00 +02006155 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, vol_val);
Takashi Iwai863b4512008-10-21 17:01:47 +02006156 if (err < 0)
6157 return err;
6158 *vol_bits |= (1 << nid_vol);
6159 }
Takashi Iwai0afe5f82009-10-02 09:20:00 +02006160 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, sw_val);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006161 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01006162 return err;
6163 return 1;
6164}
6165
6166/* add playback controls from the parsed DAC table */
6167static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec,
6168 const struct auto_pin_cfg *cfg)
6169{
6170 hda_nid_t nid;
6171 int err;
Takashi Iwai863b4512008-10-21 17:01:47 +02006172 int vols = 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01006173
6174 spec->multiout.num_dacs = 1;
6175 spec->multiout.dac_nids = spec->private_dac_nids;
6176 spec->multiout.dac_nids[0] = 0x02;
6177
6178 nid = cfg->line_out_pins[0];
6179 if (nid) {
Takashi Iwai23112d62009-08-25 16:07:08 +02006180 const char *pfx;
6181 if (!cfg->speaker_pins[0] && !cfg->hp_pins[0])
6182 pfx = "Master";
6183 else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
6184 pfx = "Speaker";
6185 else
6186 pfx = "Front";
6187 err = alc260_add_playback_controls(spec, nid, pfx, &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01006188 if (err < 0)
6189 return err;
6190 }
6191
Takashi Iwai82bc9552006-03-21 11:24:42 +01006192 nid = cfg->speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006193 if (nid) {
Takashi Iwai863b4512008-10-21 17:01:47 +02006194 err = alc260_add_playback_controls(spec, nid, "Speaker", &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01006195 if (err < 0)
6196 return err;
6197 }
6198
Takashi Iwaieb06ed82006-09-20 17:10:27 +02006199 nid = cfg->hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006200 if (nid) {
Takashi Iwai863b4512008-10-21 17:01:47 +02006201 err = alc260_add_playback_controls(spec, nid, "Headphone",
6202 &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01006203 if (err < 0)
6204 return err;
6205 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006206 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01006207}
6208
6209/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +02006210static int alc260_auto_create_input_ctls(struct hda_codec *codec,
Kailang Yangdf694da2005-12-05 19:42:22 +01006211 const struct auto_pin_cfg *cfg)
6212{
Takashi Iwai05f5f472009-08-25 13:10:18 +02006213 return alc_auto_create_input_ctls(codec, cfg, 0x07, 0x04, 0x05);
Kailang Yangdf694da2005-12-05 19:42:22 +01006214}
6215
6216static void alc260_auto_set_output_and_unmute(struct hda_codec *codec,
6217 hda_nid_t nid, int pin_type,
6218 int sel_idx)
6219{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006220 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01006221 /* need the manual connection? */
6222 if (nid >= 0x12) {
6223 int idx = nid - 0x12;
6224 snd_hda_codec_write(codec, idx + 0x0b, 0,
6225 AC_VERB_SET_CONNECT_SEL, sel_idx);
Kailang Yangdf694da2005-12-05 19:42:22 +01006226 }
6227}
6228
6229static void alc260_auto_init_multi_out(struct hda_codec *codec)
6230{
6231 struct alc_spec *spec = codec->spec;
6232 hda_nid_t nid;
6233
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006234 nid = spec->autocfg.line_out_pins[0];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02006235 if (nid) {
6236 int pin_type = get_pin_type(spec->autocfg.line_out_type);
6237 alc260_auto_set_output_and_unmute(codec, nid, pin_type, 0);
6238 }
Kailang Yangea1fb292008-08-26 12:58:38 +02006239
Takashi Iwai82bc9552006-03-21 11:24:42 +01006240 nid = spec->autocfg.speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006241 if (nid)
6242 alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
6243
Takashi Iwaieb06ed82006-09-20 17:10:27 +02006244 nid = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006245 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02006246 alc260_auto_set_output_and_unmute(codec, nid, PIN_HP, 0);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006247}
Kailang Yangdf694da2005-12-05 19:42:22 +01006248
6249#define ALC260_PIN_CD_NID 0x16
6250static void alc260_auto_init_analog_input(struct hda_codec *codec)
6251{
6252 struct alc_spec *spec = codec->spec;
6253 int i;
6254
6255 for (i = 0; i < AUTO_PIN_LAST; i++) {
6256 hda_nid_t nid = spec->autocfg.input_pins[i];
6257 if (nid >= 0x12) {
Takashi Iwai23f0c042009-02-26 13:03:58 +01006258 alc_set_input_pin(codec, nid, i);
Takashi Iwaie82c0252009-03-23 15:17:38 +01006259 if (nid != ALC260_PIN_CD_NID &&
6260 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006261 snd_hda_codec_write(codec, nid, 0,
6262 AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangdf694da2005-12-05 19:42:22 +01006263 AMP_OUT_MUTE);
6264 }
6265 }
6266}
6267
6268/*
6269 * generic initialization of ADC, input mixers and output mixers
6270 */
6271static struct hda_verb alc260_volume_init_verbs[] = {
6272 /*
6273 * Unmute ADC0-1 and set the default input to mic-in
6274 */
6275 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
6276 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6277 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
6278 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +02006279
Kailang Yangdf694da2005-12-05 19:42:22 +01006280 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
6281 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006282 * Note: PASD motherboards uses the Line In 2 as the input for
6283 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01006284 */
6285 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02006286 /* mute analog inputs */
6287 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6288 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6289 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6290 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6291 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01006292
6293 /*
6294 * Set up output mixers (0x08 - 0x0a)
6295 */
6296 /* set vol=0 to output mixers */
6297 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6298 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6299 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6300 /* set up input amps for analog loopback */
6301 /* Amp Indices: DAC = 0, mixer = 1 */
6302 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6303 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6304 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6305 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6306 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6307 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +02006308
Kailang Yangdf694da2005-12-05 19:42:22 +01006309 { }
6310};
6311
6312static int alc260_parse_auto_config(struct hda_codec *codec)
6313{
6314 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01006315 int err;
6316 static hda_nid_t alc260_ignore[] = { 0x17, 0 };
6317
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006318 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
6319 alc260_ignore);
6320 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01006321 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006322 err = alc260_auto_create_multi_out_ctls(spec, &spec->autocfg);
6323 if (err < 0)
Takashi Iwai4a471b72005-12-07 13:56:29 +01006324 return err;
Takashi Iwai603c4012008-07-30 15:01:44 +02006325 if (!spec->kctls.list)
Kailang Yangdf694da2005-12-05 19:42:22 +01006326 return 0; /* can't find valid BIOS pin config */
Takashi Iwai05f5f472009-08-25 13:10:18 +02006327 err = alc260_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006328 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01006329 return err;
6330
6331 spec->multiout.max_channels = 2;
6332
Takashi Iwai0852d7a2009-02-11 11:35:15 +01006333 if (spec->autocfg.dig_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +01006334 spec->multiout.dig_out_nid = ALC260_DIGOUT_NID;
Takashi Iwai603c4012008-07-30 15:01:44 +02006335 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +01006336 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +01006337
Takashi Iwaid88897e2008-10-31 15:01:37 +01006338 add_verb(spec, alc260_volume_init_verbs);
Kailang Yangdf694da2005-12-05 19:42:22 +01006339
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006340 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02006341 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006342
Takashi Iwai4a79ba32009-04-22 16:31:35 +02006343 alc_ssid_check(codec, 0x10, 0x15, 0x0f);
6344
Kailang Yangdf694da2005-12-05 19:42:22 +01006345 return 1;
6346}
6347
Takashi Iwaiae6b8132006-03-03 16:47:17 +01006348/* additional initialization for auto-configuration model */
6349static void alc260_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01006350{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006351 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01006352 alc260_auto_init_multi_out(codec);
6353 alc260_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006354 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02006355 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01006356}
6357
Takashi Iwaicb53c622007-08-10 17:21:45 +02006358#ifdef CONFIG_SND_HDA_POWER_SAVE
6359static struct hda_amp_list alc260_loopbacks[] = {
6360 { 0x07, HDA_INPUT, 0 },
6361 { 0x07, HDA_INPUT, 1 },
6362 { 0x07, HDA_INPUT, 2 },
6363 { 0x07, HDA_INPUT, 3 },
6364 { 0x07, HDA_INPUT, 4 },
6365 { } /* end */
6366};
6367#endif
6368
Kailang Yangdf694da2005-12-05 19:42:22 +01006369/*
6370 * ALC260 configurations
6371 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006372static const char *alc260_models[ALC260_MODEL_LAST] = {
6373 [ALC260_BASIC] = "basic",
6374 [ALC260_HP] = "hp",
6375 [ALC260_HP_3013] = "hp-3013",
Takashi Iwai2922c9a2008-08-27 18:12:42 +02006376 [ALC260_HP_DC7600] = "hp-dc7600",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006377 [ALC260_FUJITSU_S702X] = "fujitsu",
6378 [ALC260_ACER] = "acer",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006379 [ALC260_WILL] = "will",
6380 [ALC260_REPLACER_672V] = "replacer",
Michael Schwingencc959482009-02-22 18:58:45 +01006381 [ALC260_FAVORIT100] = "favorit100",
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006382#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006383 [ALC260_TEST] = "test",
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006384#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006385 [ALC260_AUTO] = "auto",
6386};
6387
6388static struct snd_pci_quirk alc260_cfg_tbl[] = {
Jonathan Woithebd869482006-11-28 11:35:52 +01006389 SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER),
Daniel T Chen950200e2009-12-13 14:11:02 -05006390 SND_PCI_QUIRK(0x1025, 0x007f, "Acer", ALC260_WILL),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006391 SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER),
Michael Schwingencc959482009-02-22 18:58:45 +01006392 SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FAVORIT100),
Takashi Iwai9720b712007-03-13 21:46:23 +01006393 SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013),
Takashi Iwai4ac55982009-11-10 16:08:45 +01006394 SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_AUTO), /* no quirk */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006395 SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013),
Jaroslav Kysela34ec8a02008-07-10 14:49:19 +02006396 SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP_3013),
Kailang Yang3f878302008-08-26 13:02:23 +02006397 SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_DC7600),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006398 SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013),
6399 SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP),
6400 SND_PCI_QUIRK(0x103c, 0x3015, "HP", ALC260_HP),
6401 SND_PCI_QUIRK(0x103c, 0x3016, "HP", ALC260_HP),
6402 SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_BASIC),
6403 SND_PCI_QUIRK(0x104d, 0x81cc, "Sony VAIO", ALC260_BASIC),
6404 SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC),
6405 SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X),
6406 SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006407 SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_REPLACER_672V),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01006408 SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_WILL),
Takashi Iwai16ded522005-06-10 19:58:24 +02006409 {}
6410};
6411
Kailang Yangdf694da2005-12-05 19:42:22 +01006412static struct alc_config_preset alc260_presets[] = {
6413 [ALC260_BASIC] = {
6414 .mixers = { alc260_base_output_mixer,
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01006415 alc260_input_mixer },
Kailang Yangdf694da2005-12-05 19:42:22 +01006416 .init_verbs = { alc260_init_verbs },
6417 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6418 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006419 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
Kailang Yangdf694da2005-12-05 19:42:22 +01006420 .adc_nids = alc260_adc_nids,
6421 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6422 .channel_mode = alc260_modes,
6423 .input_mux = &alc260_capture_source,
6424 },
6425 [ALC260_HP] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01006426 .mixers = { alc260_hp_output_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006427 alc260_input_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01006428 .init_verbs = { alc260_init_verbs,
6429 alc260_hp_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01006430 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6431 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006432 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
6433 .adc_nids = alc260_adc_nids_alt,
Kailang Yangdf694da2005-12-05 19:42:22 +01006434 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6435 .channel_mode = alc260_modes,
6436 .input_mux = &alc260_capture_source,
Takashi Iwaibec15c32008-01-28 18:16:30 +01006437 .unsol_event = alc260_hp_unsol_event,
6438 .init_hook = alc260_hp_automute,
Kailang Yangdf694da2005-12-05 19:42:22 +01006439 },
Kailang Yang3f878302008-08-26 13:02:23 +02006440 [ALC260_HP_DC7600] = {
6441 .mixers = { alc260_hp_dc7600_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006442 alc260_input_mixer },
Kailang Yang3f878302008-08-26 13:02:23 +02006443 .init_verbs = { alc260_init_verbs,
6444 alc260_hp_dc7600_verbs },
6445 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6446 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006447 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
6448 .adc_nids = alc260_adc_nids_alt,
Kailang Yang3f878302008-08-26 13:02:23 +02006449 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6450 .channel_mode = alc260_modes,
6451 .input_mux = &alc260_capture_source,
6452 .unsol_event = alc260_hp_3012_unsol_event,
6453 .init_hook = alc260_hp_3012_automute,
6454 },
Kailang Yangdf694da2005-12-05 19:42:22 +01006455 [ALC260_HP_3013] = {
6456 .mixers = { alc260_hp_3013_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006457 alc260_input_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01006458 .init_verbs = { alc260_hp_3013_init_verbs,
6459 alc260_hp_3013_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01006460 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6461 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006462 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
6463 .adc_nids = alc260_adc_nids_alt,
Kailang Yangdf694da2005-12-05 19:42:22 +01006464 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6465 .channel_mode = alc260_modes,
6466 .input_mux = &alc260_capture_source,
Takashi Iwaibec15c32008-01-28 18:16:30 +01006467 .unsol_event = alc260_hp_3013_unsol_event,
6468 .init_hook = alc260_hp_3013_automute,
Kailang Yangdf694da2005-12-05 19:42:22 +01006469 },
6470 [ALC260_FUJITSU_S702X] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006471 .mixers = { alc260_fujitsu_mixer },
Kailang Yangdf694da2005-12-05 19:42:22 +01006472 .init_verbs = { alc260_fujitsu_init_verbs },
6473 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6474 .dac_nids = alc260_dac_nids,
Jonathan Woithed57fdac2006-02-28 11:38:35 +01006475 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
6476 .adc_nids = alc260_dual_adc_nids,
Kailang Yangdf694da2005-12-05 19:42:22 +01006477 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6478 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006479 .num_mux_defs = ARRAY_SIZE(alc260_fujitsu_capture_sources),
6480 .input_mux = alc260_fujitsu_capture_sources,
Kailang Yangdf694da2005-12-05 19:42:22 +01006481 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006482 [ALC260_ACER] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006483 .mixers = { alc260_acer_mixer },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006484 .init_verbs = { alc260_acer_init_verbs },
6485 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6486 .dac_nids = alc260_dac_nids,
6487 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
6488 .adc_nids = alc260_dual_adc_nids,
6489 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6490 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006491 .num_mux_defs = ARRAY_SIZE(alc260_acer_capture_sources),
6492 .input_mux = alc260_acer_capture_sources,
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006493 },
Michael Schwingencc959482009-02-22 18:58:45 +01006494 [ALC260_FAVORIT100] = {
6495 .mixers = { alc260_favorit100_mixer },
6496 .init_verbs = { alc260_favorit100_init_verbs },
6497 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6498 .dac_nids = alc260_dac_nids,
6499 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
6500 .adc_nids = alc260_dual_adc_nids,
6501 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6502 .channel_mode = alc260_modes,
6503 .num_mux_defs = ARRAY_SIZE(alc260_favorit100_capture_sources),
6504 .input_mux = alc260_favorit100_capture_sources,
6505 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006506 [ALC260_WILL] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006507 .mixers = { alc260_will_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006508 .init_verbs = { alc260_init_verbs, alc260_will_verbs },
6509 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6510 .dac_nids = alc260_dac_nids,
6511 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
6512 .adc_nids = alc260_adc_nids,
6513 .dig_out_nid = ALC260_DIGOUT_NID,
6514 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6515 .channel_mode = alc260_modes,
6516 .input_mux = &alc260_capture_source,
6517 },
6518 [ALC260_REPLACER_672V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006519 .mixers = { alc260_replacer_672v_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006520 .init_verbs = { alc260_init_verbs, alc260_replacer_672v_verbs },
6521 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
6522 .dac_nids = alc260_dac_nids,
6523 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
6524 .adc_nids = alc260_adc_nids,
6525 .dig_out_nid = ALC260_DIGOUT_NID,
6526 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6527 .channel_mode = alc260_modes,
6528 .input_mux = &alc260_capture_source,
6529 .unsol_event = alc260_replacer_672v_unsol_event,
6530 .init_hook = alc260_replacer_672v_automute,
6531 },
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006532#ifdef CONFIG_SND_DEBUG
6533 [ALC260_TEST] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006534 .mixers = { alc260_test_mixer },
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006535 .init_verbs = { alc260_test_init_verbs },
6536 .num_dacs = ARRAY_SIZE(alc260_test_dac_nids),
6537 .dac_nids = alc260_test_dac_nids,
6538 .num_adc_nids = ARRAY_SIZE(alc260_test_adc_nids),
6539 .adc_nids = alc260_test_adc_nids,
6540 .num_channel_mode = ARRAY_SIZE(alc260_modes),
6541 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006542 .num_mux_defs = ARRAY_SIZE(alc260_test_capture_sources),
6543 .input_mux = alc260_test_capture_sources,
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006544 },
6545#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01006546};
6547
Linus Torvalds1da177e2005-04-16 15:20:36 -07006548static int patch_alc260(struct hda_codec *codec)
6549{
6550 struct alc_spec *spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01006551 int err, board_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006552
Takashi Iwaie560d8d2005-09-09 14:21:46 +02006553 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006554 if (spec == NULL)
6555 return -ENOMEM;
6556
6557 codec->spec = spec;
6558
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006559 board_config = snd_hda_check_board_config(codec, ALC260_MODEL_LAST,
6560 alc260_models,
6561 alc260_cfg_tbl);
6562 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +02006563 snd_printd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
Takashi Iwai6c627f32009-05-18 12:33:36 +02006564 codec->chip_name);
Kailang Yangdf694da2005-12-05 19:42:22 +01006565 board_config = ALC260_AUTO;
Takashi Iwai16ded522005-06-10 19:58:24 +02006566 }
6567
Kailang Yangdf694da2005-12-05 19:42:22 +01006568 if (board_config == ALC260_AUTO) {
6569 /* automatic parse from the BIOS config */
6570 err = alc260_parse_auto_config(codec);
6571 if (err < 0) {
6572 alc_free(codec);
6573 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006574 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006575 printk(KERN_INFO
6576 "hda_codec: Cannot set up configuration "
6577 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01006578 board_config = ALC260_BASIC;
6579 }
Takashi Iwai16ded522005-06-10 19:58:24 +02006580 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006581
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09006582 err = snd_hda_attach_beep_device(codec, 0x1);
6583 if (err < 0) {
6584 alc_free(codec);
6585 return err;
6586 }
6587
Kailang Yangdf694da2005-12-05 19:42:22 +01006588 if (board_config != ALC260_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +02006589 setup_preset(codec, &alc260_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006590
Linus Torvalds1da177e2005-04-16 15:20:36 -07006591 spec->stream_analog_playback = &alc260_pcm_analog_playback;
6592 spec->stream_analog_capture = &alc260_pcm_analog_capture;
6593
Takashi Iwaia3bcba32005-12-06 19:05:29 +01006594 spec->stream_digital_playback = &alc260_pcm_digital_playback;
6595 spec->stream_digital_capture = &alc260_pcm_digital_capture;
6596
Takashi Iwai4ef0ef12008-11-03 17:47:49 +01006597 if (!spec->adc_nids && spec->input_mux) {
6598 /* check whether NID 0x04 is valid */
6599 unsigned int wcap = get_wcaps(codec, 0x04);
Takashi Iwaia22d5432009-07-27 12:54:26 +02006600 wcap = get_wcaps_type(wcap);
Takashi Iwai4ef0ef12008-11-03 17:47:49 +01006601 /* get type */
6602 if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
6603 spec->adc_nids = alc260_adc_nids_alt;
6604 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt);
6605 } else {
6606 spec->adc_nids = alc260_adc_nids;
6607 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids);
6608 }
6609 }
Takashi Iwaib59bdf32009-08-11 09:47:30 +02006610 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01006611 set_beep_amp(spec, 0x07, 0x05, HDA_INPUT);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006612
Takashi Iwai2134ea42008-01-10 16:53:55 +01006613 spec->vmaster_nid = 0x08;
6614
Linus Torvalds1da177e2005-04-16 15:20:36 -07006615 codec->patch_ops = alc_patch_ops;
Kailang Yangdf694da2005-12-05 19:42:22 +01006616 if (board_config == ALC260_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01006617 spec->init_hook = alc260_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02006618#ifdef CONFIG_SND_HDA_POWER_SAVE
6619 if (!spec->loopback.amplist)
6620 spec->loopback.amplist = alc260_loopbacks;
6621#endif
Takashi Iwaidaead532008-11-28 12:55:36 +01006622 codec->proc_widget_hook = print_realtek_coef;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006623
6624 return 0;
6625}
6626
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006627
Linus Torvalds1da177e2005-04-16 15:20:36 -07006628/*
Takashi Iwai4953550a2009-06-30 15:28:30 +02006629 * ALC882/883/885/888/889 support
Linus Torvalds1da177e2005-04-16 15:20:36 -07006630 *
6631 * ALC882 is almost identical with ALC880 but has cleaner and more flexible
6632 * configuration. Each pin widget can choose any input DACs and a mixer.
6633 * Each ADC is connected from a mixer of all inputs. This makes possible
6634 * 6-channel independent captures.
6635 *
6636 * In addition, an independent DAC for the multi-playback (not used in this
6637 * driver yet).
6638 */
Kailang Yangdf694da2005-12-05 19:42:22 +01006639#define ALC882_DIGOUT_NID 0x06
6640#define ALC882_DIGIN_NID 0x0a
Takashi Iwai4953550a2009-06-30 15:28:30 +02006641#define ALC883_DIGOUT_NID ALC882_DIGOUT_NID
6642#define ALC883_DIGIN_NID ALC882_DIGIN_NID
6643#define ALC1200_DIGOUT_NID 0x10
6644
Linus Torvalds1da177e2005-04-16 15:20:36 -07006645
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01006646static struct hda_channel_mode alc882_ch_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006647 { 8, NULL }
6648};
6649
Takashi Iwai4953550a2009-06-30 15:28:30 +02006650/* DACs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006651static hda_nid_t alc882_dac_nids[4] = {
6652 /* front, rear, clfe, rear_surr */
6653 0x02, 0x03, 0x04, 0x05
6654};
Takashi Iwai4953550a2009-06-30 15:28:30 +02006655#define alc883_dac_nids alc882_dac_nids
Linus Torvalds1da177e2005-04-16 15:20:36 -07006656
Takashi Iwai4953550a2009-06-30 15:28:30 +02006657/* ADCs */
Kailang Yangdf694da2005-12-05 19:42:22 +01006658#define alc882_adc_nids alc880_adc_nids
6659#define alc882_adc_nids_alt alc880_adc_nids_alt
Takashi Iwai4953550a2009-06-30 15:28:30 +02006660#define alc883_adc_nids alc882_adc_nids_alt
6661static hda_nid_t alc883_adc_nids_alt[1] = { 0x08 };
6662static hda_nid_t alc883_adc_nids_rev[2] = { 0x09, 0x08 };
6663#define alc889_adc_nids alc880_adc_nids
Linus Torvalds1da177e2005-04-16 15:20:36 -07006664
Takashi Iwaie1406342008-02-11 18:32:32 +01006665static hda_nid_t alc882_capsrc_nids[3] = { 0x24, 0x23, 0x22 };
6666static hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 };
Takashi Iwai4953550a2009-06-30 15:28:30 +02006667#define alc883_capsrc_nids alc882_capsrc_nids_alt
6668static hda_nid_t alc883_capsrc_nids_rev[2] = { 0x22, 0x23 };
6669#define alc889_capsrc_nids alc882_capsrc_nids
Takashi Iwaie1406342008-02-11 18:32:32 +01006670
Linus Torvalds1da177e2005-04-16 15:20:36 -07006671/* input MUX */
6672/* FIXME: should be a matrix-type input source selection */
6673
6674static struct hda_input_mux alc882_capture_source = {
6675 .num_items = 4,
6676 .items = {
6677 { "Mic", 0x0 },
6678 { "Front Mic", 0x1 },
6679 { "Line", 0x2 },
6680 { "CD", 0x4 },
6681 },
6682};
Kacper Szczesniak41d55452009-05-07 12:47:43 +02006683
Takashi Iwai4953550a2009-06-30 15:28:30 +02006684#define alc883_capture_source alc882_capture_source
6685
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02006686static struct hda_input_mux alc889_capture_source = {
6687 .num_items = 3,
6688 .items = {
6689 { "Front Mic", 0x0 },
6690 { "Mic", 0x3 },
6691 { "Line", 0x2 },
6692 },
6693};
6694
Kacper Szczesniak41d55452009-05-07 12:47:43 +02006695static struct hda_input_mux mb5_capture_source = {
6696 .num_items = 3,
6697 .items = {
6698 { "Mic", 0x1 },
6699 { "Line", 0x2 },
6700 { "CD", 0x4 },
6701 },
6702};
6703
Takashi Iwai4953550a2009-06-30 15:28:30 +02006704static struct hda_input_mux alc883_3stack_6ch_intel = {
6705 .num_items = 4,
6706 .items = {
6707 { "Mic", 0x1 },
6708 { "Front Mic", 0x0 },
6709 { "Line", 0x2 },
6710 { "CD", 0x4 },
6711 },
6712};
6713
6714static struct hda_input_mux alc883_lenovo_101e_capture_source = {
6715 .num_items = 2,
6716 .items = {
6717 { "Mic", 0x1 },
6718 { "Line", 0x2 },
6719 },
6720};
6721
6722static struct hda_input_mux alc883_lenovo_nb0763_capture_source = {
6723 .num_items = 4,
6724 .items = {
6725 { "Mic", 0x0 },
6726 { "iMic", 0x1 },
6727 { "Line", 0x2 },
6728 { "CD", 0x4 },
6729 },
6730};
6731
6732static struct hda_input_mux alc883_fujitsu_pi2515_capture_source = {
6733 .num_items = 2,
6734 .items = {
6735 { "Mic", 0x0 },
6736 { "Int Mic", 0x1 },
6737 },
6738};
6739
6740static struct hda_input_mux alc883_lenovo_sky_capture_source = {
6741 .num_items = 3,
6742 .items = {
6743 { "Mic", 0x0 },
6744 { "Front Mic", 0x1 },
6745 { "Line", 0x4 },
6746 },
6747};
6748
6749static struct hda_input_mux alc883_asus_eee1601_capture_source = {
6750 .num_items = 2,
6751 .items = {
6752 { "Mic", 0x0 },
6753 { "Line", 0x2 },
6754 },
6755};
6756
6757static struct hda_input_mux alc889A_mb31_capture_source = {
6758 .num_items = 2,
6759 .items = {
6760 { "Mic", 0x0 },
6761 /* Front Mic (0x01) unused */
6762 { "Line", 0x2 },
6763 /* Line 2 (0x03) unused */
André Goddard Rosaaf901ca2009-11-14 13:09:05 -02006764 /* CD (0x04) unused? */
Takashi Iwai4953550a2009-06-30 15:28:30 +02006765 },
6766};
6767
6768/*
6769 * 2ch mode
6770 */
6771static struct hda_channel_mode alc883_3ST_2ch_modes[1] = {
6772 { 2, NULL }
6773};
6774
Kailang Yangdf694da2005-12-05 19:42:22 +01006775/*
Kailang Yang272a5272007-05-14 11:00:38 +02006776 * 2ch mode
6777 */
6778static struct hda_verb alc882_3ST_ch2_init[] = {
6779 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
6780 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6781 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
6782 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6783 { } /* end */
6784};
6785
6786/*
Takashi Iwai4953550a2009-06-30 15:28:30 +02006787 * 4ch mode
6788 */
6789static struct hda_verb alc882_3ST_ch4_init[] = {
6790 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
6791 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6792 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6793 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6794 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6795 { } /* end */
6796};
6797
6798/*
Kailang Yang272a5272007-05-14 11:00:38 +02006799 * 6ch mode
6800 */
6801static struct hda_verb alc882_3ST_ch6_init[] = {
6802 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6803 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6804 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
6805 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6806 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6807 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6808 { } /* end */
6809};
6810
Takashi Iwai4953550a2009-06-30 15:28:30 +02006811static struct hda_channel_mode alc882_3ST_6ch_modes[3] = {
Kailang Yang272a5272007-05-14 11:00:38 +02006812 { 2, alc882_3ST_ch2_init },
Takashi Iwai4953550a2009-06-30 15:28:30 +02006813 { 4, alc882_3ST_ch4_init },
Kailang Yang272a5272007-05-14 11:00:38 +02006814 { 6, alc882_3ST_ch6_init },
6815};
6816
Takashi Iwai4953550a2009-06-30 15:28:30 +02006817#define alc883_3ST_6ch_modes alc882_3ST_6ch_modes
6818
Kailang Yang272a5272007-05-14 11:00:38 +02006819/*
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04306820 * 2ch mode
6821 */
6822static struct hda_verb alc883_3ST_ch2_clevo_init[] = {
6823 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
6824 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
6825 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6826 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
6827 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6828 { } /* end */
6829};
6830
6831/*
6832 * 4ch mode
6833 */
6834static struct hda_verb alc883_3ST_ch4_clevo_init[] = {
6835 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6836 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
6837 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6838 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6839 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6840 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6841 { } /* end */
6842};
6843
6844/*
6845 * 6ch mode
6846 */
6847static struct hda_verb alc883_3ST_ch6_clevo_init[] = {
6848 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6849 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6850 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6851 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
6852 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6853 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6854 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6855 { } /* end */
6856};
6857
6858static struct hda_channel_mode alc883_3ST_6ch_clevo_modes[3] = {
6859 { 2, alc883_3ST_ch2_clevo_init },
6860 { 4, alc883_3ST_ch4_clevo_init },
6861 { 6, alc883_3ST_ch6_clevo_init },
6862};
6863
6864
6865/*
Kailang Yangdf694da2005-12-05 19:42:22 +01006866 * 6ch mode
6867 */
6868static struct hda_verb alc882_sixstack_ch6_init[] = {
6869 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
6870 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6871 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6872 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6873 { } /* end */
6874};
6875
6876/*
6877 * 8ch mode
6878 */
6879static struct hda_verb alc882_sixstack_ch8_init[] = {
6880 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6881 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6882 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6883 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6884 { } /* end */
6885};
6886
6887static struct hda_channel_mode alc882_sixstack_modes[2] = {
6888 { 6, alc882_sixstack_ch6_init },
6889 { 8, alc882_sixstack_ch8_init },
6890};
6891
Takashi Iwai87350ad2007-08-16 18:19:38 +02006892/*
Sasha Alexandrdef319f2009-06-16 16:00:15 -04006893 * macbook pro ALC885 can switch LineIn to LineOut without losing Mic
Takashi Iwai87350ad2007-08-16 18:19:38 +02006894 */
6895
6896/*
6897 * 2ch mode
6898 */
6899static struct hda_verb alc885_mbp_ch2_init[] = {
6900 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
6901 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6902 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6903 { } /* end */
6904};
6905
6906/*
Takashi Iwaia3f730a2009-08-31 08:15:26 +02006907 * 4ch mode
Takashi Iwai87350ad2007-08-16 18:19:38 +02006908 */
Takashi Iwaia3f730a2009-08-31 08:15:26 +02006909static struct hda_verb alc885_mbp_ch4_init[] = {
Takashi Iwai87350ad2007-08-16 18:19:38 +02006910 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6911 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6912 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6913 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6914 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6915 { } /* end */
6916};
6917
Takashi Iwaia3f730a2009-08-31 08:15:26 +02006918static struct hda_channel_mode alc885_mbp_4ch_modes[2] = {
Takashi Iwai87350ad2007-08-16 18:19:38 +02006919 { 2, alc885_mbp_ch2_init },
Takashi Iwaia3f730a2009-08-31 08:15:26 +02006920 { 4, alc885_mbp_ch4_init },
Takashi Iwai87350ad2007-08-16 18:19:38 +02006921};
6922
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02006923/*
6924 * 2ch
6925 * Speakers/Woofer/HP = Front
6926 * LineIn = Input
6927 */
6928static struct hda_verb alc885_mb5_ch2_init[] = {
6929 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
6930 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
6931 { } /* end */
6932};
6933
6934/*
6935 * 6ch mode
6936 * Speakers/HP = Front
6937 * Woofer = LFE
6938 * LineIn = Surround
6939 */
6940static struct hda_verb alc885_mb5_ch6_init[] = {
6941 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6942 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6943 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
6944 { } /* end */
6945};
6946
6947static struct hda_channel_mode alc885_mb5_6ch_modes[2] = {
6948 { 2, alc885_mb5_ch2_init },
6949 { 6, alc885_mb5_ch6_init },
6950};
Takashi Iwai87350ad2007-08-16 18:19:38 +02006951
Takashi Iwai4953550a2009-06-30 15:28:30 +02006952
6953/*
6954 * 2ch mode
6955 */
6956static struct hda_verb alc883_4ST_ch2_init[] = {
6957 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6958 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6959 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
6960 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6961 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
6962 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6963 { } /* end */
6964};
6965
6966/*
6967 * 4ch mode
6968 */
6969static struct hda_verb alc883_4ST_ch4_init[] = {
6970 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6971 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6972 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
6973 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
6974 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6975 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6976 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6977 { } /* end */
6978};
6979
6980/*
6981 * 6ch mode
6982 */
6983static struct hda_verb alc883_4ST_ch6_init[] = {
6984 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6985 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6986 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6987 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6988 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
6989 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
6990 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
6991 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
6992 { } /* end */
6993};
6994
6995/*
6996 * 8ch mode
6997 */
6998static struct hda_verb alc883_4ST_ch8_init[] = {
6999 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7000 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7001 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
7002 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7003 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7004 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7005 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7006 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7007 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7008 { } /* end */
7009};
7010
7011static struct hda_channel_mode alc883_4ST_8ch_modes[4] = {
7012 { 2, alc883_4ST_ch2_init },
7013 { 4, alc883_4ST_ch4_init },
7014 { 6, alc883_4ST_ch6_init },
7015 { 8, alc883_4ST_ch8_init },
7016};
7017
7018
7019/*
7020 * 2ch mode
7021 */
7022static struct hda_verb alc883_3ST_ch2_intel_init[] = {
7023 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7024 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7025 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7026 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7027 { } /* end */
7028};
7029
7030/*
7031 * 4ch mode
7032 */
7033static struct hda_verb alc883_3ST_ch4_intel_init[] = {
7034 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7035 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7036 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7037 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7038 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7039 { } /* end */
7040};
7041
7042/*
7043 * 6ch mode
7044 */
7045static struct hda_verb alc883_3ST_ch6_intel_init[] = {
7046 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7047 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7048 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x02 },
7049 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7050 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7051 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7052 { } /* end */
7053};
7054
7055static struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = {
7056 { 2, alc883_3ST_ch2_intel_init },
7057 { 4, alc883_3ST_ch4_intel_init },
7058 { 6, alc883_3ST_ch6_intel_init },
7059};
7060
7061/*
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007062 * 2ch mode
7063 */
7064static struct hda_verb alc889_ch2_intel_init[] = {
7065 { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
7066 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x00 },
7067 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x00 },
7068 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00 },
7069 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7070 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7071 { } /* end */
7072};
7073
7074/*
Takashi Iwai4953550a2009-06-30 15:28:30 +02007075 * 6ch mode
7076 */
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007077static struct hda_verb alc889_ch6_intel_init[] = {
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007078 { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
7079 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 },
7080 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 },
7081 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
7082 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007083 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7084 { } /* end */
7085};
7086
7087/*
7088 * 8ch mode
7089 */
7090static struct hda_verb alc889_ch8_intel_init[] = {
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007091 { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
7092 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 },
7093 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 },
7094 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
7095 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x03 },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007096 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7097 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007098 { } /* end */
7099};
7100
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007101static struct hda_channel_mode alc889_8ch_intel_modes[3] = {
7102 { 2, alc889_ch2_intel_init },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007103 { 6, alc889_ch6_intel_init },
7104 { 8, alc889_ch8_intel_init },
7105};
7106
7107/*
7108 * 6ch mode
7109 */
Takashi Iwai4953550a2009-06-30 15:28:30 +02007110static struct hda_verb alc883_sixstack_ch6_init[] = {
7111 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
7112 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7113 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7114 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7115 { } /* end */
7116};
7117
7118/*
7119 * 8ch mode
7120 */
7121static struct hda_verb alc883_sixstack_ch8_init[] = {
7122 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7123 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7124 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7125 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7126 { } /* end */
7127};
7128
7129static struct hda_channel_mode alc883_sixstack_modes[2] = {
7130 { 6, alc883_sixstack_ch6_init },
7131 { 8, alc883_sixstack_ch8_init },
7132};
7133
7134
Linus Torvalds1da177e2005-04-16 15:20:36 -07007135/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
7136 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
7137 */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01007138static struct snd_kcontrol_new alc882_base_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02007139 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01007140 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02007141 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01007142 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02007143 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7144 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01007145 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7146 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02007147 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01007148 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07007149 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7150 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7151 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7152 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7153 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7154 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007155 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07007156 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7157 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01007158 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07007159 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07007160 { } /* end */
7161};
7162
Takashi Iwai87350ad2007-08-16 18:19:38 +02007163static struct snd_kcontrol_new alc885_mbp3_mixer[] = {
Takashi Iwaia3f730a2009-08-31 08:15:26 +02007164 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
7165 HDA_BIND_MUTE ("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT),
7166 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
7167 HDA_BIND_MUTE ("Headphone Playback Switch", 0x0e, 0x02, HDA_INPUT),
7168 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01007169 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7170 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02007171 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
7172 HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01007173 HDA_CODEC_VOLUME("Line Boost", 0x1a, 0x00, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02007174 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT),
7175 { } /* end */
7176};
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007177
7178static struct snd_kcontrol_new alc885_mb5_mixer[] = {
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007179 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
7180 HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
7181 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
7182 HDA_BIND_MUTE ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
7183 HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
7184 HDA_BIND_MUTE ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT),
7185 HDA_CODEC_VOLUME("HP Playback Volume", 0x0f, 0x00, HDA_OUTPUT),
7186 HDA_BIND_MUTE ("HP Playback Switch", 0x0f, 0x02, HDA_INPUT),
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007187 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7188 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7189 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
7190 HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
7191 HDA_CODEC_VOLUME("Line Boost", 0x15, 0x00, HDA_INPUT),
7192 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0x00, HDA_INPUT),
7193 { } /* end */
7194};
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007195
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08007196static struct snd_kcontrol_new alc885_imac91_mixer[] = {
7197 HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
7198 HDA_BIND_MUTE ("Line-Out Playback Switch", 0x0c, 0x02, HDA_INPUT),
7199 HDA_CODEC_MUTE ("Speaker Playback Switch", 0x14, 0x00, HDA_OUTPUT),
7200 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
7201 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7202 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7203 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
7204 HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
7205 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT),
7206 { } /* end */
7207};
7208
7209
Kailang Yangbdd148a2007-05-08 15:19:08 +02007210static struct snd_kcontrol_new alc882_w2jc_mixer[] = {
7211 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7212 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7213 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7214 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7215 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7216 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7217 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7218 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7219 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangbdd148a2007-05-08 15:19:08 +02007220 { } /* end */
7221};
7222
Kailang Yang272a5272007-05-14 11:00:38 +02007223static struct snd_kcontrol_new alc882_targa_mixer[] = {
7224 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7225 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7226 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7227 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7228 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7229 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7230 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7231 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7232 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai96fe7cc2007-09-07 10:57:44 +02007233 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02007234 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7235 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai96fe7cc2007-09-07 10:57:44 +02007236 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02007237 { } /* end */
7238};
7239
7240/* Pin assignment: Front=0x14, HP = 0x15, Front = 0x16, ???
7241 * Front Mic=0x18, Line In = 0x1a, Line In = 0x1b, CD = 0x1c
7242 */
7243static struct snd_kcontrol_new alc882_asus_a7j_mixer[] = {
7244 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7245 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
7246 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
7247 HDA_CODEC_MUTE("Mobile Front Playback Switch", 0x16, 0x0, HDA_OUTPUT),
7248 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7249 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7250 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7251 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7252 HDA_CODEC_VOLUME("Mobile Line Playback Volume", 0x0b, 0x03, HDA_INPUT),
7253 HDA_CODEC_MUTE("Mobile Line Playback Switch", 0x0b, 0x03, HDA_INPUT),
7254 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7255 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai96fe7cc2007-09-07 10:57:44 +02007256 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02007257 { } /* end */
7258};
7259
Takashi Iwai914759b2007-09-06 14:52:04 +02007260static struct snd_kcontrol_new alc882_asus_a7m_mixer[] = {
7261 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7262 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7263 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
7264 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7265 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7266 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7267 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7268 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7269 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
7270 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai914759b2007-09-06 14:52:04 +02007271 { } /* end */
7272};
7273
Kailang Yangdf694da2005-12-05 19:42:22 +01007274static struct snd_kcontrol_new alc882_chmode_mixer[] = {
7275 {
7276 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7277 .name = "Channel Mode",
7278 .info = alc_ch_mode_info,
7279 .get = alc_ch_mode_get,
7280 .put = alc_ch_mode_put,
7281 },
7282 { } /* end */
7283};
7284
Takashi Iwai4953550a2009-06-30 15:28:30 +02007285static struct hda_verb alc882_base_init_verbs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007286 /* Front mixer: unmute input/output amp left and right (volume = 0) */
Takashi Iwai05acb862005-06-10 19:50:25 +02007287 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7288 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7289 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007290 /* Rear mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02007291 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7292 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7293 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007294 /* CLFE mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02007295 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7296 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7297 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007298 /* Side mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02007299 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7300 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7301 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007302
Takashi Iwaicb6381222009-07-03 10:56:10 +02007303 /* mute analog input loopbacks */
7304 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7305 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7306 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7307 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7308 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
7309
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007310 /* Front Pin: output 0 (0x0c) */
Takashi Iwai05acb862005-06-10 19:50:25 +02007311 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02007312 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007313 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007314 /* Rear Pin: output 1 (0x0d) */
Takashi Iwai05acb862005-06-10 19:50:25 +02007315 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02007316 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007317 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007318 /* CLFE Pin: output 2 (0x0e) */
Takashi Iwai05acb862005-06-10 19:50:25 +02007319 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02007320 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007321 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007322 /* Side Pin: output 3 (0x0f) */
Takashi Iwai05acb862005-06-10 19:50:25 +02007323 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02007324 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007325 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007326 /* Mic (rear) pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02007327 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007328 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7329 /* Front Mic pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02007330 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007331 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7332 /* Line In pin: input */
Takashi Iwai05acb862005-06-10 19:50:25 +02007333 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007334 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7335 /* Line-2 In: Headphone output (output 0 - 0x0c) */
7336 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7337 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7338 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007339 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02007340 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007341
7342 /* FIXME: use matrix-type input source selection */
7343 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007344 /* Input mixer2 */
Takashi Iwai05acb862005-06-10 19:50:25 +02007345 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7346 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7347 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7348 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007349 /* Input mixer3 */
Takashi Iwai05acb862005-06-10 19:50:25 +02007350 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7351 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7352 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7353 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai05acb862005-06-10 19:50:25 +02007354 /* ADC2: mute amp left and right */
7355 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02007356 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02007357 /* ADC3: mute amp left and right */
7358 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02007359 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07007360
7361 { }
7362};
7363
Takashi Iwai4953550a2009-06-30 15:28:30 +02007364static struct hda_verb alc882_adc1_init_verbs[] = {
7365 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
7366 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7367 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7368 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7369 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
7370 /* ADC1: mute amp left and right */
7371 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7372 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
7373 { }
7374};
7375
Takashi Iwai4b146cb2006-07-28 14:42:36 +02007376static struct hda_verb alc882_eapd_verbs[] = {
7377 /* change to EAPD mode */
7378 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01007379 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007380 { }
Takashi Iwai4b146cb2006-07-28 14:42:36 +02007381};
7382
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007383static struct hda_verb alc889_eapd_verbs[] = {
7384 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
7385 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
7386 { }
7387};
7388
Wu Fengguang6732bd02009-07-30 09:19:14 +02007389static struct hda_verb alc_hp15_unsol_verbs[] = {
7390 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
7391 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7392 {}
7393};
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007394
7395static struct hda_verb alc885_init_verbs[] = {
7396 /* Front mixer: unmute input/output amp left and right (volume = 0) */
7397 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7398 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7399 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7400 /* Rear mixer */
7401 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7402 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7403 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7404 /* CLFE mixer */
7405 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7406 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7407 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7408 /* Side mixer */
7409 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7410 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7411 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7412
7413 /* mute analog input loopbacks */
7414 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7415 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7416 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7417
7418 /* Front HP Pin: output 0 (0x0c) */
Wu Fengguang6732bd02009-07-30 09:19:14 +02007419 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007420 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7421 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7422 /* Front Pin: output 0 (0x0c) */
7423 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7424 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7425 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
7426 /* Rear Pin: output 1 (0x0d) */
7427 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7428 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7429 {0x19, AC_VERB_SET_CONNECT_SEL, 0x01},
7430 /* CLFE Pin: output 2 (0x0e) */
7431 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7432 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7433 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
7434 /* Side Pin: output 3 (0x0f) */
7435 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7436 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7437 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
7438 /* Mic (rear) pin: input vref at 80% */
7439 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7440 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7441 /* Front Mic pin: input vref at 80% */
7442 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7443 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7444 /* Line In pin: input */
7445 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
7446 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7447
7448 /* Mixer elements: 0x18, , 0x1a, 0x1b */
7449 /* Input mixer1 */
7450 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
7451 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7452 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7453 /* Input mixer2 */
7454 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7455 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7456 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7457 /* Input mixer3 */
7458 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
7459 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7460 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7461 /* ADC2: mute amp left and right */
7462 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7463 /* ADC3: mute amp left and right */
7464 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7465
7466 { }
7467};
7468
7469static struct hda_verb alc885_init_input_verbs[] = {
7470 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7471 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
7472 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
7473 { }
7474};
7475
7476
7477/* Unmute Selector 24h and set the default input to front mic */
7478static struct hda_verb alc889_init_input_verbs[] = {
7479 {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
7480 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7481 { }
7482};
7483
7484
Takashi Iwai4953550a2009-06-30 15:28:30 +02007485#define alc883_init_verbs alc882_base_init_verbs
7486
Tobin Davis9102cd12006-12-15 10:02:12 +01007487/* Mac Pro test */
7488static struct snd_kcontrol_new alc882_macpro_mixer[] = {
7489 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7490 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7491 HDA_CODEC_MUTE("Headphone Playback Switch", 0x18, 0x0, HDA_OUTPUT),
7492 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
7493 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01007494 /* FIXME: this looks suspicious...
Jaroslav Kyselad355c82a2009-11-03 15:47:25 +01007495 HDA_CODEC_VOLUME("Beep Playback Volume", 0x0b, 0x02, HDA_INPUT),
7496 HDA_CODEC_MUTE("Beep Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01007497 */
Tobin Davis9102cd12006-12-15 10:02:12 +01007498 { } /* end */
7499};
7500
7501static struct hda_verb alc882_macpro_init_verbs[] = {
7502 /* Front mixer: unmute input/output amp left and right (volume = 0) */
7503 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7504 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7505 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7506 /* Front Pin: output 0 (0x0c) */
7507 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7508 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7509 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7510 /* Front Mic pin: input vref at 80% */
7511 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7512 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7513 /* Speaker: output */
7514 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7515 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7516 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x04},
7517 /* Headphone output (output 0 - 0x0c) */
7518 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7519 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7520 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
7521
7522 /* FIXME: use matrix-type input source selection */
7523 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
7524 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
7525 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7526 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7527 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7528 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
7529 /* Input mixer2 */
7530 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7531 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7532 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7533 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
7534 /* Input mixer3 */
7535 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7536 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7537 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7538 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
7539 /* ADC1: mute amp left and right */
7540 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7541 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
7542 /* ADC2: mute amp left and right */
7543 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7544 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
7545 /* ADC3: mute amp left and right */
7546 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7547 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
7548
7549 { }
7550};
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007551
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007552/* Macbook 5,1 */
7553static struct hda_verb alc885_mb5_init_verbs[] = {
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007554 /* DACs */
7555 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7556 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7557 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7558 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007559 /* Front mixer */
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007560 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7561 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7562 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007563 /* Surround mixer */
7564 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7565 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7566 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7567 /* LFE mixer */
7568 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7569 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7570 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7571 /* HP mixer */
7572 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7573 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7574 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7575 /* Front Pin (0x0c) */
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007576 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
7577 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007578 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
7579 /* LFE Pin (0x0e) */
7580 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
7581 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7582 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02},
7583 /* HP Pin (0x0f) */
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007584 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7585 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007586 {0x14, AC_VERB_SET_CONNECT_SEL, 0x03},
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007587 /* Front Mic pin: input vref at 80% */
7588 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7589 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7590 /* Line In pin */
7591 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
7592 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7593
7594 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7595 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7596 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7597 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
7598 { }
7599};
7600
Takashi Iwai87350ad2007-08-16 18:19:38 +02007601/* Macbook Pro rev3 */
7602static struct hda_verb alc885_mbp3_init_verbs[] = {
7603 /* Front mixer: unmute input/output amp left and right (volume = 0) */
7604 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7605 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7606 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7607 /* Rear mixer */
7608 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7609 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7610 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwaia3f730a2009-08-31 08:15:26 +02007611 /* HP mixer */
7612 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7613 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7614 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai87350ad2007-08-16 18:19:38 +02007615 /* Front Pin: output 0 (0x0c) */
7616 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7617 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7618 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaia3f730a2009-08-31 08:15:26 +02007619 /* HP Pin: output 0 (0x0e) */
Takashi Iwai87350ad2007-08-16 18:19:38 +02007620 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
Takashi Iwaia3f730a2009-08-31 08:15:26 +02007621 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7622 {0x15, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai87350ad2007-08-16 18:19:38 +02007623 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7624 /* Mic (rear) pin: input vref at 80% */
7625 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7626 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7627 /* Front Mic pin: input vref at 80% */
7628 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7629 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7630 /* Line In pin: use output 1 when in LineOut mode */
7631 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
7632 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7633 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
7634
7635 /* FIXME: use matrix-type input source selection */
7636 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
7637 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
7638 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7639 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7640 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7641 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
7642 /* Input mixer2 */
7643 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7644 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7645 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7646 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
7647 /* Input mixer3 */
7648 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7649 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7650 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7651 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
7652 /* ADC1: mute amp left and right */
7653 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7654 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
7655 /* ADC2: mute amp left and right */
7656 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7657 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
7658 /* ADC3: mute amp left and right */
7659 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7660 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
7661
7662 { }
7663};
7664
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08007665/* iMac 9,1 */
7666static struct hda_verb alc885_imac91_init_verbs[] = {
7667 /* Line-Out mixer: unmute input/output amp left and right (volume = 0) */
7668 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7669 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7670 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7671 /* Rear mixer */
7672 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7673 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7674 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7675 /* HP Pin: output 0 (0x0c) */
7676 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7677 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7678 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
7679 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7680 /* Internal Speakers: output 0 (0x0d) */
7681 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7682 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7683 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
7684 /* Mic (rear) pin: input vref at 80% */
7685 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7686 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7687 /* Front Mic pin: input vref at 80% */
7688 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7689 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7690 /* Line In pin: use output 1 when in LineOut mode */
7691 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
7692 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7693 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
7694
7695 /* FIXME: use matrix-type input source selection */
7696 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
7697 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
7698 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7699 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7700 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7701 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
7702 /* Input mixer2 */
7703 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7704 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7705 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7706 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
7707 /* Input mixer3 */
7708 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7709 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7710 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7711 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
7712 /* ADC1: mute amp left and right */
7713 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7714 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
7715 /* ADC2: mute amp left and right */
7716 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7717 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
7718 /* ADC3: mute amp left and right */
7719 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7720 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
7721
7722 { }
7723};
7724
Nicola Fagnanic54728d2007-07-19 23:28:52 +02007725/* iMac 24 mixer. */
7726static struct snd_kcontrol_new alc885_imac24_mixer[] = {
7727 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
7728 HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x00, HDA_INPUT),
7729 { } /* end */
7730};
7731
7732/* iMac 24 init verbs. */
7733static struct hda_verb alc885_imac24_init_verbs[] = {
7734 /* Internal speakers: output 0 (0x0c) */
7735 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7736 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7737 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
7738 /* Internal speakers: output 0 (0x0c) */
7739 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7740 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7741 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
7742 /* Headphone: output 0 (0x0c) */
7743 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7744 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7745 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
7746 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
7747 /* Front Mic: input vref at 80% */
7748 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
7749 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7750 { }
7751};
7752
7753/* Toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02007754static void alc885_imac24_setup(struct hda_codec *codec)
Nicola Fagnanic54728d2007-07-19 23:28:52 +02007755{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02007756 struct alc_spec *spec = codec->spec;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02007757
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02007758 spec->autocfg.hp_pins[0] = 0x14;
7759 spec->autocfg.speaker_pins[0] = 0x18;
7760 spec->autocfg.speaker_pins[1] = 0x1a;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02007761}
7762
Takashi Iwai4f5d17062009-08-11 18:17:46 +02007763static void alc885_mbp3_setup(struct hda_codec *codec)
Nicola Fagnanic54728d2007-07-19 23:28:52 +02007764{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02007765 struct alc_spec *spec = codec->spec;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02007766
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02007767 spec->autocfg.hp_pins[0] = 0x15;
7768 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai87350ad2007-08-16 18:19:38 +02007769}
7770
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08007771static void alc885_imac91_automute(struct hda_codec *codec)
7772{
7773 unsigned int present;
7774
7775 present = snd_hda_codec_read(codec, 0x14, 0,
7776 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
7777 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
7778 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7779 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0,
7780 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
7781
7782}
7783
7784static void alc885_imac91_unsol_event(struct hda_codec *codec,
7785 unsigned int res)
7786{
7787 /* Headphone insertion or removal. */
7788 if ((res >> 26) == ALC880_HP_EVENT)
7789 alc885_imac91_automute(codec);
7790}
Takashi Iwai87350ad2007-08-16 18:19:38 +02007791
Kailang Yang272a5272007-05-14 11:00:38 +02007792static struct hda_verb alc882_targa_verbs[] = {
7793 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7794 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7795
7796 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7797 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02007798
Kailang Yang272a5272007-05-14 11:00:38 +02007799 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
7800 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
7801 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
7802
7803 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yang272a5272007-05-14 11:00:38 +02007804 { } /* end */
7805};
7806
7807/* toggle speaker-output according to the hp-jack state */
7808static void alc882_targa_automute(struct hda_codec *codec)
7809{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02007810 struct alc_spec *spec = codec->spec;
7811 alc_automute_amp(codec);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02007812 snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02007813 spec->jack_present ? 1 : 3);
7814}
7815
Takashi Iwai4f5d17062009-08-11 18:17:46 +02007816static void alc882_targa_setup(struct hda_codec *codec)
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02007817{
7818 struct alc_spec *spec = codec->spec;
7819
7820 spec->autocfg.hp_pins[0] = 0x14;
7821 spec->autocfg.speaker_pins[0] = 0x1b;
Kailang Yang272a5272007-05-14 11:00:38 +02007822}
7823
7824static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res)
7825{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02007826 if ((res >> 26) == ALC880_HP_EVENT)
Kailang Yang272a5272007-05-14 11:00:38 +02007827 alc882_targa_automute(codec);
Kailang Yang272a5272007-05-14 11:00:38 +02007828}
7829
7830static struct hda_verb alc882_asus_a7j_verbs[] = {
7831 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7832 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7833
7834 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7835 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7836 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02007837
Kailang Yang272a5272007-05-14 11:00:38 +02007838 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
7839 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
7840 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
7841
7842 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
7843 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
7844 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
7845 { } /* end */
7846};
7847
Takashi Iwai914759b2007-09-06 14:52:04 +02007848static struct hda_verb alc882_asus_a7m_verbs[] = {
7849 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7850 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7851
7852 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
7853 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7854 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02007855
Takashi Iwai914759b2007-09-06 14:52:04 +02007856 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
7857 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
7858 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
7859
7860 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
7861 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
7862 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
7863 { } /* end */
7864};
7865
Tobin Davis9102cd12006-12-15 10:02:12 +01007866static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted)
7867{
7868 unsigned int gpiostate, gpiomask, gpiodir;
7869
7870 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
7871 AC_VERB_GET_GPIO_DATA, 0);
7872
7873 if (!muted)
7874 gpiostate |= (1 << pin);
7875 else
7876 gpiostate &= ~(1 << pin);
7877
7878 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
7879 AC_VERB_GET_GPIO_MASK, 0);
7880 gpiomask |= (1 << pin);
7881
7882 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
7883 AC_VERB_GET_GPIO_DIRECTION, 0);
7884 gpiodir |= (1 << pin);
7885
7886
7887 snd_hda_codec_write(codec, codec->afg, 0,
7888 AC_VERB_SET_GPIO_MASK, gpiomask);
7889 snd_hda_codec_write(codec, codec->afg, 0,
7890 AC_VERB_SET_GPIO_DIRECTION, gpiodir);
7891
7892 msleep(1);
7893
7894 snd_hda_codec_write(codec, codec->afg, 0,
7895 AC_VERB_SET_GPIO_DATA, gpiostate);
7896}
7897
Takashi Iwai7debbe52007-08-16 15:01:03 +02007898/* set up GPIO at initialization */
7899static void alc885_macpro_init_hook(struct hda_codec *codec)
7900{
7901 alc882_gpio_mute(codec, 0, 0);
7902 alc882_gpio_mute(codec, 1, 0);
7903}
7904
7905/* set up GPIO and update auto-muting at initialization */
7906static void alc885_imac24_init_hook(struct hda_codec *codec)
7907{
7908 alc885_macpro_init_hook(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +02007909 alc_automute_amp(codec);
Takashi Iwai7debbe52007-08-16 15:01:03 +02007910}
7911
Kailang Yangdf694da2005-12-05 19:42:22 +01007912/*
7913 * generic initialization of ADC, input mixers and output mixers
7914 */
Takashi Iwai4953550a2009-06-30 15:28:30 +02007915static struct hda_verb alc883_auto_init_verbs[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01007916 /*
7917 * Unmute ADC0-2 and set the default input to mic-in
7918 */
Kailang Yangdf694da2005-12-05 19:42:22 +01007919 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
7920 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7921 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
7922 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7923
Takashi Iwaicb53c622007-08-10 17:21:45 +02007924 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +01007925 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007926 * Note: PASD motherboards uses the Line In 2 as the input for
7927 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01007928 */
7929 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02007930 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7931 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7932 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7933 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7934 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01007935
7936 /*
7937 * Set up output mixers (0x0c - 0x0f)
7938 */
7939 /* set vol=0 to output mixers */
7940 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7941 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7942 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7943 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7944 /* set up input amps for analog loopback */
7945 /* Amp Indices: DAC = 0, mixer = 1 */
7946 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7947 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7948 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7949 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7950 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7951 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7952 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7953 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7954 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7955 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7956
7957 /* FIXME: use matrix-type input source selection */
7958 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
Kailang Yangdf694da2005-12-05 19:42:22 +01007959 /* Input mixer2 */
7960 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
7961 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
7962 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
7963 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
7964 /* Input mixer3 */
7965 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
7966 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
7967 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
7968 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
7969
7970 { }
7971};
7972
Torben Schulzeb4c41d2009-05-18 15:02:35 +02007973/* 2ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:front) */
7974static struct hda_verb alc889A_mb31_ch2_init[] = {
7975 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */
7976 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
7977 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Line as input */
7978 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Line off */
7979 { } /* end */
7980};
7981
7982/* 4ch mode (Speaker:front, Subwoofer:CLFE, Line:CLFE, Headphones:front) */
7983static struct hda_verb alc889A_mb31_ch4_init[] = {
7984 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */
7985 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
7986 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line as output */
7987 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */
7988 { } /* end */
7989};
7990
7991/* 5ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:rear) */
7992static struct hda_verb alc889A_mb31_ch5_init[] = {
7993 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* HP as rear */
7994 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
7995 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Line as input */
7996 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Line off */
7997 { } /* end */
7998};
7999
8000/* 6ch mode (Speaker:front, Subwoofer:off, Line:CLFE, Headphones:Rear) */
8001static struct hda_verb alc889A_mb31_ch6_init[] = {
8002 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* HP as front */
8003 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Subwoofer off */
8004 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line as output */
8005 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */
8006 { } /* end */
8007};
8008
8009static struct hda_channel_mode alc889A_mb31_6ch_modes[4] = {
8010 { 2, alc889A_mb31_ch2_init },
8011 { 4, alc889A_mb31_ch4_init },
8012 { 5, alc889A_mb31_ch5_init },
8013 { 6, alc889A_mb31_ch6_init },
8014};
8015
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008016static struct hda_verb alc883_medion_eapd_verbs[] = {
8017 /* eanable EAPD on medion laptop */
8018 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
8019 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
8020 { }
8021};
8022
Takashi Iwai4953550a2009-06-30 15:28:30 +02008023#define alc883_base_mixer alc882_base_mixer
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008024
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008025static struct snd_kcontrol_new alc883_mitac_mixer[] = {
8026 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8027 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8028 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
8029 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8030 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8031 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8032 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8033 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8034 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8035 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8036 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8037 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
8038 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008039 { } /* end */
8040};
8041
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008042static struct snd_kcontrol_new alc883_clevo_m720_mixer[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01008043 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8044 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
8045 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8046 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
8047 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8048 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8049 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8050 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8051 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
8052 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Jiang zhe368c7a92008-03-04 11:20:33 +01008053 { } /* end */
8054};
8055
Jiang zhefb97dc62008-03-06 11:07:11 +01008056static struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = {
8057 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8058 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
8059 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8060 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
8061 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8062 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8063 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8064 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8065 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
8066 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Jiang zhefb97dc62008-03-06 11:07:11 +01008067 { } /* end */
8068};
8069
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008070static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = {
8071 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8072 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8073 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8074 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8075 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8076 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8077 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8078 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008079 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008080 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8081 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008082 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008083 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008084 { } /* end */
8085};
8086
8087static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
8088 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8089 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8090 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8091 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
8092 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
8093 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8094 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8095 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8096 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8097 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8098 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8099 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8100 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8101 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008102 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008103 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8104 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008105 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008106 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008107 { } /* end */
8108};
8109
Jiang zhe17bba1b2008-06-04 12:11:07 +02008110static struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = {
8111 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8112 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8113 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8114 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
8115 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
8116 HDA_OUTPUT),
8117 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8118 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8119 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8120 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8121 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8122 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8123 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8124 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8125 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8126 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
8127 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
8128 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8129 HDA_CODEC_VOLUME("Front Mic Boost", 0x18, 0, HDA_INPUT),
8130 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Jiang zhe17bba1b2008-06-04 12:11:07 +02008131 { } /* end */
8132};
8133
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008134static struct snd_kcontrol_new alc885_8ch_intel_mixer[] = {
8135 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8136 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8137 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8138 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
8139 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
8140 HDA_OUTPUT),
8141 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8142 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8143 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8144 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
8145 HDA_BIND_MUTE("Speaker Playback Switch", 0x0f, 2, HDA_INPUT),
8146 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8147 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8148 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8149 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
8150 HDA_CODEC_VOLUME("Mic Boost", 0x1b, 0, HDA_INPUT),
8151 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
8152 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8153 HDA_CODEC_VOLUME("Front Mic Boost", 0x18, 0, HDA_INPUT),
8154 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8155 { } /* end */
8156};
8157
Takashi Iwaid1d985f2006-11-23 19:27:12 +01008158static struct snd_kcontrol_new alc883_fivestack_mixer[] = {
Tobin Davisc07584c2006-10-13 12:32:16 +02008159 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02008160 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008161 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02008162 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008163 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
8164 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02008165 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8166 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008167 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8168 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8169 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8170 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8171 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8172 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008173 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008174 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8175 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008176 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008177 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008178 { } /* end */
8179};
8180
Sasha Alexandrc2592492009-06-16 14:52:54 -04008181static struct snd_kcontrol_new alc883_targa_mixer[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02008182 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02008183 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008184 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02008185 HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008186 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8187 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
8188 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
8189 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8190 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8191 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8192 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8193 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8194 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8195 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8196 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008197 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008198 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008199 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008200};
Kailang Yangccc656c2006-10-17 12:32:26 +02008201
Sasha Alexandrc2592492009-06-16 14:52:54 -04008202static struct snd_kcontrol_new alc883_targa_2ch_mixer[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02008203 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02008204 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008205 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02008206 HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008207 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8208 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8209 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
Thomas De Schampheleire32360412007-01-24 16:13:35 +01008210 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008211 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Jiang zhe4383fae2008-04-14 12:58:57 +02008212 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8213 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
8214 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008215 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008216};
Kailang Yangccc656c2006-10-17 12:32:26 +02008217
Takashi Iwaib99dba32009-09-17 18:23:00 +02008218static struct snd_kcontrol_new alc883_targa_8ch_mixer[] = {
8219 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
8220 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
8221 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8222 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
8223 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
8224 { } /* end */
8225};
8226
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008227static struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = {
8228 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8229 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01008230 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8231 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008232 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8233 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8234 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8235 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008236 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008237};
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008238
Kailang Yang272a5272007-05-14 11:00:38 +02008239static struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = {
8240 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8241 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
8242 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8243 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8244 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8245 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8246 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8247 HDA_CODEC_VOLUME("iMic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8248 HDA_CODEC_MUTE("iMic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02008249 { } /* end */
8250};
8251
8252static struct snd_kcontrol_new alc883_medion_md2_mixer[] = {
8253 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8254 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8255 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8256 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8257 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8258 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8259 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8260 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8261 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02008262 { } /* end */
Kailang Yangea1fb292008-08-26 12:58:38 +02008263};
Kailang Yang272a5272007-05-14 11:00:38 +02008264
Tobin Davis2880a862007-08-07 11:50:26 +02008265static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = {
Kailang Yangd1a991a2007-08-15 16:21:59 +02008266 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8267 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02008268 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02008269 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8270 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Kailang Yangd1a991a2007-08-15 16:21:59 +02008271 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8272 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8273 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02008274 { } /* end */
Kailang Yangd1a991a2007-08-15 16:21:59 +02008275};
Tobin Davis2880a862007-08-07 11:50:26 +02008276
Tony Vroond2fd4b02009-06-21 00:40:10 +01008277static struct snd_kcontrol_new alc888_acer_aspire_6530_mixer[] = {
8278 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8279 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8280 HDA_CODEC_VOLUME("LFE Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
8281 HDA_BIND_MUTE("LFE Playback Switch", 0x0f, 2, HDA_INPUT),
Tony Vroon684a8842009-06-26 09:27:50 +01008282 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8283 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Tony Vroond2fd4b02009-06-21 00:40:10 +01008284 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8285 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8286 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8287 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8288 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8289 { } /* end */
8290};
8291
Kailang Yange2757d52008-08-26 13:17:46 +02008292static struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = {
8293 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8294 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8295 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
8296 HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
8297 HDA_CODEC_VOLUME_MONO("Center Playback Volume",
8298 0x0d, 1, 0x0, HDA_OUTPUT),
8299 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
8300 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
8301 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
8302 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
8303 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02008304 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8305 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8306 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8307 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8308 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8309 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8310 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8311 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8312 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
8313 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02008314 { } /* end */
8315};
8316
Torben Schulzeb4c41d2009-05-18 15:02:35 +02008317static struct snd_kcontrol_new alc889A_mb31_mixer[] = {
8318 /* Output mixers */
8319 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
8320 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
8321 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
8322 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
8323 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x00,
8324 HDA_OUTPUT),
8325 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x02, HDA_INPUT),
8326 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x00, HDA_OUTPUT),
8327 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x02, HDA_INPUT),
8328 /* Output switches */
8329 HDA_CODEC_MUTE("Enable Speaker", 0x14, 0x00, HDA_OUTPUT),
8330 HDA_CODEC_MUTE("Enable Headphones", 0x15, 0x00, HDA_OUTPUT),
8331 HDA_CODEC_MUTE_MONO("Enable LFE", 0x16, 2, 0x00, HDA_OUTPUT),
8332 /* Boost mixers */
8333 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT),
8334 HDA_CODEC_VOLUME("Line Boost", 0x1a, 0x00, HDA_INPUT),
8335 /* Input mixers */
8336 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
8337 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
8338 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8339 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8340 { } /* end */
8341};
8342
Guido Günther3e1647c2009-06-05 00:47:26 +02008343static struct snd_kcontrol_new alc883_vaiott_mixer[] = {
8344 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8345 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8346 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8347 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8348 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
8349 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
8350 { } /* end */
8351};
8352
Kailang Yange2757d52008-08-26 13:17:46 +02008353static struct hda_bind_ctls alc883_bind_cap_vol = {
8354 .ops = &snd_hda_bind_vol,
8355 .values = {
8356 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
8357 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
8358 0
8359 },
8360};
8361
8362static struct hda_bind_ctls alc883_bind_cap_switch = {
8363 .ops = &snd_hda_bind_sw,
8364 .values = {
8365 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
8366 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
8367 0
8368 },
8369};
8370
8371static struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = {
8372 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8373 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8374 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8375 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8376 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8377 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8378 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
8379 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaif9e336f2008-10-31 16:37:07 +01008380 { } /* end */
8381};
8382
8383static struct snd_kcontrol_new alc883_asus_eee1601_cap_mixer[] = {
Kailang Yange2757d52008-08-26 13:17:46 +02008384 HDA_BIND_VOL("Capture Volume", &alc883_bind_cap_vol),
8385 HDA_BIND_SW("Capture Switch", &alc883_bind_cap_switch),
8386 {
8387 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8388 /* .name = "Capture Source", */
8389 .name = "Input Source",
8390 .count = 1,
Takashi Iwai54cbc9a2008-10-31 15:24:04 +01008391 .info = alc_mux_enum_info,
8392 .get = alc_mux_enum_get,
8393 .put = alc_mux_enum_put,
Kailang Yange2757d52008-08-26 13:17:46 +02008394 },
8395 { } /* end */
8396};
8397
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008398static struct snd_kcontrol_new alc883_chmode_mixer[] = {
8399 {
8400 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8401 .name = "Channel Mode",
8402 .info = alc_ch_mode_info,
8403 .get = alc_ch_mode_get,
8404 .put = alc_ch_mode_put,
8405 },
8406 { } /* end */
8407};
8408
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008409/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008410static void alc883_mitac_setup(struct hda_codec *codec)
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008411{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008412 struct alc_spec *spec = codec->spec;
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008413
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008414 spec->autocfg.hp_pins[0] = 0x15;
8415 spec->autocfg.speaker_pins[0] = 0x14;
8416 spec->autocfg.speaker_pins[1] = 0x17;
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008417}
8418
8419/* auto-toggle front mic */
8420/*
8421static void alc883_mitac_mic_automute(struct hda_codec *codec)
8422{
Wu Fengguang864f92b2009-11-18 12:38:02 +08008423 unsigned char bits = snd_hda_jack_detect(codec, 0x18) ? HDA_AMP_MUTE : 0;
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008424
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008425 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
8426}
8427*/
8428
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008429static struct hda_verb alc883_mitac_verbs[] = {
8430 /* HP */
8431 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8432 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8433 /* Subwoofer */
8434 {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
8435 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8436
8437 /* enable unsolicited event */
8438 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8439 /* {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, */
8440
8441 { } /* end */
8442};
8443
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04308444static struct hda_verb alc883_clevo_m540r_verbs[] = {
8445 /* HP */
8446 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8447 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8448 /* Int speaker */
8449 /*{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},*/
8450
8451 /* enable unsolicited event */
8452 /*
8453 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8454 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
8455 */
8456
8457 { } /* end */
8458};
8459
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008460static struct hda_verb alc883_clevo_m720_verbs[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01008461 /* HP */
8462 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8463 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8464 /* Int speaker */
8465 {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
8466 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8467
8468 /* enable unsolicited event */
8469 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008470 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Jiang zhe368c7a92008-03-04 11:20:33 +01008471
8472 { } /* end */
8473};
8474
Jiang zhefb97dc62008-03-06 11:07:11 +01008475static struct hda_verb alc883_2ch_fujitsu_pi2515_verbs[] = {
8476 /* HP */
8477 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8478 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8479 /* Subwoofer */
8480 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
8481 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8482
8483 /* enable unsolicited event */
8484 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8485
8486 { } /* end */
8487};
8488
Sasha Alexandrc2592492009-06-16 14:52:54 -04008489static struct hda_verb alc883_targa_verbs[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02008490 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8491 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8492
8493 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8494 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02008495
David Heidelberger64a8be72009-06-08 16:15:18 +02008496/* Connect Line-Out side jack (SPDIF) to Side */
8497 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8498 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8499 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
8500/* Connect Mic jack to CLFE */
8501 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8502 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8503 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02},
8504/* Connect Line-in jack to Surround */
8505 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8506 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8507 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
8508/* Connect HP out jack to Front */
8509 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8510 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8511 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangccc656c2006-10-17 12:32:26 +02008512
8513 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yangccc656c2006-10-17 12:32:26 +02008514
8515 { } /* end */
8516};
8517
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008518static struct hda_verb alc883_lenovo_101e_verbs[] = {
8519 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8520 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT|AC_USRSP_EN},
8521 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT|AC_USRSP_EN},
8522 { } /* end */
8523};
8524
Kailang Yang272a5272007-05-14 11:00:38 +02008525static struct hda_verb alc883_lenovo_nb0763_verbs[] = {
8526 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8527 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8528 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8529 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8530 { } /* end */
8531};
8532
8533static struct hda_verb alc888_lenovo_ms7195_verbs[] = {
8534 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8535 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8536 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8537 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT | AC_USRSP_EN},
8538 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8539 { } /* end */
8540};
8541
Kailang Yang189609a2007-08-20 11:31:23 +02008542static struct hda_verb alc883_haier_w66_verbs[] = {
8543 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8544 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8545
8546 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8547
8548 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
8549 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8550 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8551 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8552 { } /* end */
8553};
8554
Kailang Yange2757d52008-08-26 13:17:46 +02008555static struct hda_verb alc888_lenovo_sky_verbs[] = {
8556 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8557 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8558 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8559 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8560 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8561 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8562 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
8563 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8564 { } /* end */
8565};
8566
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03008567static struct hda_verb alc888_6st_dell_verbs[] = {
8568 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8569 { }
8570};
8571
Guido Günther3e1647c2009-06-05 00:47:26 +02008572static struct hda_verb alc883_vaiott_verbs[] = {
8573 /* HP */
8574 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8575 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8576
8577 /* enable unsolicited event */
8578 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8579
8580 { } /* end */
8581};
8582
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008583static void alc888_3st_hp_setup(struct hda_codec *codec)
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03008584{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008585 struct alc_spec *spec = codec->spec;
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03008586
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008587 spec->autocfg.hp_pins[0] = 0x1b;
8588 spec->autocfg.speaker_pins[0] = 0x14;
8589 spec->autocfg.speaker_pins[1] = 0x16;
8590 spec->autocfg.speaker_pins[2] = 0x18;
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03008591}
8592
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008593static struct hda_verb alc888_3st_hp_verbs[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008594 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */
Herton Ronaldo Krzesinskif32a19e2008-03-18 09:27:08 +01008595 {0x16, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Rear : output 1 (0x0d) */
8596 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* CLFE : output 2 (0x0e) */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008597 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03008598 { } /* end */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008599};
8600
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03008601/*
8602 * 2ch mode
8603 */
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008604static struct hda_verb alc888_3st_hp_2ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008605 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
8606 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
8607 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
8608 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03008609 { } /* end */
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008610};
8611
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03008612/*
8613 * 4ch mode
8614 */
8615static struct hda_verb alc888_3st_hp_4ch_init[] = {
8616 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
8617 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
8618 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8619 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
8620 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 },
8621 { } /* end */
8622};
8623
8624/*
8625 * 6ch mode
8626 */
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008627static struct hda_verb alc888_3st_hp_6ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008628 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8629 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03008630 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008631 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8632 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03008633 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 },
8634 { } /* end */
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008635};
8636
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03008637static struct hda_channel_mode alc888_3st_hp_modes[3] = {
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008638 { 2, alc888_3st_hp_2ch_init },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03008639 { 4, alc888_3st_hp_4ch_init },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008640 { 6, alc888_3st_hp_6ch_init },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02008641};
8642
Kailang Yang272a5272007-05-14 11:00:38 +02008643/* toggle front-jack and RCA according to the hp-jack state */
8644static void alc888_lenovo_ms7195_front_automute(struct hda_codec *codec)
8645{
Wu Fengguang864f92b2009-11-18 12:38:02 +08008646 unsigned int present = snd_hda_jack_detect(codec, 0x1b);
Kailang Yangea1fb292008-08-26 12:58:38 +02008647
Takashi Iwai47fd8302007-08-10 17:11:07 +02008648 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8649 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
8650 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8651 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02008652}
8653
8654/* toggle RCA according to the front-jack state */
8655static void alc888_lenovo_ms7195_rca_automute(struct hda_codec *codec)
8656{
Wu Fengguang864f92b2009-11-18 12:38:02 +08008657 unsigned int present = snd_hda_jack_detect(codec, 0x14);
Kailang Yangea1fb292008-08-26 12:58:38 +02008658
Takashi Iwai47fd8302007-08-10 17:11:07 +02008659 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8660 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02008661}
Takashi Iwai47fd8302007-08-10 17:11:07 +02008662
Kailang Yang272a5272007-05-14 11:00:38 +02008663static void alc883_lenovo_ms7195_unsol_event(struct hda_codec *codec,
8664 unsigned int res)
8665{
8666 if ((res >> 26) == ALC880_HP_EVENT)
8667 alc888_lenovo_ms7195_front_automute(codec);
8668 if ((res >> 26) == ALC880_FRONT_EVENT)
8669 alc888_lenovo_ms7195_rca_automute(codec);
8670}
8671
8672static struct hda_verb alc883_medion_md2_verbs[] = {
8673 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8674 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8675
8676 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8677
8678 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8679 { } /* end */
8680};
8681
8682/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008683static void alc883_medion_md2_setup(struct hda_codec *codec)
Kailang Yang272a5272007-05-14 11:00:38 +02008684{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008685 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02008686
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008687 spec->autocfg.hp_pins[0] = 0x14;
8688 spec->autocfg.speaker_pins[0] = 0x15;
Kailang Yang272a5272007-05-14 11:00:38 +02008689}
8690
Kailang Yangccc656c2006-10-17 12:32:26 +02008691/* toggle speaker-output according to the hp-jack state */
Sasha Alexandrc2592492009-06-16 14:52:54 -04008692#define alc883_targa_init_hook alc882_targa_init_hook
8693#define alc883_targa_unsol_event alc882_targa_unsol_event
Jiang zhe368c7a92008-03-04 11:20:33 +01008694
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008695static void alc883_clevo_m720_mic_automute(struct hda_codec *codec)
8696{
8697 unsigned int present;
8698
Takashi Iwaid56757a2009-11-18 08:00:14 +01008699 present = snd_hda_jack_detect(codec, 0x18);
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008700 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
8701 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
8702}
8703
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008704static void alc883_clevo_m720_setup(struct hda_codec *codec)
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008705{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008706 struct alc_spec *spec = codec->spec;
8707
8708 spec->autocfg.hp_pins[0] = 0x15;
8709 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008710}
8711
8712static void alc883_clevo_m720_init_hook(struct hda_codec *codec)
8713{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008714 alc_automute_amp(codec);
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008715 alc883_clevo_m720_mic_automute(codec);
8716}
8717
8718static void alc883_clevo_m720_unsol_event(struct hda_codec *codec,
Jiang zhe368c7a92008-03-04 11:20:33 +01008719 unsigned int res)
8720{
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008721 switch (res >> 26) {
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008722 case ALC880_MIC_EVENT:
8723 alc883_clevo_m720_mic_automute(codec);
8724 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008725 default:
8726 alc_automute_amp_unsol_event(codec, res);
8727 break;
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008728 }
Jiang zhe368c7a92008-03-04 11:20:33 +01008729}
8730
Jiang zhefb97dc62008-03-06 11:07:11 +01008731/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008732static void alc883_2ch_fujitsu_pi2515_setup(struct hda_codec *codec)
Jiang zhefb97dc62008-03-06 11:07:11 +01008733{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008734 struct alc_spec *spec = codec->spec;
Jiang zhefb97dc62008-03-06 11:07:11 +01008735
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008736 spec->autocfg.hp_pins[0] = 0x14;
8737 spec->autocfg.speaker_pins[0] = 0x15;
Jiang zhefb97dc62008-03-06 11:07:11 +01008738}
8739
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008740static void alc883_haier_w66_setup(struct hda_codec *codec)
Jiang zhefb97dc62008-03-06 11:07:11 +01008741{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008742 struct alc_spec *spec = codec->spec;
Jiang zhefb97dc62008-03-06 11:07:11 +01008743
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008744 spec->autocfg.hp_pins[0] = 0x1b;
8745 spec->autocfg.speaker_pins[0] = 0x14;
Kailang Yang189609a2007-08-20 11:31:23 +02008746}
8747
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008748static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
8749{
Wu Fengguang864f92b2009-11-18 12:38:02 +08008750 int bits = snd_hda_jack_detect(codec, 0x14) ? HDA_AMP_MUTE : 0;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008751
Takashi Iwai47fd8302007-08-10 17:11:07 +02008752 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8753 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008754}
8755
8756static void alc883_lenovo_101e_all_automute(struct hda_codec *codec)
8757{
Wu Fengguang864f92b2009-11-18 12:38:02 +08008758 int bits = snd_hda_jack_detect(codec, 0x1b) ? HDA_AMP_MUTE : 0;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008759
Takashi Iwai47fd8302007-08-10 17:11:07 +02008760 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
8761 HDA_AMP_MUTE, bits);
8762 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8763 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008764}
8765
8766static void alc883_lenovo_101e_unsol_event(struct hda_codec *codec,
8767 unsigned int res)
8768{
8769 if ((res >> 26) == ALC880_HP_EVENT)
8770 alc883_lenovo_101e_all_automute(codec);
8771 if ((res >> 26) == ALC880_FRONT_EVENT)
8772 alc883_lenovo_101e_ispeaker_automute(codec);
8773}
8774
Takashi Iwai676a9b52007-08-16 15:23:35 +02008775/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008776static void alc883_acer_aspire_setup(struct hda_codec *codec)
Takashi Iwai676a9b52007-08-16 15:23:35 +02008777{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008778 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02008779
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008780 spec->autocfg.hp_pins[0] = 0x14;
8781 spec->autocfg.speaker_pins[0] = 0x15;
8782 spec->autocfg.speaker_pins[1] = 0x16;
Takashi Iwai676a9b52007-08-16 15:23:35 +02008783}
8784
Kailang Yangd1a991a2007-08-15 16:21:59 +02008785static struct hda_verb alc883_acer_eapd_verbs[] = {
8786 /* HP Pin: output 0 (0x0c) */
8787 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8788 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8789 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8790 /* Front Pin: output 0 (0x0c) */
Takashi Iwai676a9b52007-08-16 15:23:35 +02008791 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8792 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangd1a991a2007-08-15 16:21:59 +02008793 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangd1a991a2007-08-15 16:21:59 +02008794 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
8795 /* eanable EAPD on medion laptop */
8796 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
8797 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
Takashi Iwai676a9b52007-08-16 15:23:35 +02008798 /* enable unsolicited event */
8799 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yangd1a991a2007-08-15 16:21:59 +02008800 { }
8801};
8802
Denis Kuplyakovfc86f952009-08-25 18:15:59 +02008803static struct hda_verb alc888_acer_aspire_7730G_verbs[] = {
8804 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8805 {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
8806 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8807 { } /* end */
8808};
8809
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008810static void alc888_6st_dell_setup(struct hda_codec *codec)
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008811{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008812 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02008813
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008814 spec->autocfg.hp_pins[0] = 0x1b;
8815 spec->autocfg.speaker_pins[0] = 0x14;
8816 spec->autocfg.speaker_pins[1] = 0x15;
8817 spec->autocfg.speaker_pins[2] = 0x16;
8818 spec->autocfg.speaker_pins[3] = 0x17;
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008819}
8820
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008821static void alc888_lenovo_sky_setup(struct hda_codec *codec)
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008822{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008823 struct alc_spec *spec = codec->spec;
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008824
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008825 spec->autocfg.hp_pins[0] = 0x1b;
8826 spec->autocfg.speaker_pins[0] = 0x14;
8827 spec->autocfg.speaker_pins[1] = 0x15;
8828 spec->autocfg.speaker_pins[2] = 0x16;
8829 spec->autocfg.speaker_pins[3] = 0x17;
8830 spec->autocfg.speaker_pins[4] = 0x1a;
Kailang Yange2757d52008-08-26 13:17:46 +02008831}
8832
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008833static void alc883_vaiott_setup(struct hda_codec *codec)
Guido Günther3e1647c2009-06-05 00:47:26 +02008834{
8835 struct alc_spec *spec = codec->spec;
8836
8837 spec->autocfg.hp_pins[0] = 0x15;
8838 spec->autocfg.speaker_pins[0] = 0x14;
8839 spec->autocfg.speaker_pins[1] = 0x17;
Guido Günther3e1647c2009-06-05 00:47:26 +02008840}
8841
Kailang Yange2757d52008-08-26 13:17:46 +02008842static struct hda_verb alc888_asus_m90v_verbs[] = {
8843 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8844 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8845 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8846 /* enable unsolicited event */
8847 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8848 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
8849 { } /* end */
8850};
8851
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008852static void alc883_mode2_setup(struct hda_codec *codec)
Kailang Yange2757d52008-08-26 13:17:46 +02008853{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008854 struct alc_spec *spec = codec->spec;
Kailang Yange2757d52008-08-26 13:17:46 +02008855
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008856 spec->autocfg.hp_pins[0] = 0x1b;
8857 spec->autocfg.speaker_pins[0] = 0x14;
8858 spec->autocfg.speaker_pins[1] = 0x15;
8859 spec->autocfg.speaker_pins[2] = 0x16;
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008860 spec->ext_mic.pin = 0x18;
8861 spec->int_mic.pin = 0x19;
8862 spec->ext_mic.mux_idx = 0;
8863 spec->int_mic.mux_idx = 1;
8864 spec->auto_mic = 1;
Kailang Yange2757d52008-08-26 13:17:46 +02008865}
8866
8867static struct hda_verb alc888_asus_eee1601_verbs[] = {
8868 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8869 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8870 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8871 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8872 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8873 {0x20, AC_VERB_SET_COEF_INDEX, 0x0b},
8874 {0x20, AC_VERB_SET_PROC_COEF, 0x0838},
8875 /* enable unsolicited event */
8876 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8877 { } /* end */
8878};
8879
Kailang Yange2757d52008-08-26 13:17:46 +02008880static void alc883_eee1601_inithook(struct hda_codec *codec)
8881{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008882 struct alc_spec *spec = codec->spec;
8883
8884 spec->autocfg.hp_pins[0] = 0x14;
8885 spec->autocfg.speaker_pins[0] = 0x1b;
8886 alc_automute_pin(codec);
Kailang Yange2757d52008-08-26 13:17:46 +02008887}
8888
Torben Schulzeb4c41d2009-05-18 15:02:35 +02008889static struct hda_verb alc889A_mb31_verbs[] = {
8890 /* Init rear pin (used as headphone output) */
8891 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4}, /* Apple Headphones */
8892 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Connect to front */
8893 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8894 /* Init line pin (used as output in 4ch and 6ch mode) */
8895 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02}, /* Connect to CLFE */
8896 /* Init line 2 pin (used as headphone out by default) */
8897 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Use as input */
8898 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Mute output */
8899 { } /* end */
8900};
8901
8902/* Mute speakers according to the headphone jack state */
8903static void alc889A_mb31_automute(struct hda_codec *codec)
8904{
8905 unsigned int present;
8906
8907 /* Mute only in 2ch or 4ch mode */
8908 if (snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_CONNECT_SEL, 0)
8909 == 0x00) {
Wu Fengguang864f92b2009-11-18 12:38:02 +08008910 present = snd_hda_jack_detect(codec, 0x15);
Torben Schulzeb4c41d2009-05-18 15:02:35 +02008911 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
8912 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
8913 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
8914 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
8915 }
8916}
8917
8918static void alc889A_mb31_unsol_event(struct hda_codec *codec, unsigned int res)
8919{
8920 if ((res >> 26) == ALC880_HP_EVENT)
8921 alc889A_mb31_automute(codec);
8922}
8923
Takashi Iwai4953550a2009-06-30 15:28:30 +02008924
Takashi Iwaicb53c622007-08-10 17:21:45 +02008925#ifdef CONFIG_SND_HDA_POWER_SAVE
Takashi Iwai4953550a2009-06-30 15:28:30 +02008926#define alc882_loopbacks alc880_loopbacks
Takashi Iwaicb53c622007-08-10 17:21:45 +02008927#endif
8928
Sasha Alexandrdef319f2009-06-16 16:00:15 -04008929/* pcm configuration: identical with ALC880 */
Takashi Iwai4953550a2009-06-30 15:28:30 +02008930#define alc882_pcm_analog_playback alc880_pcm_analog_playback
8931#define alc882_pcm_analog_capture alc880_pcm_analog_capture
8932#define alc882_pcm_digital_playback alc880_pcm_digital_playback
8933#define alc882_pcm_digital_capture alc880_pcm_digital_capture
8934
8935static hda_nid_t alc883_slave_dig_outs[] = {
8936 ALC1200_DIGOUT_NID, 0,
8937};
8938
8939static hda_nid_t alc1200_slave_dig_outs[] = {
8940 ALC883_DIGOUT_NID, 0,
8941};
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008942
8943/*
8944 * configuration and preset
8945 */
Takashi Iwai4953550a2009-06-30 15:28:30 +02008946static const char *alc882_models[ALC882_MODEL_LAST] = {
8947 [ALC882_3ST_DIG] = "3stack-dig",
8948 [ALC882_6ST_DIG] = "6stack-dig",
8949 [ALC882_ARIMA] = "arima",
8950 [ALC882_W2JC] = "w2jc",
8951 [ALC882_TARGA] = "targa",
8952 [ALC882_ASUS_A7J] = "asus-a7j",
8953 [ALC882_ASUS_A7M] = "asus-a7m",
8954 [ALC885_MACPRO] = "macpro",
8955 [ALC885_MB5] = "mb5",
8956 [ALC885_MBP3] = "mbp3",
8957 [ALC885_IMAC24] = "imac24",
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008958 [ALC885_IMAC91] = "imac91",
Takashi Iwai4953550a2009-06-30 15:28:30 +02008959 [ALC883_3ST_2ch_DIG] = "3stack-2ch-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008960 [ALC883_3ST_6ch_DIG] = "3stack-6ch-dig",
8961 [ALC883_3ST_6ch] = "3stack-6ch",
Takashi Iwai4953550a2009-06-30 15:28:30 +02008962 [ALC883_6ST_DIG] = "alc883-6stack-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008963 [ALC883_TARGA_DIG] = "targa-dig",
8964 [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig",
David Heidelberger64a8be72009-06-08 16:15:18 +02008965 [ALC883_TARGA_8ch_DIG] = "targa-8ch-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008966 [ALC883_ACER] = "acer",
Tobin Davis2880a862007-08-07 11:50:26 +02008967 [ALC883_ACER_ASPIRE] = "acer-aspire",
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08008968 [ALC888_ACER_ASPIRE_4930G] = "acer-aspire-4930g",
Takashi Iwaib1a91462009-06-21 10:56:44 +02008969 [ALC888_ACER_ASPIRE_6530G] = "acer-aspire-6530g",
Hector Martin3b315d72009-06-02 10:54:19 +02008970 [ALC888_ACER_ASPIRE_8930G] = "acer-aspire-8930g",
Denis Kuplyakovfc86f952009-08-25 18:15:59 +02008971 [ALC888_ACER_ASPIRE_7730G] = "acer-aspire-7730g",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008972 [ALC883_MEDION] = "medion",
Kailang Yang272a5272007-05-14 11:00:38 +02008973 [ALC883_MEDION_MD2] = "medion-md2",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008974 [ALC883_LAPTOP_EAPD] = "laptop-eapd",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02008975 [ALC883_LENOVO_101E_2ch] = "lenovo-101e",
Kailang Yang272a5272007-05-14 11:00:38 +02008976 [ALC883_LENOVO_NB0763] = "lenovo-nb0763",
8977 [ALC888_LENOVO_MS7195_DIG] = "lenovo-ms7195-dig",
Kailang Yange2757d52008-08-26 13:17:46 +02008978 [ALC888_LENOVO_SKY] = "lenovo-sky",
Kailang Yang189609a2007-08-20 11:31:23 +02008979 [ALC883_HAIER_W66] = "haier-w66",
Claudio Matsuoka4723c022007-07-13 14:36:19 +02008980 [ALC888_3ST_HP] = "3stack-hp",
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01008981 [ALC888_6ST_DELL] = "6stack-dell",
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008982 [ALC883_MITAC] = "mitac",
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04308983 [ALC883_CLEVO_M540R] = "clevo-m540r",
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008984 [ALC883_CLEVO_M720] = "clevo-m720",
Jiang zhefb97dc62008-03-06 11:07:11 +01008985 [ALC883_FUJITSU_PI2515] = "fujitsu-pi2515",
Vincent Petryef8ef5f2008-11-23 11:31:41 +08008986 [ALC888_FUJITSU_XA3530] = "fujitsu-xa3530",
Jiang zhe17bba1b2008-06-04 12:11:07 +02008987 [ALC883_3ST_6ch_INTEL] = "3stack-6ch-intel",
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008988 [ALC889A_INTEL] = "intel-alc889a",
8989 [ALC889_INTEL] = "intel-x58",
Wu Fengguang3ab90932008-11-17 09:51:09 +01008990 [ALC1200_ASUS_P5Q] = "asus-p5q",
Torben Schulzeb4c41d2009-05-18 15:02:35 +02008991 [ALC889A_MB31] = "mb31",
Guido Günther3e1647c2009-06-05 00:47:26 +02008992 [ALC883_SONY_VAIO_TT] = "sony-vaio-tt",
Takashi Iwai4953550a2009-06-30 15:28:30 +02008993 [ALC882_AUTO] = "auto",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01008994};
8995
Takashi Iwai4953550a2009-06-30 15:28:30 +02008996static struct snd_pci_quirk alc882_cfg_tbl[] = {
8997 SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG),
8998
Takashi Iwaiac3e3742007-12-17 17:14:18 +01008999 SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE),
Takashi Iwai69e50282008-11-03 10:07:43 +01009000 SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_ACER_ASPIRE),
Takashi Iwai9b6682f2009-03-23 22:50:52 +01009001 SND_PCI_QUIRK(0x1025, 0x010a, "Acer Ferrari 5000", ALC883_ACER_ASPIRE),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009002 SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE),
9003 SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE),
Jaroslav Kysela0b18cb12008-07-28 17:07:07 +02009004 SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_ACER_ASPIRE),
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08009005 SND_PCI_QUIRK(0x1025, 0x013e, "Acer Aspire 4930G",
9006 ALC888_ACER_ASPIRE_4930G),
Lukasz Wojnilowicza8e4f9d2009-01-08 12:00:49 +01009007 SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G",
Takashi Iwai83dd7402009-11-24 08:57:53 +01009008 ALC888_ACER_ASPIRE_4930G),
Hector Martin3b315d72009-06-02 10:54:19 +02009009 SND_PCI_QUIRK(0x1025, 0x0145, "Acer Aspire 8930G",
9010 ALC888_ACER_ASPIRE_8930G),
Takashi Iwaie46b0c82009-06-13 10:16:43 +02009011 SND_PCI_QUIRK(0x1025, 0x0146, "Acer Aspire 6935G",
9012 ALC888_ACER_ASPIRE_8930G),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009013 SND_PCI_QUIRK(0x1025, 0x0157, "Acer X3200", ALC882_AUTO),
9014 SND_PCI_QUIRK(0x1025, 0x0158, "Acer AX1700-U3700A", ALC882_AUTO),
Lukasz Wojnilowicza8e4f9d2009-01-08 12:00:49 +01009015 SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G",
Takashi Iwaidde65352009-06-25 08:25:35 +02009016 ALC888_ACER_ASPIRE_6530G),
Juan Jesus Garcia de Soriacc374c42009-02-23 08:11:59 +01009017 SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G",
Tony Vroond2fd4b02009-06-21 00:40:10 +01009018 ALC888_ACER_ASPIRE_6530G),
Denis Kuplyakovfc86f952009-08-25 18:15:59 +02009019 SND_PCI_QUIRK(0x1025, 0x0142, "Acer Aspire 7730G",
9020 ALC888_ACER_ASPIRE_7730G),
Takashi Iwai22b530e2009-05-13 11:32:52 +02009021 /* default Acer -- disabled as it causes more problems.
9022 * model=auto should work fine now
9023 */
9024 /* SND_PCI_QUIRK_VENDOR(0x1025, "Acer laptop", ALC883_ACER), */
Takashi Iwai4953550a2009-06-30 15:28:30 +02009025
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009026 SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009027
Tobin Davisfebe3372007-06-12 11:27:46 +02009028 SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009029 SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP),
9030 SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP),
Herton Ronaldo Krzesinski5d85f8d2008-03-20 12:13:46 +01009031 SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG),
Chris Bagwell06bf3e12009-01-01 10:32:08 +01009032 SND_PCI_QUIRK(0x103c, 0x2a66, "HP Acacia", ALC888_3ST_HP),
Herton Ronaldo Krzesinski7ec30f02009-03-04 14:22:52 -03009033 SND_PCI_QUIRK(0x103c, 0x2a72, "HP Educ.ar", ALC888_3ST_HP),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009034
9035 SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J),
9036 SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J),
9037 SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M),
Kailang Yanga01c30c2008-10-15 11:14:58 +02009038 SND_PCI_QUIRK(0x1043, 0x1873, "Asus M90V", ALC888_ASUS_M90V),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009039 SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC),
9040 SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG),
9041 SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009042 SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG),
Mackenzie Morgan44a678d2009-02-10 17:13:43 +01009043 SND_PCI_QUIRK(0x1043, 0x8284, "Asus Z37E", ALC883_6ST_DIG),
Wu Fengguang3ab90932008-11-17 09:51:09 +01009044 SND_PCI_QUIRK(0x1043, 0x82fe, "Asus P5Q-EM HDMI", ALC1200_ASUS_P5Q),
Kailang Yange2757d52008-08-26 13:17:46 +02009045 SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_ASUS_EEE1601),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009046
9047 SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC883_SONY_VAIO_TT),
Travis Place97ec7102008-05-23 18:31:46 +02009048 SND_PCI_QUIRK(0x105b, 0x0ce8, "Foxconn P35AX-S", ALC883_6ST_DIG),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009049 SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG),
Luke Yelavich2de686d2009-01-16 15:08:02 +11009050 SND_PCI_QUIRK(0x1071, 0x8227, "Mitac 82801H", ALC883_MITAC),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009051 SND_PCI_QUIRK(0x1071, 0x8253, "Mitac 8252d", ALC883_MITAC),
9052 SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD),
Kailang Yange2757d52008-08-26 13:17:46 +02009053 SND_PCI_QUIRK(0x10f1, 0x2350, "TYAN-S2350", ALC888_6ST_DELL),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009054 SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009055 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG),
9056
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009057 SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG),
9058 SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG),
9059 SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009060 SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */
Takashi Iwai2fef62c2009-12-18 08:48:42 +01009061 SND_PCI_QUIRK(0x1462, 0x2fb3, "MSI", ALC882_AUTO),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009062 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009063 SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG),
Pascal Terjan82808232008-03-04 11:33:28 +01009064 SND_PCI_QUIRK(0x1462, 0x3783, "NEC S970", ALC883_TARGA_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009065 SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG),
9066 SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG),
9067 SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG),
9068 SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG),
9069 SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG),
9070 SND_PCI_QUIRK(0x1462, 0x3fdf, "MSI", ALC883_TARGA_DIG),
William Westonb1e44222009-07-08 01:10:05 -07009071 SND_PCI_QUIRK(0x1462, 0x42cd, "MSI", ALC883_TARGA_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009072 SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG),
9073 SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG),
9074 SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG),
David Heidelberger64a8be72009-06-08 16:15:18 +02009075 SND_PCI_QUIRK(0x1462, 0x6510, "MSI GX620", ALC883_TARGA_8ch_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009076 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG),
9077 SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG),
Tobin Davis799f88a2007-05-29 14:29:08 +02009078 SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG),
Takashi Iwaiee095432008-11-25 15:03:38 +01009079 SND_PCI_QUIRK(0x1462, 0x7260, "MSI 7260", ALC883_TARGA_DIG),
Herton Ronaldo Krzesinski86d34b72008-03-18 09:27:59 +01009080 SND_PCI_QUIRK(0x1462, 0x7267, "MSI", ALC883_3ST_6ch_DIG),
Leonard Norrgard2a296cb2007-01-08 11:28:22 +01009081 SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG),
Tobin Davis2dcd5222007-07-10 17:04:57 +02009082 SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG),
Sasha Alexandrdf01b8a2009-06-16 14:46:17 -04009083 SND_PCI_QUIRK(0x1462, 0x7350, "MSI", ALC883_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009084 SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG),
William Westonb1e44222009-07-08 01:10:05 -07009085 SND_PCI_QUIRK(0x1462, 0xaa08, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009086
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009087 SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG),
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009088 SND_PCI_QUIRK(0x1558, 0x0721, "Clevo laptop M720R", ALC883_CLEVO_M720),
9089 SND_PCI_QUIRK(0x1558, 0x0722, "Clevo laptop M720SR", ALC883_CLEVO_M720),
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04309090 SND_PCI_QUIRK(0x1558, 0x5409, "Clevo laptop M540R", ALC883_CLEVO_M540R),
Takashi Iwaidea0a502009-02-09 17:14:52 +01009091 SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC883_LAPTOP_EAPD),
Daniel T Chene60623b2007-05-29 03:41:55 -04009092 SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009093 /* SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA), */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009094 SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION),
Takashi Iwaibfb53032009-04-14 14:51:04 +02009095 SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1100, "FSC AMILO Xi/Pi25xx",
Takashi Iwaif67d8172009-02-04 23:30:19 +01009096 ALC883_FUJITSU_PI2515),
Takashi Iwaibfb53032009-04-14 14:51:04 +02009097 SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1130, "Fujitsu AMILO Xa35xx",
Vincent Petryef8ef5f2008-11-23 11:31:41 +08009098 ALC888_FUJITSU_XA3530),
Kailang Yang272a5272007-05-14 11:00:38 +02009099 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch),
Kailang Yang272a5272007-05-14 11:00:38 +02009100 SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009101 SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763),
9102 SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Kailang Yange2757d52008-08-26 13:17:46 +02009103 SND_PCI_QUIRK(0x17aa, 0x101d, "Lenovo Sky", ALC888_LENOVO_SKY),
Kailang Yang272a5272007-05-14 11:00:38 +02009104 SND_PCI_QUIRK(0x17c0, 0x4071, "MEDION MD2", ALC883_MEDION_MD2),
Takashi Iwai959973b2008-11-05 11:30:56 +01009105 SND_PCI_QUIRK(0x17c0, 0x4085, "MEDION MD96630", ALC888_LENOVO_MS7195_DIG),
Andrew Paprocki0b167bf2008-02-03 10:15:44 +01009106 SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG),
Kailang Yang189609a2007-08-20 11:31:23 +02009107 SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009108
Jiang zhe17bba1b2008-06-04 12:11:07 +02009109 SND_PCI_QUIRK(0x8086, 0x0001, "DG33BUC", ALC883_3ST_6ch_INTEL),
9110 SND_PCI_QUIRK(0x8086, 0x0002, "DG33FBC", ALC883_3ST_6ch_INTEL),
Luke Yelavich2de686d2009-01-16 15:08:02 +11009111 SND_PCI_QUIRK(0x8086, 0x2503, "82801H", ALC883_MITAC),
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009112 SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC889_INTEL),
9113 SND_PCI_QUIRK(0x8086, 0x0021, "Intel IbexPeak", ALC889A_INTEL),
9114 SND_PCI_QUIRK(0x8086, 0x3b56, "Intel IbexPeak", ALC889A_INTEL),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009115 SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009116
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009117 {}
9118};
9119
Takashi Iwai4953550a2009-06-30 15:28:30 +02009120/* codec SSID table for Intel Mac */
9121static struct snd_pci_quirk alc882_ssid_cfg_tbl[] = {
9122 SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC885_MBP3),
9123 SND_PCI_QUIRK(0x106b, 0x00a1, "Macbook", ALC885_MBP3),
9124 SND_PCI_QUIRK(0x106b, 0x00a4, "MacbookPro 4,1", ALC885_MBP3),
9125 SND_PCI_QUIRK(0x106b, 0x0c00, "Mac Pro", ALC885_MACPRO),
9126 SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_IMAC24),
9127 SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_IMAC24),
9128 SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC885_MBP3),
9129 SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889A_MB31),
9130 SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC885_MBP3),
9131 SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_IMAC24),
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08009132 SND_PCI_QUIRK(0x106b, 0x4900, "iMac 9,1 Aluminum", ALC885_IMAC91),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009133 SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC885_MB5),
Daniel T Chen46ef6ec2009-11-11 14:32:10 -05009134 /* FIXME: HP jack sense seems not working for MBP 5,1 or 5,2,
9135 * so apparently no perfect solution yet
Takashi Iwai4953550a2009-06-30 15:28:30 +02009136 */
9137 SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC885_MB5),
Daniel T Chen46ef6ec2009-11-11 14:32:10 -05009138 SND_PCI_QUIRK(0x106b, 0x4600, "MacbookPro 5,2", ALC885_MB5),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009139 {} /* terminator */
Wu Fengguangf3cd3f52009-04-02 19:44:18 +08009140};
9141
Takashi Iwai4953550a2009-06-30 15:28:30 +02009142static struct alc_config_preset alc882_presets[] = {
9143 [ALC882_3ST_DIG] = {
9144 .mixers = { alc882_base_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009145 .init_verbs = { alc882_base_init_verbs,
9146 alc882_adc1_init_verbs },
Takashi Iwai4953550a2009-06-30 15:28:30 +02009147 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9148 .dac_nids = alc882_dac_nids,
9149 .dig_out_nid = ALC882_DIGOUT_NID,
9150 .dig_in_nid = ALC882_DIGIN_NID,
9151 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
9152 .channel_mode = alc882_ch_modes,
9153 .need_dac_fix = 1,
9154 .input_mux = &alc882_capture_source,
9155 },
9156 [ALC882_6ST_DIG] = {
9157 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009158 .init_verbs = { alc882_base_init_verbs,
9159 alc882_adc1_init_verbs },
Takashi Iwai4953550a2009-06-30 15:28:30 +02009160 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9161 .dac_nids = alc882_dac_nids,
9162 .dig_out_nid = ALC882_DIGOUT_NID,
9163 .dig_in_nid = ALC882_DIGIN_NID,
9164 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
9165 .channel_mode = alc882_sixstack_modes,
9166 .input_mux = &alc882_capture_source,
9167 },
9168 [ALC882_ARIMA] = {
9169 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009170 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
9171 alc882_eapd_verbs },
Takashi Iwai4953550a2009-06-30 15:28:30 +02009172 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9173 .dac_nids = alc882_dac_nids,
9174 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
9175 .channel_mode = alc882_sixstack_modes,
9176 .input_mux = &alc882_capture_source,
9177 },
9178 [ALC882_W2JC] = {
9179 .mixers = { alc882_w2jc_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009180 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
9181 alc882_eapd_verbs, alc880_gpio1_init_verbs },
Takashi Iwai4953550a2009-06-30 15:28:30 +02009182 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9183 .dac_nids = alc882_dac_nids,
9184 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
9185 .channel_mode = alc880_threestack_modes,
9186 .need_dac_fix = 1,
9187 .input_mux = &alc882_capture_source,
9188 .dig_out_nid = ALC882_DIGOUT_NID,
9189 },
9190 [ALC885_MBP3] = {
9191 .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer },
9192 .init_verbs = { alc885_mbp3_init_verbs,
9193 alc880_gpio1_init_verbs },
Takashi Iwaibe0ae922009-08-31 08:27:10 +02009194 .num_dacs = 2,
Takashi Iwai4953550a2009-06-30 15:28:30 +02009195 .dac_nids = alc882_dac_nids,
Takashi Iwaibe0ae922009-08-31 08:27:10 +02009196 .hp_nid = 0x04,
9197 .channel_mode = alc885_mbp_4ch_modes,
9198 .num_channel_mode = ARRAY_SIZE(alc885_mbp_4ch_modes),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009199 .input_mux = &alc882_capture_source,
9200 .dig_out_nid = ALC882_DIGOUT_NID,
9201 .dig_in_nid = ALC882_DIGIN_NID,
9202 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009203 .setup = alc885_mbp3_setup,
9204 .init_hook = alc_automute_amp,
Takashi Iwai4953550a2009-06-30 15:28:30 +02009205 },
9206 [ALC885_MB5] = {
9207 .mixers = { alc885_mb5_mixer, alc882_chmode_mixer },
9208 .init_verbs = { alc885_mb5_init_verbs,
9209 alc880_gpio1_init_verbs },
9210 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9211 .dac_nids = alc882_dac_nids,
9212 .channel_mode = alc885_mb5_6ch_modes,
9213 .num_channel_mode = ARRAY_SIZE(alc885_mb5_6ch_modes),
9214 .input_mux = &mb5_capture_source,
9215 .dig_out_nid = ALC882_DIGOUT_NID,
9216 .dig_in_nid = ALC882_DIGIN_NID,
9217 },
9218 [ALC885_MACPRO] = {
9219 .mixers = { alc882_macpro_mixer },
9220 .init_verbs = { alc882_macpro_init_verbs },
9221 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9222 .dac_nids = alc882_dac_nids,
9223 .dig_out_nid = ALC882_DIGOUT_NID,
9224 .dig_in_nid = ALC882_DIGIN_NID,
9225 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
9226 .channel_mode = alc882_ch_modes,
9227 .input_mux = &alc882_capture_source,
9228 .init_hook = alc885_macpro_init_hook,
9229 },
9230 [ALC885_IMAC24] = {
9231 .mixers = { alc885_imac24_mixer },
9232 .init_verbs = { alc885_imac24_init_verbs },
9233 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9234 .dac_nids = alc882_dac_nids,
9235 .dig_out_nid = ALC882_DIGOUT_NID,
9236 .dig_in_nid = ALC882_DIGIN_NID,
9237 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
9238 .channel_mode = alc882_ch_modes,
9239 .input_mux = &alc882_capture_source,
9240 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009241 .setup = alc885_imac24_setup,
Takashi Iwai4953550a2009-06-30 15:28:30 +02009242 .init_hook = alc885_imac24_init_hook,
9243 },
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08009244 [ALC885_IMAC91] = {
9245 .mixers = { alc885_imac91_mixer, alc882_chmode_mixer },
9246 .init_verbs = { alc885_imac91_init_verbs,
9247 alc880_gpio1_init_verbs },
9248 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9249 .dac_nids = alc882_dac_nids,
9250 .channel_mode = alc885_mbp_4ch_modes,
9251 .num_channel_mode = ARRAY_SIZE(alc885_mbp_4ch_modes),
9252 .input_mux = &alc882_capture_source,
9253 .dig_out_nid = ALC882_DIGOUT_NID,
9254 .dig_in_nid = ALC882_DIGIN_NID,
9255 .unsol_event = alc885_imac91_unsol_event,
9256 .init_hook = alc885_imac91_automute,
9257 },
Takashi Iwai4953550a2009-06-30 15:28:30 +02009258 [ALC882_TARGA] = {
9259 .mixers = { alc882_targa_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009260 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
Takashi Iwai31909b82009-07-10 12:33:48 +02009261 alc880_gpio3_init_verbs, alc882_targa_verbs},
Takashi Iwai4953550a2009-06-30 15:28:30 +02009262 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9263 .dac_nids = alc882_dac_nids,
9264 .dig_out_nid = ALC882_DIGOUT_NID,
9265 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
9266 .adc_nids = alc882_adc_nids,
9267 .capsrc_nids = alc882_capsrc_nids,
9268 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
9269 .channel_mode = alc882_3ST_6ch_modes,
9270 .need_dac_fix = 1,
9271 .input_mux = &alc882_capture_source,
9272 .unsol_event = alc882_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009273 .setup = alc882_targa_setup,
9274 .init_hook = alc882_targa_automute,
Takashi Iwai4953550a2009-06-30 15:28:30 +02009275 },
9276 [ALC882_ASUS_A7J] = {
9277 .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009278 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
9279 alc882_asus_a7j_verbs},
Takashi Iwai4953550a2009-06-30 15:28:30 +02009280 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9281 .dac_nids = alc882_dac_nids,
9282 .dig_out_nid = ALC882_DIGOUT_NID,
9283 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
9284 .adc_nids = alc882_adc_nids,
9285 .capsrc_nids = alc882_capsrc_nids,
9286 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
9287 .channel_mode = alc882_3ST_6ch_modes,
9288 .need_dac_fix = 1,
9289 .input_mux = &alc882_capture_source,
9290 },
9291 [ALC882_ASUS_A7M] = {
9292 .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009293 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
9294 alc882_eapd_verbs, alc880_gpio1_init_verbs,
Takashi Iwai4953550a2009-06-30 15:28:30 +02009295 alc882_asus_a7m_verbs },
9296 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9297 .dac_nids = alc882_dac_nids,
9298 .dig_out_nid = ALC882_DIGOUT_NID,
9299 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
9300 .channel_mode = alc880_threestack_modes,
9301 .need_dac_fix = 1,
9302 .input_mux = &alc882_capture_source,
9303 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009304 [ALC883_3ST_2ch_DIG] = {
9305 .mixers = { alc883_3ST_2ch_mixer },
9306 .init_verbs = { alc883_init_verbs },
9307 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9308 .dac_nids = alc883_dac_nids,
9309 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009310 .dig_in_nid = ALC883_DIGIN_NID,
9311 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9312 .channel_mode = alc883_3ST_2ch_modes,
9313 .input_mux = &alc883_capture_source,
9314 },
9315 [ALC883_3ST_6ch_DIG] = {
9316 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
9317 .init_verbs = { alc883_init_verbs },
9318 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9319 .dac_nids = alc883_dac_nids,
9320 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009321 .dig_in_nid = ALC883_DIGIN_NID,
9322 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
9323 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02009324 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009325 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009326 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009327 [ALC883_3ST_6ch] = {
9328 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
9329 .init_verbs = { alc883_init_verbs },
9330 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9331 .dac_nids = alc883_dac_nids,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009332 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
9333 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02009334 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009335 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009336 },
Jiang zhe17bba1b2008-06-04 12:11:07 +02009337 [ALC883_3ST_6ch_INTEL] = {
9338 .mixers = { alc883_3ST_6ch_intel_mixer, alc883_chmode_mixer },
9339 .init_verbs = { alc883_init_verbs },
9340 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9341 .dac_nids = alc883_dac_nids,
9342 .dig_out_nid = ALC883_DIGOUT_NID,
9343 .dig_in_nid = ALC883_DIGIN_NID,
Wu Fengguangf3cd3f52009-04-02 19:44:18 +08009344 .slave_dig_outs = alc883_slave_dig_outs,
Jiang zhe17bba1b2008-06-04 12:11:07 +02009345 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_intel_modes),
9346 .channel_mode = alc883_3ST_6ch_intel_modes,
9347 .need_dac_fix = 1,
9348 .input_mux = &alc883_3stack_6ch_intel,
9349 },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009350 [ALC889A_INTEL] = {
9351 .mixers = { alc885_8ch_intel_mixer, alc883_chmode_mixer },
Wu Fengguang6732bd02009-07-30 09:19:14 +02009352 .init_verbs = { alc885_init_verbs, alc885_init_input_verbs,
9353 alc_hp15_unsol_verbs },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009354 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9355 .dac_nids = alc883_dac_nids,
9356 .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
9357 .adc_nids = alc889_adc_nids,
9358 .dig_out_nid = ALC883_DIGOUT_NID,
9359 .dig_in_nid = ALC883_DIGIN_NID,
9360 .slave_dig_outs = alc883_slave_dig_outs,
9361 .num_channel_mode = ARRAY_SIZE(alc889_8ch_intel_modes),
9362 .channel_mode = alc889_8ch_intel_modes,
9363 .capsrc_nids = alc889_capsrc_nids,
9364 .input_mux = &alc889_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009365 .setup = alc889_automute_setup,
9366 .init_hook = alc_automute_amp,
Wu Fengguang6732bd02009-07-30 09:19:14 +02009367 .unsol_event = alc_automute_amp_unsol_event,
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009368 .need_dac_fix = 1,
9369 },
9370 [ALC889_INTEL] = {
9371 .mixers = { alc885_8ch_intel_mixer, alc883_chmode_mixer },
9372 .init_verbs = { alc885_init_verbs, alc889_init_input_verbs,
Wu Fengguang6732bd02009-07-30 09:19:14 +02009373 alc889_eapd_verbs, alc_hp15_unsol_verbs},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009374 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9375 .dac_nids = alc883_dac_nids,
9376 .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
9377 .adc_nids = alc889_adc_nids,
9378 .dig_out_nid = ALC883_DIGOUT_NID,
9379 .dig_in_nid = ALC883_DIGIN_NID,
9380 .slave_dig_outs = alc883_slave_dig_outs,
9381 .num_channel_mode = ARRAY_SIZE(alc889_8ch_intel_modes),
9382 .channel_mode = alc889_8ch_intel_modes,
9383 .capsrc_nids = alc889_capsrc_nids,
9384 .input_mux = &alc889_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009385 .setup = alc889_automute_setup,
Wu Fengguang6732bd02009-07-30 09:19:14 +02009386 .init_hook = alc889_intel_init_hook,
9387 .unsol_event = alc_automute_amp_unsol_event,
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009388 .need_dac_fix = 1,
9389 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009390 [ALC883_6ST_DIG] = {
9391 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
9392 .init_verbs = { alc883_init_verbs },
9393 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9394 .dac_nids = alc883_dac_nids,
9395 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009396 .dig_in_nid = ALC883_DIGIN_NID,
9397 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
9398 .channel_mode = alc883_sixstack_modes,
9399 .input_mux = &alc883_capture_source,
9400 },
Kailang Yangccc656c2006-10-17 12:32:26 +02009401 [ALC883_TARGA_DIG] = {
Sasha Alexandrc2592492009-06-16 14:52:54 -04009402 .mixers = { alc883_targa_mixer, alc883_chmode_mixer },
David Heidelberger005b1072009-07-09 18:45:46 +02009403 .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
9404 alc883_targa_verbs},
Kailang Yangccc656c2006-10-17 12:32:26 +02009405 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9406 .dac_nids = alc883_dac_nids,
9407 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +02009408 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
9409 .channel_mode = alc883_3ST_6ch_modes,
9410 .need_dac_fix = 1,
9411 .input_mux = &alc883_capture_source,
Sasha Alexandrc2592492009-06-16 14:52:54 -04009412 .unsol_event = alc883_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009413 .setup = alc882_targa_setup,
9414 .init_hook = alc882_targa_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +02009415 },
9416 [ALC883_TARGA_2ch_DIG] = {
Sasha Alexandrc2592492009-06-16 14:52:54 -04009417 .mixers = { alc883_targa_2ch_mixer},
David Heidelberger005b1072009-07-09 18:45:46 +02009418 .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
9419 alc883_targa_verbs},
Kailang Yangccc656c2006-10-17 12:32:26 +02009420 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9421 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01009422 .adc_nids = alc883_adc_nids_alt,
9423 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Takashi Iwai035eb0c2009-12-17 15:00:26 +01009424 .capsrc_nids = alc883_capsrc_nids,
Kailang Yangccc656c2006-10-17 12:32:26 +02009425 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +02009426 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9427 .channel_mode = alc883_3ST_2ch_modes,
9428 .input_mux = &alc883_capture_source,
Sasha Alexandrc2592492009-06-16 14:52:54 -04009429 .unsol_event = alc883_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009430 .setup = alc882_targa_setup,
9431 .init_hook = alc882_targa_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +02009432 },
David Heidelberger64a8be72009-06-08 16:15:18 +02009433 [ALC883_TARGA_8ch_DIG] = {
Takashi Iwaib99dba32009-09-17 18:23:00 +02009434 .mixers = { alc883_targa_mixer, alc883_targa_8ch_mixer,
9435 alc883_chmode_mixer },
David Heidelberger64a8be72009-06-08 16:15:18 +02009436 .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
Sasha Alexandrc2592492009-06-16 14:52:54 -04009437 alc883_targa_verbs },
David Heidelberger64a8be72009-06-08 16:15:18 +02009438 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9439 .dac_nids = alc883_dac_nids,
9440 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
9441 .adc_nids = alc883_adc_nids_rev,
9442 .capsrc_nids = alc883_capsrc_nids_rev,
9443 .dig_out_nid = ALC883_DIGOUT_NID,
9444 .dig_in_nid = ALC883_DIGIN_NID,
9445 .num_channel_mode = ARRAY_SIZE(alc883_4ST_8ch_modes),
9446 .channel_mode = alc883_4ST_8ch_modes,
9447 .need_dac_fix = 1,
9448 .input_mux = &alc883_capture_source,
Sasha Alexandrc2592492009-06-16 14:52:54 -04009449 .unsol_event = alc883_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009450 .setup = alc882_targa_setup,
9451 .init_hook = alc882_targa_automute,
David Heidelberger64a8be72009-06-08 16:15:18 +02009452 },
Vladimir Avdoninbab282b2006-08-22 13:31:58 +02009453 [ALC883_ACER] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02009454 .mixers = { alc883_base_mixer },
Vladimir Avdoninbab282b2006-08-22 13:31:58 +02009455 /* On TravelMate laptops, GPIO 0 enables the internal speaker
9456 * and the headphone jack. Turn this on and rely on the
9457 * standard mute methods whenever the user wants to turn
9458 * these outputs off.
9459 */
9460 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs },
9461 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9462 .dac_nids = alc883_dac_nids,
Vladimir Avdoninbab282b2006-08-22 13:31:58 +02009463 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9464 .channel_mode = alc883_3ST_2ch_modes,
9465 .input_mux = &alc883_capture_source,
9466 },
Tobin Davis2880a862007-08-07 11:50:26 +02009467 [ALC883_ACER_ASPIRE] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02009468 .mixers = { alc883_acer_aspire_mixer },
Kailang Yangd1a991a2007-08-15 16:21:59 +02009469 .init_verbs = { alc883_init_verbs, alc883_acer_eapd_verbs },
Tobin Davis2880a862007-08-07 11:50:26 +02009470 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9471 .dac_nids = alc883_dac_nids,
9472 .dig_out_nid = ALC883_DIGOUT_NID,
Tobin Davis2880a862007-08-07 11:50:26 +02009473 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9474 .channel_mode = alc883_3ST_2ch_modes,
9475 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009476 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009477 .setup = alc883_acer_aspire_setup,
9478 .init_hook = alc_automute_amp,
Kailang Yangd1a991a2007-08-15 16:21:59 +02009479 },
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08009480 [ALC888_ACER_ASPIRE_4930G] = {
Vincent Petryef8ef5f2008-11-23 11:31:41 +08009481 .mixers = { alc888_base_mixer,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08009482 alc883_chmode_mixer },
9483 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
9484 alc888_acer_aspire_4930g_verbs },
9485 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9486 .dac_nids = alc883_dac_nids,
9487 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
9488 .adc_nids = alc883_adc_nids_rev,
9489 .capsrc_nids = alc883_capsrc_nids_rev,
9490 .dig_out_nid = ALC883_DIGOUT_NID,
9491 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
9492 .channel_mode = alc883_3ST_6ch_modes,
9493 .need_dac_fix = 1,
9494 .num_mux_defs =
Vincent Petryef8ef5f2008-11-23 11:31:41 +08009495 ARRAY_SIZE(alc888_2_capture_sources),
9496 .input_mux = alc888_2_capture_sources,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009497 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009498 .setup = alc888_acer_aspire_4930g_setup,
9499 .init_hook = alc_automute_amp,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08009500 },
Tony Vroond2fd4b02009-06-21 00:40:10 +01009501 [ALC888_ACER_ASPIRE_6530G] = {
9502 .mixers = { alc888_acer_aspire_6530_mixer },
9503 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
9504 alc888_acer_aspire_6530g_verbs },
9505 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9506 .dac_nids = alc883_dac_nids,
9507 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
9508 .adc_nids = alc883_adc_nids_rev,
9509 .capsrc_nids = alc883_capsrc_nids_rev,
9510 .dig_out_nid = ALC883_DIGOUT_NID,
9511 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9512 .channel_mode = alc883_3ST_2ch_modes,
9513 .num_mux_defs =
9514 ARRAY_SIZE(alc888_2_capture_sources),
9515 .input_mux = alc888_acer_aspire_6530_sources,
9516 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009517 .setup = alc888_acer_aspire_6530g_setup,
9518 .init_hook = alc_automute_amp,
Tony Vroond2fd4b02009-06-21 00:40:10 +01009519 },
Hector Martin3b315d72009-06-02 10:54:19 +02009520 [ALC888_ACER_ASPIRE_8930G] = {
Hector Martin556eea92009-12-20 22:51:23 +01009521 .mixers = { alc889_acer_aspire_8930g_mixer,
Hector Martin3b315d72009-06-02 10:54:19 +02009522 alc883_chmode_mixer },
9523 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
Hector Martin0f86a222009-12-20 22:51:18 +01009524 alc889_acer_aspire_8930g_verbs,
9525 alc889_eapd_verbs},
Hector Martin3b315d72009-06-02 10:54:19 +02009526 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9527 .dac_nids = alc883_dac_nids,
Hector Martin018df412009-06-04 00:13:40 +02009528 .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
9529 .adc_nids = alc889_adc_nids,
9530 .capsrc_nids = alc889_capsrc_nids,
Hector Martin3b315d72009-06-02 10:54:19 +02009531 .dig_out_nid = ALC883_DIGOUT_NID,
9532 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
9533 .channel_mode = alc883_3ST_6ch_modes,
9534 .need_dac_fix = 1,
9535 .const_channel_count = 6,
9536 .num_mux_defs =
Hector Martin018df412009-06-04 00:13:40 +02009537 ARRAY_SIZE(alc889_capture_sources),
9538 .input_mux = alc889_capture_sources,
Hector Martin3b315d72009-06-02 10:54:19 +02009539 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009540 .setup = alc889_acer_aspire_8930g_setup,
9541 .init_hook = alc_automute_amp,
Hector Martinf5de24b2009-12-20 22:51:31 +01009542#ifdef CONFIG_SND_HDA_POWER_SAVE
9543 .power_hook = alc889_power_eapd,
9544#endif
Hector Martin3b315d72009-06-02 10:54:19 +02009545 },
Denis Kuplyakovfc86f952009-08-25 18:15:59 +02009546 [ALC888_ACER_ASPIRE_7730G] = {
9547 .mixers = { alc883_3ST_6ch_mixer,
9548 alc883_chmode_mixer },
9549 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
9550 alc888_acer_aspire_7730G_verbs },
9551 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9552 .dac_nids = alc883_dac_nids,
9553 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
9554 .adc_nids = alc883_adc_nids_rev,
9555 .capsrc_nids = alc883_capsrc_nids_rev,
9556 .dig_out_nid = ALC883_DIGOUT_NID,
9557 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
9558 .channel_mode = alc883_3ST_6ch_modes,
9559 .need_dac_fix = 1,
9560 .const_channel_count = 6,
9561 .input_mux = &alc883_capture_source,
9562 .unsol_event = alc_automute_amp_unsol_event,
9563 .setup = alc888_acer_aspire_6530g_setup,
9564 .init_hook = alc_automute_amp,
9565 },
Tobin Davisc07584c2006-10-13 12:32:16 +02009566 [ALC883_MEDION] = {
9567 .mixers = { alc883_fivestack_mixer,
9568 alc883_chmode_mixer },
9569 .init_verbs = { alc883_init_verbs,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01009570 alc883_medion_eapd_verbs },
Tobin Davisc07584c2006-10-13 12:32:16 +02009571 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9572 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01009573 .adc_nids = alc883_adc_nids_alt,
9574 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Takashi Iwai035eb0c2009-12-17 15:00:26 +01009575 .capsrc_nids = alc883_capsrc_nids,
Tobin Davisc07584c2006-10-13 12:32:16 +02009576 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
9577 .channel_mode = alc883_sixstack_modes,
9578 .input_mux = &alc883_capture_source,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01009579 },
Kailang Yang272a5272007-05-14 11:00:38 +02009580 [ALC883_MEDION_MD2] = {
9581 .mixers = { alc883_medion_md2_mixer},
9582 .init_verbs = { alc883_init_verbs, alc883_medion_md2_verbs},
9583 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9584 .dac_nids = alc883_dac_nids,
9585 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang272a5272007-05-14 11:00:38 +02009586 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9587 .channel_mode = alc883_3ST_2ch_modes,
9588 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009589 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009590 .setup = alc883_medion_md2_setup,
9591 .init_hook = alc_automute_amp,
Kailang Yangea1fb292008-08-26 12:58:38 +02009592 },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01009593 [ALC883_LAPTOP_EAPD] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +02009594 .mixers = { alc883_base_mixer },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01009595 .init_verbs = { alc883_init_verbs, alc882_eapd_verbs },
9596 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9597 .dac_nids = alc883_dac_nids,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01009598 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9599 .channel_mode = alc883_3ST_2ch_modes,
9600 .input_mux = &alc883_capture_source,
9601 },
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04309602 [ALC883_CLEVO_M540R] = {
9603 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
9604 .init_verbs = { alc883_init_verbs, alc883_clevo_m540r_verbs },
9605 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9606 .dac_nids = alc883_dac_nids,
9607 .dig_out_nid = ALC883_DIGOUT_NID,
9608 .dig_in_nid = ALC883_DIGIN_NID,
9609 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_clevo_modes),
9610 .channel_mode = alc883_3ST_6ch_clevo_modes,
9611 .need_dac_fix = 1,
9612 .input_mux = &alc883_capture_source,
9613 /* This machine has the hardware HP auto-muting, thus
9614 * we need no software mute via unsol event
9615 */
9616 },
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009617 [ALC883_CLEVO_M720] = {
9618 .mixers = { alc883_clevo_m720_mixer },
9619 .init_verbs = { alc883_init_verbs, alc883_clevo_m720_verbs },
Jiang zhe368c7a92008-03-04 11:20:33 +01009620 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9621 .dac_nids = alc883_dac_nids,
9622 .dig_out_nid = ALC883_DIGOUT_NID,
9623 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9624 .channel_mode = alc883_3ST_2ch_modes,
9625 .input_mux = &alc883_capture_source,
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009626 .unsol_event = alc883_clevo_m720_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009627 .setup = alc883_clevo_m720_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009628 .init_hook = alc883_clevo_m720_init_hook,
Jiang zhe368c7a92008-03-04 11:20:33 +01009629 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009630 [ALC883_LENOVO_101E_2ch] = {
9631 .mixers = { alc883_lenovo_101e_2ch_mixer},
9632 .init_verbs = { alc883_init_verbs, alc883_lenovo_101e_verbs},
9633 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9634 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01009635 .adc_nids = alc883_adc_nids_alt,
9636 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Takashi Iwai035eb0c2009-12-17 15:00:26 +01009637 .capsrc_nids = alc883_capsrc_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009638 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9639 .channel_mode = alc883_3ST_2ch_modes,
9640 .input_mux = &alc883_lenovo_101e_capture_source,
9641 .unsol_event = alc883_lenovo_101e_unsol_event,
9642 .init_hook = alc883_lenovo_101e_all_automute,
9643 },
Kailang Yang272a5272007-05-14 11:00:38 +02009644 [ALC883_LENOVO_NB0763] = {
9645 .mixers = { alc883_lenovo_nb0763_mixer },
9646 .init_verbs = { alc883_init_verbs, alc883_lenovo_nb0763_verbs},
9647 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9648 .dac_nids = alc883_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +02009649 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9650 .channel_mode = alc883_3ST_2ch_modes,
9651 .need_dac_fix = 1,
9652 .input_mux = &alc883_lenovo_nb0763_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009653 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009654 .setup = alc883_medion_md2_setup,
9655 .init_hook = alc_automute_amp,
Kailang Yang272a5272007-05-14 11:00:38 +02009656 },
9657 [ALC888_LENOVO_MS7195_DIG] = {
9658 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
9659 .init_verbs = { alc883_init_verbs, alc888_lenovo_ms7195_verbs},
9660 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9661 .dac_nids = alc883_dac_nids,
9662 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang272a5272007-05-14 11:00:38 +02009663 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
9664 .channel_mode = alc883_3ST_6ch_modes,
9665 .need_dac_fix = 1,
9666 .input_mux = &alc883_capture_source,
9667 .unsol_event = alc883_lenovo_ms7195_unsol_event,
9668 .init_hook = alc888_lenovo_ms7195_front_automute,
Kailang Yang189609a2007-08-20 11:31:23 +02009669 },
9670 [ALC883_HAIER_W66] = {
Sasha Alexandrc2592492009-06-16 14:52:54 -04009671 .mixers = { alc883_targa_2ch_mixer},
Kailang Yang189609a2007-08-20 11:31:23 +02009672 .init_verbs = { alc883_init_verbs, alc883_haier_w66_verbs},
9673 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9674 .dac_nids = alc883_dac_nids,
9675 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang189609a2007-08-20 11:31:23 +02009676 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9677 .channel_mode = alc883_3ST_2ch_modes,
9678 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009679 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009680 .setup = alc883_haier_w66_setup,
9681 .init_hook = alc_automute_amp,
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +01009682 },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009683 [ALC888_3ST_HP] = {
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +01009684 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009685 .init_verbs = { alc883_init_verbs, alc888_3st_hp_verbs },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009686 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9687 .dac_nids = alc883_dac_nids,
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009688 .num_channel_mode = ARRAY_SIZE(alc888_3st_hp_modes),
9689 .channel_mode = alc888_3st_hp_modes,
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009690 .need_dac_fix = 1,
9691 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009692 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009693 .setup = alc888_3st_hp_setup,
9694 .init_hook = alc_automute_amp,
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009695 },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009696 [ALC888_6ST_DELL] = {
Herton Ronaldo Krzesinskif24dbdc2008-03-20 12:14:28 +01009697 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009698 .init_verbs = { alc883_init_verbs, alc888_6st_dell_verbs },
9699 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9700 .dac_nids = alc883_dac_nids,
9701 .dig_out_nid = ALC883_DIGOUT_NID,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009702 .dig_in_nid = ALC883_DIGIN_NID,
9703 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
9704 .channel_mode = alc883_sixstack_modes,
9705 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009706 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009707 .setup = alc888_6st_dell_setup,
9708 .init_hook = alc_automute_amp,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009709 },
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009710 [ALC883_MITAC] = {
9711 .mixers = { alc883_mitac_mixer },
9712 .init_verbs = { alc883_init_verbs, alc883_mitac_verbs },
9713 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9714 .dac_nids = alc883_dac_nids,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009715 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9716 .channel_mode = alc883_3ST_2ch_modes,
9717 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009718 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009719 .setup = alc883_mitac_setup,
9720 .init_hook = alc_automute_amp,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009721 },
Jiang zhefb97dc62008-03-06 11:07:11 +01009722 [ALC883_FUJITSU_PI2515] = {
9723 .mixers = { alc883_2ch_fujitsu_pi2515_mixer },
9724 .init_verbs = { alc883_init_verbs,
9725 alc883_2ch_fujitsu_pi2515_verbs},
9726 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9727 .dac_nids = alc883_dac_nids,
9728 .dig_out_nid = ALC883_DIGOUT_NID,
9729 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9730 .channel_mode = alc883_3ST_2ch_modes,
9731 .input_mux = &alc883_fujitsu_pi2515_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009732 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009733 .setup = alc883_2ch_fujitsu_pi2515_setup,
9734 .init_hook = alc_automute_amp,
Jiang zhefb97dc62008-03-06 11:07:11 +01009735 },
Vincent Petryef8ef5f2008-11-23 11:31:41 +08009736 [ALC888_FUJITSU_XA3530] = {
9737 .mixers = { alc888_base_mixer, alc883_chmode_mixer },
9738 .init_verbs = { alc883_init_verbs,
9739 alc888_fujitsu_xa3530_verbs },
9740 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9741 .dac_nids = alc883_dac_nids,
9742 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
9743 .adc_nids = alc883_adc_nids_rev,
9744 .capsrc_nids = alc883_capsrc_nids_rev,
9745 .dig_out_nid = ALC883_DIGOUT_NID,
9746 .num_channel_mode = ARRAY_SIZE(alc888_4ST_8ch_intel_modes),
9747 .channel_mode = alc888_4ST_8ch_intel_modes,
9748 .num_mux_defs =
9749 ARRAY_SIZE(alc888_2_capture_sources),
9750 .input_mux = alc888_2_capture_sources,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009751 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009752 .setup = alc888_fujitsu_xa3530_setup,
9753 .init_hook = alc_automute_amp,
Vincent Petryef8ef5f2008-11-23 11:31:41 +08009754 },
Kailang Yange2757d52008-08-26 13:17:46 +02009755 [ALC888_LENOVO_SKY] = {
9756 .mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer },
9757 .init_verbs = { alc883_init_verbs, alc888_lenovo_sky_verbs},
9758 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9759 .dac_nids = alc883_dac_nids,
9760 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yange2757d52008-08-26 13:17:46 +02009761 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
9762 .channel_mode = alc883_sixstack_modes,
9763 .need_dac_fix = 1,
9764 .input_mux = &alc883_lenovo_sky_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009765 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009766 .setup = alc888_lenovo_sky_setup,
9767 .init_hook = alc_automute_amp,
Kailang Yange2757d52008-08-26 13:17:46 +02009768 },
9769 [ALC888_ASUS_M90V] = {
9770 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
9771 .init_verbs = { alc883_init_verbs, alc888_asus_m90v_verbs },
9772 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9773 .dac_nids = alc883_dac_nids,
9774 .dig_out_nid = ALC883_DIGOUT_NID,
9775 .dig_in_nid = ALC883_DIGIN_NID,
9776 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
9777 .channel_mode = alc883_3ST_6ch_modes,
9778 .need_dac_fix = 1,
9779 .input_mux = &alc883_fujitsu_pi2515_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009780 .unsol_event = alc_sku_unsol_event,
9781 .setup = alc883_mode2_setup,
9782 .init_hook = alc_inithook,
Kailang Yange2757d52008-08-26 13:17:46 +02009783 },
9784 [ALC888_ASUS_EEE1601] = {
9785 .mixers = { alc883_asus_eee1601_mixer },
Takashi Iwaif9e336f2008-10-31 16:37:07 +01009786 .cap_mixer = alc883_asus_eee1601_cap_mixer,
Kailang Yange2757d52008-08-26 13:17:46 +02009787 .init_verbs = { alc883_init_verbs, alc888_asus_eee1601_verbs },
9788 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9789 .dac_nids = alc883_dac_nids,
9790 .dig_out_nid = ALC883_DIGOUT_NID,
9791 .dig_in_nid = ALC883_DIGIN_NID,
9792 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9793 .channel_mode = alc883_3ST_2ch_modes,
9794 .need_dac_fix = 1,
9795 .input_mux = &alc883_asus_eee1601_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009796 .unsol_event = alc_sku_unsol_event,
Kailang Yange2757d52008-08-26 13:17:46 +02009797 .init_hook = alc883_eee1601_inithook,
9798 },
Wu Fengguang3ab90932008-11-17 09:51:09 +01009799 [ALC1200_ASUS_P5Q] = {
9800 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
9801 .init_verbs = { alc883_init_verbs },
9802 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9803 .dac_nids = alc883_dac_nids,
9804 .dig_out_nid = ALC1200_DIGOUT_NID,
9805 .dig_in_nid = ALC883_DIGIN_NID,
Wu Fengguangb25c9da2009-02-06 15:02:27 +08009806 .slave_dig_outs = alc1200_slave_dig_outs,
Wu Fengguang3ab90932008-11-17 09:51:09 +01009807 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
9808 .channel_mode = alc883_sixstack_modes,
9809 .input_mux = &alc883_capture_source,
9810 },
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009811 [ALC889A_MB31] = {
9812 .mixers = { alc889A_mb31_mixer, alc883_chmode_mixer},
9813 .init_verbs = { alc883_init_verbs, alc889A_mb31_verbs,
9814 alc880_gpio1_init_verbs },
9815 .adc_nids = alc883_adc_nids,
9816 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
Takashi Iwai035eb0c2009-12-17 15:00:26 +01009817 .capsrc_nids = alc883_capsrc_nids,
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009818 .dac_nids = alc883_dac_nids,
9819 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9820 .channel_mode = alc889A_mb31_6ch_modes,
9821 .num_channel_mode = ARRAY_SIZE(alc889A_mb31_6ch_modes),
9822 .input_mux = &alc889A_mb31_capture_source,
9823 .dig_out_nid = ALC883_DIGOUT_NID,
9824 .unsol_event = alc889A_mb31_unsol_event,
9825 .init_hook = alc889A_mb31_automute,
9826 },
Guido Günther3e1647c2009-06-05 00:47:26 +02009827 [ALC883_SONY_VAIO_TT] = {
9828 .mixers = { alc883_vaiott_mixer },
9829 .init_verbs = { alc883_init_verbs, alc883_vaiott_verbs },
9830 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
9831 .dac_nids = alc883_dac_nids,
9832 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
9833 .channel_mode = alc883_3ST_2ch_modes,
9834 .input_mux = &alc883_capture_source,
9835 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009836 .setup = alc883_vaiott_setup,
9837 .init_hook = alc_automute_amp,
Guido Günther3e1647c2009-06-05 00:47:26 +02009838 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009839};
9840
9841
9842/*
Takashi Iwai4953550a2009-06-30 15:28:30 +02009843 * Pin config fixes
9844 */
9845enum {
9846 PINFIX_ABIT_AW9D_MAX
9847};
9848
9849static struct alc_pincfg alc882_abit_aw9d_pinfix[] = {
9850 { 0x15, 0x01080104 }, /* side */
9851 { 0x16, 0x01011012 }, /* rear */
9852 { 0x17, 0x01016011 }, /* clfe */
9853 { }
9854};
9855
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02009856static const struct alc_fixup alc882_fixups[] = {
9857 [PINFIX_ABIT_AW9D_MAX] = {
9858 .pins = alc882_abit_aw9d_pinfix
9859 },
Takashi Iwai4953550a2009-06-30 15:28:30 +02009860};
9861
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02009862static struct snd_pci_quirk alc882_fixup_tbl[] = {
Takashi Iwai4953550a2009-06-30 15:28:30 +02009863 SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
9864 {}
9865};
9866
9867/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009868 * BIOS auto configuration
9869 */
Takashi Iwai05f5f472009-08-25 13:10:18 +02009870static int alc882_auto_create_input_ctls(struct hda_codec *codec,
9871 const struct auto_pin_cfg *cfg)
9872{
9873 return alc_auto_create_input_ctls(codec, cfg, 0x0b, 0x23, 0x22);
9874}
9875
Takashi Iwai4953550a2009-06-30 15:28:30 +02009876static void alc882_auto_set_output_and_unmute(struct hda_codec *codec,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009877 hda_nid_t nid, int pin_type,
9878 int dac_idx)
9879{
9880 /* set as output */
9881 struct alc_spec *spec = codec->spec;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009882 int idx;
9883
Takashi Iwaif6c7e542008-02-12 18:32:23 +01009884 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009885 if (spec->multiout.dac_nids[dac_idx] == 0x25)
9886 idx = 4;
9887 else
9888 idx = spec->multiout.dac_nids[dac_idx] - 2;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009889 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
9890
9891}
9892
Takashi Iwai4953550a2009-06-30 15:28:30 +02009893static void alc882_auto_init_multi_out(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009894{
9895 struct alc_spec *spec = codec->spec;
9896 int i;
9897
9898 for (i = 0; i <= HDA_SIDE; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009899 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02009900 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009901 if (nid)
Takashi Iwai4953550a2009-06-30 15:28:30 +02009902 alc882_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009903 i);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009904 }
9905}
9906
Takashi Iwai4953550a2009-06-30 15:28:30 +02009907static void alc882_auto_init_hp_out(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009908{
9909 struct alc_spec *spec = codec->spec;
9910 hda_nid_t pin;
9911
Takashi Iwaieb06ed82006-09-20 17:10:27 +02009912 pin = spec->autocfg.hp_pins[0];
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009913 if (pin) /* connect to front */
9914 /* use dac 0 */
Takashi Iwai4953550a2009-06-30 15:28:30 +02009915 alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01009916 pin = spec->autocfg.speaker_pins[0];
9917 if (pin)
Takashi Iwai4953550a2009-06-30 15:28:30 +02009918 alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009919}
9920
Takashi Iwai4953550a2009-06-30 15:28:30 +02009921static void alc882_auto_init_analog_input(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009922{
9923 struct alc_spec *spec = codec->spec;
9924 int i;
9925
9926 for (i = 0; i < AUTO_PIN_LAST; i++) {
9927 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwai4953550a2009-06-30 15:28:30 +02009928 if (!nid)
9929 continue;
Takashi Iwai0d971c92009-06-30 16:11:11 +02009930 alc_set_input_pin(codec, nid, i);
Takashi Iwai4953550a2009-06-30 15:28:30 +02009931 if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
9932 snd_hda_codec_write(codec, nid, 0,
9933 AC_VERB_SET_AMP_GAIN_MUTE,
9934 AMP_OUT_MUTE);
9935 }
9936}
9937
9938static void alc882_auto_init_input_src(struct hda_codec *codec)
9939{
9940 struct alc_spec *spec = codec->spec;
9941 int c;
9942
9943 for (c = 0; c < spec->num_adc_nids; c++) {
9944 hda_nid_t conn_list[HDA_MAX_NUM_INPUTS];
9945 hda_nid_t nid = spec->capsrc_nids[c];
9946 unsigned int mux_idx;
9947 const struct hda_input_mux *imux;
9948 int conns, mute, idx, item;
9949
9950 conns = snd_hda_get_connections(codec, nid, conn_list,
9951 ARRAY_SIZE(conn_list));
9952 if (conns < 0)
9953 continue;
9954 mux_idx = c >= spec->num_mux_defs ? 0 : c;
9955 imux = &spec->input_mux[mux_idx];
9956 for (idx = 0; idx < conns; idx++) {
9957 /* if the current connection is the selected one,
9958 * unmute it as default - otherwise mute it
9959 */
9960 mute = AMP_IN_MUTE(idx);
9961 for (item = 0; item < imux->num_items; item++) {
9962 if (imux->items[item].index == idx) {
9963 if (spec->cur_mux[c] == item)
9964 mute = AMP_IN_UNMUTE(idx);
9965 break;
9966 }
9967 }
9968 /* check if we have a selector or mixer
9969 * we could check for the widget type instead, but
9970 * just check for Amp-In presence (in case of mixer
9971 * without amp-in there is something wrong, this
9972 * function shouldn't be used or capsrc nid is wrong)
9973 */
9974 if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009975 snd_hda_codec_write(codec, nid, 0,
9976 AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwai4953550a2009-06-30 15:28:30 +02009977 mute);
9978 else if (mute != AMP_IN_MUTE(idx))
9979 snd_hda_codec_write(codec, nid, 0,
9980 AC_VERB_SET_CONNECT_SEL,
9981 idx);
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009982 }
9983 }
9984}
9985
Takashi Iwai4953550a2009-06-30 15:28:30 +02009986/* add mic boosts if needed */
9987static int alc_auto_add_mic_boost(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009988{
9989 struct alc_spec *spec = codec->spec;
Takashi Iwai4953550a2009-06-30 15:28:30 +02009990 int err;
9991 hda_nid_t nid;
9992
9993 nid = spec->autocfg.input_pins[AUTO_PIN_MIC];
9994 if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
9995 err = add_control(spec, ALC_CTL_WIDGET_VOL,
9996 "Mic Boost",
9997 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
9998 if (err < 0)
9999 return err;
10000 }
10001 nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC];
10002 if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
10003 err = add_control(spec, ALC_CTL_WIDGET_VOL,
10004 "Front Mic Boost",
10005 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
10006 if (err < 0)
10007 return err;
10008 }
10009 return 0;
10010}
10011
10012/* almost identical with ALC880 parser... */
10013static int alc882_parse_auto_config(struct hda_codec *codec)
10014{
10015 struct alc_spec *spec = codec->spec;
Takashi Iwai05f5f472009-08-25 13:10:18 +020010016 static hda_nid_t alc882_ignore[] = { 0x1d, 0 };
10017 int i, err;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010018
Takashi Iwai05f5f472009-08-25 13:10:18 +020010019 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
10020 alc882_ignore);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010021 if (err < 0)
10022 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020010023 if (!spec->autocfg.line_outs)
10024 return 0; /* can't find valid BIOS pin config */
10025
10026 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
10027 if (err < 0)
10028 return err;
10029 err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
10030 if (err < 0)
10031 return err;
10032 err = alc880_auto_create_extra_out(spec,
10033 spec->autocfg.speaker_pins[0],
10034 "Speaker");
10035 if (err < 0)
10036 return err;
10037 err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
10038 "Headphone");
10039 if (err < 0)
10040 return err;
10041 err = alc882_auto_create_input_ctls(codec, &spec->autocfg);
10042 if (err < 0)
10043 return err;
10044
10045 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
10046
10047 /* check multiple SPDIF-out (for recent codecs) */
10048 for (i = 0; i < spec->autocfg.dig_outs; i++) {
10049 hda_nid_t dig_nid;
10050 err = snd_hda_get_connections(codec,
10051 spec->autocfg.dig_out_pins[i],
10052 &dig_nid, 1);
10053 if (err < 0)
10054 continue;
10055 if (!i)
10056 spec->multiout.dig_out_nid = dig_nid;
10057 else {
10058 spec->multiout.slave_dig_outs = spec->slave_dig_outs;
Roel Kluin71121d9f2009-11-10 20:11:55 +010010059 if (i >= ARRAY_SIZE(spec->slave_dig_outs) - 1)
Takashi Iwai05f5f472009-08-25 13:10:18 +020010060 break;
Roel Kluin71121d9f2009-11-10 20:11:55 +010010061 spec->slave_dig_outs[i - 1] = dig_nid;
Takashi Iwai05f5f472009-08-25 13:10:18 +020010062 }
10063 }
10064 if (spec->autocfg.dig_in_pin)
10065 spec->dig_in_nid = ALC880_DIGIN_NID;
10066
10067 if (spec->kctls.list)
10068 add_mixer(spec, spec->kctls.list);
10069
10070 add_verb(spec, alc883_auto_init_verbs);
10071 /* if ADC 0x07 is available, initialize it, too */
10072 if (get_wcaps_type(get_wcaps(codec, 0x07)) == AC_WID_AUD_IN)
10073 add_verb(spec, alc882_adc1_init_verbs);
10074
10075 spec->num_mux_defs = 1;
10076 spec->input_mux = &spec->private_imux[0];
10077
10078 alc_ssid_check(codec, 0x15, 0x1b, 0x14);
Takashi Iwai776e1842007-08-29 15:07:11 +020010079
10080 err = alc_auto_add_mic_boost(codec);
10081 if (err < 0)
10082 return err;
10083
Takashi Iwai776e1842007-08-29 15:07:11 +020010084 return 1; /* config found */
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010085}
10086
10087/* additional initialization for auto-configuration model */
Takashi Iwai4953550a2009-06-30 15:28:30 +020010088static void alc882_auto_init(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010089{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010090 struct alc_spec *spec = codec->spec;
Takashi Iwai4953550a2009-06-30 15:28:30 +020010091 alc882_auto_init_multi_out(codec);
10092 alc882_auto_init_hp_out(codec);
10093 alc882_auto_init_analog_input(codec);
10094 alc882_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010095 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020010096 alc_inithook(codec);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010097}
10098
Takashi Iwai4953550a2009-06-30 15:28:30 +020010099static int patch_alc882(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010100{
10101 struct alc_spec *spec;
10102 int err, board_config;
10103
10104 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
10105 if (spec == NULL)
10106 return -ENOMEM;
10107
10108 codec->spec = spec;
10109
Takashi Iwai4953550a2009-06-30 15:28:30 +020010110 switch (codec->vendor_id) {
10111 case 0x10ec0882:
10112 case 0x10ec0885:
10113 break;
10114 default:
10115 /* ALC883 and variants */
10116 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
10117 break;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010118 }
10119
Takashi Iwai4953550a2009-06-30 15:28:30 +020010120 board_config = snd_hda_check_board_config(codec, ALC882_MODEL_LAST,
10121 alc882_models,
10122 alc882_cfg_tbl);
10123
10124 if (board_config < 0 || board_config >= ALC882_MODEL_LAST)
10125 board_config = snd_hda_check_board_codec_sid_config(codec,
10126 ALC882_MODEL_LAST, alc882_models, alc882_ssid_cfg_tbl);
10127
10128 if (board_config < 0 || board_config >= ALC882_MODEL_LAST) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020010129 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
Takashi Iwai4953550a2009-06-30 15:28:30 +020010130 codec->chip_name);
10131 board_config = ALC882_AUTO;
10132 }
10133
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020010134 alc_pick_fixup(codec, alc882_fixup_tbl, alc882_fixups);
Takashi Iwai4953550a2009-06-30 15:28:30 +020010135
10136 if (board_config == ALC882_AUTO) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010137 /* automatic parse from the BIOS config */
Takashi Iwai4953550a2009-06-30 15:28:30 +020010138 err = alc882_parse_auto_config(codec);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010139 if (err < 0) {
10140 alc_free(codec);
10141 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010142 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010143 printk(KERN_INFO
10144 "hda_codec: Cannot set up configuration "
10145 "from BIOS. Using base mode...\n");
Takashi Iwai4953550a2009-06-30 15:28:30 +020010146 board_config = ALC882_3ST_DIG;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010147 }
10148 }
10149
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090010150 err = snd_hda_attach_beep_device(codec, 0x1);
10151 if (err < 0) {
10152 alc_free(codec);
10153 return err;
10154 }
10155
Takashi Iwai4953550a2009-06-30 15:28:30 +020010156 if (board_config != ALC882_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020010157 setup_preset(codec, &alc882_presets[board_config]);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010158
Takashi Iwai4953550a2009-06-30 15:28:30 +020010159 spec->stream_analog_playback = &alc882_pcm_analog_playback;
10160 spec->stream_analog_capture = &alc882_pcm_analog_capture;
10161 /* FIXME: setup DAC5 */
10162 /*spec->stream_analog_alt_playback = &alc880_pcm_analog_alt_playback;*/
10163 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
10164
10165 spec->stream_digital_playback = &alc882_pcm_digital_playback;
10166 spec->stream_digital_capture = &alc882_pcm_digital_capture;
10167
10168 if (codec->vendor_id == 0x10ec0888)
Takashi Iwai4a79ba32009-04-22 16:31:35 +020010169 spec->init_amp = ALC_INIT_DEFAULT; /* always initialize */
Takashi Iwai4953550a2009-06-30 15:28:30 +020010170
10171 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwaid11f74c2009-12-08 12:52:47 +010010172 int i, j;
Takashi Iwai4953550a2009-06-30 15:28:30 +020010173 spec->num_adc_nids = 0;
10174 for (i = 0; i < ARRAY_SIZE(alc882_adc_nids); i++) {
Takashi Iwaid11f74c2009-12-08 12:52:47 +010010175 const struct hda_input_mux *imux = spec->input_mux;
Takashi Iwai4953550a2009-06-30 15:28:30 +020010176 hda_nid_t cap;
Takashi Iwaid11f74c2009-12-08 12:52:47 +010010177 hda_nid_t items[16];
Takashi Iwai4953550a2009-06-30 15:28:30 +020010178 hda_nid_t nid = alc882_adc_nids[i];
10179 unsigned int wcap = get_wcaps(codec, nid);
10180 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +020010181 wcap = get_wcaps_type(wcap);
Takashi Iwai4953550a2009-06-30 15:28:30 +020010182 if (wcap != AC_WID_AUD_IN)
10183 continue;
10184 spec->private_adc_nids[spec->num_adc_nids] = nid;
10185 err = snd_hda_get_connections(codec, nid, &cap, 1);
10186 if (err < 0)
10187 continue;
Takashi Iwaid11f74c2009-12-08 12:52:47 +010010188 err = snd_hda_get_connections(codec, cap, items,
10189 ARRAY_SIZE(items));
10190 if (err < 0)
10191 continue;
10192 for (j = 0; j < imux->num_items; j++)
10193 if (imux->items[j].index >= err)
10194 break;
10195 if (j < imux->num_items)
10196 continue;
Takashi Iwai4953550a2009-06-30 15:28:30 +020010197 spec->private_capsrc_nids[spec->num_adc_nids] = cap;
10198 spec->num_adc_nids++;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020010199 }
Takashi Iwai4953550a2009-06-30 15:28:30 +020010200 spec->adc_nids = spec->private_adc_nids;
10201 spec->capsrc_nids = spec->private_capsrc_nids;
Kailang Yang2f893282008-05-27 12:14:47 +020010202 }
10203
Takashi Iwaib59bdf32009-08-11 09:47:30 +020010204 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010010205 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010206
Takashi Iwai2134ea42008-01-10 16:53:55 +010010207 spec->vmaster_nid = 0x0c;
10208
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010209 codec->patch_ops = alc_patch_ops;
Takashi Iwai4953550a2009-06-30 15:28:30 +020010210 if (board_config == ALC882_AUTO)
10211 spec->init_hook = alc882_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020010212#ifdef CONFIG_SND_HDA_POWER_SAVE
10213 if (!spec->loopback.amplist)
Takashi Iwai4953550a2009-06-30 15:28:30 +020010214 spec->loopback.amplist = alc882_loopbacks;
Takashi Iwaicb53c622007-08-10 17:21:45 +020010215#endif
Takashi Iwaidaead532008-11-28 12:55:36 +010010216 codec->proc_widget_hook = print_realtek_coef;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010217
10218 return 0;
10219}
10220
Takashi Iwai4953550a2009-06-30 15:28:30 +020010221
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010222/*
Kailang Yangdf694da2005-12-05 19:42:22 +010010223 * ALC262 support
10224 */
10225
10226#define ALC262_DIGOUT_NID ALC880_DIGOUT_NID
10227#define ALC262_DIGIN_NID ALC880_DIGIN_NID
10228
10229#define alc262_dac_nids alc260_dac_nids
10230#define alc262_adc_nids alc882_adc_nids
10231#define alc262_adc_nids_alt alc882_adc_nids_alt
Takashi Iwai88c71a92008-02-14 17:27:17 +010010232#define alc262_capsrc_nids alc882_capsrc_nids
10233#define alc262_capsrc_nids_alt alc882_capsrc_nids_alt
Kailang Yangdf694da2005-12-05 19:42:22 +010010234
10235#define alc262_modes alc260_modes
Takashi Iwaic5f2ea02005-12-06 18:54:31 +010010236#define alc262_capture_source alc882_capture_source
Kailang Yangdf694da2005-12-05 19:42:22 +010010237
Kailang Yang4e555fe2008-08-26 13:05:55 +020010238static hda_nid_t alc262_dmic_adc_nids[1] = {
10239 /* ADC0 */
10240 0x09
10241};
10242
10243static hda_nid_t alc262_dmic_capsrc_nids[1] = { 0x22 };
10244
Kailang Yangdf694da2005-12-05 19:42:22 +010010245static struct snd_kcontrol_new alc262_base_mixer[] = {
10246 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
10247 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
10248 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
10249 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
10250 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
10251 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
10252 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10253 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +010010254 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +010010255 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
10256 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +010010257 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +010010258 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),
10259 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
10260 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
10261 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +010010262 { } /* end */
Takashi Iwai834be882006-03-01 14:16:17 +010010263};
10264
Takashi Iwaice875f02008-01-28 18:17:43 +010010265/* update HP, line and mono-out pins according to the master switch */
10266static void alc262_hp_master_update(struct hda_codec *codec)
10267{
10268 struct alc_spec *spec = codec->spec;
10269 int val = spec->master_sw;
10270
10271 /* HP & line-out */
10272 snd_hda_codec_write_cache(codec, 0x1b, 0,
10273 AC_VERB_SET_PIN_WIDGET_CONTROL,
10274 val ? PIN_HP : 0);
10275 snd_hda_codec_write_cache(codec, 0x15, 0,
10276 AC_VERB_SET_PIN_WIDGET_CONTROL,
10277 val ? PIN_HP : 0);
10278 /* mono (speaker) depending on the HP jack sense */
10279 val = val && !spec->jack_present;
10280 snd_hda_codec_write_cache(codec, 0x16, 0,
10281 AC_VERB_SET_PIN_WIDGET_CONTROL,
10282 val ? PIN_OUT : 0);
10283}
10284
10285static void alc262_hp_bpc_automute(struct hda_codec *codec)
10286{
10287 struct alc_spec *spec = codec->spec;
Wu Fengguang864f92b2009-11-18 12:38:02 +080010288
10289 spec->jack_present = snd_hda_jack_detect(codec, 0x1b);
Takashi Iwaice875f02008-01-28 18:17:43 +010010290 alc262_hp_master_update(codec);
10291}
10292
10293static void alc262_hp_bpc_unsol_event(struct hda_codec *codec, unsigned int res)
10294{
10295 if ((res >> 26) != ALC880_HP_EVENT)
10296 return;
10297 alc262_hp_bpc_automute(codec);
10298}
10299
10300static void alc262_hp_wildwest_automute(struct hda_codec *codec)
10301{
10302 struct alc_spec *spec = codec->spec;
Wu Fengguang864f92b2009-11-18 12:38:02 +080010303
10304 spec->jack_present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwaice875f02008-01-28 18:17:43 +010010305 alc262_hp_master_update(codec);
10306}
10307
10308static void alc262_hp_wildwest_unsol_event(struct hda_codec *codec,
10309 unsigned int res)
10310{
10311 if ((res >> 26) != ALC880_HP_EVENT)
10312 return;
10313 alc262_hp_wildwest_automute(codec);
10314}
10315
Takashi Iwaib72519b2009-05-08 14:31:55 +020010316#define alc262_hp_master_sw_get alc260_hp_master_sw_get
Takashi Iwaice875f02008-01-28 18:17:43 +010010317
10318static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol,
10319 struct snd_ctl_elem_value *ucontrol)
10320{
10321 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
10322 struct alc_spec *spec = codec->spec;
10323 int val = !!*ucontrol->value.integer.value;
10324
10325 if (val == spec->master_sw)
10326 return 0;
10327 spec->master_sw = val;
10328 alc262_hp_master_update(codec);
10329 return 1;
10330}
10331
Takashi Iwaib72519b2009-05-08 14:31:55 +020010332#define ALC262_HP_MASTER_SWITCH \
10333 { \
10334 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
10335 .name = "Master Playback Switch", \
10336 .info = snd_ctl_boolean_mono_info, \
10337 .get = alc262_hp_master_sw_get, \
10338 .put = alc262_hp_master_sw_put, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010010339 }, \
10340 { \
10341 .iface = NID_MAPPING, \
10342 .name = "Master Playback Switch", \
10343 .private_value = 0x15 | (0x16 << 8) | (0x1b << 16), \
Takashi Iwaib72519b2009-05-08 14:31:55 +020010344 }
10345
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010010346
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010347static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
Takashi Iwaib72519b2009-05-08 14:31:55 +020010348 ALC262_HP_MASTER_SWITCH,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010349 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
10350 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
10351 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +010010352 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
10353 HDA_OUTPUT),
10354 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
10355 HDA_OUTPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010356 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10357 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +010010358 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010359 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
10360 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +010010361 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010362 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
10363 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
10364 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
10365 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010366 HDA_CODEC_VOLUME("AUX IN Playback Volume", 0x0b, 0x06, HDA_INPUT),
10367 HDA_CODEC_MUTE("AUX IN Playback Switch", 0x0b, 0x06, HDA_INPUT),
10368 { } /* end */
10369};
10370
Kailang Yangcd7509a2007-01-26 18:33:17 +010010371static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = {
Takashi Iwaib72519b2009-05-08 14:31:55 +020010372 ALC262_HP_MASTER_SWITCH,
Kailang Yangcd7509a2007-01-26 18:33:17 +010010373 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
10374 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
10375 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
10376 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +010010377 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
10378 HDA_OUTPUT),
10379 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
10380 HDA_OUTPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010381 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT),
10382 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +010010383 HDA_CODEC_VOLUME("Front Mic Boost", 0x1a, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010384 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
10385 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
10386 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
10387 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010388 { } /* end */
10389};
10390
10391static struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = {
10392 HDA_CODEC_VOLUME("Rear Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10393 HDA_CODEC_MUTE("Rear Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaicc69d122007-02-15 19:29:26 +010010394 HDA_CODEC_VOLUME("Rear Mic Boost", 0x18, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010010395 { } /* end */
10396};
10397
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010398/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010399static void alc262_hp_t5735_setup(struct hda_codec *codec)
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010400{
10401 struct alc_spec *spec = codec->spec;
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010402
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010403 spec->autocfg.hp_pins[0] = 0x15;
10404 spec->autocfg.speaker_pins[0] = 0x0c; /* HACK: not actually a pin */
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010405}
10406
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010407static struct snd_kcontrol_new alc262_hp_t5735_mixer[] = {
Takashi Iwai86cd9292008-01-28 18:09:56 +010010408 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
10409 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang66d2a9d2007-11-14 12:06:21 +010010410 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
10411 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
10412 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10413 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
10414 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10415 { } /* end */
10416};
10417
10418static struct hda_verb alc262_hp_t5735_verbs[] = {
10419 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
10420 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
10421
10422 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
10423 { }
10424};
10425
Kailang Yang8c427222008-01-10 13:03:59 +010010426static struct snd_kcontrol_new alc262_hp_rp5700_mixer[] = {
Takashi Iwaif2f48e12008-01-28 18:14:43 +010010427 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
10428 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010010429 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
10430 HDA_CODEC_MUTE("Speaker Playback Switch", 0x16, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010010431 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
10432 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
10433 { } /* end */
10434};
10435
10436static struct hda_verb alc262_hp_rp5700_verbs[] = {
10437 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10438 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10439 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
10440 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
10441 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
10442 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
10443 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
10444 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
10445 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
10446 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
10447 {}
10448};
10449
10450static struct hda_input_mux alc262_hp_rp5700_capture_source = {
10451 .num_items = 1,
10452 .items = {
10453 { "Line", 0x1 },
10454 },
10455};
10456
Takashi Iwai42171c12009-05-08 14:11:43 +020010457/* bind hp and internal speaker mute (with plug check) as master switch */
10458static void alc262_hippo_master_update(struct hda_codec *codec)
10459{
10460 struct alc_spec *spec = codec->spec;
10461 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
10462 hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
10463 hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
10464 unsigned int mute;
10465
10466 /* HP */
10467 mute = spec->master_sw ? 0 : HDA_AMP_MUTE;
10468 snd_hda_codec_amp_stereo(codec, hp_nid, HDA_OUTPUT, 0,
10469 HDA_AMP_MUTE, mute);
10470 /* mute internal speaker per jack sense */
10471 if (spec->jack_present)
10472 mute = HDA_AMP_MUTE;
10473 if (line_nid)
10474 snd_hda_codec_amp_stereo(codec, line_nid, HDA_OUTPUT, 0,
10475 HDA_AMP_MUTE, mute);
10476 if (speaker_nid && speaker_nid != line_nid)
10477 snd_hda_codec_amp_stereo(codec, speaker_nid, HDA_OUTPUT, 0,
10478 HDA_AMP_MUTE, mute);
10479}
10480
10481#define alc262_hippo_master_sw_get alc262_hp_master_sw_get
10482
10483static int alc262_hippo_master_sw_put(struct snd_kcontrol *kcontrol,
10484 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai0724ea22007-08-23 00:31:43 +020010485{
10486 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
Takashi Iwai42171c12009-05-08 14:11:43 +020010487 struct alc_spec *spec = codec->spec;
10488 int val = !!*ucontrol->value.integer.value;
Takashi Iwai0724ea22007-08-23 00:31:43 +020010489
Takashi Iwai42171c12009-05-08 14:11:43 +020010490 if (val == spec->master_sw)
10491 return 0;
10492 spec->master_sw = val;
10493 alc262_hippo_master_update(codec);
10494 return 1;
Takashi Iwai0724ea22007-08-23 00:31:43 +020010495}
Takashi Iwai5b319542007-07-26 11:49:22 +020010496
Takashi Iwai42171c12009-05-08 14:11:43 +020010497#define ALC262_HIPPO_MASTER_SWITCH \
10498 { \
10499 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
10500 .name = "Master Playback Switch", \
10501 .info = snd_ctl_boolean_mono_info, \
10502 .get = alc262_hippo_master_sw_get, \
10503 .put = alc262_hippo_master_sw_put, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010010504 }, \
10505 { \
10506 .iface = NID_MAPPING, \
10507 .name = "Master Playback Switch", \
10508 .subdevice = SUBDEV_HP(0) | (SUBDEV_LINE(0) << 8) | \
10509 (SUBDEV_SPEAKER(0) << 16), \
Takashi Iwai42171c12009-05-08 14:11:43 +020010510 }
10511
10512static struct snd_kcontrol_new alc262_hippo_mixer[] = {
10513 ALC262_HIPPO_MASTER_SWITCH,
10514 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
10515 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
10516 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
10517 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
10518 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
10519 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10520 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
10521 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10522 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
10523 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
10524 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
10525 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
10526 { } /* end */
10527};
10528
10529static struct snd_kcontrol_new alc262_hippo1_mixer[] = {
10530 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
10531 ALC262_HIPPO_MASTER_SWITCH,
10532 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
10533 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
10534 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
10535 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
10536 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10537 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
10538 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10539 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
10540 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
10541 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
10542 { } /* end */
10543};
10544
10545/* mute/unmute internal speaker according to the hp jack and mute state */
10546static void alc262_hippo_automute(struct hda_codec *codec)
10547{
10548 struct alc_spec *spec = codec->spec;
10549 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
Takashi Iwai42171c12009-05-08 14:11:43 +020010550
Wu Fengguang864f92b2009-11-18 12:38:02 +080010551 spec->jack_present = snd_hda_jack_detect(codec, hp_nid);
Takashi Iwai42171c12009-05-08 14:11:43 +020010552 alc262_hippo_master_update(codec);
10553}
10554
10555static void alc262_hippo_unsol_event(struct hda_codec *codec, unsigned int res)
10556{
10557 if ((res >> 26) != ALC880_HP_EVENT)
10558 return;
10559 alc262_hippo_automute(codec);
10560}
10561
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010562static void alc262_hippo_setup(struct hda_codec *codec)
Takashi Iwai42171c12009-05-08 14:11:43 +020010563{
10564 struct alc_spec *spec = codec->spec;
10565
10566 spec->autocfg.hp_pins[0] = 0x15;
10567 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai42171c12009-05-08 14:11:43 +020010568}
10569
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010570static void alc262_hippo1_setup(struct hda_codec *codec)
Takashi Iwai42171c12009-05-08 14:11:43 +020010571{
10572 struct alc_spec *spec = codec->spec;
10573
10574 spec->autocfg.hp_pins[0] = 0x1b;
10575 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai42171c12009-05-08 14:11:43 +020010576}
10577
10578
Kailang Yang272a5272007-05-14 11:00:38 +020010579static struct snd_kcontrol_new alc262_sony_mixer[] = {
Takashi Iwai0724ea22007-08-23 00:31:43 +020010580 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020010581 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yang272a5272007-05-14 11:00:38 +020010582 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10583 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
10584 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
10585 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
10586 { } /* end */
10587};
10588
Kailang Yang83c34212007-07-05 11:43:05 +020010589static struct snd_kcontrol_new alc262_benq_t31_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020010590 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
10591 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yang83c34212007-07-05 11:43:05 +020010592 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
10593 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10594 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
10595 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
10596 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
10597 { } /* end */
10598};
Kailang Yang272a5272007-05-14 11:00:38 +020010599
Tony Vroonba340e82009-02-02 19:01:30 +000010600static struct snd_kcontrol_new alc262_tyan_mixer[] = {
10601 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
10602 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
10603 HDA_CODEC_VOLUME("Aux Playback Volume", 0x0b, 0x06, HDA_INPUT),
10604 HDA_CODEC_MUTE("Aux Playback Switch", 0x0b, 0x06, HDA_INPUT),
10605 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
10606 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
10607 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10608 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
10609 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10610 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
10611 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
10612 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
10613 { } /* end */
10614};
10615
10616static struct hda_verb alc262_tyan_verbs[] = {
10617 /* Headphone automute */
10618 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
10619 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
10620 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
10621
10622 /* P11 AUX_IN, white 4-pin connector */
10623 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
10624 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_1, 0xe1},
10625 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_2, 0x93},
10626 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0x19},
10627
10628 {}
10629};
10630
10631/* unsolicited event for HP jack sensing */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010632static void alc262_tyan_setup(struct hda_codec *codec)
Tony Vroonba340e82009-02-02 19:01:30 +000010633{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010634 struct alc_spec *spec = codec->spec;
Tony Vroonba340e82009-02-02 19:01:30 +000010635
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010636 spec->autocfg.hp_pins[0] = 0x1b;
10637 spec->autocfg.speaker_pins[0] = 0x15;
Tony Vroonba340e82009-02-02 19:01:30 +000010638}
10639
Tony Vroonba340e82009-02-02 19:01:30 +000010640
Kailang Yangdf694da2005-12-05 19:42:22 +010010641#define alc262_capture_mixer alc882_capture_mixer
10642#define alc262_capture_alt_mixer alc882_capture_alt_mixer
10643
10644/*
10645 * generic initialization of ADC, input mixers and output mixers
10646 */
10647static struct hda_verb alc262_init_verbs[] = {
10648 /*
10649 * Unmute ADC0-2 and set the default input to mic-in
10650 */
10651 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
10652 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10653 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
10654 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10655 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
10656 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10657
Takashi Iwaicb53c622007-08-10 17:21:45 +020010658 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +010010659 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010660 * Note: PASD motherboards uses the Line In 2 as the input for
10661 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +010010662 */
10663 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020010664 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
10665 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
10666 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
10667 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
10668 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +010010669
10670 /*
10671 * Set up output mixers (0x0c - 0x0e)
10672 */
10673 /* set vol=0 to output mixers */
10674 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10675 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10676 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
10677 /* set up input amps for analog loopback */
10678 /* Amp Indices: DAC = 0, mixer = 1 */
10679 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10680 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10681 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10682 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10683 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
10684 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10685
10686 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
10687 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
10688 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
10689 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
10690 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10691 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
10692
10693 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
10694 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
10695 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
10696 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
10697 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Kailang Yangea1fb292008-08-26 12:58:38 +020010698
Kailang Yangdf694da2005-12-05 19:42:22 +010010699 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
10700 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Kailang Yangea1fb292008-08-26 12:58:38 +020010701
Kailang Yangdf694da2005-12-05 19:42:22 +010010702 /* FIXME: use matrix-type input source selection */
10703 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
10704 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
10705 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10706 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
10707 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
10708 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
10709 /* Input mixer2 */
10710 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10711 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
10712 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
10713 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
10714 /* Input mixer3 */
10715 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
10716 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
10717 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010718 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
Kailang Yangdf694da2005-12-05 19:42:22 +010010719
10720 { }
10721};
10722
Kailang Yang4e555fe2008-08-26 13:05:55 +020010723static struct hda_verb alc262_eapd_verbs[] = {
10724 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
10725 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
10726 { }
10727};
10728
Kailang Yangccc656c2006-10-17 12:32:26 +020010729static struct hda_verb alc262_hippo1_unsol_verbs[] = {
10730 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
10731 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
10732 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
10733
10734 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
10735 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
10736 {}
10737};
10738
Kailang Yang272a5272007-05-14 11:00:38 +020010739static struct hda_verb alc262_sony_unsol_verbs[] = {
10740 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
10741 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
10742 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, // Front Mic
10743
10744 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
10745 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Akio Idehara7b1e8792008-06-09 22:46:07 +090010746 {}
Kailang Yang272a5272007-05-14 11:00:38 +020010747};
10748
Kailang Yang4e555fe2008-08-26 13:05:55 +020010749static struct snd_kcontrol_new alc262_toshiba_s06_mixer[] = {
10750 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
10751 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
10752 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
10753 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10754 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang4e555fe2008-08-26 13:05:55 +020010755 { } /* end */
10756};
10757
10758static struct hda_verb alc262_toshiba_s06_verbs[] = {
10759 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
10760 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
10761 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
10762 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
10763 {0x22, AC_VERB_SET_CONNECT_SEL, 0x09},
10764 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
10765 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
10766 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
10767 {}
10768};
10769
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010770static void alc262_toshiba_s06_setup(struct hda_codec *codec)
Kailang Yang4e555fe2008-08-26 13:05:55 +020010771{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010772 struct alc_spec *spec = codec->spec;
10773
10774 spec->autocfg.hp_pins[0] = 0x15;
10775 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010776 spec->ext_mic.pin = 0x18;
10777 spec->ext_mic.mux_idx = 0;
10778 spec->int_mic.pin = 0x12;
10779 spec->int_mic.mux_idx = 9;
10780 spec->auto_mic = 1;
Kailang Yang4e555fe2008-08-26 13:05:55 +020010781}
10782
Takashi Iwai834be882006-03-01 14:16:17 +010010783/*
Pascal Terjane8f9ae22008-08-04 14:36:05 +020010784 * nec model
10785 * 0x15 = headphone
10786 * 0x16 = internal speaker
10787 * 0x18 = external mic
10788 */
10789
10790static struct snd_kcontrol_new alc262_nec_mixer[] = {
10791 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
10792 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 0, 0x0, HDA_OUTPUT),
10793
10794 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
10795 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
10796 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
10797
10798 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
10799 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
10800 { } /* end */
10801};
10802
10803static struct hda_verb alc262_nec_verbs[] = {
10804 /* Unmute Speaker */
10805 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
10806
10807 /* Headphone */
10808 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
10809 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
10810
10811 /* External mic to headphone */
10812 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10813 /* External mic to speaker */
10814 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
10815 {}
10816};
10817
10818/*
Takashi Iwai834be882006-03-01 14:16:17 +010010819 * fujitsu model
Tony Vroon5d9fab22008-03-14 17:09:18 +010010820 * 0x14 = headphone/spdif-out, 0x15 = internal speaker,
10821 * 0x1b = port replicator headphone out
Takashi Iwai834be882006-03-01 14:16:17 +010010822 */
10823
10824#define ALC_HP_EVENT 0x37
10825
10826static struct hda_verb alc262_fujitsu_unsol_verbs[] = {
10827 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
10828 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Tony Vroon5d9fab22008-03-14 17:09:18 +010010829 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
10830 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai834be882006-03-01 14:16:17 +010010831 {}
10832};
10833
Jiang zhe0e31daf2008-03-20 12:12:39 +010010834static struct hda_verb alc262_lenovo_3000_unsol_verbs[] = {
10835 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
10836 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
10837 {}
10838};
10839
Daniel T Chene2595322009-12-19 18:19:02 -050010840static struct hda_verb alc262_lenovo_3000_init_verbs[] = {
10841 /* Front Mic pin: input vref at 50% */
10842 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
10843 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
10844 {}
10845};
10846
Takashi Iwai834be882006-03-01 14:16:17 +010010847static struct hda_input_mux alc262_fujitsu_capture_source = {
Takashi Iwai39d3ed32007-10-12 15:03:48 +020010848 .num_items = 3,
Takashi Iwai834be882006-03-01 14:16:17 +010010849 .items = {
10850 { "Mic", 0x0 },
Takashi Iwai39d3ed32007-10-12 15:03:48 +020010851 { "Int Mic", 0x1 },
Takashi Iwai834be882006-03-01 14:16:17 +010010852 { "CD", 0x4 },
10853 },
10854};
10855
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010856static struct hda_input_mux alc262_HP_capture_source = {
10857 .num_items = 5,
10858 .items = {
10859 { "Mic", 0x0 },
zhejiangaccbe492007-08-31 12:36:05 +020010860 { "Front Mic", 0x1 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010861 { "Line", 0x2 },
10862 { "CD", 0x4 },
10863 { "AUX IN", 0x6 },
10864 },
10865};
10866
zhejiangaccbe492007-08-31 12:36:05 +020010867static struct hda_input_mux alc262_HP_D7000_capture_source = {
10868 .num_items = 4,
10869 .items = {
10870 { "Mic", 0x0 },
10871 { "Front Mic", 0x2 },
10872 { "Line", 0x1 },
10873 { "CD", 0x4 },
10874 },
10875};
10876
Takashi Iwaiebc7a402008-05-20 09:23:05 +020010877/* mute/unmute internal speaker according to the hp jacks and mute state */
Takashi Iwai834be882006-03-01 14:16:17 +010010878static void alc262_fujitsu_automute(struct hda_codec *codec, int force)
10879{
10880 struct alc_spec *spec = codec->spec;
10881 unsigned int mute;
10882
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010883 if (force || !spec->sense_updated) {
Wu Fengguang864f92b2009-11-18 12:38:02 +080010884 spec->jack_present = snd_hda_jack_detect(codec, 0x14) ||
10885 snd_hda_jack_detect(codec, 0x1b);
Takashi Iwai834be882006-03-01 14:16:17 +010010886 spec->sense_updated = 1;
10887 }
Takashi Iwaiebc7a402008-05-20 09:23:05 +020010888 /* unmute internal speaker only if both HPs are unplugged and
10889 * master switch is on
10890 */
10891 if (spec->jack_present)
10892 mute = HDA_AMP_MUTE;
10893 else
Takashi Iwai834be882006-03-01 14:16:17 +010010894 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
Takashi Iwaiebc7a402008-05-20 09:23:05 +020010895 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
10896 HDA_AMP_MUTE, mute);
Takashi Iwai834be882006-03-01 14:16:17 +010010897}
10898
10899/* unsolicited event for HP jack sensing */
10900static void alc262_fujitsu_unsol_event(struct hda_codec *codec,
10901 unsigned int res)
10902{
10903 if ((res >> 26) != ALC_HP_EVENT)
10904 return;
10905 alc262_fujitsu_automute(codec, 1);
10906}
10907
Takashi Iwaiebc7a402008-05-20 09:23:05 +020010908static void alc262_fujitsu_init_hook(struct hda_codec *codec)
10909{
10910 alc262_fujitsu_automute(codec, 1);
10911}
10912
Takashi Iwai834be882006-03-01 14:16:17 +010010913/* bind volumes of both NID 0x0c and 0x0d */
Takashi Iwaicca3b372007-08-10 17:12:15 +020010914static struct hda_bind_ctls alc262_fujitsu_bind_master_vol = {
10915 .ops = &snd_hda_bind_vol,
10916 .values = {
10917 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT),
10918 HDA_COMPOSE_AMP_VAL(0x0d, 3, 0, HDA_OUTPUT),
10919 0
10920 },
10921};
Takashi Iwai834be882006-03-01 14:16:17 +010010922
Jiang zhe0e31daf2008-03-20 12:12:39 +010010923/* mute/unmute internal speaker according to the hp jack and mute state */
10924static void alc262_lenovo_3000_automute(struct hda_codec *codec, int force)
10925{
10926 struct alc_spec *spec = codec->spec;
10927 unsigned int mute;
10928
10929 if (force || !spec->sense_updated) {
Wu Fengguang864f92b2009-11-18 12:38:02 +080010930 spec->jack_present = snd_hda_jack_detect(codec, 0x1b);
Jiang zhe0e31daf2008-03-20 12:12:39 +010010931 spec->sense_updated = 1;
10932 }
10933 if (spec->jack_present) {
10934 /* mute internal speaker */
10935 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
10936 HDA_AMP_MUTE, HDA_AMP_MUTE);
10937 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
10938 HDA_AMP_MUTE, HDA_AMP_MUTE);
10939 } else {
10940 /* unmute internal speaker if necessary */
10941 mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
10942 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
10943 HDA_AMP_MUTE, mute);
10944 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
10945 HDA_AMP_MUTE, mute);
10946 }
10947}
10948
10949/* unsolicited event for HP jack sensing */
10950static void alc262_lenovo_3000_unsol_event(struct hda_codec *codec,
10951 unsigned int res)
10952{
10953 if ((res >> 26) != ALC_HP_EVENT)
10954 return;
10955 alc262_lenovo_3000_automute(codec, 1);
10956}
10957
Takashi Iwai8de56b72009-07-24 16:51:47 +020010958static int amp_stereo_mute_update(struct hda_codec *codec, hda_nid_t nid,
10959 int dir, int idx, long *valp)
10960{
10961 int i, change = 0;
10962
10963 for (i = 0; i < 2; i++, valp++)
10964 change |= snd_hda_codec_amp_update(codec, nid, i, dir, idx,
10965 HDA_AMP_MUTE,
10966 *valp ? 0 : HDA_AMP_MUTE);
10967 return change;
10968}
10969
Takashi Iwai834be882006-03-01 14:16:17 +010010970/* bind hp and internal speaker mute (with plug check) */
10971static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol,
10972 struct snd_ctl_elem_value *ucontrol)
10973{
10974 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
10975 long *valp = ucontrol->value.integer.value;
10976 int change;
10977
Takashi Iwai8de56b72009-07-24 16:51:47 +020010978 change = amp_stereo_mute_update(codec, 0x14, HDA_OUTPUT, 0, valp);
10979 change |= amp_stereo_mute_update(codec, 0x1b, HDA_OUTPUT, 0, valp);
Takashi Iwai82beb8f2007-08-10 17:09:26 +020010980 if (change)
10981 alc262_fujitsu_automute(codec, 0);
Takashi Iwai834be882006-03-01 14:16:17 +010010982 return change;
10983}
10984
10985static struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +020010986 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
Takashi Iwai834be882006-03-01 14:16:17 +010010987 {
10988 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10989 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010010990 .subdevice = HDA_SUBDEV_AMP_FLAG,
Takashi Iwai834be882006-03-01 14:16:17 +010010991 .info = snd_hda_mixer_amp_switch_info,
10992 .get = snd_hda_mixer_amp_switch_get,
10993 .put = alc262_fujitsu_master_sw_put,
10994 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
10995 },
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010010996 {
10997 .iface = NID_MAPPING,
10998 .name = "Master Playback Switch",
10999 .private_value = 0x1b,
11000 },
Takashi Iwai834be882006-03-01 14:16:17 +010011001 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11002 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11003 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11004 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11005 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai39d3ed32007-10-12 15:03:48 +020011006 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
11007 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
11008 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai834be882006-03-01 14:16:17 +010011009 { } /* end */
11010};
11011
Jiang zhe0e31daf2008-03-20 12:12:39 +010011012/* bind hp and internal speaker mute (with plug check) */
11013static int alc262_lenovo_3000_master_sw_put(struct snd_kcontrol *kcontrol,
11014 struct snd_ctl_elem_value *ucontrol)
11015{
11016 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
11017 long *valp = ucontrol->value.integer.value;
11018 int change;
11019
Takashi Iwai8de56b72009-07-24 16:51:47 +020011020 change = amp_stereo_mute_update(codec, 0x1b, HDA_OUTPUT, 0, valp);
Jiang zhe0e31daf2008-03-20 12:12:39 +010011021 if (change)
11022 alc262_lenovo_3000_automute(codec, 0);
11023 return change;
11024}
11025
11026static struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = {
11027 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
11028 {
11029 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11030 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010011031 .subdevice = HDA_SUBDEV_AMP_FLAG,
Jiang zhe0e31daf2008-03-20 12:12:39 +010011032 .info = snd_hda_mixer_amp_switch_info,
11033 .get = snd_hda_mixer_amp_switch_get,
11034 .put = alc262_lenovo_3000_master_sw_put,
11035 .private_value = HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
11036 },
11037 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11038 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11039 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11040 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11041 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11042 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
11043 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
11044 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
11045 { } /* end */
11046};
11047
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011048static struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = {
11049 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
Takashi Iwai42171c12009-05-08 14:11:43 +020011050 ALC262_HIPPO_MASTER_SWITCH,
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011051 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11052 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11053 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
11054 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11055 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11056 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
11057 { } /* end */
11058};
11059
Takashi Iwai304dcaa2006-07-25 14:51:16 +020011060/* additional init verbs for Benq laptops */
11061static struct hda_verb alc262_EAPD_verbs[] = {
11062 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
11063 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
11064 {}
11065};
11066
Kailang Yang83c34212007-07-05 11:43:05 +020011067static struct hda_verb alc262_benq_t31_EAPD_verbs[] = {
11068 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11069 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11070
11071 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
11072 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
11073 {}
11074};
11075
Tobin Davisf651b502007-10-26 12:40:47 +020011076/* Samsung Q1 Ultra Vista model setup */
11077static struct snd_kcontrol_new alc262_ultra_mixer[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011078 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11079 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +020011080 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11081 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11082 HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011083 HDA_CODEC_VOLUME("Headphone Mic Boost", 0x15, 0, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +020011084 { } /* end */
11085};
11086
11087static struct hda_verb alc262_ultra_verbs[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011088 /* output mixer */
11089 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11090 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11091 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11092 /* speaker */
11093 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11094 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11095 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11096 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
11097 /* HP */
Tobin Davisf651b502007-10-26 12:40:47 +020011098 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011099 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11100 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11101 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11102 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11103 /* internal mic */
11104 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
11105 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11106 /* ADC, choose mic */
11107 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11108 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11109 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11110 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
11111 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
11112 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
11113 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
11114 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
11115 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
11116 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(8)},
Tobin Davisf651b502007-10-26 12:40:47 +020011117 {}
11118};
11119
Tobin Davisf651b502007-10-26 12:40:47 +020011120/* mute/unmute internal speaker according to the hp jack and mute state */
11121static void alc262_ultra_automute(struct hda_codec *codec)
11122{
11123 struct alc_spec *spec = codec->spec;
11124 unsigned int mute;
Tobin Davisf651b502007-10-26 12:40:47 +020011125
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011126 mute = 0;
11127 /* auto-mute only when HP is used as HP */
11128 if (!spec->cur_mux[0]) {
Wu Fengguang864f92b2009-11-18 12:38:02 +080011129 spec->jack_present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011130 if (spec->jack_present)
11131 mute = HDA_AMP_MUTE;
Tobin Davisf651b502007-10-26 12:40:47 +020011132 }
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011133 /* mute/unmute internal speaker */
11134 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
11135 HDA_AMP_MUTE, mute);
11136 /* mute/unmute HP */
11137 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
11138 HDA_AMP_MUTE, mute ? 0 : HDA_AMP_MUTE);
Tobin Davisf651b502007-10-26 12:40:47 +020011139}
11140
11141/* unsolicited event for HP jack sensing */
11142static void alc262_ultra_unsol_event(struct hda_codec *codec,
11143 unsigned int res)
11144{
11145 if ((res >> 26) != ALC880_HP_EVENT)
11146 return;
11147 alc262_ultra_automute(codec);
11148}
11149
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011150static struct hda_input_mux alc262_ultra_capture_source = {
11151 .num_items = 2,
11152 .items = {
11153 { "Mic", 0x1 },
11154 { "Headphone", 0x7 },
11155 },
11156};
11157
11158static int alc262_ultra_mux_enum_put(struct snd_kcontrol *kcontrol,
11159 struct snd_ctl_elem_value *ucontrol)
11160{
11161 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
11162 struct alc_spec *spec = codec->spec;
11163 int ret;
11164
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010011165 ret = alc_mux_enum_put(kcontrol, ucontrol);
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011166 if (!ret)
11167 return 0;
11168 /* reprogram the HP pin as mic or HP according to the input source */
11169 snd_hda_codec_write_cache(codec, 0x15, 0,
11170 AC_VERB_SET_PIN_WIDGET_CONTROL,
11171 spec->cur_mux[0] ? PIN_VREF80 : PIN_HP);
11172 alc262_ultra_automute(codec); /* mute/unmute HP */
11173 return ret;
11174}
11175
11176static struct snd_kcontrol_new alc262_ultra_capture_mixer[] = {
11177 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
11178 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
11179 {
11180 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11181 .name = "Capture Source",
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010011182 .info = alc_mux_enum_info,
11183 .get = alc_mux_enum_get,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011184 .put = alc262_ultra_mux_enum_put,
11185 },
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011186 {
11187 .iface = NID_MAPPING,
11188 .name = "Capture Source",
11189 .private_value = 0x15,
11190 },
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011191 { } /* end */
11192};
11193
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011194/* We use two mixers depending on the output pin; 0x16 is a mono output
11195 * and thus it's bound with a different mixer.
11196 * This function returns which mixer amp should be used.
11197 */
11198static int alc262_check_volbit(hda_nid_t nid)
11199{
11200 if (!nid)
11201 return 0;
11202 else if (nid == 0x16)
11203 return 2;
11204 else
11205 return 1;
11206}
11207
11208static int alc262_add_out_vol_ctl(struct alc_spec *spec, hda_nid_t nid,
11209 const char *pfx, int *vbits)
11210{
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011211 unsigned long val;
11212 int vbit;
11213
11214 vbit = alc262_check_volbit(nid);
11215 if (!vbit)
11216 return 0;
11217 if (*vbits & vbit) /* a volume control for this mixer already there */
11218 return 0;
11219 *vbits |= vbit;
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011220 if (vbit == 2)
11221 val = HDA_COMPOSE_AMP_VAL(0x0e, 2, 0, HDA_OUTPUT);
11222 else
11223 val = HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT);
Takashi Iwai0afe5f82009-10-02 09:20:00 +020011224 return add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, val);
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011225}
11226
11227static int alc262_add_out_sw_ctl(struct alc_spec *spec, hda_nid_t nid,
11228 const char *pfx)
11229{
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011230 unsigned long val;
11231
11232 if (!nid)
11233 return 0;
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011234 if (nid == 0x16)
11235 val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
11236 else
11237 val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
Takashi Iwai0afe5f82009-10-02 09:20:00 +020011238 return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, val);
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011239}
11240
Kailang Yangdf694da2005-12-05 19:42:22 +010011241/* add playback controls from the parsed DAC table */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011242static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
11243 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010011244{
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011245 const char *pfx;
11246 int vbits;
Kailang Yangdf694da2005-12-05 19:42:22 +010011247 int err;
11248
11249 spec->multiout.num_dacs = 1; /* only use one dac */
11250 spec->multiout.dac_nids = spec->private_dac_nids;
11251 spec->multiout.dac_nids[0] = 2;
11252
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011253 if (!cfg->speaker_pins[0] && !cfg->hp_pins[0])
11254 pfx = "Master";
11255 else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
11256 pfx = "Speaker";
11257 else
11258 pfx = "Front";
11259 err = alc262_add_out_sw_ctl(spec, cfg->line_out_pins[0], pfx);
11260 if (err < 0)
11261 return err;
11262 err = alc262_add_out_sw_ctl(spec, cfg->speaker_pins[0], "Speaker");
11263 if (err < 0)
11264 return err;
11265 err = alc262_add_out_sw_ctl(spec, cfg->hp_pins[0], "Headphone");
11266 if (err < 0)
11267 return err;
Kailang Yangdf694da2005-12-05 19:42:22 +010011268
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011269 vbits = alc262_check_volbit(cfg->line_out_pins[0]) |
11270 alc262_check_volbit(cfg->speaker_pins[0]) |
11271 alc262_check_volbit(cfg->hp_pins[0]);
11272 if (vbits == 1 || vbits == 2)
11273 pfx = "Master"; /* only one mixer is used */
11274 else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
11275 pfx = "Speaker";
11276 else
11277 pfx = "Front";
11278 vbits = 0;
11279 err = alc262_add_out_vol_ctl(spec, cfg->line_out_pins[0], pfx, &vbits);
11280 if (err < 0)
11281 return err;
11282 err = alc262_add_out_vol_ctl(spec, cfg->speaker_pins[0], "Speaker",
11283 &vbits);
11284 if (err < 0)
11285 return err;
11286 err = alc262_add_out_vol_ctl(spec, cfg->hp_pins[0], "Headphone",
11287 &vbits);
11288 if (err < 0)
11289 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011290 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +010011291}
11292
Takashi Iwai05f5f472009-08-25 13:10:18 +020011293#define alc262_auto_create_input_ctls \
11294 alc880_auto_create_input_ctls
Kailang Yangdf694da2005-12-05 19:42:22 +010011295
11296/*
11297 * generic initialization of ADC, input mixers and output mixers
11298 */
11299static struct hda_verb alc262_volume_init_verbs[] = {
11300 /*
11301 * Unmute ADC0-2 and set the default input to mic-in
11302 */
11303 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
11304 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11305 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
11306 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11307 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
11308 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11309
Takashi Iwaicb53c622007-08-10 17:21:45 +020011310 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +010011311 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011312 * Note: PASD motherboards uses the Line In 2 as the input for
11313 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +010011314 */
11315 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020011316 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11317 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11318 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
11319 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
11320 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +010011321
11322 /*
11323 * Set up output mixers (0x0c - 0x0f)
11324 */
11325 /* set vol=0 to output mixers */
11326 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11327 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11328 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yangea1fb292008-08-26 12:58:38 +020011329
Kailang Yangdf694da2005-12-05 19:42:22 +010011330 /* set up input amps for analog loopback */
11331 /* Amp Indices: DAC = 0, mixer = 1 */
11332 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11333 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11334 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11335 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11336 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11337 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11338
11339 /* FIXME: use matrix-type input source selection */
11340 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
11341 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
11342 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11343 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11344 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11345 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11346 /* Input mixer2 */
11347 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11348 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11349 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11350 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11351 /* Input mixer3 */
11352 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11353 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11354 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11355 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11356
11357 { }
11358};
11359
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011360static struct hda_verb alc262_HP_BPC_init_verbs[] = {
11361 /*
11362 * Unmute ADC0-2 and set the default input to mic-in
11363 */
11364 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
11365 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11366 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
11367 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11368 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
11369 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11370
Takashi Iwaicb53c622007-08-10 17:21:45 +020011371 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011372 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011373 * Note: PASD motherboards uses the Line In 2 as the input for
11374 * front panel mic (mic 2)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011375 */
11376 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020011377 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11378 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11379 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
11380 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
11381 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
11382 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
11383 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
Kailang Yangea1fb292008-08-26 12:58:38 +020011384
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011385 /*
11386 * Set up output mixers (0x0c - 0x0e)
11387 */
11388 /* set vol=0 to output mixers */
11389 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11390 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11391 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11392
11393 /* set up input amps for analog loopback */
11394 /* Amp Indices: DAC = 0, mixer = 1 */
11395 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11396 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11397 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11398 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11399 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11400 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11401
Takashi Iwaice875f02008-01-28 18:17:43 +010011402 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011403 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
11404 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
11405
11406 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
11407 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
11408
11409 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
11410 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11411
11412 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11413 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11414 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11415 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11416 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11417
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020011418 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011419 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
11420 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020011421 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011422 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
11423 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
11424
11425
11426 /* FIXME: use matrix-type input source selection */
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020011427 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 0b, 12 */
11428 /* Input mixer1: only unmute Mic */
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011429 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020011430 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
11431 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11432 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11433 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11434 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
11435 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
11436 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
11437 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011438 /* Input mixer2 */
11439 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020011440 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
11441 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11442 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11443 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11444 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
11445 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
11446 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
11447 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011448 /* Input mixer3 */
11449 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020011450 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
11451 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11452 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11453 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11454 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
11455 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
11456 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
11457 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011458
Takashi Iwaice875f02008-01-28 18:17:43 +010011459 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
11460
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011461 { }
11462};
11463
Kailang Yangcd7509a2007-01-26 18:33:17 +010011464static struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = {
11465 /*
11466 * Unmute ADC0-2 and set the default input to mic-in
11467 */
11468 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
11469 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11470 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
11471 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11472 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
11473 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11474
Takashi Iwaicb53c622007-08-10 17:21:45 +020011475 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangcd7509a2007-01-26 18:33:17 +010011476 * mixer widget
11477 * Note: PASD motherboards uses the Line In 2 as the input for front
11478 * panel mic (mic 2)
11479 */
11480 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020011481 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11482 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11483 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
11484 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
11485 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
11486 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
11487 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
11488 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Kailang Yangcd7509a2007-01-26 18:33:17 +010011489 /*
11490 * Set up output mixers (0x0c - 0x0e)
11491 */
11492 /* set vol=0 to output mixers */
11493 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11494 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11495 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11496
11497 /* set up input amps for analog loopback */
11498 /* Amp Indices: DAC = 0, mixer = 1 */
11499 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11500 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11501 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11502 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11503 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11504 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11505
11506
11507 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP */
11508 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Mono */
11509 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* rear MIC */
11510 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* Line in */
11511 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
11512 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Line out */
11513 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD in */
11514
11515 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
11516 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
11517
11518 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
11519 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
11520
11521 /* {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, */
11522 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
11523 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
11524 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
11525 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
11526 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
11527
11528 /* FIXME: use matrix-type input source selection */
11529 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
11530 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
11531 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, /*rear MIC*/
11532 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, /*Line in*/
11533 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, /*F MIC*/
11534 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, /*Front*/
11535 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, /*CD*/
11536 /* {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
11537 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, /*HP*/
11538 /* Input mixer2 */
11539 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11540 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
11541 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
11542 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
11543 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
11544 /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
11545 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
11546 /* Input mixer3 */
11547 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11548 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
11549 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
11550 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
11551 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
11552 /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
11553 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
11554
Takashi Iwaice875f02008-01-28 18:17:43 +010011555 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
11556
Kailang Yangcd7509a2007-01-26 18:33:17 +010011557 { }
11558};
11559
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011560static struct hda_verb alc262_toshiba_rx1_unsol_verbs[] = {
11561
11562 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Front Speaker */
11563 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
11564 {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
11565
11566 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* MIC jack */
11567 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
11568 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
11569 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
11570
11571 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP jack */
11572 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11573 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11574 {}
11575};
11576
11577
Takashi Iwaicb53c622007-08-10 17:21:45 +020011578#ifdef CONFIG_SND_HDA_POWER_SAVE
11579#define alc262_loopbacks alc880_loopbacks
11580#endif
11581
Sasha Alexandrdef319f2009-06-16 16:00:15 -040011582/* pcm configuration: identical with ALC880 */
Kailang Yangdf694da2005-12-05 19:42:22 +010011583#define alc262_pcm_analog_playback alc880_pcm_analog_playback
11584#define alc262_pcm_analog_capture alc880_pcm_analog_capture
11585#define alc262_pcm_digital_playback alc880_pcm_digital_playback
11586#define alc262_pcm_digital_capture alc880_pcm_digital_capture
11587
11588/*
11589 * BIOS auto configuration
11590 */
11591static int alc262_parse_auto_config(struct hda_codec *codec)
11592{
11593 struct alc_spec *spec = codec->spec;
11594 int err;
11595 static hda_nid_t alc262_ignore[] = { 0x1d, 0 };
11596
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011597 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
11598 alc262_ignore);
11599 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010011600 return err;
Takashi Iwaie64f14f2009-01-20 18:32:55 +010011601 if (!spec->autocfg.line_outs) {
Takashi Iwai0852d7a2009-02-11 11:35:15 +010011602 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
Takashi Iwaie64f14f2009-01-20 18:32:55 +010011603 spec->multiout.max_channels = 2;
11604 spec->no_analog = 1;
11605 goto dig_only;
11606 }
Kailang Yangdf694da2005-12-05 19:42:22 +010011607 return 0; /* can't find valid BIOS pin config */
Takashi Iwaie64f14f2009-01-20 18:32:55 +010011608 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011609 err = alc262_auto_create_multi_out_ctls(spec, &spec->autocfg);
11610 if (err < 0)
11611 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020011612 err = alc262_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011613 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010011614 return err;
11615
11616 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
11617
Takashi Iwaie64f14f2009-01-20 18:32:55 +010011618 dig_only:
Takashi Iwai0852d7a2009-02-11 11:35:15 +010011619 if (spec->autocfg.dig_outs) {
Kailang Yangdf694da2005-12-05 19:42:22 +010011620 spec->multiout.dig_out_nid = ALC262_DIGOUT_NID;
Takashi Iwai0852d7a2009-02-11 11:35:15 +010011621 spec->dig_out_type = spec->autocfg.dig_out_type[0];
Takashi Iwaie64f14f2009-01-20 18:32:55 +010011622 }
Kailang Yangdf694da2005-12-05 19:42:22 +010011623 if (spec->autocfg.dig_in_pin)
11624 spec->dig_in_nid = ALC262_DIGIN_NID;
11625
Takashi Iwai603c4012008-07-30 15:01:44 +020011626 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010011627 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +010011628
Takashi Iwaid88897e2008-10-31 15:01:37 +010011629 add_verb(spec, alc262_volume_init_verbs);
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020011630 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020011631 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010011632
Takashi Iwai776e1842007-08-29 15:07:11 +020011633 err = alc_auto_add_mic_boost(codec);
11634 if (err < 0)
11635 return err;
11636
Takashi Iwai4a79ba32009-04-22 16:31:35 +020011637 alc_ssid_check(codec, 0x15, 0x14, 0x1b);
11638
Kailang Yangdf694da2005-12-05 19:42:22 +010011639 return 1;
11640}
11641
11642#define alc262_auto_init_multi_out alc882_auto_init_multi_out
11643#define alc262_auto_init_hp_out alc882_auto_init_hp_out
11644#define alc262_auto_init_analog_input alc882_auto_init_analog_input
Takashi Iwaif511b012008-08-15 16:46:42 +020011645#define alc262_auto_init_input_src alc882_auto_init_input_src
Kailang Yangdf694da2005-12-05 19:42:22 +010011646
11647
11648/* init callback for auto-configuration model -- overriding the default init */
Takashi Iwaiae6b8132006-03-03 16:47:17 +010011649static void alc262_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010011650{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010011651 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010011652 alc262_auto_init_multi_out(codec);
11653 alc262_auto_init_hp_out(codec);
11654 alc262_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020011655 alc262_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010011656 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020011657 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010011658}
11659
11660/*
11661 * configuration and preset
11662 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011663static const char *alc262_models[ALC262_MODEL_LAST] = {
11664 [ALC262_BASIC] = "basic",
11665 [ALC262_HIPPO] = "hippo",
11666 [ALC262_HIPPO_1] = "hippo_1",
11667 [ALC262_FUJITSU] = "fujitsu",
11668 [ALC262_HP_BPC] = "hp-bpc",
Kailang Yangcd7509a2007-01-26 18:33:17 +010011669 [ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000",
Takashi Iwai61dc35d2007-11-14 12:26:44 +010011670 [ALC262_HP_TC_T5735] = "hp-tc-t5735",
Kailang Yang8c427222008-01-10 13:03:59 +010011671 [ALC262_HP_RP5700] = "hp-rp5700",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011672 [ALC262_BENQ_ED8] = "benq",
Takashi Iwai0f405022007-07-06 12:24:11 +020011673 [ALC262_BENQ_T31] = "benq-t31",
11674 [ALC262_SONY_ASSAMD] = "sony-assamd",
Takashi Iwai2922c9a2008-08-27 18:12:42 +020011675 [ALC262_TOSHIBA_S06] = "toshiba-s06",
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011676 [ALC262_TOSHIBA_RX1] = "toshiba-rx1",
Tobin Davisf651b502007-10-26 12:40:47 +020011677 [ALC262_ULTRA] = "ultra",
Jiang zhe0e31daf2008-03-20 12:12:39 +010011678 [ALC262_LENOVO_3000] = "lenovo-3000",
Pascal Terjane8f9ae22008-08-04 14:36:05 +020011679 [ALC262_NEC] = "nec",
Tony Vroonba340e82009-02-02 19:01:30 +000011680 [ALC262_TYAN] = "tyan",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011681 [ALC262_AUTO] = "auto",
11682};
11683
11684static struct snd_pci_quirk alc262_cfg_tbl[] = {
11685 SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO),
Pascal Terjane8f9ae22008-08-04 14:36:05 +020011686 SND_PCI_QUIRK(0x1033, 0x8895, "NEC Versa S9100", ALC262_NEC),
Takashi Iwaidea0a502009-02-09 17:14:52 +010011687 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1200, "HP xw series",
11688 ALC262_HP_BPC),
11689 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1300, "HP xw series",
11690 ALC262_HP_BPC),
Takashi Iwai53eff7e2009-02-27 17:49:44 +010011691 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1700, "HP xw series",
11692 ALC262_HP_BPC),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011693 SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011694 SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011695 SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011696 SND_PCI_QUIRK(0x103c, 0x2803, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011697 SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011698 SND_PCI_QUIRK(0x103c, 0x2805, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011699 SND_PCI_QUIRK(0x103c, 0x2806, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011700 SND_PCI_QUIRK(0x103c, 0x2807, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011701 SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC),
11702 SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC),
11703 SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC),
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011704 SND_PCI_QUIRK(0x103c, 0x302f, "HP Thin Client T5735",
11705 ALC262_HP_TC_T5735),
Kailang Yang8c427222008-01-10 13:03:59 +010011706 SND_PCI_QUIRK(0x103c, 0x2817, "HP RP5700", ALC262_HP_RP5700),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011707 SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011708 SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011709 SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD),
Takashi Iwaibd6afe32009-03-04 11:30:25 +010011710 SND_PCI_QUIRK(0x104d, 0x9016, "Sony VAIO", ALC262_AUTO), /* dig-only */
Takashi Iwai376b5082009-06-22 11:03:13 +020011711 SND_PCI_QUIRK(0x104d, 0x9025, "Sony VAIO Z21MN", ALC262_TOSHIBA_S06),
Daniel T Chen95491d92009-11-08 19:03:55 -050011712 SND_PCI_QUIRK(0x104d, 0x9035, "Sony VAIO VGN-FW170J", ALC262_AUTO),
Takashi Iwai12929ba2009-11-17 15:58:35 +010011713 SND_PCI_QUIRK(0x104d, 0x9047, "Sony VAIO Type G", ALC262_AUTO),
Takashi Iwaic5b51652009-11-17 16:01:58 +010011714#if 0 /* disable the quirk since model=auto works better in recent versions */
Takashi Iwaif872a912009-02-26 00:57:01 +010011715 SND_PCI_QUIRK_MASK(0x104d, 0xff00, 0x9000, "Sony VAIO",
11716 ALC262_SONY_ASSAMD),
Takashi Iwaic5b51652009-11-17 16:01:58 +010011717#endif
Akio Idehara36ca6e12008-06-09 22:57:40 +090011718 SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1",
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011719 ALC262_TOSHIBA_RX1),
Kailang Yang80ffe862008-10-15 11:23:27 +020011720 SND_PCI_QUIRK(0x1179, 0xff7b, "Toshiba S06", ALC262_TOSHIBA_S06),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011721 SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU),
Tony Vroon3f1eeae2008-02-25 16:44:13 +010011722 SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU),
Tony Vroonba340e82009-02-02 19:01:30 +000011723 SND_PCI_QUIRK(0x10f1, 0x2915, "Tyan Thunder n6650W", ALC262_TYAN),
Takashi Iwaidea0a502009-02-09 17:14:52 +010011724 SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc032, "Samsung Q1",
11725 ALC262_ULTRA),
Luke Yelavich3e420e72008-12-16 12:37:47 +110011726 SND_PCI_QUIRK(0x144d, 0xc510, "Samsung Q45", ALC262_HIPPO),
Jiang zhe0e31daf2008-03-20 12:12:39 +010011727 SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 y410", ALC262_LENOVO_3000),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011728 SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8),
Kailang Yang83c34212007-07-05 11:43:05 +020011729 SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010011730 SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1),
Kailang Yangdf694da2005-12-05 19:42:22 +010011731 {}
11732};
11733
11734static struct alc_config_preset alc262_presets[] = {
11735 [ALC262_BASIC] = {
11736 .mixers = { alc262_base_mixer },
11737 .init_verbs = { alc262_init_verbs },
11738 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11739 .dac_nids = alc262_dac_nids,
11740 .hp_nid = 0x03,
11741 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11742 .channel_mode = alc262_modes,
Takashi Iwaia3bcba32005-12-06 19:05:29 +010011743 .input_mux = &alc262_capture_source,
Kailang Yangdf694da2005-12-05 19:42:22 +010011744 },
Kailang Yangccc656c2006-10-17 12:32:26 +020011745 [ALC262_HIPPO] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020011746 .mixers = { alc262_hippo_mixer },
Wu Fengguang6732bd02009-07-30 09:19:14 +020011747 .init_verbs = { alc262_init_verbs, alc_hp15_unsol_verbs},
Kailang Yangccc656c2006-10-17 12:32:26 +020011748 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11749 .dac_nids = alc262_dac_nids,
11750 .hp_nid = 0x03,
11751 .dig_out_nid = ALC262_DIGOUT_NID,
11752 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11753 .channel_mode = alc262_modes,
11754 .input_mux = &alc262_capture_source,
11755 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011756 .setup = alc262_hippo_setup,
11757 .init_hook = alc262_hippo_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020011758 },
11759 [ALC262_HIPPO_1] = {
11760 .mixers = { alc262_hippo1_mixer },
11761 .init_verbs = { alc262_init_verbs, alc262_hippo1_unsol_verbs},
11762 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11763 .dac_nids = alc262_dac_nids,
11764 .hp_nid = 0x02,
11765 .dig_out_nid = ALC262_DIGOUT_NID,
11766 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11767 .channel_mode = alc262_modes,
11768 .input_mux = &alc262_capture_source,
Takashi Iwai42171c12009-05-08 14:11:43 +020011769 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011770 .setup = alc262_hippo1_setup,
11771 .init_hook = alc262_hippo_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020011772 },
Takashi Iwai834be882006-03-01 14:16:17 +010011773 [ALC262_FUJITSU] = {
11774 .mixers = { alc262_fujitsu_mixer },
Takashi Iwai39d3ed32007-10-12 15:03:48 +020011775 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
11776 alc262_fujitsu_unsol_verbs },
Takashi Iwai834be882006-03-01 14:16:17 +010011777 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11778 .dac_nids = alc262_dac_nids,
11779 .hp_nid = 0x03,
11780 .dig_out_nid = ALC262_DIGOUT_NID,
11781 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11782 .channel_mode = alc262_modes,
11783 .input_mux = &alc262_fujitsu_capture_source,
Takashi Iwaiae6b8132006-03-03 16:47:17 +010011784 .unsol_event = alc262_fujitsu_unsol_event,
Takashi Iwaiebc7a402008-05-20 09:23:05 +020011785 .init_hook = alc262_fujitsu_init_hook,
Takashi Iwai834be882006-03-01 14:16:17 +010011786 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011787 [ALC262_HP_BPC] = {
11788 .mixers = { alc262_HP_BPC_mixer },
11789 .init_verbs = { alc262_HP_BPC_init_verbs },
11790 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11791 .dac_nids = alc262_dac_nids,
11792 .hp_nid = 0x03,
11793 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11794 .channel_mode = alc262_modes,
11795 .input_mux = &alc262_HP_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010011796 .unsol_event = alc262_hp_bpc_unsol_event,
11797 .init_hook = alc262_hp_bpc_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011798 },
Kailang Yangcd7509a2007-01-26 18:33:17 +010011799 [ALC262_HP_BPC_D7000_WF] = {
11800 .mixers = { alc262_HP_BPC_WildWest_mixer },
11801 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
11802 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11803 .dac_nids = alc262_dac_nids,
11804 .hp_nid = 0x03,
11805 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11806 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +020011807 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010011808 .unsol_event = alc262_hp_wildwest_unsol_event,
11809 .init_hook = alc262_hp_wildwest_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011810 },
Kailang Yangcd7509a2007-01-26 18:33:17 +010011811 [ALC262_HP_BPC_D7000_WL] = {
11812 .mixers = { alc262_HP_BPC_WildWest_mixer,
11813 alc262_HP_BPC_WildWest_option_mixer },
11814 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
11815 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11816 .dac_nids = alc262_dac_nids,
11817 .hp_nid = 0x03,
11818 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11819 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +020011820 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010011821 .unsol_event = alc262_hp_wildwest_unsol_event,
11822 .init_hook = alc262_hp_wildwest_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011823 },
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011824 [ALC262_HP_TC_T5735] = {
11825 .mixers = { alc262_hp_t5735_mixer },
11826 .init_verbs = { alc262_init_verbs, alc262_hp_t5735_verbs },
11827 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11828 .dac_nids = alc262_dac_nids,
11829 .hp_nid = 0x03,
11830 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11831 .channel_mode = alc262_modes,
11832 .input_mux = &alc262_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011833 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011834 .setup = alc262_hp_t5735_setup,
11835 .init_hook = alc_automute_amp,
Kailang Yang8c427222008-01-10 13:03:59 +010011836 },
11837 [ALC262_HP_RP5700] = {
11838 .mixers = { alc262_hp_rp5700_mixer },
11839 .init_verbs = { alc262_init_verbs, alc262_hp_rp5700_verbs },
11840 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11841 .dac_nids = alc262_dac_nids,
11842 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11843 .channel_mode = alc262_modes,
11844 .input_mux = &alc262_hp_rp5700_capture_source,
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011845 },
Takashi Iwai304dcaa2006-07-25 14:51:16 +020011846 [ALC262_BENQ_ED8] = {
11847 .mixers = { alc262_base_mixer },
11848 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs },
11849 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11850 .dac_nids = alc262_dac_nids,
11851 .hp_nid = 0x03,
11852 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11853 .channel_mode = alc262_modes,
11854 .input_mux = &alc262_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011855 },
Kailang Yang272a5272007-05-14 11:00:38 +020011856 [ALC262_SONY_ASSAMD] = {
11857 .mixers = { alc262_sony_mixer },
11858 .init_verbs = { alc262_init_verbs, alc262_sony_unsol_verbs},
11859 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11860 .dac_nids = alc262_dac_nids,
11861 .hp_nid = 0x02,
11862 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11863 .channel_mode = alc262_modes,
11864 .input_mux = &alc262_capture_source,
11865 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011866 .setup = alc262_hippo_setup,
11867 .init_hook = alc262_hippo_automute,
Kailang Yang83c34212007-07-05 11:43:05 +020011868 },
11869 [ALC262_BENQ_T31] = {
11870 .mixers = { alc262_benq_t31_mixer },
Wu Fengguang6732bd02009-07-30 09:19:14 +020011871 .init_verbs = { alc262_init_verbs, alc262_benq_t31_EAPD_verbs,
11872 alc_hp15_unsol_verbs },
Kailang Yang83c34212007-07-05 11:43:05 +020011873 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11874 .dac_nids = alc262_dac_nids,
11875 .hp_nid = 0x03,
11876 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11877 .channel_mode = alc262_modes,
11878 .input_mux = &alc262_capture_source,
11879 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011880 .setup = alc262_hippo_setup,
11881 .init_hook = alc262_hippo_automute,
Kailang Yangea1fb292008-08-26 12:58:38 +020011882 },
Tobin Davisf651b502007-10-26 12:40:47 +020011883 [ALC262_ULTRA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010011884 .mixers = { alc262_ultra_mixer },
11885 .cap_mixer = alc262_ultra_capture_mixer,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011886 .init_verbs = { alc262_ultra_verbs },
Tobin Davisf651b502007-10-26 12:40:47 +020011887 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11888 .dac_nids = alc262_dac_nids,
Tobin Davisf651b502007-10-26 12:40:47 +020011889 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11890 .channel_mode = alc262_modes,
11891 .input_mux = &alc262_ultra_capture_source,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011892 .adc_nids = alc262_adc_nids, /* ADC0 */
11893 .capsrc_nids = alc262_capsrc_nids,
11894 .num_adc_nids = 1, /* single ADC */
Tobin Davisf651b502007-10-26 12:40:47 +020011895 .unsol_event = alc262_ultra_unsol_event,
11896 .init_hook = alc262_ultra_automute,
11897 },
Jiang zhe0e31daf2008-03-20 12:12:39 +010011898 [ALC262_LENOVO_3000] = {
11899 .mixers = { alc262_lenovo_3000_mixer },
11900 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
Daniel T Chene2595322009-12-19 18:19:02 -050011901 alc262_lenovo_3000_unsol_verbs,
11902 alc262_lenovo_3000_init_verbs },
Jiang zhe0e31daf2008-03-20 12:12:39 +010011903 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11904 .dac_nids = alc262_dac_nids,
11905 .hp_nid = 0x03,
11906 .dig_out_nid = ALC262_DIGOUT_NID,
11907 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11908 .channel_mode = alc262_modes,
11909 .input_mux = &alc262_fujitsu_capture_source,
11910 .unsol_event = alc262_lenovo_3000_unsol_event,
11911 },
Pascal Terjane8f9ae22008-08-04 14:36:05 +020011912 [ALC262_NEC] = {
11913 .mixers = { alc262_nec_mixer },
11914 .init_verbs = { alc262_nec_verbs },
11915 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11916 .dac_nids = alc262_dac_nids,
11917 .hp_nid = 0x03,
11918 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11919 .channel_mode = alc262_modes,
11920 .input_mux = &alc262_capture_source,
11921 },
Kailang Yang4e555fe2008-08-26 13:05:55 +020011922 [ALC262_TOSHIBA_S06] = {
11923 .mixers = { alc262_toshiba_s06_mixer },
11924 .init_verbs = { alc262_init_verbs, alc262_toshiba_s06_verbs,
11925 alc262_eapd_verbs },
11926 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11927 .capsrc_nids = alc262_dmic_capsrc_nids,
11928 .dac_nids = alc262_dac_nids,
11929 .adc_nids = alc262_dmic_adc_nids, /* ADC0 */
Takashi Iwaiae14ef62009-06-22 08:16:56 +020011930 .num_adc_nids = 1, /* single ADC */
Kailang Yang4e555fe2008-08-26 13:05:55 +020011931 .dig_out_nid = ALC262_DIGOUT_NID,
11932 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11933 .channel_mode = alc262_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011934 .unsol_event = alc_sku_unsol_event,
11935 .setup = alc262_toshiba_s06_setup,
11936 .init_hook = alc_inithook,
Kailang Yang4e555fe2008-08-26 13:05:55 +020011937 },
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011938 [ALC262_TOSHIBA_RX1] = {
11939 .mixers = { alc262_toshiba_rx1_mixer },
11940 .init_verbs = { alc262_init_verbs, alc262_toshiba_rx1_unsol_verbs },
11941 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11942 .dac_nids = alc262_dac_nids,
11943 .hp_nid = 0x03,
11944 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11945 .channel_mode = alc262_modes,
11946 .input_mux = &alc262_capture_source,
11947 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011948 .setup = alc262_hippo_setup,
11949 .init_hook = alc262_hippo_automute,
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011950 },
Tony Vroonba340e82009-02-02 19:01:30 +000011951 [ALC262_TYAN] = {
11952 .mixers = { alc262_tyan_mixer },
11953 .init_verbs = { alc262_init_verbs, alc262_tyan_verbs},
11954 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
11955 .dac_nids = alc262_dac_nids,
11956 .hp_nid = 0x02,
11957 .dig_out_nid = ALC262_DIGOUT_NID,
11958 .num_channel_mode = ARRAY_SIZE(alc262_modes),
11959 .channel_mode = alc262_modes,
11960 .input_mux = &alc262_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011961 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011962 .setup = alc262_tyan_setup,
11963 .init_hook = alc_automute_amp,
Tony Vroonba340e82009-02-02 19:01:30 +000011964 },
Kailang Yangdf694da2005-12-05 19:42:22 +010011965};
11966
11967static int patch_alc262(struct hda_codec *codec)
11968{
11969 struct alc_spec *spec;
11970 int board_config;
11971 int err;
11972
Robert P. J. Daydc041e02006-12-19 14:44:15 +010011973 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010011974 if (spec == NULL)
11975 return -ENOMEM;
11976
11977 codec->spec = spec;
11978#if 0
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011979 /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is
11980 * under-run
11981 */
Kailang Yangdf694da2005-12-05 19:42:22 +010011982 {
11983 int tmp;
11984 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
11985 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
11986 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
11987 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80);
11988 }
11989#endif
11990
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020011991 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
11992
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011993 board_config = snd_hda_check_board_config(codec, ALC262_MODEL_LAST,
11994 alc262_models,
11995 alc262_cfg_tbl);
Kailang Yangcd7509a2007-01-26 18:33:17 +010011996
Takashi Iwaif5fcc132006-11-24 17:07:44 +010011997 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020011998 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
11999 codec->chip_name);
Kailang Yangdf694da2005-12-05 19:42:22 +010012000 board_config = ALC262_AUTO;
12001 }
12002
12003 if (board_config == ALC262_AUTO) {
12004 /* automatic parse from the BIOS config */
12005 err = alc262_parse_auto_config(codec);
12006 if (err < 0) {
12007 alc_free(codec);
12008 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012009 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012010 printk(KERN_INFO
12011 "hda_codec: Cannot set up configuration "
12012 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010012013 board_config = ALC262_BASIC;
12014 }
12015 }
12016
Takashi Iwai07eba612009-02-19 08:06:35 +010012017 if (!spec->no_analog) {
12018 err = snd_hda_attach_beep_device(codec, 0x1);
12019 if (err < 0) {
12020 alc_free(codec);
12021 return err;
12022 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090012023 }
12024
Kailang Yangdf694da2005-12-05 19:42:22 +010012025 if (board_config != ALC262_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020012026 setup_preset(codec, &alc262_presets[board_config]);
Kailang Yangdf694da2005-12-05 19:42:22 +010012027
Kailang Yangdf694da2005-12-05 19:42:22 +010012028 spec->stream_analog_playback = &alc262_pcm_analog_playback;
12029 spec->stream_analog_capture = &alc262_pcm_analog_capture;
Kailang Yangea1fb292008-08-26 12:58:38 +020012030
Kailang Yangdf694da2005-12-05 19:42:22 +010012031 spec->stream_digital_playback = &alc262_pcm_digital_playback;
12032 spec->stream_digital_capture = &alc262_pcm_digital_capture;
12033
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012034 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwai8c927b42009-06-22 10:56:54 +020012035 int i;
12036 /* check whether the digital-mic has to be supported */
12037 for (i = 0; i < spec->input_mux->num_items; i++) {
12038 if (spec->input_mux->items[i].index >= 9)
12039 break;
12040 }
12041 if (i < spec->input_mux->num_items) {
12042 /* use only ADC0 */
12043 spec->adc_nids = alc262_dmic_adc_nids;
12044 spec->num_adc_nids = 1;
12045 spec->capsrc_nids = alc262_dmic_capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +010012046 } else {
Takashi Iwai8c927b42009-06-22 10:56:54 +020012047 /* all analog inputs */
12048 /* check whether NID 0x07 is valid */
12049 unsigned int wcap = get_wcaps(codec, 0x07);
12050
12051 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +020012052 wcap = get_wcaps_type(wcap);
Takashi Iwai8c927b42009-06-22 10:56:54 +020012053 if (wcap != AC_WID_AUD_IN) {
12054 spec->adc_nids = alc262_adc_nids_alt;
12055 spec->num_adc_nids =
12056 ARRAY_SIZE(alc262_adc_nids_alt);
12057 spec->capsrc_nids = alc262_capsrc_nids_alt;
12058 } else {
12059 spec->adc_nids = alc262_adc_nids;
12060 spec->num_adc_nids =
12061 ARRAY_SIZE(alc262_adc_nids);
12062 spec->capsrc_nids = alc262_capsrc_nids;
12063 }
Kailang Yangdf694da2005-12-05 19:42:22 +010012064 }
12065 }
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012066 if (!spec->cap_mixer && !spec->no_analog)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020012067 set_capture_mixer(codec);
Takashi Iwai07eba612009-02-19 08:06:35 +010012068 if (!spec->no_analog)
12069 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Kailang Yangdf694da2005-12-05 19:42:22 +010012070
Takashi Iwai2134ea42008-01-10 16:53:55 +010012071 spec->vmaster_nid = 0x0c;
12072
Kailang Yangdf694da2005-12-05 19:42:22 +010012073 codec->patch_ops = alc_patch_ops;
12074 if (board_config == ALC262_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +010012075 spec->init_hook = alc262_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020012076#ifdef CONFIG_SND_HDA_POWER_SAVE
12077 if (!spec->loopback.amplist)
12078 spec->loopback.amplist = alc262_loopbacks;
12079#endif
Takashi Iwaidaead532008-11-28 12:55:36 +010012080 codec->proc_widget_hook = print_realtek_coef;
Kailang Yangea1fb292008-08-26 12:58:38 +020012081
Kailang Yangdf694da2005-12-05 19:42:22 +010012082 return 0;
12083}
12084
Kailang Yangdf694da2005-12-05 19:42:22 +010012085/*
Kailang Yanga361d842007-06-05 12:30:55 +020012086 * ALC268 channel source setting (2 channel)
12087 */
12088#define ALC268_DIGOUT_NID ALC880_DIGOUT_NID
12089#define alc268_modes alc260_modes
Kailang Yangea1fb292008-08-26 12:58:38 +020012090
Kailang Yanga361d842007-06-05 12:30:55 +020012091static hda_nid_t alc268_dac_nids[2] = {
12092 /* front, hp */
12093 0x02, 0x03
12094};
12095
12096static hda_nid_t alc268_adc_nids[2] = {
12097 /* ADC0-1 */
12098 0x08, 0x07
12099};
12100
12101static hda_nid_t alc268_adc_nids_alt[1] = {
12102 /* ADC0 */
12103 0x08
12104};
12105
Takashi Iwaie1406342008-02-11 18:32:32 +010012106static hda_nid_t alc268_capsrc_nids[2] = { 0x23, 0x24 };
12107
Kailang Yanga361d842007-06-05 12:30:55 +020012108static struct snd_kcontrol_new alc268_base_mixer[] = {
12109 /* output mixer control */
12110 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
12111 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
12112 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
12113 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai33bf17a2007-08-21 11:51:42 +020012114 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12115 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
12116 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
Kailang Yanga361d842007-06-05 12:30:55 +020012117 { }
12118};
12119
Takashi Iwai42171c12009-05-08 14:11:43 +020012120static struct snd_kcontrol_new alc268_toshiba_mixer[] = {
12121 /* output mixer control */
12122 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
12123 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
12124 ALC262_HIPPO_MASTER_SWITCH,
12125 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12126 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
12127 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
12128 { }
12129};
12130
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012131/* bind Beep switches of both NID 0x0f and 0x10 */
12132static struct hda_bind_ctls alc268_bind_beep_sw = {
12133 .ops = &snd_hda_bind_sw,
12134 .values = {
12135 HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT),
12136 HDA_COMPOSE_AMP_VAL(0x10, 3, 1, HDA_INPUT),
12137 0
12138 },
12139};
12140
12141static struct snd_kcontrol_new alc268_beep_mixer[] = {
12142 HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT),
12143 HDA_BIND_SW("Beep Playback Switch", &alc268_bind_beep_sw),
12144 { }
12145};
12146
Kailang Yangd1a991a2007-08-15 16:21:59 +020012147static struct hda_verb alc268_eapd_verbs[] = {
12148 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
12149 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
12150 { }
12151};
12152
Takashi Iwaid2738092007-08-16 14:59:45 +020012153/* Toshiba specific */
Takashi Iwaid2738092007-08-16 14:59:45 +020012154static struct hda_verb alc268_toshiba_verbs[] = {
12155 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12156 { } /* end */
12157};
12158
12159/* Acer specific */
Takashi Iwai889c4392007-08-23 18:56:52 +020012160/* bind volumes of both NID 0x02 and 0x03 */
Takashi Iwai6bc96852007-08-17 09:02:12 +020012161static struct hda_bind_ctls alc268_acer_bind_master_vol = {
12162 .ops = &snd_hda_bind_vol,
12163 .values = {
12164 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
12165 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
12166 0
12167 },
12168};
12169
Takashi Iwai889c4392007-08-23 18:56:52 +020012170/* mute/unmute internal speaker according to the hp jack and mute state */
12171static void alc268_acer_automute(struct hda_codec *codec, int force)
12172{
12173 struct alc_spec *spec = codec->spec;
12174 unsigned int mute;
12175
12176 if (force || !spec->sense_updated) {
Wu Fengguang864f92b2009-11-18 12:38:02 +080012177 spec->jack_present = snd_hda_jack_detect(codec, 0x14);
Takashi Iwai889c4392007-08-23 18:56:52 +020012178 spec->sense_updated = 1;
12179 }
12180 if (spec->jack_present)
12181 mute = HDA_AMP_MUTE; /* mute internal speaker */
12182 else /* unmute internal speaker if necessary */
12183 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
12184 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
12185 HDA_AMP_MUTE, mute);
12186}
12187
12188
12189/* bind hp and internal speaker mute (with plug check) */
12190static int alc268_acer_master_sw_put(struct snd_kcontrol *kcontrol,
12191 struct snd_ctl_elem_value *ucontrol)
12192{
12193 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
12194 long *valp = ucontrol->value.integer.value;
12195 int change;
12196
Takashi Iwai8de56b72009-07-24 16:51:47 +020012197 change = amp_stereo_mute_update(codec, 0x14, HDA_OUTPUT, 0, valp);
Takashi Iwai889c4392007-08-23 18:56:52 +020012198 if (change)
12199 alc268_acer_automute(codec, 0);
12200 return change;
12201}
Takashi Iwaid2738092007-08-16 14:59:45 +020012202
Kailang Yang8ef355d2008-08-26 13:10:22 +020012203static struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = {
12204 /* output mixer control */
12205 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
12206 {
12207 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12208 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010012209 .subdevice = HDA_SUBDEV_AMP_FLAG,
Kailang Yang8ef355d2008-08-26 13:10:22 +020012210 .info = snd_hda_mixer_amp_switch_info,
12211 .get = snd_hda_mixer_amp_switch_get,
12212 .put = alc268_acer_master_sw_put,
12213 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
12214 },
12215 HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x18, 0, HDA_INPUT),
12216 { }
12217};
12218
Takashi Iwaid2738092007-08-16 14:59:45 +020012219static struct snd_kcontrol_new alc268_acer_mixer[] = {
12220 /* output mixer control */
12221 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
12222 {
12223 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12224 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010012225 .subdevice = HDA_SUBDEV_AMP_FLAG,
Takashi Iwaid2738092007-08-16 14:59:45 +020012226 .info = snd_hda_mixer_amp_switch_info,
12227 .get = snd_hda_mixer_amp_switch_get,
12228 .put = alc268_acer_master_sw_put,
12229 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
12230 },
Takashi Iwai33bf17a2007-08-21 11:51:42 +020012231 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12232 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
12233 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
Takashi Iwaid2738092007-08-16 14:59:45 +020012234 { }
12235};
12236
Takashi Iwaic238b4f2008-11-05 14:57:20 +010012237static struct snd_kcontrol_new alc268_acer_dmic_mixer[] = {
12238 /* output mixer control */
12239 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
12240 {
12241 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12242 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010012243 .subdevice = HDA_SUBDEV_AMP_FLAG,
Takashi Iwaic238b4f2008-11-05 14:57:20 +010012244 .info = snd_hda_mixer_amp_switch_info,
12245 .get = snd_hda_mixer_amp_switch_get,
12246 .put = alc268_acer_master_sw_put,
12247 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
12248 },
12249 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12250 HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
12251 { }
12252};
12253
Kailang Yang8ef355d2008-08-26 13:10:22 +020012254static struct hda_verb alc268_acer_aspire_one_verbs[] = {
12255 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12256 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12257 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12258 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
12259 {0x23, AC_VERB_SET_CONNECT_SEL, 0x06},
12260 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, 0xa017},
12261 { }
12262};
12263
Takashi Iwaid2738092007-08-16 14:59:45 +020012264static struct hda_verb alc268_acer_verbs[] = {
Takashi Iwai0ccb5412008-03-06 16:58:35 +010012265 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* internal dmic? */
12266 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaid2738092007-08-16 14:59:45 +020012267 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12268 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai0ccb5412008-03-06 16:58:35 +010012269 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
12270 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaid2738092007-08-16 14:59:45 +020012271 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12272 { }
12273};
12274
12275/* unsolicited event for HP jack sensing */
Takashi Iwai42171c12009-05-08 14:11:43 +020012276#define alc268_toshiba_unsol_event alc262_hippo_unsol_event
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012277#define alc268_toshiba_setup alc262_hippo_setup
12278#define alc268_toshiba_automute alc262_hippo_automute
Takashi Iwaid2738092007-08-16 14:59:45 +020012279
12280static void alc268_acer_unsol_event(struct hda_codec *codec,
12281 unsigned int res)
12282{
Takashi Iwai889c4392007-08-23 18:56:52 +020012283 if ((res >> 26) != ALC880_HP_EVENT)
Takashi Iwaid2738092007-08-16 14:59:45 +020012284 return;
12285 alc268_acer_automute(codec, 1);
12286}
12287
Takashi Iwai889c4392007-08-23 18:56:52 +020012288static void alc268_acer_init_hook(struct hda_codec *codec)
12289{
12290 alc268_acer_automute(codec, 1);
12291}
12292
Kailang Yang8ef355d2008-08-26 13:10:22 +020012293/* toggle speaker-output according to the hp-jack state */
12294static void alc268_aspire_one_speaker_automute(struct hda_codec *codec)
12295{
12296 unsigned int present;
12297 unsigned char bits;
12298
Wu Fengguang864f92b2009-11-18 12:38:02 +080012299 present = snd_hda_jack_detect(codec, 0x15);
Kailang Yang8ef355d2008-08-26 13:10:22 +020012300 bits = present ? AMP_IN_MUTE(0) : 0;
12301 snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 0,
12302 AMP_IN_MUTE(0), bits);
12303 snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 1,
12304 AMP_IN_MUTE(0), bits);
12305}
12306
Kailang Yang8ef355d2008-08-26 13:10:22 +020012307static void alc268_acer_lc_unsol_event(struct hda_codec *codec,
12308 unsigned int res)
12309{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012310 switch (res >> 26) {
12311 case ALC880_HP_EVENT:
Kailang Yang8ef355d2008-08-26 13:10:22 +020012312 alc268_aspire_one_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012313 break;
12314 case ALC880_MIC_EVENT:
12315 alc_mic_automute(codec);
12316 break;
12317 }
12318}
12319
12320static void alc268_acer_lc_setup(struct hda_codec *codec)
12321{
12322 struct alc_spec *spec = codec->spec;
12323 spec->ext_mic.pin = 0x18;
12324 spec->ext_mic.mux_idx = 0;
12325 spec->int_mic.pin = 0x12;
12326 spec->int_mic.mux_idx = 6;
12327 spec->auto_mic = 1;
Kailang Yang8ef355d2008-08-26 13:10:22 +020012328}
12329
12330static void alc268_acer_lc_init_hook(struct hda_codec *codec)
12331{
12332 alc268_aspire_one_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012333 alc_mic_automute(codec);
Kailang Yang8ef355d2008-08-26 13:10:22 +020012334}
12335
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012336static struct snd_kcontrol_new alc268_dell_mixer[] = {
12337 /* output mixer control */
12338 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
12339 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
12340 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
12341 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
12342 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
12343 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
12344 { }
12345};
12346
12347static struct hda_verb alc268_dell_verbs[] = {
12348 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12349 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12350 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012351 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012352 { }
12353};
12354
12355/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012356static void alc268_dell_setup(struct hda_codec *codec)
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012357{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020012358 struct alc_spec *spec = codec->spec;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012359
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020012360 spec->autocfg.hp_pins[0] = 0x15;
12361 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012362 spec->ext_mic.pin = 0x18;
12363 spec->ext_mic.mux_idx = 0;
12364 spec->int_mic.pin = 0x19;
12365 spec->int_mic.mux_idx = 1;
12366 spec->auto_mic = 1;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012367}
12368
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012369static struct snd_kcontrol_new alc267_quanta_il1_mixer[] = {
12370 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x2, 0x0, HDA_OUTPUT),
12371 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
12372 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
12373 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
12374 HDA_CODEC_VOLUME("Mic Capture Volume", 0x23, 0x0, HDA_OUTPUT),
12375 HDA_BIND_MUTE("Mic Capture Switch", 0x23, 2, HDA_OUTPUT),
12376 HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
12377 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
12378 { }
12379};
12380
12381static struct hda_verb alc267_quanta_il1_verbs[] = {
12382 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12383 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
12384 { }
12385};
12386
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012387static void alc267_quanta_il1_setup(struct hda_codec *codec)
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012388{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020012389 struct alc_spec *spec = codec->spec;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020012390 spec->autocfg.hp_pins[0] = 0x15;
12391 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012392 spec->ext_mic.pin = 0x18;
12393 spec->ext_mic.mux_idx = 0;
12394 spec->int_mic.pin = 0x19;
12395 spec->int_mic.mux_idx = 1;
12396 spec->auto_mic = 1;
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012397}
12398
Kailang Yanga361d842007-06-05 12:30:55 +020012399/*
12400 * generic initialization of ADC, input mixers and output mixers
12401 */
12402static struct hda_verb alc268_base_init_verbs[] = {
12403 /* Unmute DAC0-1 and set vol = 0 */
12404 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020012405 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020012406
12407 /*
12408 * Set up output mixers (0x0c - 0x0e)
12409 */
12410 /* set vol=0 to output mixers */
12411 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yanga361d842007-06-05 12:30:55 +020012412 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
12413
12414 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12415 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12416
12417 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
12418 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
12419 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
12420 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
12421 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
12422 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12423 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12424 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12425
12426 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12427 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12428 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12429 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020012430 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012431
12432 /* set PCBEEP vol = 0, mute connections */
12433 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12434 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12435 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020012436
Jiang Zhea9b3aa82007-12-20 13:13:13 +010012437 /* Unmute Selector 23h,24h and set the default input to mic-in */
Kailang Yangea1fb292008-08-26 12:58:38 +020012438
Jiang Zhea9b3aa82007-12-20 13:13:13 +010012439 {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
12440 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12441 {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
12442 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020012443
Kailang Yanga361d842007-06-05 12:30:55 +020012444 { }
12445};
12446
12447/*
12448 * generic initialization of ADC, input mixers and output mixers
12449 */
12450static struct hda_verb alc268_volume_init_verbs[] = {
12451 /* set output DAC */
Takashi Iwai4cfb91c2009-01-23 12:53:09 +010012452 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12453 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020012454
12455 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
12456 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
12457 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12458 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12459 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12460
Kailang Yanga361d842007-06-05 12:30:55 +020012461 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yanga361d842007-06-05 12:30:55 +020012462 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12463 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12464
12465 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020012466 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020012467
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012468 /* set PCBEEP vol = 0, mute connections */
12469 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12470 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12471 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020012472
12473 { }
12474};
12475
Takashi Iwaifdbc66262009-08-19 00:18:10 +020012476static struct snd_kcontrol_new alc268_capture_nosrc_mixer[] = {
12477 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
12478 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
12479 { } /* end */
12480};
12481
Kailang Yanga361d842007-06-05 12:30:55 +020012482static struct snd_kcontrol_new alc268_capture_alt_mixer[] = {
12483 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
12484 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
Takashi Iwaifdbc66262009-08-19 00:18:10 +020012485 _DEFINE_CAPSRC(1),
Kailang Yanga361d842007-06-05 12:30:55 +020012486 { } /* end */
12487};
12488
12489static struct snd_kcontrol_new alc268_capture_mixer[] = {
12490 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
12491 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
12492 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x24, 0x0, HDA_OUTPUT),
12493 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x24, 0x0, HDA_OUTPUT),
Takashi Iwaifdbc66262009-08-19 00:18:10 +020012494 _DEFINE_CAPSRC(2),
Kailang Yanga361d842007-06-05 12:30:55 +020012495 { } /* end */
12496};
12497
12498static struct hda_input_mux alc268_capture_source = {
12499 .num_items = 4,
12500 .items = {
12501 { "Mic", 0x0 },
12502 { "Front Mic", 0x1 },
12503 { "Line", 0x2 },
12504 { "CD", 0x3 },
12505 },
12506};
12507
Takashi Iwai0ccb5412008-03-06 16:58:35 +010012508static struct hda_input_mux alc268_acer_capture_source = {
12509 .num_items = 3,
12510 .items = {
12511 { "Mic", 0x0 },
Takashi Iwaic238b4f2008-11-05 14:57:20 +010012512 { "Internal Mic", 0x1 },
12513 { "Line", 0x2 },
12514 },
12515};
12516
12517static struct hda_input_mux alc268_acer_dmic_capture_source = {
12518 .num_items = 3,
12519 .items = {
12520 { "Mic", 0x0 },
Takashi Iwai0ccb5412008-03-06 16:58:35 +010012521 { "Internal Mic", 0x6 },
12522 { "Line", 0x2 },
12523 },
12524};
12525
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010012526#ifdef CONFIG_SND_DEBUG
12527static struct snd_kcontrol_new alc268_test_mixer[] = {
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010012528 /* Volume widgets */
12529 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x02, 0x0, HDA_OUTPUT),
12530 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x03, 0x0, HDA_OUTPUT),
12531 HDA_BIND_MUTE_MONO("Mono sum Playback Switch", 0x0e, 1, 2, HDA_INPUT),
12532 HDA_BIND_MUTE("LINE-OUT sum Playback Switch", 0x0f, 2, HDA_INPUT),
12533 HDA_BIND_MUTE("HP-OUT sum Playback Switch", 0x10, 2, HDA_INPUT),
12534 HDA_BIND_MUTE("LINE-OUT Playback Switch", 0x14, 2, HDA_OUTPUT),
12535 HDA_BIND_MUTE("HP-OUT Playback Switch", 0x15, 2, HDA_OUTPUT),
12536 HDA_BIND_MUTE("Mono Playback Switch", 0x16, 2, HDA_OUTPUT),
12537 HDA_CODEC_VOLUME("MIC1 Capture Volume", 0x18, 0x0, HDA_INPUT),
12538 HDA_BIND_MUTE("MIC1 Capture Switch", 0x18, 2, HDA_OUTPUT),
12539 HDA_CODEC_VOLUME("MIC2 Capture Volume", 0x19, 0x0, HDA_INPUT),
12540 HDA_CODEC_VOLUME("LINE1 Capture Volume", 0x1a, 0x0, HDA_INPUT),
12541 HDA_BIND_MUTE("LINE1 Capture Switch", 0x1a, 2, HDA_OUTPUT),
Takashi Iwaif0747ee2008-01-15 11:41:41 +010012542 /* The below appears problematic on some hardwares */
12543 /*HDA_CODEC_VOLUME("PCBEEP Playback Volume", 0x1d, 0x0, HDA_INPUT),*/
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010012544 HDA_CODEC_VOLUME("PCM-IN1 Capture Volume", 0x23, 0x0, HDA_OUTPUT),
12545 HDA_BIND_MUTE("PCM-IN1 Capture Switch", 0x23, 2, HDA_OUTPUT),
12546 HDA_CODEC_VOLUME("PCM-IN2 Capture Volume", 0x24, 0x0, HDA_OUTPUT),
12547 HDA_BIND_MUTE("PCM-IN2 Capture Switch", 0x24, 2, HDA_OUTPUT),
12548
12549 /* Modes for retasking pin widgets */
12550 ALC_PIN_MODE("LINE-OUT pin mode", 0x14, ALC_PIN_DIR_INOUT),
12551 ALC_PIN_MODE("HP-OUT pin mode", 0x15, ALC_PIN_DIR_INOUT),
12552 ALC_PIN_MODE("MIC1 pin mode", 0x18, ALC_PIN_DIR_INOUT),
12553 ALC_PIN_MODE("LINE1 pin mode", 0x1a, ALC_PIN_DIR_INOUT),
12554
12555 /* Controls for GPIO pins, assuming they are configured as outputs */
12556 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
12557 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
12558 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
12559 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
12560
12561 /* Switches to allow the digital SPDIF output pin to be enabled.
12562 * The ALC268 does not have an SPDIF input.
12563 */
12564 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x06, 0x01),
12565
12566 /* A switch allowing EAPD to be enabled. Some laptops seem to use
12567 * this output to turn on an external amplifier.
12568 */
12569 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
12570 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
12571
12572 { } /* end */
12573};
12574#endif
12575
Kailang Yanga361d842007-06-05 12:30:55 +020012576/* create input playback/capture controls for the given pin */
12577static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
12578 const char *ctlname, int idx)
12579{
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020012580 hda_nid_t dac;
Kailang Yanga361d842007-06-05 12:30:55 +020012581 int err;
12582
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020012583 switch (nid) {
12584 case 0x14:
12585 case 0x16:
12586 dac = 0x02;
12587 break;
12588 case 0x15:
12589 dac = 0x03;
12590 break;
12591 default:
12592 return 0;
12593 }
12594 if (spec->multiout.dac_nids[0] != dac &&
12595 spec->multiout.dac_nids[1] != dac) {
Takashi Iwai0afe5f82009-10-02 09:20:00 +020012596 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname,
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020012597 HDA_COMPOSE_AMP_VAL(dac, 3, idx,
Kailang Yanga361d842007-06-05 12:30:55 +020012598 HDA_OUTPUT));
12599 if (err < 0)
12600 return err;
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020012601 spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
12602 }
12603
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020012604 if (nid != 0x16)
Takashi Iwai0afe5f82009-10-02 09:20:00 +020012605 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
Kailang Yanga361d842007-06-05 12:30:55 +020012606 HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020012607 else /* mono */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020012608 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020012609 HDA_COMPOSE_AMP_VAL(nid, 2, idx, HDA_OUTPUT));
Kailang Yanga361d842007-06-05 12:30:55 +020012610 if (err < 0)
12611 return err;
12612 return 0;
12613}
12614
12615/* add playback controls from the parsed DAC table */
12616static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
12617 const struct auto_pin_cfg *cfg)
12618{
12619 hda_nid_t nid;
12620 int err;
12621
Kailang Yanga361d842007-06-05 12:30:55 +020012622 spec->multiout.dac_nids = spec->private_dac_nids;
Kailang Yanga361d842007-06-05 12:30:55 +020012623
12624 nid = cfg->line_out_pins[0];
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020012625 if (nid) {
12626 const char *name;
12627 if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
12628 name = "Speaker";
12629 else
12630 name = "Front";
12631 err = alc268_new_analog_output(spec, nid, name, 0);
12632 if (err < 0)
12633 return err;
12634 }
Kailang Yanga361d842007-06-05 12:30:55 +020012635
12636 nid = cfg->speaker_pins[0];
12637 if (nid == 0x1d) {
Takashi Iwai0afe5f82009-10-02 09:20:00 +020012638 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, "Speaker",
Kailang Yanga361d842007-06-05 12:30:55 +020012639 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
12640 if (err < 0)
12641 return err;
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020012642 } else {
12643 err = alc268_new_analog_output(spec, nid, "Speaker", 0);
12644 if (err < 0)
12645 return err;
Kailang Yanga361d842007-06-05 12:30:55 +020012646 }
12647 nid = cfg->hp_pins[0];
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020012648 if (nid) {
12649 err = alc268_new_analog_output(spec, nid, "Headphone", 0);
12650 if (err < 0)
12651 return err;
12652 }
Kailang Yanga361d842007-06-05 12:30:55 +020012653
12654 nid = cfg->line_out_pins[1] | cfg->line_out_pins[2];
12655 if (nid == 0x16) {
Takashi Iwai0afe5f82009-10-02 09:20:00 +020012656 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, "Mono",
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020012657 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT));
Kailang Yanga361d842007-06-05 12:30:55 +020012658 if (err < 0)
12659 return err;
12660 }
Kailang Yangea1fb292008-08-26 12:58:38 +020012661 return 0;
Kailang Yanga361d842007-06-05 12:30:55 +020012662}
12663
12664/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +020012665static int alc268_auto_create_input_ctls(struct hda_codec *codec,
Kailang Yanga361d842007-06-05 12:30:55 +020012666 const struct auto_pin_cfg *cfg)
12667{
Takashi Iwai05f5f472009-08-25 13:10:18 +020012668 return alc_auto_create_input_ctls(codec, cfg, 0, 0x23, 0x24);
Kailang Yanga361d842007-06-05 12:30:55 +020012669}
12670
Takashi Iwaie9af4f32009-08-29 23:23:08 +020012671static void alc268_auto_set_output_and_unmute(struct hda_codec *codec,
12672 hda_nid_t nid, int pin_type)
12673{
12674 int idx;
12675
12676 alc_set_pin_output(codec, nid, pin_type);
12677 if (nid == 0x14 || nid == 0x16)
12678 idx = 0;
12679 else
12680 idx = 1;
12681 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
12682}
12683
12684static void alc268_auto_init_multi_out(struct hda_codec *codec)
12685{
12686 struct alc_spec *spec = codec->spec;
12687 hda_nid_t nid = spec->autocfg.line_out_pins[0];
12688 if (nid) {
12689 int pin_type = get_pin_type(spec->autocfg.line_out_type);
12690 alc268_auto_set_output_and_unmute(codec, nid, pin_type);
12691 }
12692}
12693
12694static void alc268_auto_init_hp_out(struct hda_codec *codec)
12695{
12696 struct alc_spec *spec = codec->spec;
12697 hda_nid_t pin;
12698
12699 pin = spec->autocfg.hp_pins[0];
12700 if (pin)
12701 alc268_auto_set_output_and_unmute(codec, pin, PIN_HP);
12702 pin = spec->autocfg.speaker_pins[0];
12703 if (pin)
12704 alc268_auto_set_output_and_unmute(codec, pin, PIN_OUT);
12705}
12706
Kailang Yanga361d842007-06-05 12:30:55 +020012707static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec)
12708{
12709 struct alc_spec *spec = codec->spec;
12710 hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
12711 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
12712 hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
12713 unsigned int dac_vol1, dac_vol2;
12714
Takashi Iwaie9af4f32009-08-29 23:23:08 +020012715 if (line_nid == 0x1d || speaker_nid == 0x1d) {
Kailang Yanga361d842007-06-05 12:30:55 +020012716 snd_hda_codec_write(codec, speaker_nid, 0,
12717 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
Takashi Iwaie9af4f32009-08-29 23:23:08 +020012718 /* mute mixer inputs from 0x1d */
Kailang Yanga361d842007-06-05 12:30:55 +020012719 snd_hda_codec_write(codec, 0x0f, 0,
12720 AC_VERB_SET_AMP_GAIN_MUTE,
12721 AMP_IN_UNMUTE(1));
12722 snd_hda_codec_write(codec, 0x10, 0,
12723 AC_VERB_SET_AMP_GAIN_MUTE,
12724 AMP_IN_UNMUTE(1));
12725 } else {
Takashi Iwaie9af4f32009-08-29 23:23:08 +020012726 /* unmute mixer inputs from 0x1d */
Kailang Yanga361d842007-06-05 12:30:55 +020012727 snd_hda_codec_write(codec, 0x0f, 0,
12728 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
12729 snd_hda_codec_write(codec, 0x10, 0,
12730 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
12731 }
12732
12733 dac_vol1 = dac_vol2 = 0xb000 | 0x40; /* set max volume */
Kailang Yangea1fb292008-08-26 12:58:38 +020012734 if (line_nid == 0x14)
Kailang Yanga361d842007-06-05 12:30:55 +020012735 dac_vol2 = AMP_OUT_ZERO;
12736 else if (line_nid == 0x15)
12737 dac_vol1 = AMP_OUT_ZERO;
Kailang Yangea1fb292008-08-26 12:58:38 +020012738 if (hp_nid == 0x14)
Kailang Yanga361d842007-06-05 12:30:55 +020012739 dac_vol2 = AMP_OUT_ZERO;
12740 else if (hp_nid == 0x15)
12741 dac_vol1 = AMP_OUT_ZERO;
12742 if (line_nid != 0x16 || hp_nid != 0x16 ||
12743 spec->autocfg.line_out_pins[1] != 0x16 ||
12744 spec->autocfg.line_out_pins[2] != 0x16)
12745 dac_vol1 = dac_vol2 = AMP_OUT_ZERO;
12746
12747 snd_hda_codec_write(codec, 0x02, 0,
12748 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol1);
12749 snd_hda_codec_write(codec, 0x03, 0,
12750 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol2);
12751}
12752
Sasha Alexandrdef319f2009-06-16 16:00:15 -040012753/* pcm configuration: identical with ALC880 */
Kailang Yanga361d842007-06-05 12:30:55 +020012754#define alc268_pcm_analog_playback alc880_pcm_analog_playback
12755#define alc268_pcm_analog_capture alc880_pcm_analog_capture
Takashi Iwai63300792008-01-24 15:31:36 +010012756#define alc268_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
Kailang Yanga361d842007-06-05 12:30:55 +020012757#define alc268_pcm_digital_playback alc880_pcm_digital_playback
12758
12759/*
12760 * BIOS auto configuration
12761 */
12762static int alc268_parse_auto_config(struct hda_codec *codec)
12763{
12764 struct alc_spec *spec = codec->spec;
12765 int err;
12766 static hda_nid_t alc268_ignore[] = { 0 };
12767
12768 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
12769 alc268_ignore);
12770 if (err < 0)
12771 return err;
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010012772 if (!spec->autocfg.line_outs) {
12773 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
12774 spec->multiout.max_channels = 2;
12775 spec->no_analog = 1;
12776 goto dig_only;
12777 }
Kailang Yanga361d842007-06-05 12:30:55 +020012778 return 0; /* can't find valid BIOS pin config */
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010012779 }
Kailang Yanga361d842007-06-05 12:30:55 +020012780 err = alc268_auto_create_multi_out_ctls(spec, &spec->autocfg);
12781 if (err < 0)
12782 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020012783 err = alc268_auto_create_input_ctls(codec, &spec->autocfg);
Kailang Yanga361d842007-06-05 12:30:55 +020012784 if (err < 0)
12785 return err;
12786
12787 spec->multiout.max_channels = 2;
12788
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010012789 dig_only:
Kailang Yanga361d842007-06-05 12:30:55 +020012790 /* digital only support output */
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010012791 if (spec->autocfg.dig_outs) {
Kailang Yanga361d842007-06-05 12:30:55 +020012792 spec->multiout.dig_out_nid = ALC268_DIGOUT_NID;
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010012793 spec->dig_out_type = spec->autocfg.dig_out_type[0];
12794 }
Takashi Iwai603c4012008-07-30 15:01:44 +020012795 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010012796 add_mixer(spec, spec->kctls.list);
Kailang Yanga361d842007-06-05 12:30:55 +020012797
Takashi Iwai892981f2009-03-02 08:04:35 +010012798 if (!spec->no_analog && spec->autocfg.speaker_pins[0] != 0x1d)
Takashi Iwaid88897e2008-10-31 15:01:37 +010012799 add_mixer(spec, alc268_beep_mixer);
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012800
Takashi Iwaid88897e2008-10-31 15:01:37 +010012801 add_verb(spec, alc268_volume_init_verbs);
Herton Ronaldo Krzesinski59085892009-08-11 22:33:09 -030012802 spec->num_mux_defs = 2;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020012803 spec->input_mux = &spec->private_imux[0];
Kailang Yanga361d842007-06-05 12:30:55 +020012804
Takashi Iwai776e1842007-08-29 15:07:11 +020012805 err = alc_auto_add_mic_boost(codec);
12806 if (err < 0)
12807 return err;
12808
Takashi Iwai1d955eb2009-06-29 11:33:53 +020012809 alc_ssid_check(codec, 0x15, 0x1b, 0x14);
12810
Kailang Yanga361d842007-06-05 12:30:55 +020012811 return 1;
12812}
12813
Kailang Yanga361d842007-06-05 12:30:55 +020012814#define alc268_auto_init_analog_input alc882_auto_init_analog_input
12815
12816/* init callback for auto-configuration model -- overriding the default init */
12817static void alc268_auto_init(struct hda_codec *codec)
12818{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012819 struct alc_spec *spec = codec->spec;
Kailang Yanga361d842007-06-05 12:30:55 +020012820 alc268_auto_init_multi_out(codec);
12821 alc268_auto_init_hp_out(codec);
12822 alc268_auto_init_mono_speaker_out(codec);
12823 alc268_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012824 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020012825 alc_inithook(codec);
Kailang Yanga361d842007-06-05 12:30:55 +020012826}
12827
12828/*
12829 * configuration and preset
12830 */
12831static const char *alc268_models[ALC268_MODEL_LAST] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012832 [ALC267_QUANTA_IL1] = "quanta-il1",
Kailang Yanga361d842007-06-05 12:30:55 +020012833 [ALC268_3ST] = "3stack",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020012834 [ALC268_TOSHIBA] = "toshiba",
Takashi Iwaid2738092007-08-16 14:59:45 +020012835 [ALC268_ACER] = "acer",
Takashi Iwaic238b4f2008-11-05 14:57:20 +010012836 [ALC268_ACER_DMIC] = "acer-dmic",
Kailang Yang8ef355d2008-08-26 13:10:22 +020012837 [ALC268_ACER_ASPIRE_ONE] = "acer-aspire",
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012838 [ALC268_DELL] = "dell",
Mirco Tischlerf12462c2008-02-04 12:33:59 +010012839 [ALC268_ZEPTO] = "zepto",
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010012840#ifdef CONFIG_SND_DEBUG
12841 [ALC268_TEST] = "test",
12842#endif
Kailang Yanga361d842007-06-05 12:30:55 +020012843 [ALC268_AUTO] = "auto",
12844};
12845
12846static struct snd_pci_quirk alc268_cfg_tbl[] = {
Takashi Iwaia0b8f7d2008-04-22 19:39:49 +020012847 SND_PCI_QUIRK(0x1025, 0x011e, "Acer Aspire 5720z", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012848 SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER),
Andy Shevchenkodafc8352008-01-25 11:53:50 +010012849 SND_PCI_QUIRK(0x1025, 0x012e, "Acer Aspire 5310", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012850 SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER),
Andy Shevchenko29a52c22008-01-24 17:29:00 +010012851 SND_PCI_QUIRK(0x1025, 0x0136, "Acer Aspire 5315", ALC268_ACER),
Kailang Yang8ef355d2008-08-26 13:10:22 +020012852 SND_PCI_QUIRK(0x1025, 0x015b, "Acer Aspire One",
12853 ALC268_ACER_ASPIRE_ONE),
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012854 SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL),
Daniel T Chena1bf8082009-11-01 18:32:29 -050012855 SND_PCI_QUIRK_MASK(0x1028, 0xfff0, 0x02b0,
12856 "Dell Inspiron Mini9/Vostro A90", ALC268_DELL),
Takashi Iwai33d78672009-09-08 11:03:41 +020012857 /* almost compatible with toshiba but with optional digital outs;
12858 * auto-probing seems working fine
12859 */
Takashi Iwai8871e5b2009-06-02 01:02:50 +020012860 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP TX25xx series",
Takashi Iwai33d78672009-09-08 11:03:41 +020012861 ALC268_AUTO),
Kailang Yanga361d842007-06-05 12:30:55 +020012862 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST),
Takashi Iwai8871e5b2009-06-02 01:02:50 +020012863 SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO),
Tony Vroon378bd6a2008-06-04 12:08:30 +020012864 SND_PCI_QUIRK(0x14c0, 0x0025, "COMPAL IFL90/JFL-92", ALC268_TOSHIBA),
Takashi Iwaib875bf32007-09-06 15:00:27 +020012865 SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER),
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012866 SND_PCI_QUIRK(0x152d, 0x0771, "Quanta IL1", ALC267_QUANTA_IL1),
Takashi Iwai8871e5b2009-06-02 01:02:50 +020012867 SND_PCI_QUIRK(0x1854, 0x1775, "LG R510", ALC268_DELL),
Kailang Yanga361d842007-06-05 12:30:55 +020012868 {}
12869};
12870
Takashi Iwai3abf2f32009-08-19 20:05:02 +020012871/* Toshiba laptops have no unique PCI SSID but only codec SSID */
12872static struct snd_pci_quirk alc268_ssid_cfg_tbl[] = {
12873 SND_PCI_QUIRK(0x1179, 0xff0a, "TOSHIBA X-200", ALC268_AUTO),
12874 SND_PCI_QUIRK(0x1179, 0xff0e, "TOSHIBA X-200 HDMI", ALC268_AUTO),
12875 SND_PCI_QUIRK_MASK(0x1179, 0xff00, 0xff00, "TOSHIBA A/Lx05",
12876 ALC268_TOSHIBA),
12877 {}
12878};
12879
Kailang Yanga361d842007-06-05 12:30:55 +020012880static struct alc_config_preset alc268_presets[] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012881 [ALC267_QUANTA_IL1] = {
Takashi Iwaifdbc66262009-08-19 00:18:10 +020012882 .mixers = { alc267_quanta_il1_mixer, alc268_beep_mixer,
12883 alc268_capture_nosrc_mixer },
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012884 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
12885 alc267_quanta_il1_verbs },
12886 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
12887 .dac_nids = alc268_dac_nids,
12888 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
12889 .adc_nids = alc268_adc_nids_alt,
12890 .hp_nid = 0x03,
12891 .num_channel_mode = ARRAY_SIZE(alc268_modes),
12892 .channel_mode = alc268_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012893 .unsol_event = alc_sku_unsol_event,
12894 .setup = alc267_quanta_il1_setup,
12895 .init_hook = alc_inithook,
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012896 },
Kailang Yanga361d842007-06-05 12:30:55 +020012897 [ALC268_3ST] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012898 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
12899 alc268_beep_mixer },
Kailang Yanga361d842007-06-05 12:30:55 +020012900 .init_verbs = { alc268_base_init_verbs },
12901 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
12902 .dac_nids = alc268_dac_nids,
12903 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
12904 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010012905 .capsrc_nids = alc268_capsrc_nids,
Kailang Yanga361d842007-06-05 12:30:55 +020012906 .hp_nid = 0x03,
12907 .dig_out_nid = ALC268_DIGOUT_NID,
12908 .num_channel_mode = ARRAY_SIZE(alc268_modes),
12909 .channel_mode = alc268_modes,
12910 .input_mux = &alc268_capture_source,
12911 },
Kailang Yangd1a991a2007-08-15 16:21:59 +020012912 [ALC268_TOSHIBA] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020012913 .mixers = { alc268_toshiba_mixer, alc268_capture_alt_mixer,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012914 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020012915 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
12916 alc268_toshiba_verbs },
Kailang Yangd1a991a2007-08-15 16:21:59 +020012917 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
12918 .dac_nids = alc268_dac_nids,
12919 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
12920 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010012921 .capsrc_nids = alc268_capsrc_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020012922 .hp_nid = 0x03,
12923 .num_channel_mode = ARRAY_SIZE(alc268_modes),
12924 .channel_mode = alc268_modes,
12925 .input_mux = &alc268_capture_source,
Takashi Iwaid2738092007-08-16 14:59:45 +020012926 .unsol_event = alc268_toshiba_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012927 .setup = alc268_toshiba_setup,
12928 .init_hook = alc268_toshiba_automute,
Takashi Iwaid2738092007-08-16 14:59:45 +020012929 },
12930 [ALC268_ACER] = {
Takashi Iwai432fd132009-09-30 08:13:44 +020012931 .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012932 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020012933 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
12934 alc268_acer_verbs },
12935 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
12936 .dac_nids = alc268_dac_nids,
12937 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
12938 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010012939 .capsrc_nids = alc268_capsrc_nids,
Takashi Iwaid2738092007-08-16 14:59:45 +020012940 .hp_nid = 0x02,
12941 .num_channel_mode = ARRAY_SIZE(alc268_modes),
12942 .channel_mode = alc268_modes,
Takashi Iwai0ccb5412008-03-06 16:58:35 +010012943 .input_mux = &alc268_acer_capture_source,
Takashi Iwaid2738092007-08-16 14:59:45 +020012944 .unsol_event = alc268_acer_unsol_event,
Takashi Iwai889c4392007-08-23 18:56:52 +020012945 .init_hook = alc268_acer_init_hook,
Kailang Yangd1a991a2007-08-15 16:21:59 +020012946 },
Takashi Iwaic238b4f2008-11-05 14:57:20 +010012947 [ALC268_ACER_DMIC] = {
12948 .mixers = { alc268_acer_dmic_mixer, alc268_capture_alt_mixer,
12949 alc268_beep_mixer },
12950 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
12951 alc268_acer_verbs },
12952 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
12953 .dac_nids = alc268_dac_nids,
12954 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
12955 .adc_nids = alc268_adc_nids_alt,
12956 .capsrc_nids = alc268_capsrc_nids,
12957 .hp_nid = 0x02,
12958 .num_channel_mode = ARRAY_SIZE(alc268_modes),
12959 .channel_mode = alc268_modes,
12960 .input_mux = &alc268_acer_dmic_capture_source,
12961 .unsol_event = alc268_acer_unsol_event,
12962 .init_hook = alc268_acer_init_hook,
12963 },
Kailang Yang8ef355d2008-08-26 13:10:22 +020012964 [ALC268_ACER_ASPIRE_ONE] = {
12965 .mixers = { alc268_acer_aspire_one_mixer,
Takashi Iwai22971e32009-02-10 11:56:44 +010012966 alc268_beep_mixer,
Takashi Iwaifdbc66262009-08-19 00:18:10 +020012967 alc268_capture_nosrc_mixer },
Kailang Yang8ef355d2008-08-26 13:10:22 +020012968 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
12969 alc268_acer_aspire_one_verbs },
12970 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
12971 .dac_nids = alc268_dac_nids,
12972 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
12973 .adc_nids = alc268_adc_nids_alt,
12974 .capsrc_nids = alc268_capsrc_nids,
12975 .hp_nid = 0x03,
12976 .num_channel_mode = ARRAY_SIZE(alc268_modes),
12977 .channel_mode = alc268_modes,
Kailang Yang8ef355d2008-08-26 13:10:22 +020012978 .unsol_event = alc268_acer_lc_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012979 .setup = alc268_acer_lc_setup,
Kailang Yang8ef355d2008-08-26 13:10:22 +020012980 .init_hook = alc268_acer_lc_init_hook,
12981 },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012982 [ALC268_DELL] = {
Takashi Iwaifdbc66262009-08-19 00:18:10 +020012983 .mixers = { alc268_dell_mixer, alc268_beep_mixer,
12984 alc268_capture_nosrc_mixer },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012985 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
12986 alc268_dell_verbs },
12987 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
12988 .dac_nids = alc268_dac_nids,
Takashi Iwaifdbc66262009-08-19 00:18:10 +020012989 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
12990 .adc_nids = alc268_adc_nids_alt,
12991 .capsrc_nids = alc268_capsrc_nids,
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012992 .hp_nid = 0x02,
12993 .num_channel_mode = ARRAY_SIZE(alc268_modes),
12994 .channel_mode = alc268_modes,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020012995 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012996 .setup = alc268_dell_setup,
12997 .init_hook = alc_inithook,
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012998 },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010012999 [ALC268_ZEPTO] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013000 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
13001 alc268_beep_mixer },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013002 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13003 alc268_toshiba_verbs },
13004 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13005 .dac_nids = alc268_dac_nids,
13006 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13007 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013008 .capsrc_nids = alc268_capsrc_nids,
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013009 .hp_nid = 0x03,
13010 .dig_out_nid = ALC268_DIGOUT_NID,
13011 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13012 .channel_mode = alc268_modes,
13013 .input_mux = &alc268_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013014 .setup = alc268_toshiba_setup,
13015 .init_hook = alc268_toshiba_automute,
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013016 },
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013017#ifdef CONFIG_SND_DEBUG
13018 [ALC268_TEST] = {
13019 .mixers = { alc268_test_mixer, alc268_capture_mixer },
13020 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13021 alc268_volume_init_verbs },
13022 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13023 .dac_nids = alc268_dac_nids,
13024 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13025 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013026 .capsrc_nids = alc268_capsrc_nids,
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013027 .hp_nid = 0x03,
13028 .dig_out_nid = ALC268_DIGOUT_NID,
13029 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13030 .channel_mode = alc268_modes,
13031 .input_mux = &alc268_capture_source,
13032 },
13033#endif
Kailang Yanga361d842007-06-05 12:30:55 +020013034};
13035
13036static int patch_alc268(struct hda_codec *codec)
13037{
13038 struct alc_spec *spec;
13039 int board_config;
Takashi Iwai22971e32009-02-10 11:56:44 +010013040 int i, has_beep, err;
Kailang Yanga361d842007-06-05 12:30:55 +020013041
13042 spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
13043 if (spec == NULL)
13044 return -ENOMEM;
13045
13046 codec->spec = spec;
13047
13048 board_config = snd_hda_check_board_config(codec, ALC268_MODEL_LAST,
13049 alc268_models,
13050 alc268_cfg_tbl);
13051
Takashi Iwai3abf2f32009-08-19 20:05:02 +020013052 if (board_config < 0 || board_config >= ALC268_MODEL_LAST)
13053 board_config = snd_hda_check_board_codec_sid_config(codec,
13054 ALC882_MODEL_LAST, alc268_models, alc268_ssid_cfg_tbl);
13055
Kailang Yanga361d842007-06-05 12:30:55 +020013056 if (board_config < 0 || board_config >= ALC268_MODEL_LAST) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020013057 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
13058 codec->chip_name);
Kailang Yanga361d842007-06-05 12:30:55 +020013059 board_config = ALC268_AUTO;
13060 }
13061
13062 if (board_config == ALC268_AUTO) {
13063 /* automatic parse from the BIOS config */
13064 err = alc268_parse_auto_config(codec);
13065 if (err < 0) {
13066 alc_free(codec);
13067 return err;
13068 } else if (!err) {
13069 printk(KERN_INFO
13070 "hda_codec: Cannot set up configuration "
13071 "from BIOS. Using base mode...\n");
13072 board_config = ALC268_3ST;
13073 }
13074 }
13075
13076 if (board_config != ALC268_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020013077 setup_preset(codec, &alc268_presets[board_config]);
Kailang Yanga361d842007-06-05 12:30:55 +020013078
Kailang Yanga361d842007-06-05 12:30:55 +020013079 spec->stream_analog_playback = &alc268_pcm_analog_playback;
13080 spec->stream_analog_capture = &alc268_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +010013081 spec->stream_analog_alt_capture = &alc268_pcm_analog_alt_capture;
Kailang Yanga361d842007-06-05 12:30:55 +020013082
Kailang Yanga361d842007-06-05 12:30:55 +020013083 spec->stream_digital_playback = &alc268_pcm_digital_playback;
13084
Takashi Iwai22971e32009-02-10 11:56:44 +010013085 has_beep = 0;
13086 for (i = 0; i < spec->num_mixers; i++) {
13087 if (spec->mixers[i] == alc268_beep_mixer) {
13088 has_beep = 1;
13089 break;
13090 }
13091 }
13092
13093 if (has_beep) {
13094 err = snd_hda_attach_beep_device(codec, 0x1);
13095 if (err < 0) {
13096 alc_free(codec);
13097 return err;
13098 }
13099 if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
13100 /* override the amp caps for beep generator */
13101 snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013102 (0x0c << AC_AMPCAP_OFFSET_SHIFT) |
13103 (0x0c << AC_AMPCAP_NUM_STEPS_SHIFT) |
13104 (0x07 << AC_AMPCAP_STEP_SIZE_SHIFT) |
13105 (0 << AC_AMPCAP_MUTE_SHIFT));
Takashi Iwai22971e32009-02-10 11:56:44 +010013106 }
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013107
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013108 if (!spec->no_analog && !spec->adc_nids && spec->input_mux) {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013109 /* check whether NID 0x07 is valid */
13110 unsigned int wcap = get_wcaps(codec, 0x07);
Takashi Iwai85860c02008-02-19 15:00:15 +010013111 int i;
Kailang Yanga361d842007-06-05 12:30:55 +020013112
Takashi Iwaidefb5ab2009-10-07 15:12:27 +020013113 spec->capsrc_nids = alc268_capsrc_nids;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013114 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +020013115 wcap = get_wcaps_type(wcap);
Takashi Iwaifdbc66262009-08-19 00:18:10 +020013116 if (spec->auto_mic ||
13117 wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013118 spec->adc_nids = alc268_adc_nids_alt;
13119 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt);
Takashi Iwaidefb5ab2009-10-07 15:12:27 +020013120 if (spec->auto_mic)
13121 fixup_automic_adc(codec);
Takashi Iwaifdbc66262009-08-19 00:18:10 +020013122 if (spec->auto_mic || spec->input_mux->num_items == 1)
13123 add_mixer(spec, alc268_capture_nosrc_mixer);
13124 else
13125 add_mixer(spec, alc268_capture_alt_mixer);
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013126 } else {
13127 spec->adc_nids = alc268_adc_nids;
13128 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids);
Takashi Iwaid88897e2008-10-31 15:01:37 +010013129 add_mixer(spec, alc268_capture_mixer);
Kailang Yanga361d842007-06-05 12:30:55 +020013130 }
Takashi Iwai85860c02008-02-19 15:00:15 +010013131 /* set default input source */
13132 for (i = 0; i < spec->num_adc_nids; i++)
13133 snd_hda_codec_write_cache(codec, alc268_capsrc_nids[i],
13134 0, AC_VERB_SET_CONNECT_SEL,
Herton Ronaldo Krzesinski59085892009-08-11 22:33:09 -030013135 i < spec->num_mux_defs ?
13136 spec->input_mux[i].items[0].index :
Takashi Iwai85860c02008-02-19 15:00:15 +010013137 spec->input_mux->items[0].index);
Kailang Yanga361d842007-06-05 12:30:55 +020013138 }
Takashi Iwai2134ea42008-01-10 16:53:55 +010013139
13140 spec->vmaster_nid = 0x02;
13141
Kailang Yanga361d842007-06-05 12:30:55 +020013142 codec->patch_ops = alc_patch_ops;
13143 if (board_config == ALC268_AUTO)
13144 spec->init_hook = alc268_auto_init;
Kailang Yangea1fb292008-08-26 12:58:38 +020013145
Takashi Iwaidaead532008-11-28 12:55:36 +010013146 codec->proc_widget_hook = print_realtek_coef;
13147
Kailang Yanga361d842007-06-05 12:30:55 +020013148 return 0;
13149}
13150
13151/*
Kailang Yangf6a92242007-12-13 16:52:54 +010013152 * ALC269 channel source setting (2 channel)
13153 */
13154#define ALC269_DIGOUT_NID ALC880_DIGOUT_NID
13155
13156#define alc269_dac_nids alc260_dac_nids
13157
13158static hda_nid_t alc269_adc_nids[1] = {
13159 /* ADC1 */
Kailang Yangf53281e2008-07-18 12:36:43 +020013160 0x08,
13161};
13162
Takashi Iwaie01bf502008-08-21 16:25:07 +020013163static hda_nid_t alc269_capsrc_nids[1] = {
13164 0x23,
13165};
13166
13167/* NOTE: ADC2 (0x07) is connected from a recording *MIXER* (0x24),
13168 * not a mux!
13169 */
13170
Kailang Yangf6a92242007-12-13 16:52:54 +010013171#define alc269_modes alc260_modes
13172#define alc269_capture_source alc880_lg_lw_capture_source
13173
13174static struct snd_kcontrol_new alc269_base_mixer[] = {
13175 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13176 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
13177 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
13178 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
13179 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13180 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13181 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13182 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
13183 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
13184 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
13185 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
13186 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
13187 { } /* end */
13188};
13189
Kailang Yang60db6b52008-08-26 13:13:00 +020013190static struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = {
13191 /* output mixer control */
13192 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
13193 {
13194 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13195 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010013196 .subdevice = HDA_SUBDEV_AMP_FLAG,
Kailang Yang60db6b52008-08-26 13:13:00 +020013197 .info = snd_hda_mixer_amp_switch_info,
13198 .get = snd_hda_mixer_amp_switch_get,
13199 .put = alc268_acer_master_sw_put,
13200 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
13201 },
13202 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13203 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13204 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13205 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
13206 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
13207 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
Kailang Yang60db6b52008-08-26 13:13:00 +020013208 { }
13209};
13210
Tony Vroon64154832008-11-06 15:08:49 +000013211static struct snd_kcontrol_new alc269_lifebook_mixer[] = {
13212 /* output mixer control */
13213 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
13214 {
13215 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13216 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010013217 .subdevice = HDA_SUBDEV_AMP_FLAG,
Tony Vroon64154832008-11-06 15:08:49 +000013218 .info = snd_hda_mixer_amp_switch_info,
13219 .get = snd_hda_mixer_amp_switch_get,
13220 .put = alc268_acer_master_sw_put,
13221 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
13222 },
13223 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13224 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
13225 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13226 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
13227 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
13228 HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
13229 HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x0b, 0x03, HDA_INPUT),
13230 HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x0b, 0x03, HDA_INPUT),
13231 HDA_CODEC_VOLUME("Dock Mic Boost", 0x1b, 0, HDA_INPUT),
Tony Vroon64154832008-11-06 15:08:49 +000013232 { }
13233};
13234
Kailang Yangf53281e2008-07-18 12:36:43 +020013235static struct snd_kcontrol_new alc269_eeepc_mixer[] = {
Takashi Iwaiaa202452009-07-03 15:00:54 +020013236 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Darren Salt508f7112009-07-08 15:29:49 +010013237 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Takashi Iwaiaa202452009-07-03 15:00:54 +020013238 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Darren Salt508f7112009-07-08 15:29:49 +010013239 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yangf53281e2008-07-18 12:36:43 +020013240 { } /* end */
13241};
13242
Kailang Yangf6a92242007-12-13 16:52:54 +010013243/* capture mixer elements */
Kailang Yangf53281e2008-07-18 12:36:43 +020013244static struct snd_kcontrol_new alc269_epc_capture_mixer[] = {
13245 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
13246 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
Takashi Iwai26f5df22008-11-03 17:39:46 +010013247 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
13248 { } /* end */
13249};
13250
13251/* FSC amilo */
Takashi Iwaiaa202452009-07-03 15:00:54 +020013252#define alc269_fujitsu_mixer alc269_eeepc_mixer
Kailang Yangf53281e2008-07-18 12:36:43 +020013253
Kailang Yang60db6b52008-08-26 13:13:00 +020013254static struct hda_verb alc269_quanta_fl1_verbs[] = {
13255 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
13256 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13257 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13258 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13259 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
13260 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13261 { }
13262};
13263
Tony Vroon64154832008-11-06 15:08:49 +000013264static struct hda_verb alc269_lifebook_verbs[] = {
13265 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
13266 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
13267 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13268 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13269 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13270 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13271 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13272 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13273 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
13274 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13275 { }
13276};
13277
Kailang Yang60db6b52008-08-26 13:13:00 +020013278/* toggle speaker-output according to the hp-jack state */
13279static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec)
13280{
13281 unsigned int present;
13282 unsigned char bits;
13283
Wu Fengguang864f92b2009-11-18 12:38:02 +080013284 present = snd_hda_jack_detect(codec, 0x15);
Kailang Yang60db6b52008-08-26 13:13:00 +020013285 bits = present ? AMP_IN_MUTE(0) : 0;
13286 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
13287 AMP_IN_MUTE(0), bits);
13288 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
13289 AMP_IN_MUTE(0), bits);
13290
13291 snd_hda_codec_write(codec, 0x20, 0,
13292 AC_VERB_SET_COEF_INDEX, 0x0c);
13293 snd_hda_codec_write(codec, 0x20, 0,
13294 AC_VERB_SET_PROC_COEF, 0x680);
13295
13296 snd_hda_codec_write(codec, 0x20, 0,
13297 AC_VERB_SET_COEF_INDEX, 0x0c);
13298 snd_hda_codec_write(codec, 0x20, 0,
13299 AC_VERB_SET_PROC_COEF, 0x480);
13300}
13301
Tony Vroon64154832008-11-06 15:08:49 +000013302/* toggle speaker-output according to the hp-jacks state */
13303static void alc269_lifebook_speaker_automute(struct hda_codec *codec)
13304{
13305 unsigned int present;
13306 unsigned char bits;
13307
13308 /* Check laptop headphone socket */
Wu Fengguang864f92b2009-11-18 12:38:02 +080013309 present = snd_hda_jack_detect(codec, 0x15);
Tony Vroon64154832008-11-06 15:08:49 +000013310
13311 /* Check port replicator headphone socket */
Wu Fengguang864f92b2009-11-18 12:38:02 +080013312 present |= snd_hda_jack_detect(codec, 0x1a);
Tony Vroon64154832008-11-06 15:08:49 +000013313
13314 bits = present ? AMP_IN_MUTE(0) : 0;
13315 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
13316 AMP_IN_MUTE(0), bits);
13317 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
13318 AMP_IN_MUTE(0), bits);
13319
13320 snd_hda_codec_write(codec, 0x20, 0,
13321 AC_VERB_SET_COEF_INDEX, 0x0c);
13322 snd_hda_codec_write(codec, 0x20, 0,
13323 AC_VERB_SET_PROC_COEF, 0x680);
13324
13325 snd_hda_codec_write(codec, 0x20, 0,
13326 AC_VERB_SET_COEF_INDEX, 0x0c);
13327 snd_hda_codec_write(codec, 0x20, 0,
13328 AC_VERB_SET_PROC_COEF, 0x480);
13329}
13330
Tony Vroon64154832008-11-06 15:08:49 +000013331static void alc269_lifebook_mic_autoswitch(struct hda_codec *codec)
13332{
13333 unsigned int present_laptop;
13334 unsigned int present_dock;
13335
Wu Fengguang864f92b2009-11-18 12:38:02 +080013336 present_laptop = snd_hda_jack_detect(codec, 0x18);
13337 present_dock = snd_hda_jack_detect(codec, 0x1b);
Tony Vroon64154832008-11-06 15:08:49 +000013338
13339 /* Laptop mic port overrides dock mic port, design decision */
13340 if (present_dock)
13341 snd_hda_codec_write(codec, 0x23, 0,
13342 AC_VERB_SET_CONNECT_SEL, 0x3);
13343 if (present_laptop)
13344 snd_hda_codec_write(codec, 0x23, 0,
13345 AC_VERB_SET_CONNECT_SEL, 0x0);
13346 if (!present_dock && !present_laptop)
13347 snd_hda_codec_write(codec, 0x23, 0,
13348 AC_VERB_SET_CONNECT_SEL, 0x1);
13349}
13350
Kailang Yang60db6b52008-08-26 13:13:00 +020013351static void alc269_quanta_fl1_unsol_event(struct hda_codec *codec,
13352 unsigned int res)
13353{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013354 switch (res >> 26) {
13355 case ALC880_HP_EVENT:
Kailang Yang60db6b52008-08-26 13:13:00 +020013356 alc269_quanta_fl1_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013357 break;
13358 case ALC880_MIC_EVENT:
13359 alc_mic_automute(codec);
13360 break;
13361 }
Kailang Yang60db6b52008-08-26 13:13:00 +020013362}
13363
Tony Vroon64154832008-11-06 15:08:49 +000013364static void alc269_lifebook_unsol_event(struct hda_codec *codec,
13365 unsigned int res)
13366{
13367 if ((res >> 26) == ALC880_HP_EVENT)
13368 alc269_lifebook_speaker_automute(codec);
13369 if ((res >> 26) == ALC880_MIC_EVENT)
13370 alc269_lifebook_mic_autoswitch(codec);
13371}
13372
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013373static void alc269_quanta_fl1_setup(struct hda_codec *codec)
13374{
13375 struct alc_spec *spec = codec->spec;
13376 spec->ext_mic.pin = 0x18;
13377 spec->ext_mic.mux_idx = 0;
13378 spec->int_mic.pin = 0x19;
13379 spec->int_mic.mux_idx = 1;
13380 spec->auto_mic = 1;
13381}
13382
Kailang Yang60db6b52008-08-26 13:13:00 +020013383static void alc269_quanta_fl1_init_hook(struct hda_codec *codec)
13384{
13385 alc269_quanta_fl1_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013386 alc_mic_automute(codec);
Kailang Yang60db6b52008-08-26 13:13:00 +020013387}
13388
Tony Vroon64154832008-11-06 15:08:49 +000013389static void alc269_lifebook_init_hook(struct hda_codec *codec)
13390{
13391 alc269_lifebook_speaker_automute(codec);
13392 alc269_lifebook_mic_autoswitch(codec);
13393}
13394
Kailang Yang60db6b52008-08-26 13:13:00 +020013395static struct hda_verb alc269_eeepc_dmic_init_verbs[] = {
13396 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
13397 {0x23, AC_VERB_SET_CONNECT_SEL, 0x05},
13398 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
13399 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
13400 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13401 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
13402 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
13403 {}
13404};
13405
13406static struct hda_verb alc269_eeepc_amic_init_verbs[] = {
13407 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
13408 {0x23, AC_VERB_SET_CONNECT_SEL, 0x01},
13409 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
13410 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x701b | (0x00 << 8))},
13411 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
13412 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
13413 {}
13414};
13415
13416/* toggle speaker-output according to the hp-jack state */
13417static void alc269_speaker_automute(struct hda_codec *codec)
13418{
Kailang Yangebb83ee2009-12-17 12:23:00 +010013419 struct alc_spec *spec = codec->spec;
13420 unsigned int nid = spec->autocfg.hp_pins[0];
Kailang Yang60db6b52008-08-26 13:13:00 +020013421 unsigned int present;
13422 unsigned char bits;
13423
Kailang Yangebb83ee2009-12-17 12:23:00 +010013424 present = snd_hda_jack_detect(codec, nid);
Kailang Yang60db6b52008-08-26 13:13:00 +020013425 bits = present ? AMP_IN_MUTE(0) : 0;
13426 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
13427 AMP_IN_MUTE(0), bits);
13428 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
13429 AMP_IN_MUTE(0), bits);
13430}
13431
Kailang Yang60db6b52008-08-26 13:13:00 +020013432/* unsolicited event for HP jack sensing */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013433static void alc269_eeepc_unsol_event(struct hda_codec *codec,
Kailang Yang60db6b52008-08-26 13:13:00 +020013434 unsigned int res)
13435{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013436 switch (res >> 26) {
13437 case ALC880_HP_EVENT:
Kailang Yang60db6b52008-08-26 13:13:00 +020013438 alc269_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013439 break;
13440 case ALC880_MIC_EVENT:
13441 alc_mic_automute(codec);
13442 break;
13443 }
Kailang Yang60db6b52008-08-26 13:13:00 +020013444}
13445
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013446static void alc269_eeepc_dmic_setup(struct hda_codec *codec)
13447{
13448 struct alc_spec *spec = codec->spec;
13449 spec->ext_mic.pin = 0x18;
13450 spec->ext_mic.mux_idx = 0;
13451 spec->int_mic.pin = 0x12;
13452 spec->int_mic.mux_idx = 5;
13453 spec->auto_mic = 1;
13454}
13455
13456static void alc269_eeepc_amic_setup(struct hda_codec *codec)
13457{
13458 struct alc_spec *spec = codec->spec;
13459 spec->ext_mic.pin = 0x18;
13460 spec->ext_mic.mux_idx = 0;
13461 spec->int_mic.pin = 0x19;
13462 spec->int_mic.mux_idx = 1;
13463 spec->auto_mic = 1;
13464}
13465
13466static void alc269_eeepc_inithook(struct hda_codec *codec)
Kailang Yang60db6b52008-08-26 13:13:00 +020013467{
13468 alc269_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013469 alc_mic_automute(codec);
Kailang Yang60db6b52008-08-26 13:13:00 +020013470}
13471
Kailang Yangf6a92242007-12-13 16:52:54 +010013472/*
13473 * generic initialization of ADC, input mixers and output mixers
13474 */
13475static struct hda_verb alc269_init_verbs[] = {
13476 /*
13477 * Unmute ADC0 and set the default input to mic-in
13478 */
Kailang Yang60db6b52008-08-26 13:13:00 +020013479 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangf6a92242007-12-13 16:52:54 +010013480
13481 /* Mute input amps (PCBeep, Line In, Mic 1 & Mic 2) of the
13482 * analog-loopback mixer widget
13483 * Note: PASD motherboards uses the Line In 2 as the input for
13484 * front panel mic (mic 2)
13485 */
13486 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
13487 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13488 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13489 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
13490 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
13491 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
13492
13493 /*
13494 * Set up output mixers (0x0c - 0x0e)
13495 */
13496 /* set vol=0 to output mixers */
13497 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13498 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13499
13500 /* set up input amps for analog loopback */
13501 /* Amp Indices: DAC = 0, mixer = 1 */
13502 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13503 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13504 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13505 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13506 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13507 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
13508
13509 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13510 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13511 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
13512 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
13513 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
13514 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13515 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13516
13517 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13518 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13519 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13520 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13521 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13522 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13523 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13524
13525 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
13526 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
13527
13528 /* FIXME: use matrix-type input source selection */
13529 /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
13530 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yang60db6b52008-08-26 13:13:00 +020013531 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
13532 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangf6a92242007-12-13 16:52:54 +010013533 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
13534 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
13535
13536 /* set EAPD */
13537 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
13538 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
13539 { }
13540};
13541
Takashi Iwai9d0b71b2009-08-24 14:10:30 +020013542#define alc269_auto_create_multi_out_ctls \
13543 alc268_auto_create_multi_out_ctls
Takashi Iwai05f5f472009-08-25 13:10:18 +020013544#define alc269_auto_create_input_ctls \
13545 alc268_auto_create_input_ctls
Kailang Yangf6a92242007-12-13 16:52:54 +010013546
13547#ifdef CONFIG_SND_HDA_POWER_SAVE
13548#define alc269_loopbacks alc880_loopbacks
13549#endif
13550
Sasha Alexandrdef319f2009-06-16 16:00:15 -040013551/* pcm configuration: identical with ALC880 */
Kailang Yangf6a92242007-12-13 16:52:54 +010013552#define alc269_pcm_analog_playback alc880_pcm_analog_playback
13553#define alc269_pcm_analog_capture alc880_pcm_analog_capture
13554#define alc269_pcm_digital_playback alc880_pcm_digital_playback
13555#define alc269_pcm_digital_capture alc880_pcm_digital_capture
13556
Takashi Iwaif03d3112009-03-05 14:18:16 +010013557static struct hda_pcm_stream alc269_44k_pcm_analog_playback = {
13558 .substreams = 1,
13559 .channels_min = 2,
13560 .channels_max = 8,
13561 .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
13562 /* NID is set in alc_build_pcms */
13563 .ops = {
13564 .open = alc880_playback_pcm_open,
13565 .prepare = alc880_playback_pcm_prepare,
13566 .cleanup = alc880_playback_pcm_cleanup
13567 },
13568};
13569
13570static struct hda_pcm_stream alc269_44k_pcm_analog_capture = {
13571 .substreams = 1,
13572 .channels_min = 2,
13573 .channels_max = 2,
13574 .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
13575 /* NID is set in alc_build_pcms */
13576};
13577
Kailang Yangf6a92242007-12-13 16:52:54 +010013578/*
13579 * BIOS auto configuration
13580 */
13581static int alc269_parse_auto_config(struct hda_codec *codec)
13582{
13583 struct alc_spec *spec = codec->spec;
Takashi Iwaicfb9fb52009-02-06 17:34:03 +010013584 int err;
Kailang Yangf6a92242007-12-13 16:52:54 +010013585 static hda_nid_t alc269_ignore[] = { 0x1d, 0 };
13586
13587 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
13588 alc269_ignore);
13589 if (err < 0)
13590 return err;
13591
13592 err = alc269_auto_create_multi_out_ctls(spec, &spec->autocfg);
13593 if (err < 0)
13594 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020013595 err = alc269_auto_create_input_ctls(codec, &spec->autocfg);
Kailang Yangf6a92242007-12-13 16:52:54 +010013596 if (err < 0)
13597 return err;
13598
13599 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
13600
Takashi Iwai0852d7a2009-02-11 11:35:15 +010013601 if (spec->autocfg.dig_outs)
Kailang Yangf6a92242007-12-13 16:52:54 +010013602 spec->multiout.dig_out_nid = ALC269_DIGOUT_NID;
13603
Takashi Iwai603c4012008-07-30 15:01:44 +020013604 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010013605 add_mixer(spec, spec->kctls.list);
Kailang Yangf6a92242007-12-13 16:52:54 +010013606
Takashi Iwaid88897e2008-10-31 15:01:37 +010013607 add_verb(spec, alc269_init_verbs);
Kailang Yangf6a92242007-12-13 16:52:54 +010013608 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020013609 spec->input_mux = &spec->private_imux[0];
Takashi Iwaie01bf502008-08-21 16:25:07 +020013610 /* set default input source */
13611 snd_hda_codec_write_cache(codec, alc269_capsrc_nids[0],
13612 0, AC_VERB_SET_CONNECT_SEL,
13613 spec->input_mux->items[0].index);
Kailang Yangf6a92242007-12-13 16:52:54 +010013614
13615 err = alc_auto_add_mic_boost(codec);
13616 if (err < 0)
13617 return err;
13618
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013619 if (!spec->cap_mixer && !spec->no_analog)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020013620 set_capture_mixer(codec);
Kailang Yangf53281e2008-07-18 12:36:43 +020013621
Takashi Iwai1d955eb2009-06-29 11:33:53 +020013622 alc_ssid_check(codec, 0x15, 0x1b, 0x14);
13623
Kailang Yangf6a92242007-12-13 16:52:54 +010013624 return 1;
13625}
13626
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013627#define alc269_auto_init_multi_out alc268_auto_init_multi_out
13628#define alc269_auto_init_hp_out alc268_auto_init_hp_out
Kailang Yangf6a92242007-12-13 16:52:54 +010013629#define alc269_auto_init_analog_input alc882_auto_init_analog_input
13630
13631
13632/* init callback for auto-configuration model -- overriding the default init */
13633static void alc269_auto_init(struct hda_codec *codec)
13634{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013635 struct alc_spec *spec = codec->spec;
Kailang Yangf6a92242007-12-13 16:52:54 +010013636 alc269_auto_init_multi_out(codec);
13637 alc269_auto_init_hp_out(codec);
13638 alc269_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013639 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020013640 alc_inithook(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010013641}
13642
13643/*
13644 * configuration and preset
13645 */
13646static const char *alc269_models[ALC269_MODEL_LAST] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020013647 [ALC269_BASIC] = "basic",
Takashi Iwai2922c9a2008-08-27 18:12:42 +020013648 [ALC269_QUANTA_FL1] = "quanta",
Kailang Yangebb83ee2009-12-17 12:23:00 +010013649 [ALC269_ASUS_AMIC] = "asus-amic",
13650 [ALC269_ASUS_DMIC] = "asus-dmic",
Tony Vroon64154832008-11-06 15:08:49 +000013651 [ALC269_FUJITSU] = "fujitsu",
Takashi Iwai3d3792c2009-09-11 07:50:47 +020013652 [ALC269_LIFEBOOK] = "lifebook",
13653 [ALC269_AUTO] = "auto",
Kailang Yangf6a92242007-12-13 16:52:54 +010013654};
13655
13656static struct snd_pci_quirk alc269_cfg_tbl[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020013657 SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_QUANTA_FL1),
Kailang Yangf53281e2008-07-18 12:36:43 +020013658 SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A",
Kailang Yangebb83ee2009-12-17 12:23:00 +010013659 ALC269_ASUS_AMIC),
13660 SND_PCI_QUIRK(0x1043, 0x1133, "ASUS UJ20ft", ALC269_ASUS_AMIC),
13661 SND_PCI_QUIRK(0x1043, 0x1273, "ASUS UL80JT", ALC269_ASUS_AMIC),
13662 SND_PCI_QUIRK(0x1043, 0x1283, "ASUS U53Jc", ALC269_ASUS_AMIC),
13663 SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS N82Jv", ALC269_ASUS_AMIC),
13664 SND_PCI_QUIRK(0x1043, 0x13a3, "ASUS UL30Vt", ALC269_ASUS_AMIC),
13665 SND_PCI_QUIRK(0x1043, 0x1373, "ASUS G73JX", ALC269_ASUS_AMIC),
13666 SND_PCI_QUIRK(0x1043, 0x1383, "ASUS UJ30Jc", ALC269_ASUS_AMIC),
13667 SND_PCI_QUIRK(0x1043, 0x13d3, "ASUS N61JA", ALC269_ASUS_AMIC),
13668 SND_PCI_QUIRK(0x1043, 0x1413, "ASUS UL50", ALC269_ASUS_AMIC),
13669 SND_PCI_QUIRK(0x1043, 0x1443, "ASUS UL30", ALC269_ASUS_AMIC),
13670 SND_PCI_QUIRK(0x1043, 0x1453, "ASUS M60Jv", ALC269_ASUS_AMIC),
13671 SND_PCI_QUIRK(0x1043, 0x1483, "ASUS UL80", ALC269_ASUS_AMIC),
13672 SND_PCI_QUIRK(0x1043, 0x14f3, "ASUS F83Vf", ALC269_ASUS_AMIC),
13673 SND_PCI_QUIRK(0x1043, 0x14e3, "ASUS UL20", ALC269_ASUS_AMIC),
13674 SND_PCI_QUIRK(0x1043, 0x1513, "ASUS UX30", ALC269_ASUS_AMIC),
13675 SND_PCI_QUIRK(0x1043, 0x15a3, "ASUS N60Jv", ALC269_ASUS_AMIC),
13676 SND_PCI_QUIRK(0x1043, 0x15b3, "ASUS N60Dp", ALC269_ASUS_AMIC),
13677 SND_PCI_QUIRK(0x1043, 0x15c3, "ASUS N70De", ALC269_ASUS_AMIC),
13678 SND_PCI_QUIRK(0x1043, 0x15e3, "ASUS F83T", ALC269_ASUS_AMIC),
13679 SND_PCI_QUIRK(0x1043, 0x1643, "ASUS M60J", ALC269_ASUS_AMIC),
13680 SND_PCI_QUIRK(0x1043, 0x1653, "ASUS U50", ALC269_ASUS_AMIC),
13681 SND_PCI_QUIRK(0x1043, 0x1693, "ASUS F50N", ALC269_ASUS_AMIC),
13682 SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS F5Q", ALC269_ASUS_AMIC),
13683 SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_ASUS_DMIC),
13684 SND_PCI_QUIRK(0x1043, 0x1723, "ASUS P80", ALC269_ASUS_AMIC),
13685 SND_PCI_QUIRK(0x1043, 0x1743, "ASUS U80", ALC269_ASUS_AMIC),
13686 SND_PCI_QUIRK(0x1043, 0x1773, "ASUS U20A", ALC269_ASUS_AMIC),
13687 SND_PCI_QUIRK(0x1043, 0x1883, "ASUS F81Se", ALC269_ASUS_AMIC),
Kailang Yangf53281e2008-07-18 12:36:43 +020013688 SND_PCI_QUIRK(0x1043, 0x831a, "ASUS Eeepc P901",
Kailang Yangebb83ee2009-12-17 12:23:00 +010013689 ALC269_ASUS_DMIC),
Kailang Yang60db6b52008-08-26 13:13:00 +020013690 SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101",
Kailang Yangebb83ee2009-12-17 12:23:00 +010013691 ALC269_ASUS_DMIC),
13692 SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005HA", ALC269_ASUS_DMIC),
13693 SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005HA", ALC269_ASUS_DMIC),
Takashi Iwai26f5df22008-11-03 17:39:46 +010013694 SND_PCI_QUIRK(0x1734, 0x115d, "FSC Amilo", ALC269_FUJITSU),
Tony Vroon64154832008-11-06 15:08:49 +000013695 SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook ICH9M-based", ALC269_LIFEBOOK),
Kailang Yangf6a92242007-12-13 16:52:54 +010013696 {}
13697};
13698
13699static struct alc_config_preset alc269_presets[] = {
13700 [ALC269_BASIC] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010013701 .mixers = { alc269_base_mixer },
Kailang Yangf6a92242007-12-13 16:52:54 +010013702 .init_verbs = { alc269_init_verbs },
13703 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
13704 .dac_nids = alc269_dac_nids,
13705 .hp_nid = 0x03,
13706 .num_channel_mode = ARRAY_SIZE(alc269_modes),
13707 .channel_mode = alc269_modes,
13708 .input_mux = &alc269_capture_source,
13709 },
Kailang Yang60db6b52008-08-26 13:13:00 +020013710 [ALC269_QUANTA_FL1] = {
13711 .mixers = { alc269_quanta_fl1_mixer },
13712 .init_verbs = { alc269_init_verbs, alc269_quanta_fl1_verbs },
13713 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
13714 .dac_nids = alc269_dac_nids,
13715 .hp_nid = 0x03,
13716 .num_channel_mode = ARRAY_SIZE(alc269_modes),
13717 .channel_mode = alc269_modes,
13718 .input_mux = &alc269_capture_source,
13719 .unsol_event = alc269_quanta_fl1_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013720 .setup = alc269_quanta_fl1_setup,
Kailang Yang60db6b52008-08-26 13:13:00 +020013721 .init_hook = alc269_quanta_fl1_init_hook,
13722 },
Kailang Yangebb83ee2009-12-17 12:23:00 +010013723 [ALC269_ASUS_AMIC] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010013724 .mixers = { alc269_eeepc_mixer },
13725 .cap_mixer = alc269_epc_capture_mixer,
Kailang Yangf53281e2008-07-18 12:36:43 +020013726 .init_verbs = { alc269_init_verbs,
13727 alc269_eeepc_amic_init_verbs },
13728 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
13729 .dac_nids = alc269_dac_nids,
13730 .hp_nid = 0x03,
13731 .num_channel_mode = ARRAY_SIZE(alc269_modes),
13732 .channel_mode = alc269_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013733 .unsol_event = alc269_eeepc_unsol_event,
13734 .setup = alc269_eeepc_amic_setup,
13735 .init_hook = alc269_eeepc_inithook,
Kailang Yangf53281e2008-07-18 12:36:43 +020013736 },
Kailang Yangebb83ee2009-12-17 12:23:00 +010013737 [ALC269_ASUS_DMIC] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010013738 .mixers = { alc269_eeepc_mixer },
13739 .cap_mixer = alc269_epc_capture_mixer,
Kailang Yangf53281e2008-07-18 12:36:43 +020013740 .init_verbs = { alc269_init_verbs,
13741 alc269_eeepc_dmic_init_verbs },
13742 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
13743 .dac_nids = alc269_dac_nids,
13744 .hp_nid = 0x03,
13745 .num_channel_mode = ARRAY_SIZE(alc269_modes),
13746 .channel_mode = alc269_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013747 .unsol_event = alc269_eeepc_unsol_event,
13748 .setup = alc269_eeepc_dmic_setup,
13749 .init_hook = alc269_eeepc_inithook,
Kailang Yangf53281e2008-07-18 12:36:43 +020013750 },
Takashi Iwai26f5df22008-11-03 17:39:46 +010013751 [ALC269_FUJITSU] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010013752 .mixers = { alc269_fujitsu_mixer },
Takashi Iwai26f5df22008-11-03 17:39:46 +010013753 .cap_mixer = alc269_epc_capture_mixer,
13754 .init_verbs = { alc269_init_verbs,
13755 alc269_eeepc_dmic_init_verbs },
13756 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
13757 .dac_nids = alc269_dac_nids,
13758 .hp_nid = 0x03,
13759 .num_channel_mode = ARRAY_SIZE(alc269_modes),
13760 .channel_mode = alc269_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013761 .unsol_event = alc269_eeepc_unsol_event,
13762 .setup = alc269_eeepc_dmic_setup,
13763 .init_hook = alc269_eeepc_inithook,
Takashi Iwai26f5df22008-11-03 17:39:46 +010013764 },
Tony Vroon64154832008-11-06 15:08:49 +000013765 [ALC269_LIFEBOOK] = {
13766 .mixers = { alc269_lifebook_mixer },
13767 .init_verbs = { alc269_init_verbs, alc269_lifebook_verbs },
13768 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
13769 .dac_nids = alc269_dac_nids,
13770 .hp_nid = 0x03,
13771 .num_channel_mode = ARRAY_SIZE(alc269_modes),
13772 .channel_mode = alc269_modes,
13773 .input_mux = &alc269_capture_source,
13774 .unsol_event = alc269_lifebook_unsol_event,
13775 .init_hook = alc269_lifebook_init_hook,
13776 },
Kailang Yangf6a92242007-12-13 16:52:54 +010013777};
13778
13779static int patch_alc269(struct hda_codec *codec)
13780{
13781 struct alc_spec *spec;
13782 int board_config;
13783 int err;
13784
13785 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
13786 if (spec == NULL)
13787 return -ENOMEM;
13788
13789 codec->spec = spec;
13790
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020013791 alc_fix_pll_init(codec, 0x20, 0x04, 15);
13792
Kailang Yang274693f2009-12-03 10:07:50 +010013793 if ((alc_read_coef_idx(codec, 0) & 0x00f0) == 0x0010){
13794 kfree(codec->chip_name);
13795 codec->chip_name = kstrdup("ALC259", GFP_KERNEL);
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010013796 if (!codec->chip_name) {
13797 alc_free(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010013798 return -ENOMEM;
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010013799 }
Kailang Yang274693f2009-12-03 10:07:50 +010013800 }
13801
Kailang Yangf6a92242007-12-13 16:52:54 +010013802 board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST,
13803 alc269_models,
13804 alc269_cfg_tbl);
13805
13806 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020013807 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
13808 codec->chip_name);
Kailang Yangf6a92242007-12-13 16:52:54 +010013809 board_config = ALC269_AUTO;
13810 }
13811
13812 if (board_config == ALC269_AUTO) {
13813 /* automatic parse from the BIOS config */
13814 err = alc269_parse_auto_config(codec);
13815 if (err < 0) {
13816 alc_free(codec);
13817 return err;
13818 } else if (!err) {
13819 printk(KERN_INFO
13820 "hda_codec: Cannot set up configuration "
13821 "from BIOS. Using base mode...\n");
13822 board_config = ALC269_BASIC;
13823 }
13824 }
13825
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090013826 err = snd_hda_attach_beep_device(codec, 0x1);
13827 if (err < 0) {
13828 alc_free(codec);
13829 return err;
13830 }
13831
Kailang Yangf6a92242007-12-13 16:52:54 +010013832 if (board_config != ALC269_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020013833 setup_preset(codec, &alc269_presets[board_config]);
Kailang Yangf6a92242007-12-13 16:52:54 +010013834
Takashi Iwaif03d3112009-03-05 14:18:16 +010013835 if (codec->subsystem_id == 0x17aa3bf8) {
13836 /* Due to a hardware problem on Lenovo Ideadpad, we need to
13837 * fix the sample rate of analog I/O to 44.1kHz
13838 */
13839 spec->stream_analog_playback = &alc269_44k_pcm_analog_playback;
13840 spec->stream_analog_capture = &alc269_44k_pcm_analog_capture;
13841 } else {
13842 spec->stream_analog_playback = &alc269_pcm_analog_playback;
13843 spec->stream_analog_capture = &alc269_pcm_analog_capture;
13844 }
Kailang Yangf6a92242007-12-13 16:52:54 +010013845 spec->stream_digital_playback = &alc269_pcm_digital_playback;
13846 spec->stream_digital_capture = &alc269_pcm_digital_capture;
13847
13848 spec->adc_nids = alc269_adc_nids;
13849 spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids);
Takashi Iwaie01bf502008-08-21 16:25:07 +020013850 spec->capsrc_nids = alc269_capsrc_nids;
Takashi Iwaif9e336f2008-10-31 16:37:07 +010013851 if (!spec->cap_mixer)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020013852 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010013853 set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
Kailang Yangf6a92242007-12-13 16:52:54 +010013854
Takashi Iwai100d5eb2009-08-10 11:55:51 +020013855 spec->vmaster_nid = 0x02;
13856
Kailang Yangf6a92242007-12-13 16:52:54 +010013857 codec->patch_ops = alc_patch_ops;
13858 if (board_config == ALC269_AUTO)
13859 spec->init_hook = alc269_auto_init;
13860#ifdef CONFIG_SND_HDA_POWER_SAVE
13861 if (!spec->loopback.amplist)
13862 spec->loopback.amplist = alc269_loopbacks;
13863#endif
Takashi Iwaidaead532008-11-28 12:55:36 +010013864 codec->proc_widget_hook = print_realtek_coef;
Kailang Yangf6a92242007-12-13 16:52:54 +010013865
13866 return 0;
13867}
13868
13869/*
Kailang Yangdf694da2005-12-05 19:42:22 +010013870 * ALC861 channel source setting (2/6 channel selection for 3-stack)
13871 */
13872
13873/*
13874 * set the path ways for 2 channel output
13875 * need to set the codec line out and mic 1 pin widgets to inputs
13876 */
13877static struct hda_verb alc861_threestack_ch2_init[] = {
13878 /* set pin widget 1Ah (line in) for input */
13879 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013880 /* set pin widget 18h (mic1/2) for input, for mic also enable
13881 * the vref
13882 */
Kailang Yangdf694da2005-12-05 19:42:22 +010013883 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13884
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013885 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
13886#if 0
13887 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
13888 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
13889#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010013890 { } /* end */
13891};
13892/*
13893 * 6ch mode
13894 * need to set the codec line out and mic 1 pin widgets to outputs
13895 */
13896static struct hda_verb alc861_threestack_ch6_init[] = {
13897 /* set pin widget 1Ah (line in) for output (Back Surround)*/
13898 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13899 /* set pin widget 18h (mic1) for output (CLFE)*/
13900 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13901
13902 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013903 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010013904
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013905 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
13906#if 0
13907 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
13908 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
13909#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010013910 { } /* end */
13911};
13912
13913static struct hda_channel_mode alc861_threestack_modes[2] = {
13914 { 2, alc861_threestack_ch2_init },
13915 { 6, alc861_threestack_ch6_init },
13916};
Takashi Iwai22309c32006-08-09 16:57:28 +020013917/* Set mic1 as input and unmute the mixer */
13918static struct hda_verb alc861_uniwill_m31_ch2_init[] = {
13919 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13920 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
13921 { } /* end */
13922};
13923/* Set mic1 as output and mute mixer */
13924static struct hda_verb alc861_uniwill_m31_ch4_init[] = {
13925 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13926 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
13927 { } /* end */
13928};
13929
13930static struct hda_channel_mode alc861_uniwill_m31_modes[2] = {
13931 { 2, alc861_uniwill_m31_ch2_init },
13932 { 4, alc861_uniwill_m31_ch4_init },
13933};
Kailang Yangdf694da2005-12-05 19:42:22 +010013934
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013935/* Set mic1 and line-in as input and unmute the mixer */
13936static struct hda_verb alc861_asus_ch2_init[] = {
13937 /* set pin widget 1Ah (line in) for input */
13938 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013939 /* set pin widget 18h (mic1/2) for input, for mic also enable
13940 * the vref
13941 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020013942 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
13943
13944 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
13945#if 0
13946 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
13947 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
13948#endif
13949 { } /* end */
13950};
13951/* Set mic1 nad line-in as output and mute mixer */
13952static struct hda_verb alc861_asus_ch6_init[] = {
13953 /* set pin widget 1Ah (line in) for output (Back Surround)*/
13954 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13955 /* { 0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
13956 /* set pin widget 18h (mic1) for output (CLFE)*/
13957 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
13958 /* { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
13959 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
13960 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
13961
13962 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
13963#if 0
13964 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
13965 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
13966#endif
13967 { } /* end */
13968};
13969
13970static struct hda_channel_mode alc861_asus_modes[2] = {
13971 { 2, alc861_asus_ch2_init },
13972 { 6, alc861_asus_ch6_init },
13973};
13974
Kailang Yangdf694da2005-12-05 19:42:22 +010013975/* patch-ALC861 */
13976
13977static struct snd_kcontrol_new alc861_base_mixer[] = {
13978 /* output mixer control */
13979 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
13980 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
13981 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
13982 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
13983 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
13984
13985 /*Input mixer control */
13986 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
13987 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
13988 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
13989 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
13990 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
13991 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
13992 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
13993 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
13994 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
13995 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013996
Kailang Yangdf694da2005-12-05 19:42:22 +010013997 { } /* end */
13998};
13999
14000static struct snd_kcontrol_new alc861_3ST_mixer[] = {
14001 /* output mixer control */
14002 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
14003 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
14004 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
14005 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
14006 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
14007
14008 /* Input mixer control */
14009 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
14010 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
14011 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
14012 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
14013 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
14014 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
14015 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
14016 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
14017 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
14018 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014019
Kailang Yangdf694da2005-12-05 19:42:22 +010014020 {
14021 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
14022 .name = "Channel Mode",
14023 .info = alc_ch_mode_info,
14024 .get = alc_ch_mode_get,
14025 .put = alc_ch_mode_put,
14026 .private_value = ARRAY_SIZE(alc861_threestack_modes),
14027 },
14028 { } /* end */
Tobin Davisa53d1ae2006-10-17 12:00:28 +020014029};
14030
Takashi Iwaid1d985f2006-11-23 19:27:12 +010014031static struct snd_kcontrol_new alc861_toshiba_mixer[] = {
Tobin Davisa53d1ae2006-10-17 12:00:28 +020014032 /* output mixer control */
14033 HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT),
14034 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
14035 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
Kailang Yangea1fb292008-08-26 12:58:38 +020014036
Tobin Davisa53d1ae2006-10-17 12:00:28 +020014037 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014038};
Tobin Davisa53d1ae2006-10-17 12:00:28 +020014039
Takashi Iwai22309c32006-08-09 16:57:28 +020014040static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = {
14041 /* output mixer control */
14042 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
14043 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
14044 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
14045 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
14046 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
14047
14048 /* Input mixer control */
14049 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
14050 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
14051 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
14052 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
14053 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
14054 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
14055 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
14056 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
14057 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
14058 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014059
Takashi Iwai22309c32006-08-09 16:57:28 +020014060 {
14061 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
14062 .name = "Channel Mode",
14063 .info = alc_ch_mode_info,
14064 .get = alc_ch_mode_get,
14065 .put = alc_ch_mode_put,
14066 .private_value = ARRAY_SIZE(alc861_uniwill_m31_modes),
14067 },
14068 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014069};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014070
14071static struct snd_kcontrol_new alc861_asus_mixer[] = {
14072 /* output mixer control */
14073 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
14074 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
14075 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
14076 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
14077 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
14078
14079 /* Input mixer control */
14080 HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
14081 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT),
14082 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
14083 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
14084 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
14085 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
14086 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
14087 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
14088 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014089 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_OUTPUT),
14090
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014091 {
14092 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
14093 .name = "Channel Mode",
14094 .info = alc_ch_mode_info,
14095 .get = alc_ch_mode_get,
14096 .put = alc_ch_mode_put,
14097 .private_value = ARRAY_SIZE(alc861_asus_modes),
14098 },
14099 { }
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010014100};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014101
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010014102/* additional mixer */
Takashi Iwaid1d985f2006-11-23 19:27:12 +010014103static struct snd_kcontrol_new alc861_asus_laptop_mixer[] = {
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010014104 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
14105 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010014106 { }
14107};
14108
Kailang Yangdf694da2005-12-05 19:42:22 +010014109/*
14110 * generic initialization of ADC, input mixers and output mixers
14111 */
14112static struct hda_verb alc861_base_init_verbs[] = {
14113 /*
14114 * Unmute ADC0 and set the default input to mic-in
14115 */
14116 /* port-A for surround (rear panel) */
14117 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14118 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x00 },
14119 /* port-B for mic-in (rear panel) with vref */
14120 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14121 /* port-C for line-in (rear panel) */
14122 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
14123 /* port-D for Front */
14124 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14125 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
14126 /* port-E for HP out (front panel) */
14127 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
14128 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010014129 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010014130 /* port-F for mic-in (front panel) with vref */
14131 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14132 /* port-G for CLFE (rear panel) */
14133 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14134 { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x00 },
14135 /* port-H for side (rear panel) */
14136 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14137 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x00 },
14138 /* CD-in */
14139 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
14140 /* route front mic to ADC1*/
14141 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
14142 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020014143
Kailang Yangdf694da2005-12-05 19:42:22 +010014144 /* Unmute DAC0~3 & spdif out*/
14145 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14146 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14147 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14148 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14149 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020014150
Kailang Yangdf694da2005-12-05 19:42:22 +010014151 /* Unmute Mixer 14 (mic) 1c (Line in)*/
14152 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14153 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14154 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14155 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020014156
Kailang Yangdf694da2005-12-05 19:42:22 +010014157 /* Unmute Stereo Mixer 15 */
14158 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14159 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14160 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014161 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010014162
14163 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14164 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14165 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14166 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14167 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14168 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14169 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14170 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014171 /* hp used DAC 3 (Front) */
14172 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010014173 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
14174
14175 { }
14176};
14177
14178static struct hda_verb alc861_threestack_init_verbs[] = {
14179 /*
14180 * Unmute ADC0 and set the default input to mic-in
14181 */
14182 /* port-A for surround (rear panel) */
14183 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
14184 /* port-B for mic-in (rear panel) with vref */
14185 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14186 /* port-C for line-in (rear panel) */
14187 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
14188 /* port-D for Front */
14189 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14190 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
14191 /* port-E for HP out (front panel) */
14192 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
14193 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010014194 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010014195 /* port-F for mic-in (front panel) with vref */
14196 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14197 /* port-G for CLFE (rear panel) */
14198 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
14199 /* port-H for side (rear panel) */
14200 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
14201 /* CD-in */
14202 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
14203 /* route front mic to ADC1*/
14204 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
14205 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14206 /* Unmute DAC0~3 & spdif out*/
14207 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14208 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14209 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14210 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14211 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020014212
Kailang Yangdf694da2005-12-05 19:42:22 +010014213 /* Unmute Mixer 14 (mic) 1c (Line in)*/
14214 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14215 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14216 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14217 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020014218
Kailang Yangdf694da2005-12-05 19:42:22 +010014219 /* Unmute Stereo Mixer 15 */
14220 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14221 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14222 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014223 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010014224
14225 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14226 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14227 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14228 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14229 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14230 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14231 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14232 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014233 /* hp used DAC 3 (Front) */
14234 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010014235 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
14236 { }
14237};
Takashi Iwai22309c32006-08-09 16:57:28 +020014238
14239static struct hda_verb alc861_uniwill_m31_init_verbs[] = {
14240 /*
14241 * Unmute ADC0 and set the default input to mic-in
14242 */
14243 /* port-A for surround (rear panel) */
14244 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
14245 /* port-B for mic-in (rear panel) with vref */
14246 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14247 /* port-C for line-in (rear panel) */
14248 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
14249 /* port-D for Front */
14250 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14251 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
14252 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014253 /* this has to be set to VREF80 */
14254 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Takashi Iwai22309c32006-08-09 16:57:28 +020014255 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010014256 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai22309c32006-08-09 16:57:28 +020014257 /* port-F for mic-in (front panel) with vref */
14258 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14259 /* port-G for CLFE (rear panel) */
14260 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
14261 /* port-H for side (rear panel) */
14262 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
14263 /* CD-in */
14264 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
14265 /* route front mic to ADC1*/
14266 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
14267 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14268 /* Unmute DAC0~3 & spdif out*/
14269 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14270 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14271 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14272 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14273 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020014274
Takashi Iwai22309c32006-08-09 16:57:28 +020014275 /* Unmute Mixer 14 (mic) 1c (Line in)*/
14276 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14277 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14278 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14279 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020014280
Takashi Iwai22309c32006-08-09 16:57:28 +020014281 /* Unmute Stereo Mixer 15 */
14282 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14283 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14284 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014285 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Takashi Iwai22309c32006-08-09 16:57:28 +020014286
14287 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14288 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14289 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14290 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14291 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14292 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14293 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14294 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014295 /* hp used DAC 3 (Front) */
14296 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Takashi Iwai22309c32006-08-09 16:57:28 +020014297 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
14298 { }
14299};
14300
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014301static struct hda_verb alc861_asus_init_verbs[] = {
14302 /*
14303 * Unmute ADC0 and set the default input to mic-in
14304 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014305 /* port-A for surround (rear panel)
14306 * according to codec#0 this is the HP jack
14307 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014308 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* was 0x00 */
14309 /* route front PCM to HP */
14310 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x01 },
14311 /* port-B for mic-in (rear panel) with vref */
14312 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14313 /* port-C for line-in (rear panel) */
14314 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
14315 /* port-D for Front */
14316 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14317 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
14318 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014319 /* this has to be set to VREF80 */
14320 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014321 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010014322 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014323 /* port-F for mic-in (front panel) with vref */
14324 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14325 /* port-G for CLFE (rear panel) */
14326 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14327 /* port-H for side (rear panel) */
14328 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14329 /* CD-in */
14330 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
14331 /* route front mic to ADC1*/
14332 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
14333 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14334 /* Unmute DAC0~3 & spdif out*/
14335 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14336 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14337 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14338 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14339 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14340 /* Unmute Mixer 14 (mic) 1c (Line in)*/
14341 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14342 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14343 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14344 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020014345
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014346 /* Unmute Stereo Mixer 15 */
14347 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14348 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14349 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014350 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014351
14352 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14353 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14354 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14355 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14356 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14357 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14358 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14359 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014360 /* hp used DAC 3 (Front) */
14361 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014362 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
14363 { }
14364};
14365
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010014366/* additional init verbs for ASUS laptops */
14367static struct hda_verb alc861_asus_laptop_init_verbs[] = {
14368 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x45 }, /* HP-out */
14369 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2) }, /* mute line-in */
14370 { }
14371};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014372
Kailang Yangdf694da2005-12-05 19:42:22 +010014373/*
14374 * generic initialization of ADC, input mixers and output mixers
14375 */
14376static struct hda_verb alc861_auto_init_verbs[] = {
14377 /*
14378 * Unmute ADC0 and set the default input to mic-in
14379 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014380 /* {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, */
Kailang Yangdf694da2005-12-05 19:42:22 +010014381 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020014382
Kailang Yangdf694da2005-12-05 19:42:22 +010014383 /* Unmute DAC0~3 & spdif out*/
14384 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14385 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14386 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14387 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
14388 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020014389
Kailang Yangdf694da2005-12-05 19:42:22 +010014390 /* Unmute Mixer 14 (mic) 1c (Line in)*/
14391 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14392 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14393 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14394 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020014395
Kailang Yangdf694da2005-12-05 19:42:22 +010014396 /* Unmute Stereo Mixer 15 */
14397 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14398 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14399 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
14400 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c},
14401
Takashi Iwai1c209302009-07-22 15:17:45 +020014402 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14403 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
14404 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14405 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
14406 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14407 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
14408 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14409 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yangdf694da2005-12-05 19:42:22 +010014410
14411 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14412 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai1c209302009-07-22 15:17:45 +020014413 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
14414 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010014415 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
14416 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai1c209302009-07-22 15:17:45 +020014417 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
14418 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010014419
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014420 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, /* set Mic 1 */
Kailang Yangdf694da2005-12-05 19:42:22 +010014421
14422 { }
14423};
14424
Tobin Davisa53d1ae2006-10-17 12:00:28 +020014425static struct hda_verb alc861_toshiba_init_verbs[] = {
14426 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014427
Tobin Davisa53d1ae2006-10-17 12:00:28 +020014428 { }
14429};
14430
14431/* toggle speaker-output according to the hp-jack state */
14432static void alc861_toshiba_automute(struct hda_codec *codec)
14433{
Wu Fengguang864f92b2009-11-18 12:38:02 +080014434 unsigned int present = snd_hda_jack_detect(codec, 0x0f);
Tobin Davisa53d1ae2006-10-17 12:00:28 +020014435
Takashi Iwai47fd8302007-08-10 17:11:07 +020014436 snd_hda_codec_amp_stereo(codec, 0x16, HDA_INPUT, 0,
14437 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
14438 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_INPUT, 3,
14439 HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE);
Tobin Davisa53d1ae2006-10-17 12:00:28 +020014440}
14441
14442static void alc861_toshiba_unsol_event(struct hda_codec *codec,
14443 unsigned int res)
14444{
Tobin Davisa53d1ae2006-10-17 12:00:28 +020014445 if ((res >> 26) == ALC880_HP_EVENT)
14446 alc861_toshiba_automute(codec);
14447}
14448
Sasha Alexandrdef319f2009-06-16 16:00:15 -040014449/* pcm configuration: identical with ALC880 */
Kailang Yangdf694da2005-12-05 19:42:22 +010014450#define alc861_pcm_analog_playback alc880_pcm_analog_playback
14451#define alc861_pcm_analog_capture alc880_pcm_analog_capture
14452#define alc861_pcm_digital_playback alc880_pcm_digital_playback
14453#define alc861_pcm_digital_capture alc880_pcm_digital_capture
14454
14455
14456#define ALC861_DIGOUT_NID 0x07
14457
14458static struct hda_channel_mode alc861_8ch_modes[1] = {
14459 { 8, NULL }
14460};
14461
14462static hda_nid_t alc861_dac_nids[4] = {
14463 /* front, surround, clfe, side */
14464 0x03, 0x06, 0x05, 0x04
14465};
14466
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014467static hda_nid_t alc660_dac_nids[3] = {
14468 /* front, clfe, surround */
14469 0x03, 0x05, 0x06
14470};
14471
Kailang Yangdf694da2005-12-05 19:42:22 +010014472static hda_nid_t alc861_adc_nids[1] = {
14473 /* ADC0-2 */
14474 0x08,
14475};
14476
14477static struct hda_input_mux alc861_capture_source = {
14478 .num_items = 5,
14479 .items = {
14480 { "Mic", 0x0 },
14481 { "Front Mic", 0x3 },
14482 { "Line", 0x1 },
14483 { "CD", 0x4 },
14484 { "Mixer", 0x5 },
14485 },
14486};
14487
Takashi Iwai1c209302009-07-22 15:17:45 +020014488static hda_nid_t alc861_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
14489{
14490 struct alc_spec *spec = codec->spec;
14491 hda_nid_t mix, srcs[5];
14492 int i, j, num;
14493
14494 if (snd_hda_get_connections(codec, pin, &mix, 1) != 1)
14495 return 0;
14496 num = snd_hda_get_connections(codec, mix, srcs, ARRAY_SIZE(srcs));
14497 if (num < 0)
14498 return 0;
14499 for (i = 0; i < num; i++) {
14500 unsigned int type;
Takashi Iwaia22d5432009-07-27 12:54:26 +020014501 type = get_wcaps_type(get_wcaps(codec, srcs[i]));
Takashi Iwai1c209302009-07-22 15:17:45 +020014502 if (type != AC_WID_AUD_OUT)
14503 continue;
14504 for (j = 0; j < spec->multiout.num_dacs; j++)
14505 if (spec->multiout.dac_nids[j] == srcs[i])
14506 break;
14507 if (j >= spec->multiout.num_dacs)
14508 return srcs[i];
14509 }
14510 return 0;
14511}
14512
Kailang Yangdf694da2005-12-05 19:42:22 +010014513/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwai1c209302009-07-22 15:17:45 +020014514static int alc861_auto_fill_dac_nids(struct hda_codec *codec,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014515 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010014516{
Takashi Iwai1c209302009-07-22 15:17:45 +020014517 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010014518 int i;
Takashi Iwai1c209302009-07-22 15:17:45 +020014519 hda_nid_t nid, dac;
Kailang Yangdf694da2005-12-05 19:42:22 +010014520
14521 spec->multiout.dac_nids = spec->private_dac_nids;
14522 for (i = 0; i < cfg->line_outs; i++) {
14523 nid = cfg->line_out_pins[i];
Takashi Iwai1c209302009-07-22 15:17:45 +020014524 dac = alc861_look_for_dac(codec, nid);
14525 if (!dac)
14526 continue;
14527 spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
Kailang Yangdf694da2005-12-05 19:42:22 +010014528 }
Kailang Yangdf694da2005-12-05 19:42:22 +010014529 return 0;
14530}
14531
Takashi Iwai1c209302009-07-22 15:17:45 +020014532static int alc861_create_out_sw(struct hda_codec *codec, const char *pfx,
14533 hda_nid_t nid, unsigned int chs)
Kailang Yangdf694da2005-12-05 19:42:22 +010014534{
Takashi Iwai0afe5f82009-10-02 09:20:00 +020014535 return add_pb_sw_ctrl(codec->spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwai1c209302009-07-22 15:17:45 +020014536 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
14537}
14538
14539/* add playback controls from the parsed DAC table */
14540static int alc861_auto_create_multi_out_ctls(struct hda_codec *codec,
14541 const struct auto_pin_cfg *cfg)
14542{
14543 struct alc_spec *spec = codec->spec;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014544 static const char *chname[4] = {
14545 "Front", "Surround", NULL /*CLFE*/, "Side"
14546 };
Kailang Yangdf694da2005-12-05 19:42:22 +010014547 hda_nid_t nid;
Takashi Iwai1c209302009-07-22 15:17:45 +020014548 int i, err;
14549
14550 if (cfg->line_outs == 1) {
14551 const char *pfx = NULL;
14552 if (!cfg->hp_outs)
14553 pfx = "Master";
14554 else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
14555 pfx = "Speaker";
14556 if (pfx) {
14557 nid = spec->multiout.dac_nids[0];
14558 return alc861_create_out_sw(codec, pfx, nid, 3);
14559 }
14560 }
Kailang Yangdf694da2005-12-05 19:42:22 +010014561
14562 for (i = 0; i < cfg->line_outs; i++) {
14563 nid = spec->multiout.dac_nids[i];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014564 if (!nid)
Kailang Yangdf694da2005-12-05 19:42:22 +010014565 continue;
Takashi Iwai1c209302009-07-22 15:17:45 +020014566 if (i == 2) {
Kailang Yangdf694da2005-12-05 19:42:22 +010014567 /* Center/LFE */
Takashi Iwai1c209302009-07-22 15:17:45 +020014568 err = alc861_create_out_sw(codec, "Center", nid, 1);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014569 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010014570 return err;
Takashi Iwai1c209302009-07-22 15:17:45 +020014571 err = alc861_create_out_sw(codec, "LFE", nid, 2);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014572 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010014573 return err;
14574 } else {
Takashi Iwai1c209302009-07-22 15:17:45 +020014575 err = alc861_create_out_sw(codec, chname[i], nid, 3);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014576 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010014577 return err;
14578 }
14579 }
14580 return 0;
14581}
14582
Takashi Iwai1c209302009-07-22 15:17:45 +020014583static int alc861_auto_create_hp_ctls(struct hda_codec *codec, hda_nid_t pin)
Kailang Yangdf694da2005-12-05 19:42:22 +010014584{
Takashi Iwai1c209302009-07-22 15:17:45 +020014585 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010014586 int err;
14587 hda_nid_t nid;
14588
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014589 if (!pin)
Kailang Yangdf694da2005-12-05 19:42:22 +010014590 return 0;
14591
14592 if ((pin >= 0x0b && pin <= 0x10) || pin == 0x1f || pin == 0x20) {
Takashi Iwai1c209302009-07-22 15:17:45 +020014593 nid = alc861_look_for_dac(codec, pin);
14594 if (nid) {
14595 err = alc861_create_out_sw(codec, "Headphone", nid, 3);
14596 if (err < 0)
14597 return err;
14598 spec->multiout.hp_nid = nid;
14599 }
Kailang Yangdf694da2005-12-05 19:42:22 +010014600 }
14601 return 0;
14602}
14603
14604/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +020014605static int alc861_auto_create_input_ctls(struct hda_codec *codec,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014606 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010014607{
Takashi Iwai05f5f472009-08-25 13:10:18 +020014608 return alc_auto_create_input_ctls(codec, cfg, 0x15, 0x08, 0);
Kailang Yangdf694da2005-12-05 19:42:22 +010014609}
14610
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014611static void alc861_auto_set_output_and_unmute(struct hda_codec *codec,
14612 hda_nid_t nid,
Takashi Iwai1c209302009-07-22 15:17:45 +020014613 int pin_type, hda_nid_t dac)
Kailang Yangdf694da2005-12-05 19:42:22 +010014614{
Takashi Iwai1c209302009-07-22 15:17:45 +020014615 hda_nid_t mix, srcs[5];
14616 int i, num;
14617
Jacek Luczak564c5be2008-05-03 18:41:23 +020014618 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
14619 pin_type);
Takashi Iwai1c209302009-07-22 15:17:45 +020014620 snd_hda_codec_write(codec, dac, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Jacek Luczak564c5be2008-05-03 18:41:23 +020014621 AMP_OUT_UNMUTE);
Takashi Iwai1c209302009-07-22 15:17:45 +020014622 if (snd_hda_get_connections(codec, nid, &mix, 1) != 1)
14623 return;
14624 num = snd_hda_get_connections(codec, mix, srcs, ARRAY_SIZE(srcs));
14625 if (num < 0)
14626 return;
14627 for (i = 0; i < num; i++) {
14628 unsigned int mute;
14629 if (srcs[i] == dac || srcs[i] == 0x15)
14630 mute = AMP_IN_UNMUTE(i);
14631 else
14632 mute = AMP_IN_MUTE(i);
14633 snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE,
14634 mute);
14635 }
Kailang Yangdf694da2005-12-05 19:42:22 +010014636}
14637
14638static void alc861_auto_init_multi_out(struct hda_codec *codec)
14639{
14640 struct alc_spec *spec = codec->spec;
14641 int i;
14642
14643 for (i = 0; i < spec->autocfg.line_outs; i++) {
14644 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020014645 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangdf694da2005-12-05 19:42:22 +010014646 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020014647 alc861_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014648 spec->multiout.dac_nids[i]);
Kailang Yangdf694da2005-12-05 19:42:22 +010014649 }
14650}
14651
14652static void alc861_auto_init_hp_out(struct hda_codec *codec)
14653{
14654 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010014655
Takashi Iwai15870f02009-10-05 08:25:13 +020014656 if (spec->autocfg.hp_outs)
14657 alc861_auto_set_output_and_unmute(codec,
14658 spec->autocfg.hp_pins[0],
14659 PIN_HP,
Takashi Iwai1c209302009-07-22 15:17:45 +020014660 spec->multiout.hp_nid);
Takashi Iwai15870f02009-10-05 08:25:13 +020014661 if (spec->autocfg.speaker_outs)
14662 alc861_auto_set_output_and_unmute(codec,
14663 spec->autocfg.speaker_pins[0],
14664 PIN_OUT,
Takashi Iwai1c209302009-07-22 15:17:45 +020014665 spec->multiout.dac_nids[0]);
Kailang Yangdf694da2005-12-05 19:42:22 +010014666}
14667
14668static void alc861_auto_init_analog_input(struct hda_codec *codec)
14669{
14670 struct alc_spec *spec = codec->spec;
14671 int i;
14672
14673 for (i = 0; i < AUTO_PIN_LAST; i++) {
14674 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwai23f0c042009-02-26 13:03:58 +010014675 if (nid >= 0x0c && nid <= 0x11)
14676 alc_set_input_pin(codec, nid, i);
Kailang Yangdf694da2005-12-05 19:42:22 +010014677 }
14678}
14679
14680/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014681/* return 1 if successful, 0 if the proper config is not found,
14682 * or a negative error code
14683 */
Kailang Yangdf694da2005-12-05 19:42:22 +010014684static int alc861_parse_auto_config(struct hda_codec *codec)
14685{
14686 struct alc_spec *spec = codec->spec;
14687 int err;
14688 static hda_nid_t alc861_ignore[] = { 0x1d, 0 };
14689
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014690 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
14691 alc861_ignore);
14692 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010014693 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014694 if (!spec->autocfg.line_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +010014695 return 0; /* can't find valid BIOS pin config */
14696
Takashi Iwai1c209302009-07-22 15:17:45 +020014697 err = alc861_auto_fill_dac_nids(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014698 if (err < 0)
14699 return err;
Takashi Iwai1c209302009-07-22 15:17:45 +020014700 err = alc861_auto_create_multi_out_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014701 if (err < 0)
14702 return err;
Takashi Iwai1c209302009-07-22 15:17:45 +020014703 err = alc861_auto_create_hp_ctls(codec, spec->autocfg.hp_pins[0]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014704 if (err < 0)
14705 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020014706 err = alc861_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014707 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010014708 return err;
14709
14710 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
14711
Takashi Iwai0852d7a2009-02-11 11:35:15 +010014712 if (spec->autocfg.dig_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +010014713 spec->multiout.dig_out_nid = ALC861_DIGOUT_NID;
14714
Takashi Iwai603c4012008-07-30 15:01:44 +020014715 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010014716 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +010014717
Takashi Iwaid88897e2008-10-31 15:01:37 +010014718 add_verb(spec, alc861_auto_init_verbs);
Kailang Yangdf694da2005-12-05 19:42:22 +010014719
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020014720 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020014721 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010014722
14723 spec->adc_nids = alc861_adc_nids;
14724 spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids);
Takashi Iwaib59bdf32009-08-11 09:47:30 +020014725 set_capture_mixer(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010014726
Takashi Iwai4a79ba32009-04-22 16:31:35 +020014727 alc_ssid_check(codec, 0x0e, 0x0f, 0x0b);
14728
Kailang Yangdf694da2005-12-05 19:42:22 +010014729 return 1;
14730}
14731
Takashi Iwaiae6b8132006-03-03 16:47:17 +010014732/* additional initialization for auto-configuration model */
14733static void alc861_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010014734{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014735 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010014736 alc861_auto_init_multi_out(codec);
14737 alc861_auto_init_hp_out(codec);
14738 alc861_auto_init_analog_input(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014739 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020014740 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010014741}
14742
Takashi Iwaicb53c622007-08-10 17:21:45 +020014743#ifdef CONFIG_SND_HDA_POWER_SAVE
14744static struct hda_amp_list alc861_loopbacks[] = {
14745 { 0x15, HDA_INPUT, 0 },
14746 { 0x15, HDA_INPUT, 1 },
14747 { 0x15, HDA_INPUT, 2 },
14748 { 0x15, HDA_INPUT, 3 },
14749 { } /* end */
14750};
14751#endif
14752
Kailang Yangdf694da2005-12-05 19:42:22 +010014753
14754/*
14755 * configuration and preset
14756 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010014757static const char *alc861_models[ALC861_MODEL_LAST] = {
14758 [ALC861_3ST] = "3stack",
14759 [ALC660_3ST] = "3stack-660",
14760 [ALC861_3ST_DIG] = "3stack-dig",
14761 [ALC861_6ST_DIG] = "6stack-dig",
14762 [ALC861_UNIWILL_M31] = "uniwill-m31",
14763 [ALC861_TOSHIBA] = "toshiba",
14764 [ALC861_ASUS] = "asus",
14765 [ALC861_ASUS_LAPTOP] = "asus-laptop",
14766 [ALC861_AUTO] = "auto",
14767};
14768
14769static struct snd_pci_quirk alc861_cfg_tbl[] = {
Takashi Iwai687a47b2007-01-10 11:25:58 +010014770 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010014771 SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP),
14772 SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP),
14773 SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010014774 SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP),
Kailang Yang83c34212007-07-05 11:43:05 +020014775 SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS P1-AH2", ALC861_3ST_DIG),
Tobin Davisad5e7732007-01-08 10:57:32 +010014776 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA),
Takashi Iwai341d4eb2007-07-09 17:53:18 +020014777 /* FIXME: the entry below breaks Toshiba A100 (model=auto works!)
14778 * Any other models that need this preset?
14779 */
14780 /* SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), */
Claudio Matsuokaef64adb2007-07-14 00:26:16 +020014781 SND_PCI_QUIRK(0x1462, 0x7254, "HP dx2200 (MSI MS-7254)", ALC861_3ST),
14782 SND_PCI_QUIRK(0x1462, 0x7297, "HP dx2250 (MSI MS-7297)", ALC861_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010014783 SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31),
14784 SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31),
14785 SND_PCI_QUIRK(0x1584, 0x9075, "Airis Praxis N1212", ALC861_ASUS_LAPTOP),
14786 /* FIXME: the below seems conflict */
14787 /* SND_PCI_QUIRK(0x1584, 0x9075, "Uniwill", ALC861_UNIWILL_M31), */
14788 SND_PCI_QUIRK(0x1849, 0x0660, "Asrock 939SLI32", ALC660_3ST),
14789 SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST),
Kailang Yangdf694da2005-12-05 19:42:22 +010014790 {}
14791};
14792
14793static struct alc_config_preset alc861_presets[] = {
14794 [ALC861_3ST] = {
14795 .mixers = { alc861_3ST_mixer },
14796 .init_verbs = { alc861_threestack_init_verbs },
14797 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
14798 .dac_nids = alc861_dac_nids,
14799 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
14800 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020014801 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010014802 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
14803 .adc_nids = alc861_adc_nids,
14804 .input_mux = &alc861_capture_source,
14805 },
14806 [ALC861_3ST_DIG] = {
14807 .mixers = { alc861_base_mixer },
14808 .init_verbs = { alc861_threestack_init_verbs },
14809 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
14810 .dac_nids = alc861_dac_nids,
14811 .dig_out_nid = ALC861_DIGOUT_NID,
14812 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
14813 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020014814 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010014815 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
14816 .adc_nids = alc861_adc_nids,
14817 .input_mux = &alc861_capture_source,
14818 },
14819 [ALC861_6ST_DIG] = {
14820 .mixers = { alc861_base_mixer },
14821 .init_verbs = { alc861_base_init_verbs },
14822 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
14823 .dac_nids = alc861_dac_nids,
14824 .dig_out_nid = ALC861_DIGOUT_NID,
14825 .num_channel_mode = ARRAY_SIZE(alc861_8ch_modes),
14826 .channel_mode = alc861_8ch_modes,
14827 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
14828 .adc_nids = alc861_adc_nids,
14829 .input_mux = &alc861_capture_source,
14830 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014831 [ALC660_3ST] = {
14832 .mixers = { alc861_3ST_mixer },
14833 .init_verbs = { alc861_threestack_init_verbs },
14834 .num_dacs = ARRAY_SIZE(alc660_dac_nids),
14835 .dac_nids = alc660_dac_nids,
14836 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
14837 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020014838 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014839 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
14840 .adc_nids = alc861_adc_nids,
14841 .input_mux = &alc861_capture_source,
14842 },
Takashi Iwai22309c32006-08-09 16:57:28 +020014843 [ALC861_UNIWILL_M31] = {
14844 .mixers = { alc861_uniwill_m31_mixer },
14845 .init_verbs = { alc861_uniwill_m31_init_verbs },
14846 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
14847 .dac_nids = alc861_dac_nids,
14848 .dig_out_nid = ALC861_DIGOUT_NID,
14849 .num_channel_mode = ARRAY_SIZE(alc861_uniwill_m31_modes),
14850 .channel_mode = alc861_uniwill_m31_modes,
14851 .need_dac_fix = 1,
14852 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
14853 .adc_nids = alc861_adc_nids,
14854 .input_mux = &alc861_capture_source,
14855 },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020014856 [ALC861_TOSHIBA] = {
14857 .mixers = { alc861_toshiba_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014858 .init_verbs = { alc861_base_init_verbs,
14859 alc861_toshiba_init_verbs },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020014860 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
14861 .dac_nids = alc861_dac_nids,
14862 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
14863 .channel_mode = alc883_3ST_2ch_modes,
14864 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
14865 .adc_nids = alc861_adc_nids,
14866 .input_mux = &alc861_capture_source,
14867 .unsol_event = alc861_toshiba_unsol_event,
14868 .init_hook = alc861_toshiba_automute,
14869 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014870 [ALC861_ASUS] = {
14871 .mixers = { alc861_asus_mixer },
14872 .init_verbs = { alc861_asus_init_verbs },
14873 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
14874 .dac_nids = alc861_dac_nids,
14875 .dig_out_nid = ALC861_DIGOUT_NID,
14876 .num_channel_mode = ARRAY_SIZE(alc861_asus_modes),
14877 .channel_mode = alc861_asus_modes,
14878 .need_dac_fix = 1,
14879 .hp_nid = 0x06,
14880 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
14881 .adc_nids = alc861_adc_nids,
14882 .input_mux = &alc861_capture_source,
14883 },
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010014884 [ALC861_ASUS_LAPTOP] = {
14885 .mixers = { alc861_toshiba_mixer, alc861_asus_laptop_mixer },
14886 .init_verbs = { alc861_asus_init_verbs,
14887 alc861_asus_laptop_init_verbs },
14888 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
14889 .dac_nids = alc861_dac_nids,
14890 .dig_out_nid = ALC861_DIGOUT_NID,
14891 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
14892 .channel_mode = alc883_3ST_2ch_modes,
14893 .need_dac_fix = 1,
14894 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
14895 .adc_nids = alc861_adc_nids,
14896 .input_mux = &alc861_capture_source,
14897 },
14898};
Kailang Yangdf694da2005-12-05 19:42:22 +010014899
Takashi Iwaicfc9b062009-12-01 12:19:37 +010014900/* Pin config fixes */
14901enum {
14902 PINFIX_FSC_AMILO_PI1505,
14903};
14904
14905static struct alc_pincfg alc861_fsc_amilo_pi1505_pinfix[] = {
14906 { 0x0b, 0x0221101f }, /* HP */
14907 { 0x0f, 0x90170310 }, /* speaker */
14908 { }
14909};
14910
14911static const struct alc_fixup alc861_fixups[] = {
14912 [PINFIX_FSC_AMILO_PI1505] = {
14913 .pins = alc861_fsc_amilo_pi1505_pinfix
14914 },
14915};
14916
14917static struct snd_pci_quirk alc861_fixup_tbl[] = {
14918 SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", PINFIX_FSC_AMILO_PI1505),
14919 {}
14920};
Kailang Yangdf694da2005-12-05 19:42:22 +010014921
14922static int patch_alc861(struct hda_codec *codec)
14923{
14924 struct alc_spec *spec;
14925 int board_config;
14926 int err;
14927
Robert P. J. Daydc041e02006-12-19 14:44:15 +010014928 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010014929 if (spec == NULL)
14930 return -ENOMEM;
14931
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014932 codec->spec = spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010014933
Takashi Iwaif5fcc132006-11-24 17:07:44 +010014934 board_config = snd_hda_check_board_config(codec, ALC861_MODEL_LAST,
14935 alc861_models,
14936 alc861_cfg_tbl);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014937
Takashi Iwaif5fcc132006-11-24 17:07:44 +010014938 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020014939 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
14940 codec->chip_name);
Kailang Yangdf694da2005-12-05 19:42:22 +010014941 board_config = ALC861_AUTO;
14942 }
14943
Takashi Iwaicfc9b062009-12-01 12:19:37 +010014944 alc_pick_fixup(codec, alc861_fixup_tbl, alc861_fixups);
14945
Kailang Yangdf694da2005-12-05 19:42:22 +010014946 if (board_config == ALC861_AUTO) {
14947 /* automatic parse from the BIOS config */
14948 err = alc861_parse_auto_config(codec);
14949 if (err < 0) {
14950 alc_free(codec);
14951 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014952 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014953 printk(KERN_INFO
14954 "hda_codec: Cannot set up configuration "
14955 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010014956 board_config = ALC861_3ST_DIG;
14957 }
14958 }
14959
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090014960 err = snd_hda_attach_beep_device(codec, 0x23);
14961 if (err < 0) {
14962 alc_free(codec);
14963 return err;
14964 }
14965
Kailang Yangdf694da2005-12-05 19:42:22 +010014966 if (board_config != ALC861_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020014967 setup_preset(codec, &alc861_presets[board_config]);
Kailang Yangdf694da2005-12-05 19:42:22 +010014968
Kailang Yangdf694da2005-12-05 19:42:22 +010014969 spec->stream_analog_playback = &alc861_pcm_analog_playback;
14970 spec->stream_analog_capture = &alc861_pcm_analog_capture;
14971
Kailang Yangdf694da2005-12-05 19:42:22 +010014972 spec->stream_digital_playback = &alc861_pcm_digital_playback;
14973 spec->stream_digital_capture = &alc861_pcm_digital_capture;
14974
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010014975 set_beep_amp(spec, 0x23, 0, HDA_OUTPUT);
14976
Takashi Iwai2134ea42008-01-10 16:53:55 +010014977 spec->vmaster_nid = 0x03;
14978
Kailang Yangdf694da2005-12-05 19:42:22 +010014979 codec->patch_ops = alc_patch_ops;
14980 if (board_config == ALC861_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +010014981 spec->init_hook = alc861_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020014982#ifdef CONFIG_SND_HDA_POWER_SAVE
14983 if (!spec->loopback.amplist)
14984 spec->loopback.amplist = alc861_loopbacks;
14985#endif
Takashi Iwaidaead532008-11-28 12:55:36 +010014986 codec->proc_widget_hook = print_realtek_coef;
Kailang Yangea1fb292008-08-26 12:58:38 +020014987
Kailang Yangdf694da2005-12-05 19:42:22 +010014988 return 0;
14989}
14990
14991/*
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010014992 * ALC861-VD support
14993 *
14994 * Based on ALC882
14995 *
14996 * In addition, an independent DAC
14997 */
14998#define ALC861VD_DIGOUT_NID 0x06
14999
15000static hda_nid_t alc861vd_dac_nids[4] = {
15001 /* front, surr, clfe, side surr */
15002 0x02, 0x03, 0x04, 0x05
15003};
15004
15005/* dac_nids for ALC660vd are in a different order - according to
15006 * Realtek's driver.
Sasha Alexandrdef319f2009-06-16 16:00:15 -040015007 * This should probably result in a different mixer for 6stack models
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015008 * of ALC660vd codecs, but for now there is only 3stack mixer
15009 * - and it is the same as in 861vd.
15010 * adc_nids in ALC660vd are (is) the same as in 861vd
15011 */
15012static hda_nid_t alc660vd_dac_nids[3] = {
15013 /* front, rear, clfe, rear_surr */
15014 0x02, 0x04, 0x03
15015};
15016
15017static hda_nid_t alc861vd_adc_nids[1] = {
15018 /* ADC0 */
15019 0x09,
15020};
15021
Takashi Iwaie1406342008-02-11 18:32:32 +010015022static hda_nid_t alc861vd_capsrc_nids[1] = { 0x22 };
15023
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015024/* input MUX */
15025/* FIXME: should be a matrix-type input source selection */
15026static struct hda_input_mux alc861vd_capture_source = {
15027 .num_items = 4,
15028 .items = {
15029 { "Mic", 0x0 },
15030 { "Front Mic", 0x1 },
15031 { "Line", 0x2 },
15032 { "CD", 0x4 },
15033 },
15034};
15035
Kailang Yang272a5272007-05-14 11:00:38 +020015036static struct hda_input_mux alc861vd_dallas_capture_source = {
Tobin Davisb419f342008-03-07 11:57:51 +010015037 .num_items = 2,
Kailang Yang272a5272007-05-14 11:00:38 +020015038 .items = {
Tobin Davisb419f342008-03-07 11:57:51 +010015039 { "Ext Mic", 0x0 },
15040 { "Int Mic", 0x1 },
Kailang Yang272a5272007-05-14 11:00:38 +020015041 },
15042};
15043
Kailang Yangd1a991a2007-08-15 16:21:59 +020015044static struct hda_input_mux alc861vd_hp_capture_source = {
15045 .num_items = 2,
15046 .items = {
15047 { "Front Mic", 0x0 },
15048 { "ATAPI Mic", 0x1 },
15049 },
15050};
15051
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015052/*
15053 * 2ch mode
15054 */
15055static struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = {
15056 { 2, NULL }
15057};
15058
15059/*
15060 * 6ch mode
15061 */
15062static struct hda_verb alc861vd_6stack_ch6_init[] = {
15063 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15064 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15065 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15066 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15067 { } /* end */
15068};
15069
15070/*
15071 * 8ch mode
15072 */
15073static struct hda_verb alc861vd_6stack_ch8_init[] = {
15074 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15075 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15076 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15077 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15078 { } /* end */
15079};
15080
15081static struct hda_channel_mode alc861vd_6stack_modes[2] = {
15082 { 6, alc861vd_6stack_ch6_init },
15083 { 8, alc861vd_6stack_ch8_init },
15084};
15085
15086static struct snd_kcontrol_new alc861vd_chmode_mixer[] = {
15087 {
15088 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
15089 .name = "Channel Mode",
15090 .info = alc_ch_mode_info,
15091 .get = alc_ch_mode_get,
15092 .put = alc_ch_mode_put,
15093 },
15094 { } /* end */
15095};
15096
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015097/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
15098 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
15099 */
15100static struct snd_kcontrol_new alc861vd_6st_mixer[] = {
15101 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15102 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
15103
15104 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
15105 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
15106
15107 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0,
15108 HDA_OUTPUT),
15109 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0,
15110 HDA_OUTPUT),
15111 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
15112 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
15113
15114 HDA_CODEC_VOLUME("Side Playback Volume", 0x05, 0x0, HDA_OUTPUT),
15115 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
15116
15117 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
15118
15119 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
15120 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15121 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15122
15123 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
15124 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15125 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
15126
15127 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
15128 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
15129
15130 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
15131 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
15132
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015133 { } /* end */
15134};
15135
15136static struct snd_kcontrol_new alc861vd_3st_mixer[] = {
15137 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15138 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
15139
15140 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
15141
15142 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
15143 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15144 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15145
15146 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
15147 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15148 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
15149
15150 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
15151 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
15152
15153 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
15154 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
15155
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015156 { } /* end */
15157};
15158
Kailang Yangbdd148a2007-05-08 15:19:08 +020015159static struct snd_kcontrol_new alc861vd_lenovo_mixer[] = {
15160 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15161 /*HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),*/
15162 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
15163
15164 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
15165
15166 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
15167 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15168 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15169
15170 HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
15171 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15172 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
15173
15174 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
15175 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
15176
15177 { } /* end */
15178};
15179
Tobin Davisb419f342008-03-07 11:57:51 +010015180/* Pin assignment: Speaker=0x14, HP = 0x15,
15181 * Ext Mic=0x18, Int Mic = 0x19, CD = 0x1c, PC Beep = 0x1d
Kailang Yang272a5272007-05-14 11:00:38 +020015182 */
15183static struct snd_kcontrol_new alc861vd_dallas_mixer[] = {
Tobin Davisb419f342008-03-07 11:57:51 +010015184 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15185 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020015186 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
15187 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
Tobin Davisb419f342008-03-07 11:57:51 +010015188 HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
15189 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15190 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15191 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
15192 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15193 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020015194 { } /* end */
15195};
15196
Kailang Yangd1a991a2007-08-15 16:21:59 +020015197/* Pin assignment: Speaker=0x14, Line-out = 0x15,
15198 * Front Mic=0x18, ATAPI Mic = 0x19,
15199 */
15200static struct snd_kcontrol_new alc861vd_hp_mixer[] = {
15201 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15202 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
15203 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
15204 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
15205 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15206 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15207 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15208 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangea1fb292008-08-26 12:58:38 +020015209
Kailang Yangd1a991a2007-08-15 16:21:59 +020015210 { } /* end */
15211};
15212
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015213/*
15214 * generic initialization of ADC, input mixers and output mixers
15215 */
15216static struct hda_verb alc861vd_volume_init_verbs[] = {
15217 /*
15218 * Unmute ADC0 and set the default input to mic-in
15219 */
15220 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
15221 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15222
15223 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of
15224 * the analog-loopback mixer widget
15225 */
15226 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020015227 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15228 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15229 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
15230 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
15231 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015232
15233 /* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yangbdd148a2007-05-08 15:19:08 +020015234 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15235 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15236 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015237 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015238
15239 /*
15240 * Set up output mixers (0x02 - 0x05)
15241 */
15242 /* set vol=0 to output mixers */
15243 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
15244 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
15245 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
15246 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
15247
15248 /* set up input amps for analog loopback */
15249 /* Amp Indices: DAC = 0, mixer = 1 */
15250 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15251 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15252 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15253 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15254 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15255 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15256 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15257 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15258
15259 { }
15260};
15261
15262/*
15263 * 3-stack pin configuration:
15264 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
15265 */
15266static struct hda_verb alc861vd_3stack_init_verbs[] = {
15267 /*
15268 * Set pin mode and muting
15269 */
15270 /* set front pin widgets 0x14 for output */
15271 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
15272 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15273 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
15274
15275 /* Mic (rear) pin: input vref at 80% */
15276 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
15277 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15278 /* Front Mic pin: input vref at 80% */
15279 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
15280 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15281 /* Line In pin: input */
15282 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15283 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15284 /* Line-2 In: Headphone output (output 0 - 0x0c) */
15285 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15286 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15287 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
15288 /* CD pin widget for input */
15289 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15290
15291 { }
15292};
15293
15294/*
15295 * 6-stack pin configuration:
15296 */
15297static struct hda_verb alc861vd_6stack_init_verbs[] = {
15298 /*
15299 * Set pin mode and muting
15300 */
15301 /* set front pin widgets 0x14 for output */
15302 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
15303 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15304 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
15305
15306 /* Rear Pin: output 1 (0x0d) */
15307 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
15308 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15309 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
15310 /* CLFE Pin: output 2 (0x0e) */
15311 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
15312 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15313 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
15314 /* Side Pin: output 3 (0x0f) */
15315 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
15316 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15317 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
15318
15319 /* Mic (rear) pin: input vref at 80% */
15320 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
15321 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15322 /* Front Mic pin: input vref at 80% */
15323 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
15324 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15325 /* Line In pin: input */
15326 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15327 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15328 /* Line-2 In: Headphone output (output 0 - 0x0c) */
15329 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
15330 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15331 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
15332 /* CD pin widget for input */
15333 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15334
15335 { }
15336};
15337
Kailang Yangbdd148a2007-05-08 15:19:08 +020015338static struct hda_verb alc861vd_eapd_verbs[] = {
15339 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
15340 { }
15341};
15342
Kailang Yangf9423e72008-05-27 12:32:25 +020015343static struct hda_verb alc660vd_eapd_verbs[] = {
15344 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
15345 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
15346 { }
15347};
15348
Kailang Yangbdd148a2007-05-08 15:19:08 +020015349static struct hda_verb alc861vd_lenovo_unsol_verbs[] = {
15350 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15351 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15352 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
15353 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Kailang Yangea1fb292008-08-26 12:58:38 +020015354 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
Kailang Yangbdd148a2007-05-08 15:19:08 +020015355 {}
15356};
15357
Kailang Yangbdd148a2007-05-08 15:19:08 +020015358static void alc861vd_lenovo_mic_automute(struct hda_codec *codec)
15359{
15360 unsigned int present;
15361 unsigned char bits;
15362
Wu Fengguang864f92b2009-11-18 12:38:02 +080015363 present = snd_hda_jack_detect(codec, 0x18);
Takashi Iwai47fd8302007-08-10 17:11:07 +020015364 bits = present ? HDA_AMP_MUTE : 0;
Wu Fengguang864f92b2009-11-18 12:38:02 +080015365
Takashi Iwai47fd8302007-08-10 17:11:07 +020015366 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
15367 HDA_AMP_MUTE, bits);
Kailang Yangbdd148a2007-05-08 15:19:08 +020015368}
15369
Takashi Iwai4f5d17062009-08-11 18:17:46 +020015370static void alc861vd_lenovo_setup(struct hda_codec *codec)
Kailang Yangbdd148a2007-05-08 15:19:08 +020015371{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020015372 struct alc_spec *spec = codec->spec;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020015373 spec->autocfg.hp_pins[0] = 0x1b;
15374 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020015375}
15376
15377static void alc861vd_lenovo_init_hook(struct hda_codec *codec)
15378{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020015379 alc_automute_amp(codec);
Kailang Yangbdd148a2007-05-08 15:19:08 +020015380 alc861vd_lenovo_mic_automute(codec);
15381}
15382
15383static void alc861vd_lenovo_unsol_event(struct hda_codec *codec,
15384 unsigned int res)
15385{
15386 switch (res >> 26) {
Kailang Yangbdd148a2007-05-08 15:19:08 +020015387 case ALC880_MIC_EVENT:
15388 alc861vd_lenovo_mic_automute(codec);
15389 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020015390 default:
15391 alc_automute_amp_unsol_event(codec, res);
15392 break;
Kailang Yangbdd148a2007-05-08 15:19:08 +020015393 }
15394}
15395
Kailang Yang272a5272007-05-14 11:00:38 +020015396static struct hda_verb alc861vd_dallas_verbs[] = {
15397 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
15398 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
15399 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
15400 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
15401
15402 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15403 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15404 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15405 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15406 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15407 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15408 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15409 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015410
Kailang Yang272a5272007-05-14 11:00:38 +020015411 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
15412 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15413 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
15414 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15415 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
15416 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15417 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
15418 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15419
15420 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
15421 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15422 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
15423 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15424 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15425 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15426 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15427 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
15428
15429 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15430 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
15431 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
15432 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
15433
15434 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015435 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yang272a5272007-05-14 11:00:38 +020015436 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
15437
15438 { } /* end */
15439};
15440
15441/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020015442static void alc861vd_dallas_setup(struct hda_codec *codec)
Kailang Yang272a5272007-05-14 11:00:38 +020015443{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020015444 struct alc_spec *spec = codec->spec;
Kailang Yang272a5272007-05-14 11:00:38 +020015445
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020015446 spec->autocfg.hp_pins[0] = 0x15;
15447 spec->autocfg.speaker_pins[0] = 0x14;
Kailang Yang272a5272007-05-14 11:00:38 +020015448}
15449
Takashi Iwaicb53c622007-08-10 17:21:45 +020015450#ifdef CONFIG_SND_HDA_POWER_SAVE
15451#define alc861vd_loopbacks alc880_loopbacks
15452#endif
15453
Sasha Alexandrdef319f2009-06-16 16:00:15 -040015454/* pcm configuration: identical with ALC880 */
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015455#define alc861vd_pcm_analog_playback alc880_pcm_analog_playback
15456#define alc861vd_pcm_analog_capture alc880_pcm_analog_capture
15457#define alc861vd_pcm_digital_playback alc880_pcm_digital_playback
15458#define alc861vd_pcm_digital_capture alc880_pcm_digital_capture
15459
15460/*
15461 * configuration and preset
15462 */
15463static const char *alc861vd_models[ALC861VD_MODEL_LAST] = {
15464 [ALC660VD_3ST] = "3stack-660",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020015465 [ALC660VD_3ST_DIG] = "3stack-660-digout",
Takashi Iwai13c94742008-11-05 08:06:08 +010015466 [ALC660VD_ASUS_V1S] = "asus-v1s",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015467 [ALC861VD_3ST] = "3stack",
15468 [ALC861VD_3ST_DIG] = "3stack-digout",
15469 [ALC861VD_6ST_DIG] = "6stack-digout",
Kailang Yangbdd148a2007-05-08 15:19:08 +020015470 [ALC861VD_LENOVO] = "lenovo",
Kailang Yang272a5272007-05-14 11:00:38 +020015471 [ALC861VD_DALLAS] = "dallas",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020015472 [ALC861VD_HP] = "hp",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015473 [ALC861VD_AUTO] = "auto",
15474};
15475
15476static struct snd_pci_quirk alc861vd_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +010015477 SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST),
15478 SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP),
Takashi Iwai07e038b2007-02-15 18:23:41 +010015479 SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST),
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020015480 /*SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),*/ /* auto */
Takashi Iwai13c94742008-11-05 08:06:08 +010015481 SND_PCI_QUIRK(0x1043, 0x1633, "Asus V1Sn", ALC660VD_ASUS_V1S),
Mike Crash6963f842007-06-25 12:12:51 +020015482 SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015483 SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010015484 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO),
Takashi Iwai38baf5a2007-08-16 17:52:43 +020015485 /*SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS),*/ /*lenovo*/
Takashi Iwaice577e82009-08-03 08:23:52 +020015486 SND_PCI_QUIRK(0x1179, 0xff01, "Toshiba A135", ALC861VD_LENOVO),
Takashi Iwai542d7c62007-08-16 18:57:30 +020015487 SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO),
Tobin Davisb419f342008-03-07 11:57:51 +010015488 SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_DALLAS),
Takashi Iwai39c5d412007-08-15 16:24:17 +020015489 SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +010015490 SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", ALC861VD_LENOVO),
Tobin Davis625dc0b2007-07-30 21:42:10 +020015491 SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015492 {}
15493};
15494
15495static struct alc_config_preset alc861vd_presets[] = {
15496 [ALC660VD_3ST] = {
15497 .mixers = { alc861vd_3st_mixer },
15498 .init_verbs = { alc861vd_volume_init_verbs,
15499 alc861vd_3stack_init_verbs },
15500 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
15501 .dac_nids = alc660vd_dac_nids,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015502 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
15503 .channel_mode = alc861vd_3stack_2ch_modes,
15504 .input_mux = &alc861vd_capture_source,
15505 },
Mike Crash6963f842007-06-25 12:12:51 +020015506 [ALC660VD_3ST_DIG] = {
15507 .mixers = { alc861vd_3st_mixer },
15508 .init_verbs = { alc861vd_volume_init_verbs,
15509 alc861vd_3stack_init_verbs },
15510 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
15511 .dac_nids = alc660vd_dac_nids,
15512 .dig_out_nid = ALC861VD_DIGOUT_NID,
Mike Crash6963f842007-06-25 12:12:51 +020015513 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
15514 .channel_mode = alc861vd_3stack_2ch_modes,
15515 .input_mux = &alc861vd_capture_source,
15516 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015517 [ALC861VD_3ST] = {
15518 .mixers = { alc861vd_3st_mixer },
15519 .init_verbs = { alc861vd_volume_init_verbs,
15520 alc861vd_3stack_init_verbs },
15521 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
15522 .dac_nids = alc861vd_dac_nids,
15523 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
15524 .channel_mode = alc861vd_3stack_2ch_modes,
15525 .input_mux = &alc861vd_capture_source,
15526 },
15527 [ALC861VD_3ST_DIG] = {
15528 .mixers = { alc861vd_3st_mixer },
15529 .init_verbs = { alc861vd_volume_init_verbs,
15530 alc861vd_3stack_init_verbs },
15531 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
15532 .dac_nids = alc861vd_dac_nids,
15533 .dig_out_nid = ALC861VD_DIGOUT_NID,
15534 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
15535 .channel_mode = alc861vd_3stack_2ch_modes,
15536 .input_mux = &alc861vd_capture_source,
15537 },
15538 [ALC861VD_6ST_DIG] = {
15539 .mixers = { alc861vd_6st_mixer, alc861vd_chmode_mixer },
15540 .init_verbs = { alc861vd_volume_init_verbs,
15541 alc861vd_6stack_init_verbs },
15542 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
15543 .dac_nids = alc861vd_dac_nids,
15544 .dig_out_nid = ALC861VD_DIGOUT_NID,
15545 .num_channel_mode = ARRAY_SIZE(alc861vd_6stack_modes),
15546 .channel_mode = alc861vd_6stack_modes,
15547 .input_mux = &alc861vd_capture_source,
15548 },
Kailang Yangbdd148a2007-05-08 15:19:08 +020015549 [ALC861VD_LENOVO] = {
15550 .mixers = { alc861vd_lenovo_mixer },
15551 .init_verbs = { alc861vd_volume_init_verbs,
15552 alc861vd_3stack_init_verbs,
15553 alc861vd_eapd_verbs,
15554 alc861vd_lenovo_unsol_verbs },
15555 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
15556 .dac_nids = alc660vd_dac_nids,
Kailang Yangbdd148a2007-05-08 15:19:08 +020015557 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
15558 .channel_mode = alc861vd_3stack_2ch_modes,
15559 .input_mux = &alc861vd_capture_source,
15560 .unsol_event = alc861vd_lenovo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020015561 .setup = alc861vd_lenovo_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020015562 .init_hook = alc861vd_lenovo_init_hook,
Kailang Yangbdd148a2007-05-08 15:19:08 +020015563 },
Kailang Yang272a5272007-05-14 11:00:38 +020015564 [ALC861VD_DALLAS] = {
15565 .mixers = { alc861vd_dallas_mixer },
15566 .init_verbs = { alc861vd_dallas_verbs },
15567 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
15568 .dac_nids = alc861vd_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +020015569 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
15570 .channel_mode = alc861vd_3stack_2ch_modes,
15571 .input_mux = &alc861vd_dallas_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020015572 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020015573 .setup = alc861vd_dallas_setup,
15574 .init_hook = alc_automute_amp,
Kailang Yangd1a991a2007-08-15 16:21:59 +020015575 },
15576 [ALC861VD_HP] = {
15577 .mixers = { alc861vd_hp_mixer },
15578 .init_verbs = { alc861vd_dallas_verbs, alc861vd_eapd_verbs },
15579 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
15580 .dac_nids = alc861vd_dac_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020015581 .dig_out_nid = ALC861VD_DIGOUT_NID,
Kailang Yangd1a991a2007-08-15 16:21:59 +020015582 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
15583 .channel_mode = alc861vd_3stack_2ch_modes,
15584 .input_mux = &alc861vd_hp_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020015585 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020015586 .setup = alc861vd_dallas_setup,
15587 .init_hook = alc_automute_amp,
Kailang Yangea1fb292008-08-26 12:58:38 +020015588 },
Takashi Iwai13c94742008-11-05 08:06:08 +010015589 [ALC660VD_ASUS_V1S] = {
15590 .mixers = { alc861vd_lenovo_mixer },
15591 .init_verbs = { alc861vd_volume_init_verbs,
15592 alc861vd_3stack_init_verbs,
15593 alc861vd_eapd_verbs,
15594 alc861vd_lenovo_unsol_verbs },
15595 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
15596 .dac_nids = alc660vd_dac_nids,
15597 .dig_out_nid = ALC861VD_DIGOUT_NID,
15598 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
15599 .channel_mode = alc861vd_3stack_2ch_modes,
15600 .input_mux = &alc861vd_capture_source,
15601 .unsol_event = alc861vd_lenovo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020015602 .setup = alc861vd_lenovo_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020015603 .init_hook = alc861vd_lenovo_init_hook,
Takashi Iwai13c94742008-11-05 08:06:08 +010015604 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015605};
15606
15607/*
15608 * BIOS auto configuration
15609 */
Takashi Iwai05f5f472009-08-25 13:10:18 +020015610static int alc861vd_auto_create_input_ctls(struct hda_codec *codec,
15611 const struct auto_pin_cfg *cfg)
15612{
15613 return alc_auto_create_input_ctls(codec, cfg, 0x15, 0x09, 0);
15614}
15615
15616
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015617static void alc861vd_auto_set_output_and_unmute(struct hda_codec *codec,
15618 hda_nid_t nid, int pin_type, int dac_idx)
15619{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010015620 alc_set_pin_output(codec, nid, pin_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015621}
15622
15623static void alc861vd_auto_init_multi_out(struct hda_codec *codec)
15624{
15625 struct alc_spec *spec = codec->spec;
15626 int i;
15627
15628 for (i = 0; i <= HDA_SIDE; i++) {
15629 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020015630 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015631 if (nid)
15632 alc861vd_auto_set_output_and_unmute(codec, nid,
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020015633 pin_type, i);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015634 }
15635}
15636
15637
15638static void alc861vd_auto_init_hp_out(struct hda_codec *codec)
15639{
15640 struct alc_spec *spec = codec->spec;
15641 hda_nid_t pin;
15642
15643 pin = spec->autocfg.hp_pins[0];
Sasha Alexandrdef319f2009-06-16 16:00:15 -040015644 if (pin) /* connect to front and use dac 0 */
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015645 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010015646 pin = spec->autocfg.speaker_pins[0];
15647 if (pin)
15648 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015649}
15650
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015651#define ALC861VD_PIN_CD_NID ALC880_PIN_CD_NID
15652
15653static void alc861vd_auto_init_analog_input(struct hda_codec *codec)
15654{
15655 struct alc_spec *spec = codec->spec;
15656 int i;
15657
15658 for (i = 0; i < AUTO_PIN_LAST; i++) {
15659 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwai05f5f472009-08-25 13:10:18 +020015660 if (alc_is_input_pin(codec, nid)) {
Takashi Iwai23f0c042009-02-26 13:03:58 +010015661 alc_set_input_pin(codec, nid, i);
Takashi Iwaie82c0252009-03-23 15:17:38 +010015662 if (nid != ALC861VD_PIN_CD_NID &&
15663 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015664 snd_hda_codec_write(codec, nid, 0,
15665 AC_VERB_SET_AMP_GAIN_MUTE,
15666 AMP_OUT_MUTE);
15667 }
15668 }
15669}
15670
Takashi Iwaif511b012008-08-15 16:46:42 +020015671#define alc861vd_auto_init_input_src alc882_auto_init_input_src
15672
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015673#define alc861vd_idx_to_mixer_vol(nid) ((nid) + 0x02)
15674#define alc861vd_idx_to_mixer_switch(nid) ((nid) + 0x0c)
15675
15676/* add playback controls from the parsed DAC table */
15677/* Based on ALC880 version. But ALC861VD has separate,
15678 * different NIDs for mute/unmute switch and volume control */
15679static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
15680 const struct auto_pin_cfg *cfg)
15681{
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015682 static const char *chname[4] = {"Front", "Surround", "CLFE", "Side"};
15683 hda_nid_t nid_v, nid_s;
15684 int i, err;
15685
15686 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015687 if (!spec->multiout.dac_nids[i])
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015688 continue;
15689 nid_v = alc861vd_idx_to_mixer_vol(
15690 alc880_dac_to_idx(
15691 spec->multiout.dac_nids[i]));
15692 nid_s = alc861vd_idx_to_mixer_switch(
15693 alc880_dac_to_idx(
15694 spec->multiout.dac_nids[i]));
15695
15696 if (i == 2) {
15697 /* Center/LFE */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020015698 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
15699 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015700 HDA_COMPOSE_AMP_VAL(nid_v, 1, 0,
15701 HDA_OUTPUT));
15702 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015703 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020015704 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
15705 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015706 HDA_COMPOSE_AMP_VAL(nid_v, 2, 0,
15707 HDA_OUTPUT));
15708 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015709 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020015710 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
15711 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015712 HDA_COMPOSE_AMP_VAL(nid_s, 1, 2,
15713 HDA_INPUT));
15714 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015715 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020015716 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
15717 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015718 HDA_COMPOSE_AMP_VAL(nid_s, 2, 2,
15719 HDA_INPUT));
15720 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015721 return err;
15722 } else {
Takashi Iwaia4fcd492009-08-25 16:12:15 +020015723 const char *pfx;
15724 if (cfg->line_outs == 1 &&
15725 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
15726 if (!cfg->hp_pins)
15727 pfx = "Speaker";
15728 else
15729 pfx = "PCM";
15730 } else
15731 pfx = chname[i];
Takashi Iwai0afe5f82009-10-02 09:20:00 +020015732 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015733 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0,
15734 HDA_OUTPUT));
15735 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015736 return err;
Takashi Iwaia4fcd492009-08-25 16:12:15 +020015737 if (cfg->line_outs == 1 &&
15738 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
15739 pfx = "Speaker";
Takashi Iwai0afe5f82009-10-02 09:20:00 +020015740 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
Kailang Yangbdd148a2007-05-08 15:19:08 +020015741 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015742 HDA_INPUT));
15743 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015744 return err;
15745 }
15746 }
15747 return 0;
15748}
15749
15750/* add playback controls for speaker and HP outputs */
15751/* Based on ALC880 version. But ALC861VD has separate,
15752 * different NIDs for mute/unmute switch and volume control */
15753static int alc861vd_auto_create_extra_out(struct alc_spec *spec,
15754 hda_nid_t pin, const char *pfx)
15755{
15756 hda_nid_t nid_v, nid_s;
15757 int err;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015758
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015759 if (!pin)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015760 return 0;
15761
15762 if (alc880_is_fixed_pin(pin)) {
15763 nid_v = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
15764 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015765 if (!spec->multiout.hp_nid)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015766 spec->multiout.hp_nid = nid_v;
15767 else
15768 spec->multiout.extra_out_nid[0] = nid_v;
15769 /* control HP volume/switch on the output mixer amp */
15770 nid_v = alc861vd_idx_to_mixer_vol(
15771 alc880_fixed_pin_idx(pin));
15772 nid_s = alc861vd_idx_to_mixer_switch(
15773 alc880_fixed_pin_idx(pin));
15774
Takashi Iwai0afe5f82009-10-02 09:20:00 +020015775 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015776 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0, HDA_OUTPUT));
15777 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015778 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020015779 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015780 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2, HDA_INPUT));
15781 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015782 return err;
15783 } else if (alc880_is_multi_pin(pin)) {
15784 /* set manual connection */
15785 /* we have only a switch on HP-out PIN */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020015786 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015787 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
15788 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015789 return err;
15790 }
15791 return 0;
15792}
15793
15794/* parse the BIOS configuration and set up the alc_spec
15795 * return 1 if successful, 0 if the proper config is not found,
15796 * or a negative error code
15797 * Based on ALC880 version - had to change it to override
15798 * alc880_auto_create_extra_out and alc880_auto_create_multi_out_ctls */
15799static int alc861vd_parse_auto_config(struct hda_codec *codec)
15800{
15801 struct alc_spec *spec = codec->spec;
15802 int err;
15803 static hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
15804
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015805 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
15806 alc861vd_ignore);
15807 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015808 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015809 if (!spec->autocfg.line_outs)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015810 return 0; /* can't find valid BIOS pin config */
15811
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015812 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
15813 if (err < 0)
15814 return err;
15815 err = alc861vd_auto_create_multi_out_ctls(spec, &spec->autocfg);
15816 if (err < 0)
15817 return err;
15818 err = alc861vd_auto_create_extra_out(spec,
15819 spec->autocfg.speaker_pins[0],
15820 "Speaker");
15821 if (err < 0)
15822 return err;
15823 err = alc861vd_auto_create_extra_out(spec,
15824 spec->autocfg.hp_pins[0],
15825 "Headphone");
15826 if (err < 0)
15827 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020015828 err = alc861vd_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015829 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015830 return err;
15831
15832 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
15833
Takashi Iwai0852d7a2009-02-11 11:35:15 +010015834 if (spec->autocfg.dig_outs)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015835 spec->multiout.dig_out_nid = ALC861VD_DIGOUT_NID;
15836
Takashi Iwai603c4012008-07-30 15:01:44 +020015837 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010015838 add_mixer(spec, spec->kctls.list);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015839
Takashi Iwaid88897e2008-10-31 15:01:37 +010015840 add_verb(spec, alc861vd_volume_init_verbs);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015841
15842 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020015843 spec->input_mux = &spec->private_imux[0];
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015844
Takashi Iwai776e1842007-08-29 15:07:11 +020015845 err = alc_auto_add_mic_boost(codec);
15846 if (err < 0)
15847 return err;
15848
Takashi Iwai4a79ba32009-04-22 16:31:35 +020015849 alc_ssid_check(codec, 0x15, 0x1b, 0x14);
15850
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015851 return 1;
15852}
15853
15854/* additional initialization for auto-configuration model */
15855static void alc861vd_auto_init(struct hda_codec *codec)
15856{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010015857 struct alc_spec *spec = codec->spec;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015858 alc861vd_auto_init_multi_out(codec);
15859 alc861vd_auto_init_hp_out(codec);
15860 alc861vd_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020015861 alc861vd_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010015862 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020015863 alc_inithook(codec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015864}
15865
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020015866enum {
15867 ALC660VD_FIX_ASUS_GPIO1
15868};
15869
15870/* reset GPIO1 */
15871static const struct hda_verb alc660vd_fix_asus_gpio1_verbs[] = {
15872 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
15873 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
15874 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
15875 { }
15876};
15877
15878static const struct alc_fixup alc861vd_fixups[] = {
15879 [ALC660VD_FIX_ASUS_GPIO1] = {
15880 .verbs = alc660vd_fix_asus_gpio1_verbs,
15881 },
15882};
15883
15884static struct snd_pci_quirk alc861vd_fixup_tbl[] = {
15885 SND_PCI_QUIRK(0x1043, 0x1339, "ASUS A7-K", ALC660VD_FIX_ASUS_GPIO1),
15886 {}
15887};
15888
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015889static int patch_alc861vd(struct hda_codec *codec)
15890{
15891 struct alc_spec *spec;
15892 int err, board_config;
15893
15894 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
15895 if (spec == NULL)
15896 return -ENOMEM;
15897
15898 codec->spec = spec;
15899
15900 board_config = snd_hda_check_board_config(codec, ALC861VD_MODEL_LAST,
15901 alc861vd_models,
15902 alc861vd_cfg_tbl);
15903
15904 if (board_config < 0 || board_config >= ALC861VD_MODEL_LAST) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020015905 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
15906 codec->chip_name);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015907 board_config = ALC861VD_AUTO;
15908 }
15909
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020015910 alc_pick_fixup(codec, alc861vd_fixup_tbl, alc861vd_fixups);
15911
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015912 if (board_config == ALC861VD_AUTO) {
15913 /* automatic parse from the BIOS config */
15914 err = alc861vd_parse_auto_config(codec);
15915 if (err < 0) {
15916 alc_free(codec);
15917 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015918 } else if (!err) {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015919 printk(KERN_INFO
15920 "hda_codec: Cannot set up configuration "
15921 "from BIOS. Using base mode...\n");
15922 board_config = ALC861VD_3ST;
15923 }
15924 }
15925
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090015926 err = snd_hda_attach_beep_device(codec, 0x23);
15927 if (err < 0) {
15928 alc_free(codec);
15929 return err;
15930 }
15931
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015932 if (board_config != ALC861VD_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020015933 setup_preset(codec, &alc861vd_presets[board_config]);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015934
Kailang Yang2f893282008-05-27 12:14:47 +020015935 if (codec->vendor_id == 0x10ec0660) {
Kailang Yangf9423e72008-05-27 12:32:25 +020015936 /* always turn on EAPD */
Takashi Iwaid88897e2008-10-31 15:01:37 +010015937 add_verb(spec, alc660vd_eapd_verbs);
Kailang Yang2f893282008-05-27 12:14:47 +020015938 }
15939
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015940 spec->stream_analog_playback = &alc861vd_pcm_analog_playback;
15941 spec->stream_analog_capture = &alc861vd_pcm_analog_capture;
15942
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015943 spec->stream_digital_playback = &alc861vd_pcm_digital_playback;
15944 spec->stream_digital_capture = &alc861vd_pcm_digital_capture;
15945
Takashi Iwaidd704692009-08-11 08:45:11 +020015946 if (!spec->adc_nids) {
15947 spec->adc_nids = alc861vd_adc_nids;
15948 spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids);
15949 }
15950 if (!spec->capsrc_nids)
15951 spec->capsrc_nids = alc861vd_capsrc_nids;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015952
Takashi Iwaib59bdf32009-08-11 09:47:30 +020015953 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010015954 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015955
Takashi Iwai2134ea42008-01-10 16:53:55 +010015956 spec->vmaster_nid = 0x02;
15957
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015958 codec->patch_ops = alc_patch_ops;
15959
15960 if (board_config == ALC861VD_AUTO)
15961 spec->init_hook = alc861vd_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020015962#ifdef CONFIG_SND_HDA_POWER_SAVE
15963 if (!spec->loopback.amplist)
15964 spec->loopback.amplist = alc861vd_loopbacks;
15965#endif
Takashi Iwaidaead532008-11-28 12:55:36 +010015966 codec->proc_widget_hook = print_realtek_coef;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015967
15968 return 0;
15969}
15970
15971/*
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015972 * ALC662 support
15973 *
15974 * ALC662 is almost identical with ALC880 but has cleaner and more flexible
15975 * configuration. Each pin widget can choose any input DACs and a mixer.
15976 * Each ADC is connected from a mixer of all inputs. This makes possible
15977 * 6-channel independent captures.
15978 *
15979 * In addition, an independent DAC for the multi-playback (not used in this
15980 * driver yet).
15981 */
15982#define ALC662_DIGOUT_NID 0x06
15983#define ALC662_DIGIN_NID 0x0a
15984
15985static hda_nid_t alc662_dac_nids[4] = {
15986 /* front, rear, clfe, rear_surr */
15987 0x02, 0x03, 0x04
15988};
15989
Kailang Yang622e84c2009-04-21 07:39:04 +020015990static hda_nid_t alc272_dac_nids[2] = {
15991 0x02, 0x03
15992};
15993
Takashi Iwaib59bdf32009-08-11 09:47:30 +020015994static hda_nid_t alc662_adc_nids[2] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015995 /* ADC1-2 */
Takashi Iwaib59bdf32009-08-11 09:47:30 +020015996 0x09, 0x08
Kailang Yangbc9f98a2007-04-12 13:06:07 +020015997};
Takashi Iwaie1406342008-02-11 18:32:32 +010015998
Kailang Yang622e84c2009-04-21 07:39:04 +020015999static hda_nid_t alc272_adc_nids[1] = {
16000 /* ADC1-2 */
16001 0x08,
16002};
16003
Takashi Iwaib59bdf32009-08-11 09:47:30 +020016004static hda_nid_t alc662_capsrc_nids[2] = { 0x22, 0x23 };
Kailang Yang622e84c2009-04-21 07:39:04 +020016005static hda_nid_t alc272_capsrc_nids[1] = { 0x23 };
16006
Takashi Iwaie1406342008-02-11 18:32:32 +010016007
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016008/* input MUX */
16009/* FIXME: should be a matrix-type input source selection */
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016010static struct hda_input_mux alc662_capture_source = {
16011 .num_items = 4,
16012 .items = {
16013 { "Mic", 0x0 },
16014 { "Front Mic", 0x1 },
16015 { "Line", 0x2 },
16016 { "CD", 0x4 },
16017 },
16018};
16019
16020static struct hda_input_mux alc662_lenovo_101e_capture_source = {
16021 .num_items = 2,
16022 .items = {
16023 { "Mic", 0x1 },
16024 { "Line", 0x2 },
16025 },
16026};
Kailang Yang291702f2007-10-16 14:28:03 +020016027
Kailang Yang6dda9f42008-05-27 12:05:31 +020016028static struct hda_input_mux alc663_capture_source = {
16029 .num_items = 3,
16030 .items = {
16031 { "Mic", 0x0 },
16032 { "Front Mic", 0x1 },
16033 { "Line", 0x2 },
16034 },
16035};
16036
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016037#if 0 /* set to 1 for testing other input sources below */
Chris Pockelé9541ba12009-05-12 08:08:53 +020016038static struct hda_input_mux alc272_nc10_capture_source = {
16039 .num_items = 16,
16040 .items = {
16041 { "Autoselect Mic", 0x0 },
16042 { "Internal Mic", 0x1 },
16043 { "In-0x02", 0x2 },
16044 { "In-0x03", 0x3 },
16045 { "In-0x04", 0x4 },
16046 { "In-0x05", 0x5 },
16047 { "In-0x06", 0x6 },
16048 { "In-0x07", 0x7 },
16049 { "In-0x08", 0x8 },
16050 { "In-0x09", 0x9 },
16051 { "In-0x0a", 0x0a },
16052 { "In-0x0b", 0x0b },
16053 { "In-0x0c", 0x0c },
16054 { "In-0x0d", 0x0d },
16055 { "In-0x0e", 0x0e },
16056 { "In-0x0f", 0x0f },
16057 },
16058};
16059#endif
16060
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016061/*
16062 * 2ch mode
16063 */
16064static struct hda_channel_mode alc662_3ST_2ch_modes[1] = {
16065 { 2, NULL }
16066};
16067
16068/*
16069 * 2ch mode
16070 */
16071static struct hda_verb alc662_3ST_ch2_init[] = {
16072 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
16073 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
16074 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
16075 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
16076 { } /* end */
16077};
16078
16079/*
16080 * 6ch mode
16081 */
16082static struct hda_verb alc662_3ST_ch6_init[] = {
16083 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16084 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
16085 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
16086 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16087 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
16088 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
16089 { } /* end */
16090};
16091
16092static struct hda_channel_mode alc662_3ST_6ch_modes[2] = {
16093 { 2, alc662_3ST_ch2_init },
16094 { 6, alc662_3ST_ch6_init },
16095};
16096
16097/*
16098 * 2ch mode
16099 */
16100static struct hda_verb alc662_sixstack_ch6_init[] = {
16101 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
16102 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
16103 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16104 { } /* end */
16105};
16106
16107/*
16108 * 6ch mode
16109 */
16110static struct hda_verb alc662_sixstack_ch8_init[] = {
16111 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16112 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16113 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16114 { } /* end */
16115};
16116
16117static struct hda_channel_mode alc662_5stack_modes[2] = {
16118 { 2, alc662_sixstack_ch6_init },
16119 { 6, alc662_sixstack_ch8_init },
16120};
16121
16122/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
16123 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
16124 */
16125
16126static struct snd_kcontrol_new alc662_base_mixer[] = {
16127 /* output mixer control */
16128 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010016129 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016130 HDA_CODEC_VOLUME("Surround Playback Volume", 0x3, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010016131 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016132 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
16133 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010016134 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
16135 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016136 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16137
16138 /*Input mixer control */
16139 HDA_CODEC_VOLUME("CD Playback Volume", 0xb, 0x4, HDA_INPUT),
16140 HDA_CODEC_MUTE("CD Playback Switch", 0xb, 0x4, HDA_INPUT),
16141 HDA_CODEC_VOLUME("Line Playback Volume", 0xb, 0x02, HDA_INPUT),
16142 HDA_CODEC_MUTE("Line Playback Switch", 0xb, 0x02, HDA_INPUT),
16143 HDA_CODEC_VOLUME("Mic Playback Volume", 0xb, 0x0, HDA_INPUT),
16144 HDA_CODEC_MUTE("Mic Playback Switch", 0xb, 0x0, HDA_INPUT),
16145 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0xb, 0x01, HDA_INPUT),
16146 HDA_CODEC_MUTE("Front Mic Playback Switch", 0xb, 0x01, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016147 { } /* end */
16148};
16149
16150static struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = {
16151 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010016152 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016153 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16154 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
16155 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
16156 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
16157 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
16158 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16159 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16160 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16161 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016162 { } /* end */
16163};
16164
16165static struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = {
16166 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010016167 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016168 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010016169 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016170 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
16171 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010016172 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
16173 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016174 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16175 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
16176 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
16177 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
16178 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
16179 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16180 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16181 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16182 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016183 { } /* end */
16184};
16185
16186static struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = {
16187 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16188 HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010016189 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x03, 0x0, HDA_OUTPUT),
16190 HDA_BIND_MUTE("Speaker Playback Switch", 0x03, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016191 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16192 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
16193 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
16194 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16195 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016196 { } /* end */
16197};
16198
Kailang Yang291702f2007-10-16 14:28:03 +020016199static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020016200 HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16201 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yang291702f2007-10-16 14:28:03 +020016202
16203 HDA_CODEC_VOLUME("e-Mic Boost", 0x18, 0, HDA_INPUT),
16204 HDA_CODEC_VOLUME("e-Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16205 HDA_CODEC_MUTE("e-Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16206
16207 HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT),
16208 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16209 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16210 { } /* end */
16211};
16212
Kailang Yang8c427222008-01-10 13:03:59 +010016213static struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020016214 ALC262_HIPPO_MASTER_SWITCH,
16215 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010016216 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010016217 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
16218 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010016219 HDA_BIND_MUTE("MuteCtrl Playback Switch", 0x0c, 2, HDA_INPUT),
16220 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
16221 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
16222 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16223 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16224 { } /* end */
16225};
16226
Kailang Yangf1d4e282008-08-26 14:03:29 +020016227static struct hda_bind_ctls alc663_asus_bind_master_vol = {
16228 .ops = &snd_hda_bind_vol,
16229 .values = {
16230 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
16231 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
16232 0
16233 },
16234};
16235
16236static struct hda_bind_ctls alc663_asus_one_bind_switch = {
16237 .ops = &snd_hda_bind_sw,
16238 .values = {
16239 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
16240 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
16241 0
16242 },
16243};
16244
Kailang Yang6dda9f42008-05-27 12:05:31 +020016245static struct snd_kcontrol_new alc663_m51va_mixer[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020016246 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
16247 HDA_BIND_SW("Master Playback Switch", &alc663_asus_one_bind_switch),
16248 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16249 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16250 { } /* end */
16251};
16252
16253static struct hda_bind_ctls alc663_asus_tree_bind_switch = {
16254 .ops = &snd_hda_bind_sw,
16255 .values = {
16256 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
16257 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
16258 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
16259 0
16260 },
16261};
16262
16263static struct snd_kcontrol_new alc663_two_hp_m1_mixer[] = {
16264 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
16265 HDA_BIND_SW("Master Playback Switch", &alc663_asus_tree_bind_switch),
16266 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16267 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16268 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16269 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16270
16271 { } /* end */
16272};
16273
16274static struct hda_bind_ctls alc663_asus_four_bind_switch = {
16275 .ops = &snd_hda_bind_sw,
16276 .values = {
16277 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
16278 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
16279 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
16280 0
16281 },
16282};
16283
16284static struct snd_kcontrol_new alc663_two_hp_m2_mixer[] = {
16285 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
16286 HDA_BIND_SW("Master Playback Switch", &alc663_asus_four_bind_switch),
16287 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16288 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16289 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16290 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16291 { } /* end */
16292};
16293
16294static struct snd_kcontrol_new alc662_1bjd_mixer[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020016295 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16296 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020016297 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16298 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16299 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16300 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16301 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16302 { } /* end */
16303};
16304
16305static struct hda_bind_ctls alc663_asus_two_bind_master_vol = {
16306 .ops = &snd_hda_bind_vol,
16307 .values = {
16308 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
16309 HDA_COMPOSE_AMP_VAL(0x04, 3, 0, HDA_OUTPUT),
16310 0
16311 },
16312};
16313
16314static struct hda_bind_ctls alc663_asus_two_bind_switch = {
16315 .ops = &snd_hda_bind_sw,
16316 .values = {
16317 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
16318 HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT),
16319 0
16320 },
16321};
16322
16323static struct snd_kcontrol_new alc663_asus_21jd_clfe_mixer[] = {
16324 HDA_BIND_VOL("Master Playback Volume",
16325 &alc663_asus_two_bind_master_vol),
16326 HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
16327 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020016328 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
16329 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16330 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020016331 { } /* end */
16332};
16333
16334static struct snd_kcontrol_new alc663_asus_15jd_clfe_mixer[] = {
16335 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
16336 HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
16337 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
16338 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
16339 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16340 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020016341 { } /* end */
16342};
16343
16344static struct snd_kcontrol_new alc663_g71v_mixer[] = {
16345 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16346 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
16347 HDA_CODEC_VOLUME("Front Playback Volume", 0x03, 0x0, HDA_OUTPUT),
16348 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
16349 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
16350
16351 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16352 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16353 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16354 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16355 { } /* end */
16356};
16357
16358static struct snd_kcontrol_new alc663_g50v_mixer[] = {
16359 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16360 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
16361 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
16362
16363 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16364 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16365 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16366 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16367 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
16368 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
16369 { } /* end */
16370};
16371
Kailang Yangebb83ee2009-12-17 12:23:00 +010016372static struct hda_bind_ctls alc663_asus_mode7_8_all_bind_switch = {
16373 .ops = &snd_hda_bind_sw,
16374 .values = {
16375 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
16376 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
16377 HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT),
16378 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
16379 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
16380 0
16381 },
16382};
16383
16384static struct hda_bind_ctls alc663_asus_mode7_8_sp_bind_switch = {
16385 .ops = &snd_hda_bind_sw,
16386 .values = {
16387 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
16388 HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT),
16389 0
16390 },
16391};
16392
16393static struct snd_kcontrol_new alc663_mode7_mixer[] = {
16394 HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch),
16395 HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol),
16396 HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch),
16397 HDA_CODEC_MUTE("Headphone1 Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16398 HDA_CODEC_MUTE("Headphone2 Playback Switch", 0x21, 0x0, HDA_OUTPUT),
16399 HDA_CODEC_VOLUME("IntMic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16400 HDA_CODEC_MUTE("IntMic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16401 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16402 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16403 { } /* end */
16404};
16405
16406static struct snd_kcontrol_new alc663_mode8_mixer[] = {
16407 HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch),
16408 HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol),
16409 HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch),
16410 HDA_CODEC_MUTE("Headphone1 Playback Switch", 0x15, 0x0, HDA_OUTPUT),
16411 HDA_CODEC_MUTE("Headphone2 Playback Switch", 0x21, 0x0, HDA_OUTPUT),
16412 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16413 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16414 { } /* end */
16415};
16416
16417
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016418static struct snd_kcontrol_new alc662_chmode_mixer[] = {
16419 {
16420 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
16421 .name = "Channel Mode",
16422 .info = alc_ch_mode_info,
16423 .get = alc_ch_mode_get,
16424 .put = alc_ch_mode_put,
16425 },
16426 { } /* end */
16427};
16428
16429static struct hda_verb alc662_init_verbs[] = {
16430 /* ADC: mute amp left and right */
16431 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16432 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
16433 /* Front mixer: unmute input/output amp left and right (volume = 0) */
16434
Takashi Iwaicb53c622007-08-10 17:21:45 +020016435 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16436 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16437 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
16438 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
16439 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016440
Kailang Yangb60dd392007-09-20 12:50:29 +020016441 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16442 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16443 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16444 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16445 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16446 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016447
16448 /* Front Pin: output 0 (0x0c) */
16449 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16450 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16451
16452 /* Rear Pin: output 1 (0x0d) */
16453 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16454 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16455
16456 /* CLFE Pin: output 2 (0x0e) */
16457 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16458 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16459
16460 /* Mic (rear) pin: input vref at 80% */
16461 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16462 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16463 /* Front Mic pin: input vref at 80% */
16464 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16465 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16466 /* Line In pin: input */
16467 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16468 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16469 /* Line-2 In: Headphone output (output 0 - 0x0c) */
16470 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16471 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16472 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
16473 /* CD pin widget for input */
16474 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16475
16476 /* FIXME: use matrix-type input source selection */
16477 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
16478 /* Input mixer */
16479 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yang291702f2007-10-16 14:28:03 +020016480 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yang6dda9f42008-05-27 12:05:31 +020016481
16482 /* always trun on EAPD */
16483 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
16484 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
16485
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016486 { }
16487};
16488
16489static struct hda_verb alc662_sue_init_verbs[] = {
16490 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
16491 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
Kailang Yang291702f2007-10-16 14:28:03 +020016492 {}
16493};
16494
16495static struct hda_verb alc662_eeepc_sue_init_verbs[] = {
16496 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
16497 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16498 {}
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016499};
16500
Kailang Yang8c427222008-01-10 13:03:59 +010016501/* Set Unsolicited Event*/
16502static struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = {
16503 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16504 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16505 {}
16506};
16507
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016508/*
16509 * generic initialization of ADC, input mixers and output mixers
16510 */
16511static struct hda_verb alc662_auto_init_verbs[] = {
16512 /*
16513 * Unmute ADC and set the default input to mic-in
16514 */
16515 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
16516 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16517
16518 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
16519 * mixer widget
16520 * Note: PASD motherboards uses the Line In 2 as the input for front
16521 * panel mic (mic 2)
16522 */
16523 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020016524 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16525 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16526 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
16527 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
16528 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016529
16530 /*
16531 * Set up output mixers (0x0c - 0x0f)
16532 */
16533 /* set vol=0 to output mixers */
16534 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16535 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16536 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16537
16538 /* set up input amps for analog loopback */
16539 /* Amp Indices: DAC = 0, mixer = 1 */
Kailang Yangb60dd392007-09-20 12:50:29 +020016540 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16541 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16542 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16543 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16544 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16545 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016546
16547
16548 /* FIXME: use matrix-type input source selection */
16549 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
16550 /* Input mixer */
16551 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangd1a991a2007-08-15 16:21:59 +020016552 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016553 { }
16554};
16555
Takashi Iwai24fb9172008-09-02 14:48:20 +020016556/* additional verbs for ALC663 */
16557static struct hda_verb alc663_auto_init_verbs[] = {
16558 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16559 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16560 { }
16561};
16562
Kailang Yang6dda9f42008-05-27 12:05:31 +020016563static struct hda_verb alc663_m51va_init_verbs[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020016564 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16565 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yang6dda9f42008-05-27 12:05:31 +020016566 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16567 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangf1d4e282008-08-26 14:03:29 +020016568 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
16569 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16570 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
Kailang Yang6dda9f42008-05-27 12:05:31 +020016571 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
16572 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16573 {}
16574};
16575
Kailang Yangf1d4e282008-08-26 14:03:29 +020016576static struct hda_verb alc663_21jd_amic_init_verbs[] = {
16577 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16578 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16579 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
16580 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16581 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16582 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
16583 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16584 {}
16585};
16586
16587static struct hda_verb alc662_1bjd_amic_init_verbs[] = {
16588 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16589 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16590 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16591 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
16592 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16593 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16594 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
16595 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16596 {}
16597};
16598
16599static struct hda_verb alc663_15jd_amic_init_verbs[] = {
16600 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16601 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16602 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
16603 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16604 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16605 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
16606 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16607 {}
16608};
16609
16610static struct hda_verb alc663_two_hp_amic_m1_init_verbs[] = {
16611 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16612 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16613 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16614 {0x21, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */
16615 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16616 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16617 {0x15, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */
16618 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16619 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16620 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
16621 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16622 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16623 {}
16624};
16625
16626static struct hda_verb alc663_two_hp_amic_m2_init_verbs[] = {
16627 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16628 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16629 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16630 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
16631 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16632 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16633 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
16634 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16635 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16636 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
16637 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16638 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16639 {}
16640};
16641
Kailang Yang6dda9f42008-05-27 12:05:31 +020016642static struct hda_verb alc663_g71v_init_verbs[] = {
16643 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16644 /* {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
16645 /* {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, */ /* Headphone */
16646
16647 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16648 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16649 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
16650
16651 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
16652 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_MIC_EVENT},
16653 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
16654 {}
16655};
16656
16657static struct hda_verb alc663_g50v_init_verbs[] = {
16658 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16659 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16660 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
16661
16662 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
16663 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16664 {}
16665};
16666
Kailang Yangf1d4e282008-08-26 14:03:29 +020016667static struct hda_verb alc662_ecs_init_verbs[] = {
16668 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
16669 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16670 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
16671 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16672 {}
16673};
16674
Kailang Yang622e84c2009-04-21 07:39:04 +020016675static struct hda_verb alc272_dell_zm1_init_verbs[] = {
16676 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16677 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16678 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16679 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16680 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16681 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16682 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
16683 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16684 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
16685 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
16686 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16687 {}
16688};
16689
16690static struct hda_verb alc272_dell_init_verbs[] = {
16691 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16692 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16693 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16694 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16695 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16696 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16697 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
16698 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16699 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
16700 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
16701 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16702 {}
16703};
16704
Kailang Yangebb83ee2009-12-17 12:23:00 +010016705static struct hda_verb alc663_mode7_init_verbs[] = {
16706 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16707 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16708 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16709 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16710 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16711 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16712 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01},
16713 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16714 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16715 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
16716 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16717 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
16718 {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
16719 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16720 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16721 {}
16722};
16723
16724static struct hda_verb alc663_mode8_init_verbs[] = {
16725 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16726 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16727 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16728 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
16729 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16730 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16731 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16732 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16733 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16734 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16735 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
16736 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16737 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
16738 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16739 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
16740 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16741 {}
16742};
16743
Kailang Yangf1d4e282008-08-26 14:03:29 +020016744static struct snd_kcontrol_new alc662_auto_capture_mixer[] = {
16745 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
16746 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
16747 { } /* end */
16748};
16749
Kailang Yang622e84c2009-04-21 07:39:04 +020016750static struct snd_kcontrol_new alc272_auto_capture_mixer[] = {
16751 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
16752 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
16753 { } /* end */
16754};
16755
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016756static void alc662_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
16757{
16758 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016759 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016760
Wu Fengguang864f92b2009-11-18 12:38:02 +080016761 present = snd_hda_jack_detect(codec, 0x14);
Takashi Iwai47fd8302007-08-10 17:11:07 +020016762 bits = present ? HDA_AMP_MUTE : 0;
Wu Fengguang864f92b2009-11-18 12:38:02 +080016763
Takashi Iwai47fd8302007-08-10 17:11:07 +020016764 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
16765 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016766}
16767
16768static void alc662_lenovo_101e_all_automute(struct hda_codec *codec)
16769{
16770 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016771 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016772
Wu Fengguang864f92b2009-11-18 12:38:02 +080016773 present = snd_hda_jack_detect(codec, 0x1b);
Takashi Iwai47fd8302007-08-10 17:11:07 +020016774 bits = present ? HDA_AMP_MUTE : 0;
Wu Fengguang864f92b2009-11-18 12:38:02 +080016775
Takashi Iwai47fd8302007-08-10 17:11:07 +020016776 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
16777 HDA_AMP_MUTE, bits);
16778 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
16779 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016780}
16781
16782static void alc662_lenovo_101e_unsol_event(struct hda_codec *codec,
16783 unsigned int res)
16784{
16785 if ((res >> 26) == ALC880_HP_EVENT)
16786 alc662_lenovo_101e_all_automute(codec);
16787 if ((res >> 26) == ALC880_FRONT_EVENT)
16788 alc662_lenovo_101e_ispeaker_automute(codec);
16789}
16790
Kailang Yang291702f2007-10-16 14:28:03 +020016791/* unsolicited event for HP jack sensing */
16792static void alc662_eeepc_unsol_event(struct hda_codec *codec,
16793 unsigned int res)
16794{
Kailang Yang291702f2007-10-16 14:28:03 +020016795 if ((res >> 26) == ALC880_MIC_EVENT)
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016796 alc_mic_automute(codec);
Takashi Iwai42171c12009-05-08 14:11:43 +020016797 else
16798 alc262_hippo_unsol_event(codec, res);
Kailang Yang291702f2007-10-16 14:28:03 +020016799}
16800
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016801static void alc662_eeepc_setup(struct hda_codec *codec)
Kailang Yang291702f2007-10-16 14:28:03 +020016802{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016803 struct alc_spec *spec = codec->spec;
16804
16805 alc262_hippo1_setup(codec);
16806 spec->ext_mic.pin = 0x18;
16807 spec->ext_mic.mux_idx = 0;
16808 spec->int_mic.pin = 0x19;
16809 spec->int_mic.mux_idx = 1;
16810 spec->auto_mic = 1;
Kailang Yang291702f2007-10-16 14:28:03 +020016811}
16812
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016813static void alc662_eeepc_inithook(struct hda_codec *codec)
16814{
16815 alc262_hippo_automute(codec);
16816 alc_mic_automute(codec);
16817}
16818
16819static void alc662_eeepc_ep20_setup(struct hda_codec *codec)
Kailang Yang8c427222008-01-10 13:03:59 +010016820{
Takashi Iwai42171c12009-05-08 14:11:43 +020016821 struct alc_spec *spec = codec->spec;
16822
16823 spec->autocfg.hp_pins[0] = 0x14;
16824 spec->autocfg.speaker_pins[0] = 0x1b;
Kailang Yang8c427222008-01-10 13:03:59 +010016825}
16826
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016827#define alc662_eeepc_ep20_inithook alc262_hippo_master_update
16828
Kailang Yang6dda9f42008-05-27 12:05:31 +020016829static void alc663_m51va_speaker_automute(struct hda_codec *codec)
16830{
16831 unsigned int present;
16832 unsigned char bits;
16833
Wu Fengguang864f92b2009-11-18 12:38:02 +080016834 present = snd_hda_jack_detect(codec, 0x21);
Kailang Yang6dda9f42008-05-27 12:05:31 +020016835 bits = present ? HDA_AMP_MUTE : 0;
Kailang Yangf1d4e282008-08-26 14:03:29 +020016836 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
16837 AMP_IN_MUTE(0), bits);
16838 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
16839 AMP_IN_MUTE(0), bits);
16840}
16841
16842static void alc663_21jd_two_speaker_automute(struct hda_codec *codec)
16843{
16844 unsigned int present;
16845 unsigned char bits;
16846
Wu Fengguang864f92b2009-11-18 12:38:02 +080016847 present = snd_hda_jack_detect(codec, 0x21);
Kailang Yangf1d4e282008-08-26 14:03:29 +020016848 bits = present ? HDA_AMP_MUTE : 0;
16849 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
16850 AMP_IN_MUTE(0), bits);
16851 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
16852 AMP_IN_MUTE(0), bits);
16853 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0,
16854 AMP_IN_MUTE(0), bits);
16855 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1,
16856 AMP_IN_MUTE(0), bits);
16857}
16858
16859static void alc663_15jd_two_speaker_automute(struct hda_codec *codec)
16860{
16861 unsigned int present;
16862 unsigned char bits;
16863
Wu Fengguang864f92b2009-11-18 12:38:02 +080016864 present = snd_hda_jack_detect(codec, 0x15);
Kailang Yangf1d4e282008-08-26 14:03:29 +020016865 bits = present ? HDA_AMP_MUTE : 0;
16866 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
16867 AMP_IN_MUTE(0), bits);
16868 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
16869 AMP_IN_MUTE(0), bits);
16870 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0,
16871 AMP_IN_MUTE(0), bits);
16872 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1,
16873 AMP_IN_MUTE(0), bits);
16874}
16875
16876static void alc662_f5z_speaker_automute(struct hda_codec *codec)
16877{
16878 unsigned int present;
16879 unsigned char bits;
16880
Wu Fengguang864f92b2009-11-18 12:38:02 +080016881 present = snd_hda_jack_detect(codec, 0x1b);
Kailang Yangf1d4e282008-08-26 14:03:29 +020016882 bits = present ? 0 : PIN_OUT;
16883 snd_hda_codec_write(codec, 0x14, 0,
16884 AC_VERB_SET_PIN_WIDGET_CONTROL, bits);
16885}
16886
16887static void alc663_two_hp_m1_speaker_automute(struct hda_codec *codec)
16888{
16889 unsigned int present1, present2;
16890
Wu Fengguang864f92b2009-11-18 12:38:02 +080016891 present1 = snd_hda_jack_detect(codec, 0x21);
16892 present2 = snd_hda_jack_detect(codec, 0x15);
Kailang Yangf1d4e282008-08-26 14:03:29 +020016893
16894 if (present1 || present2) {
16895 snd_hda_codec_write_cache(codec, 0x14, 0,
16896 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
16897 } else {
16898 snd_hda_codec_write_cache(codec, 0x14, 0,
16899 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
16900 }
16901}
16902
16903static void alc663_two_hp_m2_speaker_automute(struct hda_codec *codec)
16904{
16905 unsigned int present1, present2;
16906
Wu Fengguang864f92b2009-11-18 12:38:02 +080016907 present1 = snd_hda_jack_detect(codec, 0x1b);
16908 present2 = snd_hda_jack_detect(codec, 0x15);
Kailang Yangf1d4e282008-08-26 14:03:29 +020016909
16910 if (present1 || present2) {
16911 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
16912 AMP_IN_MUTE(0), AMP_IN_MUTE(0));
16913 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
16914 AMP_IN_MUTE(0), AMP_IN_MUTE(0));
16915 } else {
16916 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
16917 AMP_IN_MUTE(0), 0);
16918 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
16919 AMP_IN_MUTE(0), 0);
16920 }
Kailang Yang6dda9f42008-05-27 12:05:31 +020016921}
16922
Kailang Yangebb83ee2009-12-17 12:23:00 +010016923static void alc663_two_hp_m7_speaker_automute(struct hda_codec *codec)
16924{
16925 unsigned int present1, present2;
16926
16927 present1 = snd_hda_codec_read(codec, 0x1b, 0,
16928 AC_VERB_GET_PIN_SENSE, 0)
16929 & AC_PINSENSE_PRESENCE;
16930 present2 = snd_hda_codec_read(codec, 0x21, 0,
16931 AC_VERB_GET_PIN_SENSE, 0)
16932 & AC_PINSENSE_PRESENCE;
16933
16934 if (present1 || present2) {
16935 snd_hda_codec_write_cache(codec, 0x14, 0,
16936 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
16937 snd_hda_codec_write_cache(codec, 0x17, 0,
16938 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
16939 } else {
16940 snd_hda_codec_write_cache(codec, 0x14, 0,
16941 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
16942 snd_hda_codec_write_cache(codec, 0x17, 0,
16943 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
16944 }
16945}
16946
16947static void alc663_two_hp_m8_speaker_automute(struct hda_codec *codec)
16948{
16949 unsigned int present1, present2;
16950
16951 present1 = snd_hda_codec_read(codec, 0x21, 0,
16952 AC_VERB_GET_PIN_SENSE, 0)
16953 & AC_PINSENSE_PRESENCE;
16954 present2 = snd_hda_codec_read(codec, 0x15, 0,
16955 AC_VERB_GET_PIN_SENSE, 0)
16956 & AC_PINSENSE_PRESENCE;
16957
16958 if (present1 || present2) {
16959 snd_hda_codec_write_cache(codec, 0x14, 0,
16960 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
16961 snd_hda_codec_write_cache(codec, 0x17, 0,
16962 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
16963 } else {
16964 snd_hda_codec_write_cache(codec, 0x14, 0,
16965 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
16966 snd_hda_codec_write_cache(codec, 0x17, 0,
16967 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
16968 }
16969}
16970
Kailang Yang6dda9f42008-05-27 12:05:31 +020016971static void alc663_m51va_unsol_event(struct hda_codec *codec,
16972 unsigned int res)
16973{
16974 switch (res >> 26) {
16975 case ALC880_HP_EVENT:
16976 alc663_m51va_speaker_automute(codec);
16977 break;
16978 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016979 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020016980 break;
16981 }
16982}
16983
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016984static void alc663_m51va_setup(struct hda_codec *codec)
16985{
16986 struct alc_spec *spec = codec->spec;
16987 spec->ext_mic.pin = 0x18;
16988 spec->ext_mic.mux_idx = 0;
16989 spec->int_mic.pin = 0x12;
Kailang Yangebb83ee2009-12-17 12:23:00 +010016990 spec->int_mic.mux_idx = 9;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016991 spec->auto_mic = 1;
16992}
16993
Kailang Yang6dda9f42008-05-27 12:05:31 +020016994static void alc663_m51va_inithook(struct hda_codec *codec)
16995{
16996 alc663_m51va_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016997 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020016998}
16999
Kailang Yangf1d4e282008-08-26 14:03:29 +020017000/* ***************** Mode1 ******************************/
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017001#define alc663_mode1_unsol_event alc663_m51va_unsol_event
Kailang Yangebb83ee2009-12-17 12:23:00 +010017002
17003static void alc663_mode1_setup(struct hda_codec *codec)
17004{
17005 struct alc_spec *spec = codec->spec;
17006 spec->ext_mic.pin = 0x18;
17007 spec->ext_mic.mux_idx = 0;
17008 spec->int_mic.pin = 0x19;
17009 spec->int_mic.mux_idx = 1;
17010 spec->auto_mic = 1;
17011}
17012
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017013#define alc663_mode1_inithook alc663_m51va_inithook
Kailang Yangf1d4e282008-08-26 14:03:29 +020017014
Kailang Yangf1d4e282008-08-26 14:03:29 +020017015/* ***************** Mode2 ******************************/
17016static void alc662_mode2_unsol_event(struct hda_codec *codec,
17017 unsigned int res)
17018{
17019 switch (res >> 26) {
17020 case ALC880_HP_EVENT:
17021 alc662_f5z_speaker_automute(codec);
17022 break;
17023 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017024 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017025 break;
17026 }
17027}
17028
Kailang Yangebb83ee2009-12-17 12:23:00 +010017029#define alc662_mode2_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017030
Kailang Yangf1d4e282008-08-26 14:03:29 +020017031static void alc662_mode2_inithook(struct hda_codec *codec)
17032{
17033 alc662_f5z_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017034 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017035}
17036/* ***************** Mode3 ******************************/
17037static void alc663_mode3_unsol_event(struct hda_codec *codec,
17038 unsigned int res)
17039{
17040 switch (res >> 26) {
17041 case ALC880_HP_EVENT:
17042 alc663_two_hp_m1_speaker_automute(codec);
17043 break;
17044 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017045 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017046 break;
17047 }
17048}
17049
Kailang Yangebb83ee2009-12-17 12:23:00 +010017050#define alc663_mode3_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017051
Kailang Yangf1d4e282008-08-26 14:03:29 +020017052static void alc663_mode3_inithook(struct hda_codec *codec)
17053{
17054 alc663_two_hp_m1_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017055 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017056}
17057/* ***************** Mode4 ******************************/
17058static void alc663_mode4_unsol_event(struct hda_codec *codec,
17059 unsigned int res)
17060{
17061 switch (res >> 26) {
17062 case ALC880_HP_EVENT:
17063 alc663_21jd_two_speaker_automute(codec);
17064 break;
17065 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017066 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017067 break;
17068 }
17069}
17070
Kailang Yangebb83ee2009-12-17 12:23:00 +010017071#define alc663_mode4_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017072
Kailang Yangf1d4e282008-08-26 14:03:29 +020017073static void alc663_mode4_inithook(struct hda_codec *codec)
17074{
17075 alc663_21jd_two_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017076 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017077}
17078/* ***************** Mode5 ******************************/
17079static void alc663_mode5_unsol_event(struct hda_codec *codec,
17080 unsigned int res)
17081{
17082 switch (res >> 26) {
17083 case ALC880_HP_EVENT:
17084 alc663_15jd_two_speaker_automute(codec);
17085 break;
17086 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017087 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017088 break;
17089 }
17090}
17091
Kailang Yangebb83ee2009-12-17 12:23:00 +010017092#define alc663_mode5_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017093
Kailang Yangf1d4e282008-08-26 14:03:29 +020017094static void alc663_mode5_inithook(struct hda_codec *codec)
17095{
17096 alc663_15jd_two_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017097 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017098}
17099/* ***************** Mode6 ******************************/
17100static void alc663_mode6_unsol_event(struct hda_codec *codec,
17101 unsigned int res)
17102{
17103 switch (res >> 26) {
17104 case ALC880_HP_EVENT:
17105 alc663_two_hp_m2_speaker_automute(codec);
17106 break;
17107 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017108 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017109 break;
17110 }
17111}
17112
Kailang Yangebb83ee2009-12-17 12:23:00 +010017113#define alc663_mode6_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017114
Kailang Yangf1d4e282008-08-26 14:03:29 +020017115static void alc663_mode6_inithook(struct hda_codec *codec)
17116{
17117 alc663_two_hp_m2_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017118 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020017119}
17120
Kailang Yangebb83ee2009-12-17 12:23:00 +010017121/* ***************** Mode7 ******************************/
17122static void alc663_mode7_unsol_event(struct hda_codec *codec,
17123 unsigned int res)
17124{
17125 switch (res >> 26) {
17126 case ALC880_HP_EVENT:
17127 alc663_two_hp_m7_speaker_automute(codec);
17128 break;
17129 case ALC880_MIC_EVENT:
17130 alc_mic_automute(codec);
17131 break;
17132 }
17133}
17134
17135#define alc663_mode7_setup alc663_mode1_setup
17136
17137static void alc663_mode7_inithook(struct hda_codec *codec)
17138{
17139 alc663_two_hp_m7_speaker_automute(codec);
17140 alc_mic_automute(codec);
17141}
17142
17143/* ***************** Mode8 ******************************/
17144static void alc663_mode8_unsol_event(struct hda_codec *codec,
17145 unsigned int res)
17146{
17147 switch (res >> 26) {
17148 case ALC880_HP_EVENT:
17149 alc663_two_hp_m8_speaker_automute(codec);
17150 break;
17151 case ALC880_MIC_EVENT:
17152 alc_mic_automute(codec);
17153 break;
17154 }
17155}
17156
17157#define alc663_mode8_setup alc663_m51va_setup
17158
17159static void alc663_mode8_inithook(struct hda_codec *codec)
17160{
17161 alc663_two_hp_m8_speaker_automute(codec);
17162 alc_mic_automute(codec);
17163}
17164
Kailang Yang6dda9f42008-05-27 12:05:31 +020017165static void alc663_g71v_hp_automute(struct hda_codec *codec)
17166{
17167 unsigned int present;
17168 unsigned char bits;
17169
Wu Fengguang864f92b2009-11-18 12:38:02 +080017170 present = snd_hda_jack_detect(codec, 0x21);
Kailang Yang6dda9f42008-05-27 12:05:31 +020017171 bits = present ? HDA_AMP_MUTE : 0;
17172 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
17173 HDA_AMP_MUTE, bits);
17174 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
17175 HDA_AMP_MUTE, bits);
17176}
17177
17178static void alc663_g71v_front_automute(struct hda_codec *codec)
17179{
17180 unsigned int present;
17181 unsigned char bits;
17182
Wu Fengguang864f92b2009-11-18 12:38:02 +080017183 present = snd_hda_jack_detect(codec, 0x15);
Kailang Yang6dda9f42008-05-27 12:05:31 +020017184 bits = present ? HDA_AMP_MUTE : 0;
17185 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
17186 HDA_AMP_MUTE, bits);
17187}
17188
17189static void alc663_g71v_unsol_event(struct hda_codec *codec,
17190 unsigned int res)
17191{
17192 switch (res >> 26) {
17193 case ALC880_HP_EVENT:
17194 alc663_g71v_hp_automute(codec);
17195 break;
17196 case ALC880_FRONT_EVENT:
17197 alc663_g71v_front_automute(codec);
17198 break;
17199 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017200 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020017201 break;
17202 }
17203}
17204
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017205#define alc663_g71v_setup alc663_m51va_setup
17206
Kailang Yang6dda9f42008-05-27 12:05:31 +020017207static void alc663_g71v_inithook(struct hda_codec *codec)
17208{
17209 alc663_g71v_front_automute(codec);
17210 alc663_g71v_hp_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017211 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020017212}
17213
17214static void alc663_g50v_unsol_event(struct hda_codec *codec,
17215 unsigned int res)
17216{
17217 switch (res >> 26) {
17218 case ALC880_HP_EVENT:
17219 alc663_m51va_speaker_automute(codec);
17220 break;
17221 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017222 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020017223 break;
17224 }
17225}
17226
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017227#define alc663_g50v_setup alc663_m51va_setup
17228
Kailang Yang6dda9f42008-05-27 12:05:31 +020017229static void alc663_g50v_inithook(struct hda_codec *codec)
17230{
17231 alc663_m51va_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017232 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020017233}
17234
Kailang Yangf1d4e282008-08-26 14:03:29 +020017235static struct snd_kcontrol_new alc662_ecs_mixer[] = {
17236 HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020017237 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017238
17239 HDA_CODEC_VOLUME("e-Mic/LineIn Boost", 0x18, 0, HDA_INPUT),
17240 HDA_CODEC_VOLUME("e-Mic/LineIn Playback Volume", 0x0b, 0x0, HDA_INPUT),
17241 HDA_CODEC_MUTE("e-Mic/LineIn Playback Switch", 0x0b, 0x0, HDA_INPUT),
17242
17243 HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT),
17244 HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17245 HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17246 { } /* end */
17247};
17248
Chris Pockelé9541ba12009-05-12 08:08:53 +020017249static struct snd_kcontrol_new alc272_nc10_mixer[] = {
17250 /* Master Playback automatically created from Speaker and Headphone */
17251 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17252 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
17253 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
17254 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17255
17256 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17257 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17258 HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
17259
17260 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17261 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17262 HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
17263 { } /* end */
17264};
17265
Takashi Iwaicb53c622007-08-10 17:21:45 +020017266#ifdef CONFIG_SND_HDA_POWER_SAVE
17267#define alc662_loopbacks alc880_loopbacks
17268#endif
17269
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017270
Sasha Alexandrdef319f2009-06-16 16:00:15 -040017271/* pcm configuration: identical with ALC880 */
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017272#define alc662_pcm_analog_playback alc880_pcm_analog_playback
17273#define alc662_pcm_analog_capture alc880_pcm_analog_capture
17274#define alc662_pcm_digital_playback alc880_pcm_digital_playback
17275#define alc662_pcm_digital_capture alc880_pcm_digital_capture
17276
17277/*
17278 * configuration and preset
17279 */
17280static const char *alc662_models[ALC662_MODEL_LAST] = {
17281 [ALC662_3ST_2ch_DIG] = "3stack-dig",
17282 [ALC662_3ST_6ch_DIG] = "3stack-6ch-dig",
17283 [ALC662_3ST_6ch] = "3stack-6ch",
17284 [ALC662_5ST_DIG] = "6stack-dig",
17285 [ALC662_LENOVO_101E] = "lenovo-101e",
Takashi Iwaib995d762007-10-17 10:41:06 +020017286 [ALC662_ASUS_EEEPC_P701] = "eeepc-p701",
Kailang Yang8c427222008-01-10 13:03:59 +010017287 [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20",
Kailang Yangf1d4e282008-08-26 14:03:29 +020017288 [ALC662_ECS] = "ecs",
Kailang Yang6dda9f42008-05-27 12:05:31 +020017289 [ALC663_ASUS_M51VA] = "m51va",
17290 [ALC663_ASUS_G71V] = "g71v",
17291 [ALC663_ASUS_H13] = "h13",
17292 [ALC663_ASUS_G50V] = "g50v",
Kailang Yangf1d4e282008-08-26 14:03:29 +020017293 [ALC663_ASUS_MODE1] = "asus-mode1",
17294 [ALC662_ASUS_MODE2] = "asus-mode2",
17295 [ALC663_ASUS_MODE3] = "asus-mode3",
17296 [ALC663_ASUS_MODE4] = "asus-mode4",
17297 [ALC663_ASUS_MODE5] = "asus-mode5",
17298 [ALC663_ASUS_MODE6] = "asus-mode6",
Kailang Yangebb83ee2009-12-17 12:23:00 +010017299 [ALC663_ASUS_MODE7] = "asus-mode7",
17300 [ALC663_ASUS_MODE8] = "asus-mode8",
Takashi Iwai01f2bd42009-05-11 08:12:43 +020017301 [ALC272_DELL] = "dell",
17302 [ALC272_DELL_ZM1] = "dell-zm1",
Chris Pockelé9541ba12009-05-12 08:08:53 +020017303 [ALC272_SAMSUNG_NC10] = "samsung-nc10",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017304 [ALC662_AUTO] = "auto",
17305};
17306
17307static struct snd_pci_quirk alc662_cfg_tbl[] = {
Takashi Iwaidea0a502009-02-09 17:14:52 +010017308 SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_ECS),
Kailang Yang622e84c2009-04-21 07:39:04 +020017309 SND_PCI_QUIRK(0x1028, 0x02d6, "DELL", ALC272_DELL),
17310 SND_PCI_QUIRK(0x1028, 0x02f4, "DELL ZM1", ALC272_DELL_ZM1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017311 SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC663_ASUS_MODE1),
17312 SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC663_ASUS_MODE3),
17313 SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC663_ASUS_MODE3),
17314 SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC663_ASUS_MODE1),
17315 SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_ASUS_MODE2),
17316 SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC663_ASUS_MODE1),
Kailang Yangebb83ee2009-12-17 12:23:00 +010017317 SND_PCI_QUIRK(0x1043, 0x1303, "ASUS G60J", ALC663_ASUS_MODE1),
17318 SND_PCI_QUIRK(0x1043, 0x1333, "ASUS G60Jx", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017319 SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yangebb83ee2009-12-17 12:23:00 +010017320 SND_PCI_QUIRK(0x1043, 0x13e3, "ASUS N71JA", ALC663_ASUS_MODE7),
17321 SND_PCI_QUIRK(0x1043, 0x1463, "ASUS N71", ALC663_ASUS_MODE7),
17322 SND_PCI_QUIRK(0x1043, 0x14d3, "ASUS G72", ALC663_ASUS_MODE8),
17323 SND_PCI_QUIRK(0x1043, 0x1563, "ASUS N90", ALC663_ASUS_MODE3),
17324 SND_PCI_QUIRK(0x1043, 0x15d3, "ASUS N50SF F50SF", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017325 SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yangebb83ee2009-12-17 12:23:00 +010017326 SND_PCI_QUIRK(0x1043, 0x16f3, "ASUS K40C K50C", ALC662_ASUS_MODE2),
17327 SND_PCI_QUIRK(0x1043, 0x1733, "ASUS N81De", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017328 SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_ASUS_MODE2),
17329 SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC663_ASUS_MODE6),
17330 SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC663_ASUS_MODE6),
17331 SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yangebb83ee2009-12-17 12:23:00 +010017332 SND_PCI_QUIRK(0x1043, 0x1793, "ASUS F50GX", ALC663_ASUS_MODE1),
Kailang Yang622e84c2009-04-21 07:39:04 +020017333 SND_PCI_QUIRK(0x1043, 0x17b3, "ASUS F70SL", ALC663_ASUS_MODE3),
17334 SND_PCI_QUIRK(0x1043, 0x17c3, "ASUS UX20", ALC663_ASUS_M51VA),
17335 SND_PCI_QUIRK(0x1043, 0x17f3, "ASUS X58LE", ALC662_ASUS_MODE2),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017336 SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_ASUS_MODE2),
17337 SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC663_ASUS_MODE5),
17338 SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC663_ASUS_MODE6),
17339 SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020017340 SND_PCI_QUIRK(0x1043, 0x1853, "ASUS F50Z", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017341 SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_ASUS_MODE2),
17342 SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yang6dda9f42008-05-27 12:05:31 +020017343 SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M51VA", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017344 /*SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M50Vr", ALC663_ASUS_MODE1),*/
17345 SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC663_ASUS_MODE3),
17346 SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC663_ASUS_MODE3),
Kailang Yang622e84c2009-04-21 07:39:04 +020017347 SND_PCI_QUIRK(0x1043, 0x18b3, "ASUS N80Vc", ALC663_ASUS_MODE1),
17348 SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS N81Te", ALC663_ASUS_MODE1),
17349 SND_PCI_QUIRK(0x1043, 0x18f3, "ASUS N505Tp", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017350 SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC663_ASUS_MODE1),
17351 SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_ASUS_MODE2),
17352 SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020017353 SND_PCI_QUIRK(0x1043, 0x1943, "ASUS Vx3V", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017354 SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC663_ASUS_MODE1),
17355 SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC663_ASUS_MODE3),
Kailang Yang622e84c2009-04-21 07:39:04 +020017356 SND_PCI_QUIRK(0x1043, 0x1983, "ASUS N5051A", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017357 SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC663_ASUS_MODE1),
Kailang Yang80ffe862008-10-15 11:23:27 +020017358 SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS G50V", ALC663_ASUS_G50V),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017359 /*SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS NB", ALC663_ASUS_MODE1),*/
17360 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC663_ASUS_MODE1),
17361 SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020017362 SND_PCI_QUIRK(0x1043, 0x19d3, "ASUS NB", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017363 SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC663_ASUS_MODE1),
17364 SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC663_ASUS_MODE4),
Herton Ronaldo Krzesinski3da23ca2008-03-14 12:52:59 +010017365 SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG),
Kailang Yang291702f2007-10-16 14:28:03 +020017366 SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701),
Kailang Yang8c427222008-01-10 13:03:59 +010017367 SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017368 SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS),
Herton Ronaldo Krzesinski95fe5f22008-09-26 23:48:45 -030017369 SND_PCI_QUIRK(0x105b, 0x0d47, "Foxconn 45CMX/45GMX/45CMX-K",
17370 ALC662_3ST_6ch_DIG),
Manoj Iyer3db6c032009-09-22 18:33:29 -050017371 SND_PCI_QUIRK(0x1179, 0xff6e, "Toshiba NB200", ALC663_ASUS_MODE4),
Chris Pockelé9541ba12009-05-12 08:08:53 +020017372 SND_PCI_QUIRK(0x144d, 0xca00, "Samsung NC10", ALC272_SAMSUNG_NC10),
Herton Ronaldo Krzesinskicb559742008-09-26 23:47:45 -030017373 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L",
17374 ALC662_3ST_6ch_DIG),
Vedran Miletic19c009a2008-09-29 20:29:25 +020017375 SND_PCI_QUIRK(0x1565, 0x820f, "Biostar TA780G M2+", ALC662_3ST_6ch_DIG),
Takashi Iwai5bd37292009-04-21 18:36:30 +020017376 SND_PCI_QUIRK(0x1631, 0xc10c, "PB RS65", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017377 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E),
Takashi Iwai238713d2008-10-05 10:57:39 +020017378 SND_PCI_QUIRK(0x1849, 0x3662, "ASROCK K10N78FullHD-hSLI R3.0",
Vedran Miletic19c009a2008-09-29 20:29:25 +020017379 ALC662_3ST_6ch_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017380 SND_PCI_QUIRK_MASK(0x1854, 0xf000, 0x2000, "ASUS H13-200x",
17381 ALC663_ASUS_H13),
David Santinoli7aee6742009-12-09 12:34:26 +010017382 SND_PCI_QUIRK(0x8086, 0xd604, "Intel mobo", ALC662_3ST_2ch_DIG),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017383 {}
17384};
17385
17386static struct alc_config_preset alc662_presets[] = {
17387 [ALC662_3ST_2ch_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017388 .mixers = { alc662_3ST_2ch_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017389 .init_verbs = { alc662_init_verbs },
17390 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17391 .dac_nids = alc662_dac_nids,
17392 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017393 .dig_in_nid = ALC662_DIGIN_NID,
17394 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17395 .channel_mode = alc662_3ST_2ch_modes,
17396 .input_mux = &alc662_capture_source,
17397 },
17398 [ALC662_3ST_6ch_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017399 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017400 .init_verbs = { alc662_init_verbs },
17401 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17402 .dac_nids = alc662_dac_nids,
17403 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017404 .dig_in_nid = ALC662_DIGIN_NID,
17405 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
17406 .channel_mode = alc662_3ST_6ch_modes,
17407 .need_dac_fix = 1,
17408 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017409 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017410 [ALC662_3ST_6ch] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017411 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017412 .init_verbs = { alc662_init_verbs },
17413 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17414 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017415 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
17416 .channel_mode = alc662_3ST_6ch_modes,
17417 .need_dac_fix = 1,
17418 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017419 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017420 [ALC662_5ST_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017421 .mixers = { alc662_base_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017422 .init_verbs = { alc662_init_verbs },
17423 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17424 .dac_nids = alc662_dac_nids,
17425 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017426 .dig_in_nid = ALC662_DIGIN_NID,
17427 .num_channel_mode = ARRAY_SIZE(alc662_5stack_modes),
17428 .channel_mode = alc662_5stack_modes,
17429 .input_mux = &alc662_capture_source,
17430 },
17431 [ALC662_LENOVO_101E] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017432 .mixers = { alc662_lenovo_101e_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017433 .init_verbs = { alc662_init_verbs, alc662_sue_init_verbs },
17434 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17435 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017436 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17437 .channel_mode = alc662_3ST_2ch_modes,
17438 .input_mux = &alc662_lenovo_101e_capture_source,
17439 .unsol_event = alc662_lenovo_101e_unsol_event,
17440 .init_hook = alc662_lenovo_101e_all_automute,
17441 },
Kailang Yang291702f2007-10-16 14:28:03 +020017442 [ALC662_ASUS_EEEPC_P701] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017443 .mixers = { alc662_eeepc_p701_mixer },
Kailang Yang291702f2007-10-16 14:28:03 +020017444 .init_verbs = { alc662_init_verbs,
17445 alc662_eeepc_sue_init_verbs },
17446 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17447 .dac_nids = alc662_dac_nids,
Kailang Yang291702f2007-10-16 14:28:03 +020017448 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17449 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang291702f2007-10-16 14:28:03 +020017450 .unsol_event = alc662_eeepc_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017451 .setup = alc662_eeepc_setup,
Kailang Yang291702f2007-10-16 14:28:03 +020017452 .init_hook = alc662_eeepc_inithook,
17453 },
Kailang Yang8c427222008-01-10 13:03:59 +010017454 [ALC662_ASUS_EEEPC_EP20] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017455 .mixers = { alc662_eeepc_ep20_mixer,
Kailang Yang8c427222008-01-10 13:03:59 +010017456 alc662_chmode_mixer },
17457 .init_verbs = { alc662_init_verbs,
17458 alc662_eeepc_ep20_sue_init_verbs },
17459 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17460 .dac_nids = alc662_dac_nids,
Kailang Yang8c427222008-01-10 13:03:59 +010017461 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
17462 .channel_mode = alc662_3ST_6ch_modes,
17463 .input_mux = &alc662_lenovo_101e_capture_source,
Takashi Iwai42171c12009-05-08 14:11:43 +020017464 .unsol_event = alc662_eeepc_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017465 .setup = alc662_eeepc_ep20_setup,
Kailang Yang8c427222008-01-10 13:03:59 +010017466 .init_hook = alc662_eeepc_ep20_inithook,
17467 },
Kailang Yangf1d4e282008-08-26 14:03:29 +020017468 [ALC662_ECS] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017469 .mixers = { alc662_ecs_mixer },
Kailang Yangf1d4e282008-08-26 14:03:29 +020017470 .init_verbs = { alc662_init_verbs,
17471 alc662_ecs_init_verbs },
17472 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17473 .dac_nids = alc662_dac_nids,
17474 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17475 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017476 .unsol_event = alc662_eeepc_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017477 .setup = alc662_eeepc_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017478 .init_hook = alc662_eeepc_inithook,
17479 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020017480 [ALC663_ASUS_M51VA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017481 .mixers = { alc663_m51va_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020017482 .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
17483 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17484 .dac_nids = alc662_dac_nids,
17485 .dig_out_nid = ALC662_DIGOUT_NID,
17486 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17487 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang6dda9f42008-05-27 12:05:31 +020017488 .unsol_event = alc663_m51va_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017489 .setup = alc663_m51va_setup,
Kailang Yang6dda9f42008-05-27 12:05:31 +020017490 .init_hook = alc663_m51va_inithook,
17491 },
17492 [ALC663_ASUS_G71V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017493 .mixers = { alc663_g71v_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020017494 .init_verbs = { alc662_init_verbs, alc663_g71v_init_verbs },
17495 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17496 .dac_nids = alc662_dac_nids,
17497 .dig_out_nid = ALC662_DIGOUT_NID,
17498 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17499 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang6dda9f42008-05-27 12:05:31 +020017500 .unsol_event = alc663_g71v_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017501 .setup = alc663_g71v_setup,
Kailang Yang6dda9f42008-05-27 12:05:31 +020017502 .init_hook = alc663_g71v_inithook,
17503 },
17504 [ALC663_ASUS_H13] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017505 .mixers = { alc663_m51va_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020017506 .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
17507 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17508 .dac_nids = alc662_dac_nids,
17509 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17510 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang6dda9f42008-05-27 12:05:31 +020017511 .unsol_event = alc663_m51va_unsol_event,
17512 .init_hook = alc663_m51va_inithook,
17513 },
17514 [ALC663_ASUS_G50V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017515 .mixers = { alc663_g50v_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020017516 .init_verbs = { alc662_init_verbs, alc663_g50v_init_verbs },
17517 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17518 .dac_nids = alc662_dac_nids,
17519 .dig_out_nid = ALC662_DIGOUT_NID,
17520 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
17521 .channel_mode = alc662_3ST_6ch_modes,
17522 .input_mux = &alc663_capture_source,
17523 .unsol_event = alc663_g50v_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017524 .setup = alc663_g50v_setup,
Kailang Yang6dda9f42008-05-27 12:05:31 +020017525 .init_hook = alc663_g50v_inithook,
17526 },
Kailang Yangf1d4e282008-08-26 14:03:29 +020017527 [ALC663_ASUS_MODE1] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017528 .mixers = { alc663_m51va_mixer },
17529 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017530 .init_verbs = { alc662_init_verbs,
17531 alc663_21jd_amic_init_verbs },
17532 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17533 .hp_nid = 0x03,
17534 .dac_nids = alc662_dac_nids,
17535 .dig_out_nid = ALC662_DIGOUT_NID,
17536 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17537 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017538 .unsol_event = alc663_mode1_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017539 .setup = alc663_mode1_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017540 .init_hook = alc663_mode1_inithook,
17541 },
17542 [ALC662_ASUS_MODE2] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017543 .mixers = { alc662_1bjd_mixer },
17544 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017545 .init_verbs = { alc662_init_verbs,
17546 alc662_1bjd_amic_init_verbs },
17547 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17548 .dac_nids = alc662_dac_nids,
17549 .dig_out_nid = ALC662_DIGOUT_NID,
17550 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17551 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017552 .unsol_event = alc662_mode2_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017553 .setup = alc662_mode2_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017554 .init_hook = alc662_mode2_inithook,
17555 },
17556 [ALC663_ASUS_MODE3] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017557 .mixers = { alc663_two_hp_m1_mixer },
17558 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017559 .init_verbs = { alc662_init_verbs,
17560 alc663_two_hp_amic_m1_init_verbs },
17561 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17562 .hp_nid = 0x03,
17563 .dac_nids = alc662_dac_nids,
17564 .dig_out_nid = ALC662_DIGOUT_NID,
17565 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17566 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017567 .unsol_event = alc663_mode3_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017568 .setup = alc663_mode3_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017569 .init_hook = alc663_mode3_inithook,
17570 },
17571 [ALC663_ASUS_MODE4] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017572 .mixers = { alc663_asus_21jd_clfe_mixer },
17573 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017574 .init_verbs = { alc662_init_verbs,
17575 alc663_21jd_amic_init_verbs},
17576 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17577 .hp_nid = 0x03,
17578 .dac_nids = alc662_dac_nids,
17579 .dig_out_nid = ALC662_DIGOUT_NID,
17580 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17581 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017582 .unsol_event = alc663_mode4_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017583 .setup = alc663_mode4_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017584 .init_hook = alc663_mode4_inithook,
17585 },
17586 [ALC663_ASUS_MODE5] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017587 .mixers = { alc663_asus_15jd_clfe_mixer },
17588 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017589 .init_verbs = { alc662_init_verbs,
17590 alc663_15jd_amic_init_verbs },
17591 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17592 .hp_nid = 0x03,
17593 .dac_nids = alc662_dac_nids,
17594 .dig_out_nid = ALC662_DIGOUT_NID,
17595 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17596 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017597 .unsol_event = alc663_mode5_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017598 .setup = alc663_mode5_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017599 .init_hook = alc663_mode5_inithook,
17600 },
17601 [ALC663_ASUS_MODE6] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017602 .mixers = { alc663_two_hp_m2_mixer },
17603 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017604 .init_verbs = { alc662_init_verbs,
17605 alc663_two_hp_amic_m2_init_verbs },
17606 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17607 .hp_nid = 0x03,
17608 .dac_nids = alc662_dac_nids,
17609 .dig_out_nid = ALC662_DIGOUT_NID,
17610 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17611 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017612 .unsol_event = alc663_mode6_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017613 .setup = alc663_mode6_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017614 .init_hook = alc663_mode6_inithook,
17615 },
Kailang Yangebb83ee2009-12-17 12:23:00 +010017616 [ALC663_ASUS_MODE7] = {
17617 .mixers = { alc663_mode7_mixer },
17618 .cap_mixer = alc662_auto_capture_mixer,
17619 .init_verbs = { alc662_init_verbs,
17620 alc663_mode7_init_verbs },
17621 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17622 .hp_nid = 0x03,
17623 .dac_nids = alc662_dac_nids,
17624 .dig_out_nid = ALC662_DIGOUT_NID,
17625 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17626 .channel_mode = alc662_3ST_2ch_modes,
17627 .unsol_event = alc663_mode7_unsol_event,
17628 .setup = alc663_mode7_setup,
17629 .init_hook = alc663_mode7_inithook,
17630 },
17631 [ALC663_ASUS_MODE8] = {
17632 .mixers = { alc663_mode8_mixer },
17633 .cap_mixer = alc662_auto_capture_mixer,
17634 .init_verbs = { alc662_init_verbs,
17635 alc663_mode8_init_verbs },
17636 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17637 .hp_nid = 0x03,
17638 .dac_nids = alc662_dac_nids,
17639 .dig_out_nid = ALC662_DIGOUT_NID,
17640 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17641 .channel_mode = alc662_3ST_2ch_modes,
17642 .unsol_event = alc663_mode8_unsol_event,
17643 .setup = alc663_mode8_setup,
17644 .init_hook = alc663_mode8_inithook,
17645 },
Kailang Yang622e84c2009-04-21 07:39:04 +020017646 [ALC272_DELL] = {
17647 .mixers = { alc663_m51va_mixer },
17648 .cap_mixer = alc272_auto_capture_mixer,
17649 .init_verbs = { alc662_init_verbs, alc272_dell_init_verbs },
17650 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
17651 .dac_nids = alc662_dac_nids,
17652 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17653 .adc_nids = alc272_adc_nids,
17654 .num_adc_nids = ARRAY_SIZE(alc272_adc_nids),
17655 .capsrc_nids = alc272_capsrc_nids,
17656 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang622e84c2009-04-21 07:39:04 +020017657 .unsol_event = alc663_m51va_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017658 .setup = alc663_m51va_setup,
Kailang Yang622e84c2009-04-21 07:39:04 +020017659 .init_hook = alc663_m51va_inithook,
17660 },
17661 [ALC272_DELL_ZM1] = {
17662 .mixers = { alc663_m51va_mixer },
17663 .cap_mixer = alc662_auto_capture_mixer,
17664 .init_verbs = { alc662_init_verbs, alc272_dell_zm1_init_verbs },
17665 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
17666 .dac_nids = alc662_dac_nids,
17667 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17668 .adc_nids = alc662_adc_nids,
Takashi Iwaib59bdf32009-08-11 09:47:30 +020017669 .num_adc_nids = 1,
Kailang Yang622e84c2009-04-21 07:39:04 +020017670 .capsrc_nids = alc662_capsrc_nids,
17671 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang622e84c2009-04-21 07:39:04 +020017672 .unsol_event = alc663_m51va_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017673 .setup = alc663_m51va_setup,
Kailang Yang622e84c2009-04-21 07:39:04 +020017674 .init_hook = alc663_m51va_inithook,
17675 },
Chris Pockelé9541ba12009-05-12 08:08:53 +020017676 [ALC272_SAMSUNG_NC10] = {
17677 .mixers = { alc272_nc10_mixer },
17678 .init_verbs = { alc662_init_verbs,
17679 alc663_21jd_amic_init_verbs },
17680 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
17681 .dac_nids = alc272_dac_nids,
17682 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17683 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017684 /*.input_mux = &alc272_nc10_capture_source,*/
Chris Pockelé9541ba12009-05-12 08:08:53 +020017685 .unsol_event = alc663_mode4_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017686 .setup = alc663_mode4_setup,
Chris Pockelé9541ba12009-05-12 08:08:53 +020017687 .init_hook = alc663_mode4_inithook,
17688 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017689};
17690
17691
17692/*
17693 * BIOS auto configuration
17694 */
17695
Takashi Iwai7085ec12009-10-02 09:03:58 +020017696/* convert from MIX nid to DAC */
17697static inline hda_nid_t alc662_mix_to_dac(hda_nid_t nid)
17698{
17699 if (nid == 0x0f)
17700 return 0x02;
17701 else if (nid >= 0x0c && nid <= 0x0e)
17702 return nid - 0x0c + 0x02;
17703 else
17704 return 0;
17705}
17706
17707/* get MIX nid connected to the given pin targeted to DAC */
17708static hda_nid_t alc662_dac_to_mix(struct hda_codec *codec, hda_nid_t pin,
17709 hda_nid_t dac)
17710{
17711 hda_nid_t mix[4];
17712 int i, num;
17713
17714 num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix));
17715 for (i = 0; i < num; i++) {
17716 if (alc662_mix_to_dac(mix[i]) == dac)
17717 return mix[i];
17718 }
17719 return 0;
17720}
17721
17722/* look for an empty DAC slot */
17723static hda_nid_t alc662_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
17724{
17725 struct alc_spec *spec = codec->spec;
17726 hda_nid_t srcs[5];
17727 int i, j, num;
17728
17729 num = snd_hda_get_connections(codec, pin, srcs, ARRAY_SIZE(srcs));
17730 if (num < 0)
17731 return 0;
17732 for (i = 0; i < num; i++) {
17733 hda_nid_t nid = alc662_mix_to_dac(srcs[i]);
17734 if (!nid)
17735 continue;
17736 for (j = 0; j < spec->multiout.num_dacs; j++)
17737 if (spec->multiout.dac_nids[j] == nid)
17738 break;
17739 if (j >= spec->multiout.num_dacs)
17740 return nid;
17741 }
17742 return 0;
17743}
17744
17745/* fill in the dac_nids table from the parsed pin configuration */
17746static int alc662_auto_fill_dac_nids(struct hda_codec *codec,
17747 const struct auto_pin_cfg *cfg)
17748{
17749 struct alc_spec *spec = codec->spec;
17750 int i;
17751 hda_nid_t dac;
17752
17753 spec->multiout.dac_nids = spec->private_dac_nids;
17754 for (i = 0; i < cfg->line_outs; i++) {
17755 dac = alc662_look_for_dac(codec, cfg->line_out_pins[i]);
17756 if (!dac)
17757 continue;
17758 spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
17759 }
17760 return 0;
17761}
17762
Takashi Iwai0afe5f82009-10-02 09:20:00 +020017763static inline int alc662_add_vol_ctl(struct alc_spec *spec, const char *pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020017764 hda_nid_t nid, unsigned int chs)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017765{
Takashi Iwai0afe5f82009-10-02 09:20:00 +020017766 return add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020017767 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
17768}
17769
Takashi Iwai0afe5f82009-10-02 09:20:00 +020017770static inline int alc662_add_sw_ctl(struct alc_spec *spec, const char *pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020017771 hda_nid_t nid, unsigned int chs)
17772{
Takashi Iwai0afe5f82009-10-02 09:20:00 +020017773 return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020017774 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_INPUT));
17775}
17776
17777#define alc662_add_stereo_vol(spec, pfx, nid) \
17778 alc662_add_vol_ctl(spec, pfx, nid, 3)
17779#define alc662_add_stereo_sw(spec, pfx, nid) \
17780 alc662_add_sw_ctl(spec, pfx, nid, 3)
17781
17782/* add playback controls from the parsed DAC table */
17783static int alc662_auto_create_multi_out_ctls(struct hda_codec *codec,
17784 const struct auto_pin_cfg *cfg)
17785{
17786 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017787 static const char *chname[4] = {
17788 "Front", "Surround", NULL /*CLFE*/, "Side"
17789 };
Takashi Iwai7085ec12009-10-02 09:03:58 +020017790 hda_nid_t nid, mix;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017791 int i, err;
17792
17793 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwai7085ec12009-10-02 09:03:58 +020017794 nid = spec->multiout.dac_nids[i];
17795 if (!nid)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017796 continue;
Takashi Iwai7085ec12009-10-02 09:03:58 +020017797 mix = alc662_dac_to_mix(codec, cfg->line_out_pins[i], nid);
17798 if (!mix)
17799 continue;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017800 if (i == 2) {
17801 /* Center/LFE */
Takashi Iwai7085ec12009-10-02 09:03:58 +020017802 err = alc662_add_vol_ctl(spec, "Center", nid, 1);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017803 if (err < 0)
17804 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020017805 err = alc662_add_vol_ctl(spec, "LFE", nid, 2);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017806 if (err < 0)
17807 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020017808 err = alc662_add_sw_ctl(spec, "Center", mix, 1);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017809 if (err < 0)
17810 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020017811 err = alc662_add_sw_ctl(spec, "LFE", mix, 2);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017812 if (err < 0)
17813 return err;
17814 } else {
Takashi Iwai0d884cb2009-08-25 16:14:35 +020017815 const char *pfx;
17816 if (cfg->line_outs == 1 &&
17817 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
Takashi Iwai7085ec12009-10-02 09:03:58 +020017818 if (cfg->hp_outs)
Takashi Iwai0d884cb2009-08-25 16:14:35 +020017819 pfx = "Speaker";
17820 else
17821 pfx = "PCM";
17822 } else
17823 pfx = chname[i];
Takashi Iwai7085ec12009-10-02 09:03:58 +020017824 err = alc662_add_vol_ctl(spec, pfx, nid, 3);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017825 if (err < 0)
17826 return err;
Takashi Iwai0d884cb2009-08-25 16:14:35 +020017827 if (cfg->line_outs == 1 &&
17828 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
17829 pfx = "Speaker";
Takashi Iwai7085ec12009-10-02 09:03:58 +020017830 err = alc662_add_sw_ctl(spec, pfx, mix, 3);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017831 if (err < 0)
17832 return err;
17833 }
17834 }
17835 return 0;
17836}
17837
17838/* add playback controls for speaker and HP outputs */
Takashi Iwai7085ec12009-10-02 09:03:58 +020017839/* return DAC nid if any new DAC is assigned */
17840static int alc662_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017841 const char *pfx)
17842{
Takashi Iwai7085ec12009-10-02 09:03:58 +020017843 struct alc_spec *spec = codec->spec;
17844 hda_nid_t nid, mix;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017845 int err;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017846
17847 if (!pin)
17848 return 0;
Takashi Iwai7085ec12009-10-02 09:03:58 +020017849 nid = alc662_look_for_dac(codec, pin);
17850 if (!nid) {
Takashi Iwai7085ec12009-10-02 09:03:58 +020017851 /* the corresponding DAC is already occupied */
17852 if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP))
17853 return 0; /* no way */
17854 /* create a switch only */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020017855 return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020017856 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
17857 }
17858
17859 mix = alc662_dac_to_mix(codec, pin, nid);
17860 if (!mix)
17861 return 0;
17862 err = alc662_add_vol_ctl(spec, pfx, nid, 3);
17863 if (err < 0)
Takashi Iwai24fb9172008-09-02 14:48:20 +020017864 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020017865 err = alc662_add_sw_ctl(spec, pfx, mix, 3);
17866 if (err < 0)
17867 return err;
17868 return nid;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017869}
17870
17871/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +020017872#define alc662_auto_create_input_ctls \
Takashi Iwai4b7348a2009-10-14 18:25:23 +020017873 alc882_auto_create_input_ctls
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017874
17875static void alc662_auto_set_output_and_unmute(struct hda_codec *codec,
17876 hda_nid_t nid, int pin_type,
Takashi Iwai7085ec12009-10-02 09:03:58 +020017877 hda_nid_t dac)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017878{
Takashi Iwai7085ec12009-10-02 09:03:58 +020017879 int i, num;
17880 hda_nid_t srcs[4];
17881
Takashi Iwaif6c7e542008-02-12 18:32:23 +010017882 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017883 /* need the manual connection? */
Takashi Iwai7085ec12009-10-02 09:03:58 +020017884 num = snd_hda_get_connections(codec, nid, srcs, ARRAY_SIZE(srcs));
17885 if (num <= 1)
17886 return;
17887 for (i = 0; i < num; i++) {
17888 if (alc662_mix_to_dac(srcs[i]) != dac)
17889 continue;
17890 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, i);
17891 return;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017892 }
17893}
17894
17895static void alc662_auto_init_multi_out(struct hda_codec *codec)
17896{
17897 struct alc_spec *spec = codec->spec;
Takashi Iwai7085ec12009-10-02 09:03:58 +020017898 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017899 int i;
17900
17901 for (i = 0; i <= HDA_SIDE; i++) {
17902 hda_nid_t nid = spec->autocfg.line_out_pins[i];
17903 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020017904 alc662_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwai7085ec12009-10-02 09:03:58 +020017905 spec->multiout.dac_nids[i]);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017906 }
17907}
17908
17909static void alc662_auto_init_hp_out(struct hda_codec *codec)
17910{
17911 struct alc_spec *spec = codec->spec;
17912 hda_nid_t pin;
17913
17914 pin = spec->autocfg.hp_pins[0];
Takashi Iwai7085ec12009-10-02 09:03:58 +020017915 if (pin)
17916 alc662_auto_set_output_and_unmute(codec, pin, PIN_HP,
17917 spec->multiout.hp_nid);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010017918 pin = spec->autocfg.speaker_pins[0];
17919 if (pin)
Takashi Iwai7085ec12009-10-02 09:03:58 +020017920 alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT,
17921 spec->multiout.extra_out_nid[0]);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017922}
17923
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017924#define ALC662_PIN_CD_NID ALC880_PIN_CD_NID
17925
17926static void alc662_auto_init_analog_input(struct hda_codec *codec)
17927{
17928 struct alc_spec *spec = codec->spec;
17929 int i;
17930
17931 for (i = 0; i < AUTO_PIN_LAST; i++) {
17932 hda_nid_t nid = spec->autocfg.input_pins[i];
Takashi Iwai05f5f472009-08-25 13:10:18 +020017933 if (alc_is_input_pin(codec, nid)) {
Takashi Iwai23f0c042009-02-26 13:03:58 +010017934 alc_set_input_pin(codec, nid, i);
Takashi Iwai52ca15b2009-03-23 12:51:55 +010017935 if (nid != ALC662_PIN_CD_NID &&
Takashi Iwaie82c0252009-03-23 15:17:38 +010017936 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017937 snd_hda_codec_write(codec, nid, 0,
17938 AC_VERB_SET_AMP_GAIN_MUTE,
17939 AMP_OUT_MUTE);
17940 }
17941 }
17942}
17943
Takashi Iwaif511b012008-08-15 16:46:42 +020017944#define alc662_auto_init_input_src alc882_auto_init_input_src
17945
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017946static int alc662_parse_auto_config(struct hda_codec *codec)
17947{
17948 struct alc_spec *spec = codec->spec;
17949 int err;
17950 static hda_nid_t alc662_ignore[] = { 0x1d, 0 };
17951
17952 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
17953 alc662_ignore);
17954 if (err < 0)
17955 return err;
17956 if (!spec->autocfg.line_outs)
17957 return 0; /* can't find valid BIOS pin config */
17958
Takashi Iwai7085ec12009-10-02 09:03:58 +020017959 err = alc662_auto_fill_dac_nids(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017960 if (err < 0)
17961 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020017962 err = alc662_auto_create_multi_out_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017963 if (err < 0)
17964 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020017965 err = alc662_auto_create_extra_out(codec,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017966 spec->autocfg.speaker_pins[0],
17967 "Speaker");
17968 if (err < 0)
17969 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020017970 if (err)
17971 spec->multiout.extra_out_nid[0] = err;
17972 err = alc662_auto_create_extra_out(codec, spec->autocfg.hp_pins[0],
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017973 "Headphone");
17974 if (err < 0)
17975 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020017976 if (err)
17977 spec->multiout.hp_nid = err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020017978 err = alc662_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017979 if (err < 0)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017980 return err;
17981
17982 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
17983
Takashi Iwai0852d7a2009-02-11 11:35:15 +010017984 if (spec->autocfg.dig_outs)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017985 spec->multiout.dig_out_nid = ALC880_DIGOUT_NID;
17986
Takashi Iwai603c4012008-07-30 15:01:44 +020017987 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010017988 add_mixer(spec, spec->kctls.list);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017989
17990 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020017991 spec->input_mux = &spec->private_imux[0];
Kailang Yangea1fb292008-08-26 12:58:38 +020017992
Takashi Iwaid88897e2008-10-31 15:01:37 +010017993 add_verb(spec, alc662_auto_init_verbs);
Takashi Iwai24fb9172008-09-02 14:48:20 +020017994 if (codec->vendor_id == 0x10ec0663)
Takashi Iwaid88897e2008-10-31 15:01:37 +010017995 add_verb(spec, alc663_auto_init_verbs);
Takashi Iwaiee979a142008-09-02 15:42:20 +020017996
17997 err = alc_auto_add_mic_boost(codec);
17998 if (err < 0)
17999 return err;
18000
Takashi Iwai4a79ba32009-04-22 16:31:35 +020018001 alc_ssid_check(codec, 0x15, 0x1b, 0x14);
18002
Takashi Iwai8c872862007-06-19 12:11:16 +020018003 return 1;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018004}
18005
18006/* additional initialization for auto-configuration model */
18007static void alc662_auto_init(struct hda_codec *codec)
18008{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010018009 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018010 alc662_auto_init_multi_out(codec);
18011 alc662_auto_init_hp_out(codec);
18012 alc662_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020018013 alc662_auto_init_input_src(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010018014 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020018015 alc_inithook(codec);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018016}
18017
18018static int patch_alc662(struct hda_codec *codec)
18019{
18020 struct alc_spec *spec;
18021 int err, board_config;
18022
18023 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
18024 if (!spec)
18025 return -ENOMEM;
18026
18027 codec->spec = spec;
18028
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020018029 alc_fix_pll_init(codec, 0x20, 0x04, 15);
18030
Kailang Yang274693f2009-12-03 10:07:50 +010018031 if (alc_read_coef_idx(codec, 0)==0x8020){
18032 kfree(codec->chip_name);
18033 codec->chip_name = kstrdup("ALC661", GFP_KERNEL);
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010018034 if (!codec->chip_name) {
18035 alc_free(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010018036 return -ENOMEM;
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010018037 }
Kailang Yang274693f2009-12-03 10:07:50 +010018038 }
18039
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018040 board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST,
18041 alc662_models,
18042 alc662_cfg_tbl);
18043 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020018044 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
18045 codec->chip_name);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018046 board_config = ALC662_AUTO;
18047 }
18048
18049 if (board_config == ALC662_AUTO) {
18050 /* automatic parse from the BIOS config */
18051 err = alc662_parse_auto_config(codec);
18052 if (err < 0) {
18053 alc_free(codec);
18054 return err;
Takashi Iwai8c872862007-06-19 12:11:16 +020018055 } else if (!err) {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018056 printk(KERN_INFO
18057 "hda_codec: Cannot set up configuration "
18058 "from BIOS. Using base mode...\n");
18059 board_config = ALC662_3ST_2ch_DIG;
18060 }
18061 }
18062
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090018063 err = snd_hda_attach_beep_device(codec, 0x1);
18064 if (err < 0) {
18065 alc_free(codec);
18066 return err;
18067 }
18068
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018069 if (board_config != ALC662_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020018070 setup_preset(codec, &alc662_presets[board_config]);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018071
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018072 spec->stream_analog_playback = &alc662_pcm_analog_playback;
18073 spec->stream_analog_capture = &alc662_pcm_analog_capture;
18074
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018075 spec->stream_digital_playback = &alc662_pcm_digital_playback;
18076 spec->stream_digital_capture = &alc662_pcm_digital_capture;
18077
Takashi Iwaidd704692009-08-11 08:45:11 +020018078 if (!spec->adc_nids) {
18079 spec->adc_nids = alc662_adc_nids;
18080 spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids);
18081 }
18082 if (!spec->capsrc_nids)
18083 spec->capsrc_nids = alc662_capsrc_nids;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018084
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018085 if (!spec->cap_mixer)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020018086 set_capture_mixer(codec);
Takashi Iwaib9591442009-03-16 15:25:00 +010018087 if (codec->vendor_id == 0x10ec0662)
18088 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
18089 else
18090 set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018091
Takashi Iwai2134ea42008-01-10 16:53:55 +010018092 spec->vmaster_nid = 0x02;
18093
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018094 codec->patch_ops = alc_patch_ops;
18095 if (board_config == ALC662_AUTO)
18096 spec->init_hook = alc662_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020018097#ifdef CONFIG_SND_HDA_POWER_SAVE
18098 if (!spec->loopback.amplist)
18099 spec->loopback.amplist = alc662_loopbacks;
18100#endif
Takashi Iwaidaead532008-11-28 12:55:36 +010018101 codec->proc_widget_hook = print_realtek_coef;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018102
18103 return 0;
18104}
18105
Kailang Yang274693f2009-12-03 10:07:50 +010018106static int patch_alc888(struct hda_codec *codec)
18107{
18108 if ((alc_read_coef_idx(codec, 0) & 0x00f0)==0x0030){
18109 kfree(codec->chip_name);
18110 codec->chip_name = kstrdup("ALC888-VD", GFP_KERNEL);
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010018111 if (!codec->chip_name) {
18112 alc_free(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010018113 return -ENOMEM;
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010018114 }
18115 return patch_alc662(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010018116 }
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010018117 return patch_alc882(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010018118}
18119
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018120/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070018121 * patch entries
18122 */
Takashi Iwai1289e9e2008-11-27 15:47:11 +010018123static struct hda_codec_preset snd_hda_preset_realtek[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070018124 { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
Kailang Yangdf694da2005-12-05 19:42:22 +010018125 { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
Kailang Yangf6a92242007-12-13 16:52:54 +010018126 { .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 },
Kailang Yanga361d842007-06-05 12:30:55 +020018127 { .id = 0x10ec0268, .name = "ALC268", .patch = patch_alc268 },
Kailang Yangf6a92242007-12-13 16:52:54 +010018128 { .id = 0x10ec0269, .name = "ALC269", .patch = patch_alc269 },
Kailang Yangebb83ee2009-12-17 12:23:00 +010018129 { .id = 0x10ec0270, .name = "ALC270", .patch = patch_alc269 },
Kailang Yang01afd412008-10-15 11:22:09 +020018130 { .id = 0x10ec0272, .name = "ALC272", .patch = patch_alc662 },
Kailang Yangebb83ee2009-12-17 12:23:00 +010018131 { .id = 0x10ec0275, .name = "ALC275", .patch = patch_alc269 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010018132 { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018133 .patch = patch_alc861 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010018134 { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
18135 { .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 },
18136 { .id = 0x10ec0862, .name = "ALC861-VD", .patch = patch_alc861vd },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018137 { .id = 0x10ec0662, .rev = 0x100002, .name = "ALC662 rev2",
Takashi Iwai4953550a2009-06-30 15:28:30 +020018138 .patch = patch_alc882 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018139 { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1",
18140 .patch = patch_alc662 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018141 { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010018142 { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070018143 { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
Takashi Iwai4953550a2009-06-30 15:28:30 +020018144 { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc882 },
Clive Messer669faba2008-09-30 15:49:13 +020018145 { .id = 0x10ec0885, .rev = 0x100101, .name = "ALC889A",
Takashi Iwai4953550a2009-06-30 15:28:30 +020018146 .patch = patch_alc882 },
Takashi Iwaicb308f92008-04-16 14:13:29 +020018147 { .id = 0x10ec0885, .rev = 0x100103, .name = "ALC889A",
Takashi Iwai4953550a2009-06-30 15:28:30 +020018148 .patch = patch_alc882 },
Kailang Yangdf694da2005-12-05 19:42:22 +010018149 { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
Takashi Iwai4953550a2009-06-30 15:28:30 +020018150 { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc882 },
Kailang Yang44426082008-10-15 11:18:05 +020018151 { .id = 0x10ec0888, .rev = 0x100101, .name = "ALC1200",
Takashi Iwai4953550a2009-06-30 15:28:30 +020018152 .patch = patch_alc882 },
Kailang Yang274693f2009-12-03 10:07:50 +010018153 { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc888 },
Takashi Iwai4953550a2009-06-30 15:28:30 +020018154 { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc882 },
Kailang Yang274693f2009-12-03 10:07:50 +010018155 { .id = 0x10ec0892, .name = "ALC892", .patch = patch_alc662 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070018156 {} /* terminator */
18157};
Takashi Iwai1289e9e2008-11-27 15:47:11 +010018158
18159MODULE_ALIAS("snd-hda-codec-id:10ec*");
18160
18161MODULE_LICENSE("GPL");
18162MODULE_DESCRIPTION("Realtek HD-audio codec");
18163
18164static struct hda_codec_preset_list realtek_list = {
18165 .preset = snd_hda_preset_realtek,
18166 .owner = THIS_MODULE,
18167};
18168
18169static int __init patch_realtek_init(void)
18170{
18171 return snd_hda_add_codec_preset(&realtek_list);
18172}
18173
18174static void __exit patch_realtek_exit(void)
18175{
18176 snd_hda_delete_codec_preset(&realtek_list);
18177}
18178
18179module_init(patch_realtek_init)
18180module_exit(patch_realtek_exit)