blob: ab6b9fa203d0a37bed29ab460c45b111b4f626f9 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Universal Interface for Intel High Definition Audio Codec
3 *
Takashi Iwai1d045db2011-07-07 18:23:21 +02004 * HD audio interface patch for Realtek ALC codecs
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 *
Kailang Yangdf694da2005-12-05 19:42:22 +01006 * Copyright (c) 2004 Kailang Yang <kailang@realtek.com.tw>
7 * PeiSen Hou <pshou@realtek.com.tw>
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 * Takashi Iwai <tiwai@suse.de>
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01009 * Jonathan Woithe <jwoithe@physics.adelaide.edu.au>
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 *
11 * This driver is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This driver is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <linux/init.h>
27#include <linux/delay.h>
28#include <linux/slab.h>
29#include <linux/pci.h>
30#include <sound/core.h>
Kailang Yang9ad0e492010-09-14 23:22:00 +020031#include <sound/jack.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include "hda_codec.h"
33#include "hda_local.h"
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090034#include "hda_beep.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070035
Takashi Iwai1d045db2011-07-07 18:23:21 +020036/* unsol event tags */
37#define ALC_FRONT_EVENT 0x01
38#define ALC_DCVOL_EVENT 0x02
39#define ALC_HP_EVENT 0x04
40#define ALC_MIC_EVENT 0x08
Takashi Iwaid4a86d82010-06-23 17:51:26 +020041
Kailang Yangdf694da2005-12-05 19:42:22 +010042/* for GPIO Poll */
43#define GPIO_MASK 0x03
44
Takashi Iwai4a79ba32009-04-22 16:31:35 +020045/* extra amp-initialization sequence types */
46enum {
47 ALC_INIT_NONE,
48 ALC_INIT_DEFAULT,
49 ALC_INIT_GPIO1,
50 ALC_INIT_GPIO2,
51 ALC_INIT_GPIO3,
52};
53
Kailang Yangda00c242010-03-19 11:23:45 +010054struct alc_customize_define {
55 unsigned int sku_cfg;
56 unsigned char port_connectivity;
57 unsigned char check_sum;
58 unsigned char customization;
59 unsigned char external_amp;
60 unsigned int enable_pcbeep:1;
61 unsigned int platform_type:1;
62 unsigned int swap:1;
63 unsigned int override:1;
David Henningsson90622912010-10-14 14:50:18 +020064 unsigned int fixup:1; /* Means that this sku is set by driver, not read from hw */
Kailang Yangda00c242010-03-19 11:23:45 +010065};
66
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010067struct alc_fixup;
68
Takashi Iwaice764ab2011-04-27 16:35:23 +020069struct alc_multi_io {
70 hda_nid_t pin; /* multi-io widget pin NID */
71 hda_nid_t dac; /* DAC to be connected */
72 unsigned int ctl_in; /* cached input-pin control value */
73};
74
Takashi Iwaid922b512011-04-28 12:18:53 +020075enum {
Takashi Iwai3b8510c2011-04-28 14:03:24 +020076 ALC_AUTOMUTE_PIN, /* change the pin control */
77 ALC_AUTOMUTE_AMP, /* mute/unmute the pin AMP */
78 ALC_AUTOMUTE_MIXER, /* mute/unmute mixer widget AMP */
Takashi Iwaid922b512011-04-28 12:18:53 +020079};
80
Linus Torvalds1da177e2005-04-16 15:20:36 -070081struct alc_spec {
82 /* codec parameterization */
Takashi Iwaia9111322011-05-02 11:30:18 +020083 const struct snd_kcontrol_new *mixers[5]; /* mixer arrays */
Linus Torvalds1da177e2005-04-16 15:20:36 -070084 unsigned int num_mixers;
Takashi Iwaia9111322011-05-02 11:30:18 +020085 const struct snd_kcontrol_new *cap_mixer; /* capture mixer */
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010086 unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */
Linus Torvalds1da177e2005-04-16 15:20:36 -070087
Takashi Iwai2d9c6482009-10-13 08:06:55 +020088 const struct hda_verb *init_verbs[10]; /* initialization verbs
Takashi Iwai9c7f8522006-06-28 15:08:22 +020089 * don't forget NULL
90 * termination!
Takashi Iwaie9edcee2005-06-13 14:16:38 +020091 */
92 unsigned int num_init_verbs;
Linus Torvalds1da177e2005-04-16 15:20:36 -070093
Takashi Iwaiaa563af2009-07-31 10:05:11 +020094 char stream_name_analog[32]; /* analog PCM stream */
Takashi Iwaia9111322011-05-02 11:30:18 +020095 const struct hda_pcm_stream *stream_analog_playback;
96 const struct hda_pcm_stream *stream_analog_capture;
97 const struct hda_pcm_stream *stream_analog_alt_playback;
98 const struct hda_pcm_stream *stream_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -070099
Takashi Iwaiaa563af2009-07-31 10:05:11 +0200100 char stream_name_digital[32]; /* digital PCM stream */
Takashi Iwaia9111322011-05-02 11:30:18 +0200101 const struct hda_pcm_stream *stream_digital_playback;
102 const struct hda_pcm_stream *stream_digital_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103
104 /* playback */
Takashi Iwai16ded522005-06-10 19:58:24 +0200105 struct hda_multi_out multiout; /* playback set-up
106 * max_channels, dacs must be set
107 * dig_out_nid and hp_nid are optional
108 */
Takashi Iwai63300792008-01-24 15:31:36 +0100109 hda_nid_t alt_dac_nid;
Takashi Iwai6a05ac42009-02-13 11:19:09 +0100110 hda_nid_t slave_dig_outs[3]; /* optional - for auto-parsing */
Takashi Iwai8c441982009-01-20 18:30:20 +0100111 int dig_out_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112
113 /* capture */
114 unsigned int num_adc_nids;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +0200115 const hda_nid_t *adc_nids;
116 const hda_nid_t *capsrc_nids;
Takashi Iwai16ded522005-06-10 19:58:24 +0200117 hda_nid_t dig_in_nid; /* digital-in NID; optional */
Takashi Iwai1f0f4b82011-06-27 10:52:59 +0200118 hda_nid_t mixer_nid; /* analog-mixer NID */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119
Takashi Iwai840b64c2010-07-13 22:49:01 +0200120 /* capture setup for dynamic dual-adc switch */
Takashi Iwai840b64c2010-07-13 22:49:01 +0200121 hda_nid_t cur_adc;
122 unsigned int cur_adc_stream_tag;
123 unsigned int cur_adc_format;
124
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125 /* capture source */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200126 unsigned int num_mux_defs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127 const struct hda_input_mux *input_mux;
128 unsigned int cur_mux[3];
Takashi Iwai21268962011-07-07 15:01:13 +0200129 hda_nid_t ext_mic_pin;
130 hda_nid_t dock_mic_pin;
131 hda_nid_t int_mic_pin;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132
133 /* channel model */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100134 const struct hda_channel_mode *channel_mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135 int num_channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200136 int need_dac_fix;
Hector Martin3b315d72009-06-02 10:54:19 +0200137 int const_channel_count;
138 int ext_channel_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139
140 /* PCM information */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100141 struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */
Takashi Iwai41e41f12005-06-08 14:48:49 +0200142
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200143 /* dynamic controls, init_verbs and input_mux */
144 struct auto_pin_cfg autocfg;
Kailang Yangda00c242010-03-19 11:23:45 +0100145 struct alc_customize_define cdefine;
Takashi Iwai603c4012008-07-30 15:01:44 +0200146 struct snd_array kctls;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -0200147 struct hda_input_mux private_imux[3];
Takashi Iwai41923e42007-10-22 17:20:10 +0200148 hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
Takashi Iwai4953550a2009-06-30 15:28:30 +0200149 hda_nid_t private_adc_nids[AUTO_CFG_MAX_OUTS];
150 hda_nid_t private_capsrc_nids[AUTO_CFG_MAX_OUTS];
Takashi Iwai21268962011-07-07 15:01:13 +0200151 hda_nid_t imux_pins[HDA_MAX_NUM_INPUTS];
152 unsigned int dyn_adc_idx[HDA_MAX_NUM_INPUTS];
153 int int_mic_idx, ext_mic_idx, dock_mic_idx; /* for auto-mic */
Takashi Iwai834be882006-03-01 14:16:17 +0100154
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100155 /* hooks */
156 void (*init_hook)(struct hda_codec *codec);
157 void (*unsol_event)(struct hda_codec *codec, unsigned int res);
Hector Martinf5de24b2009-12-20 22:51:31 +0100158#ifdef CONFIG_SND_HDA_POWER_SAVE
Daniel T Chenc97259d2009-12-27 18:52:08 -0500159 void (*power_hook)(struct hda_codec *codec);
Hector Martinf5de24b2009-12-20 22:51:31 +0100160#endif
Takashi Iwai1c7161532011-04-07 10:37:16 +0200161 void (*shutup)(struct hda_codec *codec);
Takashi Iwai24519912011-08-16 15:08:49 +0200162 void (*automute_hook)(struct hda_codec *codec);
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100163
Takashi Iwai834be882006-03-01 14:16:17 +0100164 /* for pin sensing */
David Henningsson42cf0d02011-09-20 12:04:56 +0200165 unsigned int hp_jack_present:1;
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200166 unsigned int line_jack_present:1;
Takashi Iwaie9427962011-04-28 15:46:07 +0200167 unsigned int master_mute:1;
Takashi Iwai6c819492009-08-10 18:47:44 +0200168 unsigned int auto_mic:1;
Takashi Iwai21268962011-07-07 15:01:13 +0200169 unsigned int auto_mic_valid_imux:1; /* valid imux for auto-mic */
David Henningsson42cf0d02011-09-20 12:04:56 +0200170 unsigned int automute_speaker:1; /* automute speaker outputs */
171 unsigned int automute_lo:1; /* automute LO outputs */
172 unsigned int detect_hp:1; /* Headphone detection enabled */
173 unsigned int detect_lo:1; /* Line-out detection enabled */
174 unsigned int automute_speaker_possible:1; /* there are speakers and either LO or HP */
175 unsigned int automute_lo_possible:1; /* there are line outs and HP */
Takashi Iwaicb53c622007-08-10 17:21:45 +0200176
Takashi Iwaie64f14f2009-01-20 18:32:55 +0100177 /* other flags */
178 unsigned int no_analog :1; /* digital I/O only */
Takashi Iwai21268962011-07-07 15:01:13 +0200179 unsigned int dyn_adc_switch:1; /* switch ADCs (for ALC275) */
Takashi Iwai584c0c42011-03-10 12:51:11 +0100180 unsigned int single_input_src:1;
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +0200181 unsigned int vol_in_capsrc:1; /* use capsrc volume (ADC has no vol) */
Takashi Iwai53c334a2011-08-23 18:27:14 +0200182 unsigned int parse_flags; /* passed to snd_hda_parse_pin_defcfg() */
Takashi Iwaid922b512011-04-28 12:18:53 +0200183
184 /* auto-mute control */
185 int automute_mode;
Takashi Iwai3b8510c2011-04-28 14:03:24 +0200186 hda_nid_t automute_mixer_nid[AUTO_CFG_MAX_OUTS];
Takashi Iwaid922b512011-04-28 12:18:53 +0200187
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200188 int init_amp;
Takashi Iwaid433a672010-09-20 15:11:54 +0200189 int codec_variant; /* flag for other variants */
Takashi Iwaie64f14f2009-01-20 18:32:55 +0100190
Takashi Iwai2134ea42008-01-10 16:53:55 +0100191 /* for virtual master */
192 hda_nid_t vmaster_nid;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200193#ifdef CONFIG_SND_HDA_POWER_SAVE
194 struct hda_loopback_check loopback;
195#endif
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +0200196
197 /* for PLL fix */
198 hda_nid_t pll_nid;
199 unsigned int pll_coef_idx, pll_coef_bit;
Takashi Iwaib5bfbc62011-01-13 14:22:32 +0100200
201 /* fix-up list */
202 int fixup_id;
203 const struct alc_fixup *fixup_list;
204 const char *fixup_name;
Takashi Iwaice764ab2011-04-27 16:35:23 +0200205
206 /* multi-io */
207 int multi_ios;
208 struct alc_multi_io multi_io[4];
Takashi Iwai23c09b02011-08-19 09:05:35 +0200209
210 /* bind volumes */
211 struct snd_array bind_ctls;
Kailang Yangdf694da2005-12-05 19:42:22 +0100212};
213
Takashi Iwai1d045db2011-07-07 18:23:21 +0200214#define ALC_MODEL_AUTO 0 /* common for all chips */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215
Takashi Iwai44c02402011-07-08 15:14:19 +0200216static bool check_amp_caps(struct hda_codec *codec, hda_nid_t nid,
217 int dir, unsigned int bits)
218{
219 if (!nid)
220 return false;
221 if (get_wcaps(codec, nid) & (1 << (dir + 1)))
222 if (query_amp_caps(codec, nid, dir) & bits)
223 return true;
224 return false;
225}
226
227#define nid_has_mute(codec, nid, dir) \
228 check_amp_caps(codec, nid, dir, AC_AMPCAP_MUTE)
229#define nid_has_volume(codec, nid, dir) \
230 check_amp_caps(codec, nid, dir, AC_AMPCAP_NUM_STEPS)
231
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232/*
233 * input MUX handling
234 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200235static int alc_mux_enum_info(struct snd_kcontrol *kcontrol,
236 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237{
238 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
239 struct alc_spec *spec = codec->spec;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200240 unsigned int mux_idx = snd_ctl_get_ioffidx(kcontrol, &uinfo->id);
241 if (mux_idx >= spec->num_mux_defs)
242 mux_idx = 0;
Takashi Iwai53111142010-03-08 12:13:07 +0100243 if (!spec->input_mux[mux_idx].num_items && mux_idx > 0)
244 mux_idx = 0;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200245 return snd_hda_input_mux_info(&spec->input_mux[mux_idx], uinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246}
247
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200248static int alc_mux_enum_get(struct snd_kcontrol *kcontrol,
249 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250{
251 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
252 struct alc_spec *spec = codec->spec;
253 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
254
255 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
256 return 0;
257}
258
Takashi Iwai21268962011-07-07 15:01:13 +0200259static bool alc_dyn_adc_pcm_resetup(struct hda_codec *codec, int cur)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260{
Takashi Iwai21268962011-07-07 15:01:13 +0200261 struct alc_spec *spec = codec->spec;
262 hda_nid_t new_adc = spec->adc_nids[spec->dyn_adc_idx[cur]];
263
264 if (spec->cur_adc && spec->cur_adc != new_adc) {
265 /* stream is running, let's swap the current ADC */
266 __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1);
267 spec->cur_adc = new_adc;
268 snd_hda_codec_setup_stream(codec, new_adc,
269 spec->cur_adc_stream_tag, 0,
270 spec->cur_adc_format);
271 return true;
272 }
273 return false;
274}
275
276/* select the given imux item; either unmute exclusively or select the route */
277static int alc_mux_select(struct hda_codec *codec, unsigned int adc_idx,
278 unsigned int idx, bool force)
279{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 struct alc_spec *spec = codec->spec;
Takashi Iwaicd896c32008-11-18 12:36:33 +0100281 const struct hda_input_mux *imux;
Takashi Iwaicd896c32008-11-18 12:36:33 +0100282 unsigned int mux_idx;
Takashi Iwai21268962011-07-07 15:01:13 +0200283 int i, type;
284 hda_nid_t nid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285
Takashi Iwaicd896c32008-11-18 12:36:33 +0100286 mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx;
287 imux = &spec->input_mux[mux_idx];
Takashi Iwai53111142010-03-08 12:13:07 +0100288 if (!imux->num_items && mux_idx > 0)
289 imux = &spec->input_mux[0];
Takashi Iwaicd896c32008-11-18 12:36:33 +0100290
Takashi Iwai21268962011-07-07 15:01:13 +0200291 if (idx >= imux->num_items)
292 idx = imux->num_items - 1;
293 if (spec->cur_mux[adc_idx] == idx && !force)
294 return 0;
295 spec->cur_mux[adc_idx] = idx;
296
297 if (spec->dyn_adc_switch) {
298 alc_dyn_adc_pcm_resetup(codec, idx);
299 adc_idx = spec->dyn_adc_idx[idx];
300 }
301
302 nid = spec->capsrc_nids ?
303 spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx];
304
305 /* no selection? */
306 if (snd_hda_get_conn_list(codec, nid, NULL) <= 1)
307 return 1;
308
Takashi Iwaia22d5432009-07-27 12:54:26 +0200309 type = get_wcaps_type(get_wcaps(codec, nid));
Takashi Iwai0169b6b2009-06-22 10:50:19 +0200310 if (type == AC_WID_AUD_MIX) {
Takashi Iwai54cbc9a2008-10-31 15:24:04 +0100311 /* Matrix-mixer style (e.g. ALC882) */
Takashi Iwai54cbc9a2008-10-31 15:24:04 +0100312 for (i = 0; i < imux->num_items; i++) {
313 unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE;
314 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT,
315 imux->items[i].index,
316 HDA_AMP_MUTE, v);
317 }
Takashi Iwai54cbc9a2008-10-31 15:24:04 +0100318 } else {
319 /* MUX style (e.g. ALC880) */
Takashi Iwai21268962011-07-07 15:01:13 +0200320 snd_hda_codec_write_cache(codec, nid, 0,
321 AC_VERB_SET_CONNECT_SEL,
322 imux->items[idx].index);
Takashi Iwai54cbc9a2008-10-31 15:24:04 +0100323 }
Takashi Iwai21268962011-07-07 15:01:13 +0200324 return 1;
325}
326
327static int alc_mux_enum_put(struct snd_kcontrol *kcontrol,
328 struct snd_ctl_elem_value *ucontrol)
329{
330 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
331 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
332 return alc_mux_select(codec, adc_idx,
333 ucontrol->value.enumerated.item[0], false);
Takashi Iwai54cbc9a2008-10-31 15:24:04 +0100334}
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200335
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336/*
Takashi Iwai23f0c042009-02-26 13:03:58 +0100337 * set up the input pin config (depending on the given auto-pin type)
338 */
339static void alc_set_input_pin(struct hda_codec *codec, hda_nid_t nid,
340 int auto_pin_type)
341{
342 unsigned int val = PIN_IN;
343
Takashi Iwai86e29592010-09-09 14:50:17 +0200344 if (auto_pin_type == AUTO_PIN_MIC) {
Takashi Iwai23f0c042009-02-26 13:03:58 +0100345 unsigned int pincap;
Takashi Iwai954a29c2010-07-30 10:55:44 +0200346 unsigned int oldval;
347 oldval = snd_hda_codec_read(codec, nid, 0,
348 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
Takashi Iwai1327a322009-03-23 13:07:47 +0100349 pincap = snd_hda_query_pin_caps(codec, nid);
Takashi Iwai23f0c042009-02-26 13:03:58 +0100350 pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
Takashi Iwai954a29c2010-07-30 10:55:44 +0200351 /* if the default pin setup is vref50, we give it priority */
352 if ((pincap & AC_PINCAP_VREF_80) && oldval != PIN_VREF50)
Takashi Iwai23f0c042009-02-26 13:03:58 +0100353 val = PIN_VREF80;
Takashi Iwai461c6c32009-05-25 08:06:02 +0200354 else if (pincap & AC_PINCAP_VREF_50)
355 val = PIN_VREF50;
356 else if (pincap & AC_PINCAP_VREF_100)
357 val = PIN_VREF100;
358 else if (pincap & AC_PINCAP_VREF_GRD)
359 val = PIN_VREFGRD;
Takashi Iwai23f0c042009-02-26 13:03:58 +0100360 }
361 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, val);
362}
363
364/*
Takashi Iwai1d045db2011-07-07 18:23:21 +0200365 * Append the given mixer and verb elements for the later use
366 * The mixer array is referred in build_controls(), and init_verbs are
367 * called in init().
Takashi Iwaid88897e2008-10-31 15:01:37 +0100368 */
Takashi Iwaia9111322011-05-02 11:30:18 +0200369static void add_mixer(struct alc_spec *spec, const struct snd_kcontrol_new *mix)
Takashi Iwaid88897e2008-10-31 15:01:37 +0100370{
371 if (snd_BUG_ON(spec->num_mixers >= ARRAY_SIZE(spec->mixers)))
372 return;
373 spec->mixers[spec->num_mixers++] = mix;
374}
375
376static void add_verb(struct alc_spec *spec, const struct hda_verb *verb)
377{
378 if (snd_BUG_ON(spec->num_init_verbs >= ARRAY_SIZE(spec->init_verbs)))
379 return;
380 spec->init_verbs[spec->num_init_verbs++] = verb;
381}
382
383/*
Takashi Iwai1d045db2011-07-07 18:23:21 +0200384 * GPIO setup tables, used in initialization
Kailang Yangdf694da2005-12-05 19:42:22 +0100385 */
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200386/* Enable GPIO mask and set output */
Takashi Iwaia9111322011-05-02 11:30:18 +0200387static const struct hda_verb alc_gpio1_init_verbs[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200388 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
389 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
390 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
391 { }
392};
393
Takashi Iwaia9111322011-05-02 11:30:18 +0200394static const struct hda_verb alc_gpio2_init_verbs[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200395 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
396 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
397 {0x01, AC_VERB_SET_GPIO_DATA, 0x02},
398 { }
399};
400
Takashi Iwaia9111322011-05-02 11:30:18 +0200401static const struct hda_verb alc_gpio3_init_verbs[] = {
Kailang Yangbdd148a2007-05-08 15:19:08 +0200402 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
403 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
404 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
405 { }
406};
407
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +0200408/*
409 * Fix hardware PLL issue
410 * On some codecs, the analog PLL gating control must be off while
411 * the default value is 1.
412 */
413static void alc_fix_pll(struct hda_codec *codec)
414{
415 struct alc_spec *spec = codec->spec;
416 unsigned int val;
417
418 if (!spec->pll_nid)
419 return;
420 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
421 spec->pll_coef_idx);
422 val = snd_hda_codec_read(codec, spec->pll_nid, 0,
423 AC_VERB_GET_PROC_COEF, 0);
424 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
425 spec->pll_coef_idx);
426 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_PROC_COEF,
427 val & ~(1 << spec->pll_coef_bit));
428}
429
430static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
431 unsigned int coef_idx, unsigned int coef_bit)
432{
433 struct alc_spec *spec = codec->spec;
434 spec->pll_nid = nid;
435 spec->pll_coef_idx = coef_idx;
436 spec->pll_coef_bit = coef_bit;
437 alc_fix_pll(codec);
438}
439
Takashi Iwai1d045db2011-07-07 18:23:21 +0200440/*
441 * Jack-reporting via input-jack layer
442 */
443
444/* initialization of jacks; currently checks only a few known pins */
Kailang Yang9ad0e492010-09-14 23:22:00 +0200445static int alc_init_jacks(struct hda_codec *codec)
446{
Takashi Iwaicd372fb2011-03-03 14:40:14 +0100447#ifdef CONFIG_SND_HDA_INPUT_JACK
Kailang Yang9ad0e492010-09-14 23:22:00 +0200448 struct alc_spec *spec = codec->spec;
449 int err;
450 unsigned int hp_nid = spec->autocfg.hp_pins[0];
Takashi Iwai21268962011-07-07 15:01:13 +0200451 unsigned int mic_nid = spec->ext_mic_pin;
452 unsigned int dock_nid = spec->dock_mic_pin;
Kailang Yang9ad0e492010-09-14 23:22:00 +0200453
Takashi Iwai265a0242010-09-21 11:26:21 +0200454 if (hp_nid) {
Takashi Iwaicd372fb2011-03-03 14:40:14 +0100455 err = snd_hda_input_jack_add(codec, hp_nid,
456 SND_JACK_HEADPHONE, NULL);
Takashi Iwai265a0242010-09-21 11:26:21 +0200457 if (err < 0)
458 return err;
Takashi Iwaicd372fb2011-03-03 14:40:14 +0100459 snd_hda_input_jack_report(codec, hp_nid);
Takashi Iwai265a0242010-09-21 11:26:21 +0200460 }
Kailang Yang9ad0e492010-09-14 23:22:00 +0200461
Takashi Iwai265a0242010-09-21 11:26:21 +0200462 if (mic_nid) {
Takashi Iwaicd372fb2011-03-03 14:40:14 +0100463 err = snd_hda_input_jack_add(codec, mic_nid,
464 SND_JACK_MICROPHONE, NULL);
Takashi Iwai265a0242010-09-21 11:26:21 +0200465 if (err < 0)
466 return err;
Takashi Iwaicd372fb2011-03-03 14:40:14 +0100467 snd_hda_input_jack_report(codec, mic_nid);
Takashi Iwai265a0242010-09-21 11:26:21 +0200468 }
Takashi Iwai8ed99d92011-05-17 12:05:02 +0200469 if (dock_nid) {
470 err = snd_hda_input_jack_add(codec, dock_nid,
471 SND_JACK_MICROPHONE, NULL);
472 if (err < 0)
473 return err;
474 snd_hda_input_jack_report(codec, dock_nid);
475 }
Takashi Iwaicd372fb2011-03-03 14:40:14 +0100476#endif /* CONFIG_SND_HDA_INPUT_JACK */
Kailang Yang9ad0e492010-09-14 23:22:00 +0200477 return 0;
478}
Kailang Yang9ad0e492010-09-14 23:22:00 +0200479
Takashi Iwai1d045db2011-07-07 18:23:21 +0200480/*
481 * Jack detections for HP auto-mute and mic-switch
482 */
483
484/* check each pin in the given array; returns true if any of them is plugged */
485static bool detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins)
Kailang Yangc9b58002007-10-16 14:30:01 +0200486{
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200487 int i, present = 0;
Kailang Yangc9b58002007-10-16 14:30:01 +0200488
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200489 for (i = 0; i < num_pins; i++) {
490 hda_nid_t nid = pins[i];
Takashi Iwaibb35feb2010-09-08 15:30:49 +0200491 if (!nid)
492 break;
Takashi Iwaicd372fb2011-03-03 14:40:14 +0100493 snd_hda_input_jack_report(codec, nid);
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200494 present |= snd_hda_jack_detect(codec, nid);
Takashi Iwaibb35feb2010-09-08 15:30:49 +0200495 }
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200496 return present;
497}
Takashi Iwaibb35feb2010-09-08 15:30:49 +0200498
Takashi Iwai1d045db2011-07-07 18:23:21 +0200499/* standard HP/line-out auto-mute helper */
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200500static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins,
Takashi Iwaie9427962011-04-28 15:46:07 +0200501 bool mute, bool hp_out)
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200502{
503 struct alc_spec *spec = codec->spec;
504 unsigned int mute_bits = mute ? HDA_AMP_MUTE : 0;
Takashi Iwaie9427962011-04-28 15:46:07 +0200505 unsigned int pin_bits = mute ? 0 : (hp_out ? PIN_HP : PIN_OUT);
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200506 int i;
507
508 for (i = 0; i < num_pins; i++) {
509 hda_nid_t nid = pins[i];
Takashi Iwaia9fd4f32009-05-08 15:57:59 +0200510 if (!nid)
511 break;
Takashi Iwai3b8510c2011-04-28 14:03:24 +0200512 switch (spec->automute_mode) {
513 case ALC_AUTOMUTE_PIN:
Takashi Iwaibb35feb2010-09-08 15:30:49 +0200514 snd_hda_codec_write(codec, nid, 0,
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200515 AC_VERB_SET_PIN_WIDGET_CONTROL,
516 pin_bits);
Takashi Iwai3b8510c2011-04-28 14:03:24 +0200517 break;
518 case ALC_AUTOMUTE_AMP:
Takashi Iwaibb35feb2010-09-08 15:30:49 +0200519 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200520 HDA_AMP_MUTE, mute_bits);
Takashi Iwai3b8510c2011-04-28 14:03:24 +0200521 break;
522 case ALC_AUTOMUTE_MIXER:
523 nid = spec->automute_mixer_nid[i];
524 if (!nid)
525 break;
526 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200527 HDA_AMP_MUTE, mute_bits);
Takashi Iwai3b8510c2011-04-28 14:03:24 +0200528 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 1,
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200529 HDA_AMP_MUTE, mute_bits);
Takashi Iwai3b8510c2011-04-28 14:03:24 +0200530 break;
Takashi Iwaibb35feb2010-09-08 15:30:49 +0200531 }
Takashi Iwaia9fd4f32009-05-08 15:57:59 +0200532 }
Kailang Yangc9b58002007-10-16 14:30:01 +0200533}
534
David Henningsson42cf0d02011-09-20 12:04:56 +0200535/* Toggle outputs muting */
536static void update_outputs(struct hda_codec *codec)
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200537{
538 struct alc_spec *spec = codec->spec;
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200539 int on;
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200540
Takashi Iwaic0a20262011-06-10 15:28:15 +0200541 /* Control HP pins/amps depending on master_mute state;
542 * in general, HP pins/amps control should be enabled in all cases,
543 * but currently set only for master_mute, just to be safe
544 */
545 do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins),
546 spec->autocfg.hp_pins, spec->master_mute, true);
547
David Henningsson42cf0d02011-09-20 12:04:56 +0200548 if (!spec->automute_speaker)
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200549 on = 0;
550 else
David Henningsson42cf0d02011-09-20 12:04:56 +0200551 on = spec->hp_jack_present | spec->line_jack_present;
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200552 on |= spec->master_mute;
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200553 do_automute(codec, ARRAY_SIZE(spec->autocfg.speaker_pins),
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200554 spec->autocfg.speaker_pins, on, false);
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200555
556 /* toggle line-out mutes if needed, too */
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200557 /* if LO is a copy of either HP or Speaker, don't need to handle it */
558 if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0] ||
559 spec->autocfg.line_out_pins[0] == spec->autocfg.speaker_pins[0])
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200560 return;
David Henningsson42cf0d02011-09-20 12:04:56 +0200561 if (!spec->automute_lo)
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200562 on = 0;
563 else
David Henningsson42cf0d02011-09-20 12:04:56 +0200564 on = spec->hp_jack_present;
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200565 on |= spec->master_mute;
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200566 do_automute(codec, ARRAY_SIZE(spec->autocfg.line_out_pins),
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200567 spec->autocfg.line_out_pins, on, false);
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200568}
569
David Henningsson42cf0d02011-09-20 12:04:56 +0200570static void call_update_outputs(struct hda_codec *codec)
Takashi Iwai24519912011-08-16 15:08:49 +0200571{
572 struct alc_spec *spec = codec->spec;
573 if (spec->automute_hook)
574 spec->automute_hook(codec);
575 else
David Henningsson42cf0d02011-09-20 12:04:56 +0200576 update_outputs(codec);
Takashi Iwai24519912011-08-16 15:08:49 +0200577}
578
Takashi Iwai1d045db2011-07-07 18:23:21 +0200579/* standard HP-automute helper */
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200580static void alc_hp_automute(struct hda_codec *codec)
581{
582 struct alc_spec *spec = codec->spec;
583
David Henningsson42cf0d02011-09-20 12:04:56 +0200584 spec->hp_jack_present =
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200585 detect_jacks(codec, ARRAY_SIZE(spec->autocfg.hp_pins),
586 spec->autocfg.hp_pins);
David Henningsson42cf0d02011-09-20 12:04:56 +0200587 if (!spec->detect_hp || (!spec->automute_speaker && !spec->automute_lo))
Takashi Iwai3c715a92011-08-23 12:41:09 +0200588 return;
David Henningsson42cf0d02011-09-20 12:04:56 +0200589 call_update_outputs(codec);
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200590}
591
Takashi Iwai1d045db2011-07-07 18:23:21 +0200592/* standard line-out-automute helper */
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200593static void alc_line_automute(struct hda_codec *codec)
594{
595 struct alc_spec *spec = codec->spec;
596
Takashi Iwaie0d32e32011-09-26 15:19:55 +0200597 /* check LO jack only when it's different from HP */
598 if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0])
599 return;
600
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200601 spec->line_jack_present =
602 detect_jacks(codec, ARRAY_SIZE(spec->autocfg.line_out_pins),
603 spec->autocfg.line_out_pins);
David Henningsson42cf0d02011-09-20 12:04:56 +0200604 if (!spec->automute_speaker || !spec->detect_lo)
Takashi Iwai3c715a92011-08-23 12:41:09 +0200605 return;
David Henningsson42cf0d02011-09-20 12:04:56 +0200606 call_update_outputs(codec);
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200607}
608
Takashi Iwai8d087c72011-06-28 12:45:47 +0200609#define get_connection_index(codec, mux, nid) \
610 snd_hda_get_conn_index(codec, mux, nid, 0)
Takashi Iwai6c819492009-08-10 18:47:44 +0200611
Takashi Iwai1d045db2011-07-07 18:23:21 +0200612/* standard mic auto-switch helper */
Kailang Yang7fb0d782008-10-15 11:12:35 +0200613static void alc_mic_automute(struct hda_codec *codec)
614{
615 struct alc_spec *spec = codec->spec;
Takashi Iwai21268962011-07-07 15:01:13 +0200616 hda_nid_t *pins = spec->imux_pins;
Kailang Yang7fb0d782008-10-15 11:12:35 +0200617
Takashi Iwai21268962011-07-07 15:01:13 +0200618 if (!spec->auto_mic || !spec->auto_mic_valid_imux)
Takashi Iwai6c819492009-08-10 18:47:44 +0200619 return;
620 if (snd_BUG_ON(!spec->adc_nids))
621 return;
Takashi Iwai21268962011-07-07 15:01:13 +0200622 if (snd_BUG_ON(spec->int_mic_idx < 0 || spec->ext_mic_idx < 0))
Takashi Iwai840b64c2010-07-13 22:49:01 +0200623 return;
Takashi Iwai840b64c2010-07-13 22:49:01 +0200624
Takashi Iwai21268962011-07-07 15:01:13 +0200625 if (snd_hda_jack_detect(codec, pins[spec->ext_mic_idx]))
626 alc_mux_select(codec, 0, spec->ext_mic_idx, false);
627 else if (spec->dock_mic_idx >= 0 &&
628 snd_hda_jack_detect(codec, pins[spec->dock_mic_idx]))
629 alc_mux_select(codec, 0, spec->dock_mic_idx, false);
630 else
631 alc_mux_select(codec, 0, spec->int_mic_idx, false);
Takashi Iwai6c819492009-08-10 18:47:44 +0200632
Takashi Iwai21268962011-07-07 15:01:13 +0200633 snd_hda_input_jack_report(codec, pins[spec->ext_mic_idx]);
634 if (spec->dock_mic_idx >= 0)
635 snd_hda_input_jack_report(codec, pins[spec->dock_mic_idx]);
Kailang Yang7fb0d782008-10-15 11:12:35 +0200636}
637
Kailang Yangc9b58002007-10-16 14:30:01 +0200638/* unsolicited event for HP jack sensing */
639static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res)
640{
641 if (codec->vendor_id == 0x10ec0880)
642 res >>= 28;
643 else
644 res >>= 26;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +0200645 switch (res) {
Takashi Iwai1d045db2011-07-07 18:23:21 +0200646 case ALC_HP_EVENT:
Takashi Iwaid922b512011-04-28 12:18:53 +0200647 alc_hp_automute(codec);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +0200648 break;
Takashi Iwai1d045db2011-07-07 18:23:21 +0200649 case ALC_FRONT_EVENT:
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200650 alc_line_automute(codec);
651 break;
Takashi Iwai1d045db2011-07-07 18:23:21 +0200652 case ALC_MIC_EVENT:
Kailang Yang7fb0d782008-10-15 11:12:35 +0200653 alc_mic_automute(codec);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +0200654 break;
655 }
Kailang Yang7fb0d782008-10-15 11:12:35 +0200656}
657
Takashi Iwai1d045db2011-07-07 18:23:21 +0200658/* call init functions of standard auto-mute helpers */
Kailang Yang7fb0d782008-10-15 11:12:35 +0200659static void alc_inithook(struct hda_codec *codec)
660{
Takashi Iwaid922b512011-04-28 12:18:53 +0200661 alc_hp_automute(codec);
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200662 alc_line_automute(codec);
Kailang Yang7fb0d782008-10-15 11:12:35 +0200663 alc_mic_automute(codec);
Kailang Yangc9b58002007-10-16 14:30:01 +0200664}
665
Kailang Yangf9423e72008-05-27 12:32:25 +0200666/* additional initialization for ALC888 variants */
667static void alc888_coef_init(struct hda_codec *codec)
668{
669 unsigned int tmp;
670
671 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0);
672 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
673 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
Takashi Iwai37db6232009-03-05 09:40:16 +0100674 if ((tmp & 0xf0) == 0x20)
Kailang Yangf9423e72008-05-27 12:32:25 +0200675 /* alc888S-VC */
676 snd_hda_codec_read(codec, 0x20, 0,
677 AC_VERB_SET_PROC_COEF, 0x830);
678 else
679 /* alc888-VB */
680 snd_hda_codec_read(codec, 0x20, 0,
681 AC_VERB_SET_PROC_COEF, 0x3030);
682}
683
Takashi Iwai1d045db2011-07-07 18:23:21 +0200684/* additional initialization for ALC889 variants */
Jaroslav Kysela87a8c372009-07-23 10:58:29 +0200685static void alc889_coef_init(struct hda_codec *codec)
686{
687 unsigned int tmp;
688
689 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
690 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
691 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
692 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF, tmp|0x2010);
693}
694
Takashi Iwai3fb4a502010-01-19 15:46:37 +0100695/* turn on/off EAPD control (only if available) */
696static void set_eapd(struct hda_codec *codec, hda_nid_t nid, int on)
697{
698 if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
699 return;
700 if (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)
701 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
702 on ? 2 : 0);
703}
704
Takashi Iwai691f1fc2011-04-07 10:31:43 +0200705/* turn on/off EAPD controls of the codec */
706static void alc_auto_setup_eapd(struct hda_codec *codec, bool on)
707{
708 /* We currently only handle front, HP */
Takashi Iwai39fa84e2011-06-27 15:28:57 +0200709 static hda_nid_t pins[] = {
710 0x0f, 0x10, 0x14, 0x15, 0
711 };
712 hda_nid_t *p;
713 for (p = pins; *p; p++)
714 set_eapd(codec, *p, on);
Takashi Iwai691f1fc2011-04-07 10:31:43 +0200715}
716
Takashi Iwai1c7161532011-04-07 10:37:16 +0200717/* generic shutup callback;
718 * just turning off EPAD and a little pause for avoiding pop-noise
719 */
720static void alc_eapd_shutup(struct hda_codec *codec)
721{
722 alc_auto_setup_eapd(codec, false);
723 msleep(200);
724}
725
Takashi Iwai1d045db2011-07-07 18:23:21 +0200726/* generic EAPD initialization */
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200727static void alc_auto_init_amp(struct hda_codec *codec, int type)
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200728{
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200729 unsigned int tmp;
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200730
Takashi Iwai39fa84e2011-06-27 15:28:57 +0200731 alc_auto_setup_eapd(codec, true);
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200732 switch (type) {
733 case ALC_INIT_GPIO1:
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200734 snd_hda_sequence_write(codec, alc_gpio1_init_verbs);
735 break;
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200736 case ALC_INIT_GPIO2:
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200737 snd_hda_sequence_write(codec, alc_gpio2_init_verbs);
738 break;
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200739 case ALC_INIT_GPIO3:
Kailang Yangbdd148a2007-05-08 15:19:08 +0200740 snd_hda_sequence_write(codec, alc_gpio3_init_verbs);
741 break;
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200742 case ALC_INIT_DEFAULT:
Kailang Yangc9b58002007-10-16 14:30:01 +0200743 switch (codec->vendor_id) {
744 case 0x10ec0260:
745 snd_hda_codec_write(codec, 0x1a, 0,
746 AC_VERB_SET_COEF_INDEX, 7);
747 tmp = snd_hda_codec_read(codec, 0x1a, 0,
748 AC_VERB_GET_PROC_COEF, 0);
749 snd_hda_codec_write(codec, 0x1a, 0,
750 AC_VERB_SET_COEF_INDEX, 7);
751 snd_hda_codec_write(codec, 0x1a, 0,
752 AC_VERB_SET_PROC_COEF,
753 tmp | 0x2010);
754 break;
755 case 0x10ec0262:
756 case 0x10ec0880:
757 case 0x10ec0882:
758 case 0x10ec0883:
759 case 0x10ec0885:
Takashi Iwai4a5a4c52009-02-06 12:46:59 +0100760 case 0x10ec0887:
Takashi Iwai20b67dd2011-03-23 22:54:32 +0100761 /*case 0x10ec0889:*/ /* this causes an SPDIF problem */
Jaroslav Kysela87a8c372009-07-23 10:58:29 +0200762 alc889_coef_init(codec);
Kailang Yangc9b58002007-10-16 14:30:01 +0200763 break;
Kailang Yangf9423e72008-05-27 12:32:25 +0200764 case 0x10ec0888:
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200765 alc888_coef_init(codec);
Kailang Yangf9423e72008-05-27 12:32:25 +0200766 break;
Takashi Iwai0aea7782010-01-25 15:44:11 +0100767#if 0 /* XXX: This may cause the silent output on speaker on some machines */
Kailang Yangc9b58002007-10-16 14:30:01 +0200768 case 0x10ec0267:
769 case 0x10ec0268:
770 snd_hda_codec_write(codec, 0x20, 0,
771 AC_VERB_SET_COEF_INDEX, 7);
772 tmp = snd_hda_codec_read(codec, 0x20, 0,
773 AC_VERB_GET_PROC_COEF, 0);
774 snd_hda_codec_write(codec, 0x20, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +0200775 AC_VERB_SET_COEF_INDEX, 7);
Kailang Yangc9b58002007-10-16 14:30:01 +0200776 snd_hda_codec_write(codec, 0x20, 0,
777 AC_VERB_SET_PROC_COEF,
778 tmp | 0x3000);
779 break;
Takashi Iwai0aea7782010-01-25 15:44:11 +0100780#endif /* XXX */
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200781 }
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200782 break;
783 }
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200784}
Kailang Yangea1fb292008-08-26 12:58:38 +0200785
Takashi Iwai1d045db2011-07-07 18:23:21 +0200786/*
787 * Auto-Mute mode mixer enum support
788 */
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200789static int alc_automute_mode_info(struct snd_kcontrol *kcontrol,
790 struct snd_ctl_elem_info *uinfo)
791{
Takashi Iwaiae8a60a2011-04-28 18:09:52 +0200792 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
793 struct alc_spec *spec = codec->spec;
794 static const char * const texts2[] = {
795 "Disabled", "Enabled"
796 };
797 static const char * const texts3[] = {
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200798 "Disabled", "Speaker Only", "Line-Out+Speaker"
799 };
Takashi Iwaiae8a60a2011-04-28 18:09:52 +0200800 const char * const *texts;
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200801
802 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
803 uinfo->count = 1;
David Henningsson42cf0d02011-09-20 12:04:56 +0200804 if (spec->automute_speaker_possible && spec->automute_lo_possible) {
Takashi Iwaiae8a60a2011-04-28 18:09:52 +0200805 uinfo->value.enumerated.items = 3;
806 texts = texts3;
807 } else {
808 uinfo->value.enumerated.items = 2;
809 texts = texts2;
810 }
811 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
812 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200813 strcpy(uinfo->value.enumerated.name,
814 texts[uinfo->value.enumerated.item]);
815 return 0;
816}
817
818static int alc_automute_mode_get(struct snd_kcontrol *kcontrol,
819 struct snd_ctl_elem_value *ucontrol)
820{
821 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
822 struct alc_spec *spec = codec->spec;
David Henningsson42cf0d02011-09-20 12:04:56 +0200823 unsigned int val = 0;
824 if (spec->automute_speaker)
825 val++;
826 if (spec->automute_lo)
827 val++;
828
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200829 ucontrol->value.enumerated.item[0] = val;
830 return 0;
831}
832
833static int alc_automute_mode_put(struct snd_kcontrol *kcontrol,
834 struct snd_ctl_elem_value *ucontrol)
835{
836 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
837 struct alc_spec *spec = codec->spec;
838
839 switch (ucontrol->value.enumerated.item[0]) {
840 case 0:
David Henningsson42cf0d02011-09-20 12:04:56 +0200841 if (!spec->automute_speaker && !spec->automute_lo)
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200842 return 0;
David Henningsson42cf0d02011-09-20 12:04:56 +0200843 spec->automute_speaker = 0;
844 spec->automute_lo = 0;
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200845 break;
846 case 1:
David Henningsson42cf0d02011-09-20 12:04:56 +0200847 if (spec->automute_speaker_possible) {
848 if (!spec->automute_lo && spec->automute_speaker)
849 return 0;
850 spec->automute_speaker = 1;
851 spec->automute_lo = 0;
852 } else if (spec->automute_lo_possible) {
853 if (spec->automute_lo)
854 return 0;
855 spec->automute_lo = 1;
856 } else
857 return -EINVAL;
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200858 break;
859 case 2:
David Henningsson42cf0d02011-09-20 12:04:56 +0200860 if (!spec->automute_lo_possible || !spec->automute_speaker_possible)
Takashi Iwaiae8a60a2011-04-28 18:09:52 +0200861 return -EINVAL;
David Henningsson42cf0d02011-09-20 12:04:56 +0200862 if (spec->automute_speaker && spec->automute_lo)
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200863 return 0;
David Henningsson42cf0d02011-09-20 12:04:56 +0200864 spec->automute_speaker = 1;
865 spec->automute_lo = 1;
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200866 break;
867 default:
868 return -EINVAL;
869 }
David Henningsson42cf0d02011-09-20 12:04:56 +0200870 call_update_outputs(codec);
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200871 return 1;
872}
873
Takashi Iwaia9111322011-05-02 11:30:18 +0200874static const struct snd_kcontrol_new alc_automute_mode_enum = {
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200875 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
876 .name = "Auto-Mute Mode",
877 .info = alc_automute_mode_info,
878 .get = alc_automute_mode_get,
879 .put = alc_automute_mode_put,
880};
881
Takashi Iwai1d045db2011-07-07 18:23:21 +0200882static struct snd_kcontrol_new *alc_kcontrol_new(struct alc_spec *spec)
883{
884 snd_array_init(&spec->kctls, sizeof(struct snd_kcontrol_new), 32);
885 return snd_array_new(&spec->kctls);
886}
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200887
888static int alc_add_automute_mode_enum(struct hda_codec *codec)
889{
890 struct alc_spec *spec = codec->spec;
891 struct snd_kcontrol_new *knew;
892
893 knew = alc_kcontrol_new(spec);
894 if (!knew)
895 return -ENOMEM;
896 *knew = alc_automute_mode_enum;
897 knew->name = kstrdup("Auto-Mute Mode", GFP_KERNEL);
898 if (!knew->name)
899 return -ENOMEM;
900 return 0;
901}
902
Takashi Iwai1d045db2011-07-07 18:23:21 +0200903/*
904 * Check the availability of HP/line-out auto-mute;
905 * Set up appropriately if really supported
906 */
David Henningsson42cf0d02011-09-20 12:04:56 +0200907static void alc_init_automute(struct hda_codec *codec)
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200908{
909 struct alc_spec *spec = codec->spec;
Takashi Iwaibb35feb2010-09-08 15:30:49 +0200910 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwai1daf5f42011-04-28 17:57:46 +0200911 int present = 0;
Takashi Iwaibb35feb2010-09-08 15:30:49 +0200912 int i;
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200913
Takashi Iwai1daf5f42011-04-28 17:57:46 +0200914 if (cfg->hp_pins[0])
915 present++;
916 if (cfg->line_out_pins[0])
917 present++;
918 if (cfg->speaker_pins[0])
919 present++;
920 if (present < 2) /* need two different output types */
921 return;
Kailang Yangc9b58002007-10-16 14:30:01 +0200922
Takashi Iwaic48a8fb2011-07-27 16:41:57 +0200923 if (!cfg->speaker_pins[0] &&
924 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
Takashi Iwaibb35feb2010-09-08 15:30:49 +0200925 memcpy(cfg->speaker_pins, cfg->line_out_pins,
926 sizeof(cfg->speaker_pins));
927 cfg->speaker_outs = cfg->line_outs;
928 }
929
Takashi Iwaic48a8fb2011-07-27 16:41:57 +0200930 if (!cfg->hp_pins[0] &&
931 cfg->line_out_type == AUTO_PIN_HP_OUT) {
Takashi Iwaibb35feb2010-09-08 15:30:49 +0200932 memcpy(cfg->hp_pins, cfg->line_out_pins,
933 sizeof(cfg->hp_pins));
934 cfg->hp_outs = cfg->line_outs;
935 }
936
David Henningsson42cf0d02011-09-20 12:04:56 +0200937 spec->automute_mode = ALC_AUTOMUTE_PIN;
938
Takashi Iwaibb35feb2010-09-08 15:30:49 +0200939 for (i = 0; i < cfg->hp_outs; i++) {
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200940 hda_nid_t nid = cfg->hp_pins[i];
Takashi Iwai06dec222011-05-17 10:00:16 +0200941 if (!is_jack_detectable(codec, nid))
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200942 continue;
Takashi Iwaibb35feb2010-09-08 15:30:49 +0200943 snd_printdd("realtek: Enable HP auto-muting on NID 0x%x\n",
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200944 nid);
945 snd_hda_codec_write_cache(codec, nid, 0,
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200946 AC_VERB_SET_UNSOLICITED_ENABLE,
Takashi Iwai1d045db2011-07-07 18:23:21 +0200947 AC_USRSP_EN | ALC_HP_EVENT);
David Henningsson42cf0d02011-09-20 12:04:56 +0200948 spec->detect_hp = 1;
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200949 }
Takashi Iwaiae8a60a2011-04-28 18:09:52 +0200950
David Henningsson42cf0d02011-09-20 12:04:56 +0200951 if (cfg->line_out_type == AUTO_PIN_LINE_OUT && cfg->line_outs) {
952 if (cfg->speaker_outs)
953 for (i = 0; i < cfg->line_outs; i++) {
954 hda_nid_t nid = cfg->line_out_pins[i];
955 if (!is_jack_detectable(codec, nid))
956 continue;
957 snd_printdd("realtek: Enable Line-Out "
958 "auto-muting on NID 0x%x\n", nid);
959 snd_hda_codec_write_cache(codec, nid, 0,
960 AC_VERB_SET_UNSOLICITED_ENABLE,
961 AC_USRSP_EN | ALC_FRONT_EVENT);
962 spec->detect_lo = 1;
963 }
964 spec->automute_lo_possible = spec->detect_hp;
965 }
966
967 spec->automute_speaker_possible = cfg->speaker_outs &&
968 (spec->detect_hp || spec->detect_lo);
969
970 spec->automute_lo = spec->automute_lo_possible;
971 spec->automute_speaker = spec->automute_speaker_possible;
972
973 if (spec->automute_speaker_possible || spec->automute_lo_possible) {
Takashi Iwaiae8a60a2011-04-28 18:09:52 +0200974 /* create a control for automute mode */
975 alc_add_automute_mode_enum(codec);
976 spec->unsol_event = alc_sku_unsol_event;
977 }
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200978}
979
Takashi Iwai1d045db2011-07-07 18:23:21 +0200980/* return the position of NID in the list, or -1 if not found */
Takashi Iwai21268962011-07-07 15:01:13 +0200981static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
982{
983 int i;
984 for (i = 0; i < nums; i++)
985 if (list[i] == nid)
986 return i;
987 return -1;
988}
989
Takashi Iwai1d045db2011-07-07 18:23:21 +0200990/* check whether dynamic ADC-switching is available */
991static bool alc_check_dyn_adc_switch(struct hda_codec *codec)
992{
993 struct alc_spec *spec = codec->spec;
994 struct hda_input_mux *imux = &spec->private_imux[0];
995 int i, n, idx;
996 hda_nid_t cap, pin;
997
998 if (imux != spec->input_mux) /* no dynamic imux? */
999 return false;
1000
1001 for (n = 0; n < spec->num_adc_nids; n++) {
1002 cap = spec->private_capsrc_nids[n];
1003 for (i = 0; i < imux->num_items; i++) {
1004 pin = spec->imux_pins[i];
1005 if (!pin)
1006 return false;
1007 if (get_connection_index(codec, cap, pin) < 0)
1008 break;
1009 }
1010 if (i >= imux->num_items)
Takashi Iwai268ff6f2011-07-08 14:37:35 +02001011 return true; /* no ADC-switch is needed */
Takashi Iwai1d045db2011-07-07 18:23:21 +02001012 }
1013
1014 for (i = 0; i < imux->num_items; i++) {
1015 pin = spec->imux_pins[i];
1016 for (n = 0; n < spec->num_adc_nids; n++) {
1017 cap = spec->private_capsrc_nids[n];
1018 idx = get_connection_index(codec, cap, pin);
1019 if (idx >= 0) {
1020 imux->items[i].index = idx;
1021 spec->dyn_adc_idx[i] = n;
1022 break;
1023 }
1024 }
1025 }
1026
1027 snd_printdd("realtek: enabling ADC switching\n");
1028 spec->dyn_adc_switch = 1;
1029 return true;
1030}
Takashi Iwai21268962011-07-07 15:01:13 +02001031
1032/* rebuild imux for matching with the given auto-mic pins (if not yet) */
1033static bool alc_rebuild_imux_for_auto_mic(struct hda_codec *codec)
1034{
1035 struct alc_spec *spec = codec->spec;
1036 struct hda_input_mux *imux;
1037 static char * const texts[3] = {
1038 "Mic", "Internal Mic", "Dock Mic"
1039 };
1040 int i;
1041
1042 if (!spec->auto_mic)
1043 return false;
1044 imux = &spec->private_imux[0];
1045 if (spec->input_mux == imux)
1046 return true;
1047 spec->imux_pins[0] = spec->ext_mic_pin;
1048 spec->imux_pins[1] = spec->int_mic_pin;
1049 spec->imux_pins[2] = spec->dock_mic_pin;
1050 for (i = 0; i < 3; i++) {
1051 strcpy(imux->items[i].label, texts[i]);
1052 if (spec->imux_pins[i])
1053 imux->num_items = i + 1;
1054 }
1055 spec->num_mux_defs = 1;
1056 spec->input_mux = imux;
1057 return true;
1058}
1059
1060/* check whether all auto-mic pins are valid; setup indices if OK */
1061static bool alc_auto_mic_check_imux(struct hda_codec *codec)
1062{
1063 struct alc_spec *spec = codec->spec;
1064 const struct hda_input_mux *imux;
1065
1066 if (!spec->auto_mic)
1067 return false;
1068 if (spec->auto_mic_valid_imux)
1069 return true; /* already checked */
1070
1071 /* fill up imux indices */
1072 if (!alc_check_dyn_adc_switch(codec)) {
1073 spec->auto_mic = 0;
1074 return false;
1075 }
1076
1077 imux = spec->input_mux;
1078 spec->ext_mic_idx = find_idx_in_nid_list(spec->ext_mic_pin,
1079 spec->imux_pins, imux->num_items);
1080 spec->int_mic_idx = find_idx_in_nid_list(spec->int_mic_pin,
1081 spec->imux_pins, imux->num_items);
1082 spec->dock_mic_idx = find_idx_in_nid_list(spec->dock_mic_pin,
1083 spec->imux_pins, imux->num_items);
1084 if (spec->ext_mic_idx < 0 || spec->int_mic_idx < 0) {
1085 spec->auto_mic = 0;
1086 return false; /* no corresponding imux */
1087 }
1088
1089 snd_hda_codec_write_cache(codec, spec->ext_mic_pin, 0,
1090 AC_VERB_SET_UNSOLICITED_ENABLE,
Takashi Iwai1d045db2011-07-07 18:23:21 +02001091 AC_USRSP_EN | ALC_MIC_EVENT);
Takashi Iwai21268962011-07-07 15:01:13 +02001092 if (spec->dock_mic_pin)
1093 snd_hda_codec_write_cache(codec, spec->dock_mic_pin, 0,
1094 AC_VERB_SET_UNSOLICITED_ENABLE,
Takashi Iwai1d045db2011-07-07 18:23:21 +02001095 AC_USRSP_EN | ALC_MIC_EVENT);
Takashi Iwai21268962011-07-07 15:01:13 +02001096
1097 spec->auto_mic_valid_imux = 1;
1098 spec->auto_mic = 1;
1099 return true;
1100}
1101
Takashi Iwai1d045db2011-07-07 18:23:21 +02001102/*
1103 * Check the availability of auto-mic switch;
1104 * Set up if really supported
1105 */
Takashi Iwai6c819492009-08-10 18:47:44 +02001106static void alc_init_auto_mic(struct hda_codec *codec)
1107{
1108 struct alc_spec *spec = codec->spec;
1109 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001110 hda_nid_t fixed, ext, dock;
Takashi Iwai6c819492009-08-10 18:47:44 +02001111 int i;
1112
Takashi Iwai21268962011-07-07 15:01:13 +02001113 spec->ext_mic_idx = spec->int_mic_idx = spec->dock_mic_idx = -1;
1114
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001115 fixed = ext = dock = 0;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02001116 for (i = 0; i < cfg->num_inputs; i++) {
1117 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai6c819492009-08-10 18:47:44 +02001118 unsigned int defcfg;
Takashi Iwai6c819492009-08-10 18:47:44 +02001119 defcfg = snd_hda_codec_get_pincfg(codec, nid);
Takashi Iwai99ae28b2010-09-17 14:42:34 +02001120 switch (snd_hda_get_input_pin_attr(defcfg)) {
1121 case INPUT_PIN_ATTR_INT:
Takashi Iwai6c819492009-08-10 18:47:44 +02001122 if (fixed)
1123 return; /* already occupied */
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001124 if (cfg->inputs[i].type != AUTO_PIN_MIC)
1125 return; /* invalid type */
Takashi Iwai6c819492009-08-10 18:47:44 +02001126 fixed = nid;
1127 break;
Takashi Iwai99ae28b2010-09-17 14:42:34 +02001128 case INPUT_PIN_ATTR_UNUSED:
1129 return; /* invalid entry */
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001130 case INPUT_PIN_ATTR_DOCK:
1131 if (dock)
1132 return; /* already occupied */
1133 if (cfg->inputs[i].type > AUTO_PIN_LINE_IN)
1134 return; /* invalid type */
1135 dock = nid;
1136 break;
Takashi Iwai99ae28b2010-09-17 14:42:34 +02001137 default:
Takashi Iwai6c819492009-08-10 18:47:44 +02001138 if (ext)
1139 return; /* already occupied */
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001140 if (cfg->inputs[i].type != AUTO_PIN_MIC)
1141 return; /* invalid type */
Takashi Iwai6c819492009-08-10 18:47:44 +02001142 ext = nid;
1143 break;
Takashi Iwai6c819492009-08-10 18:47:44 +02001144 }
1145 }
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001146 if (!ext && dock) {
1147 ext = dock;
1148 dock = 0;
1149 }
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01001150 if (!ext || !fixed)
1151 return;
Takashi Iwaie35d9d62011-05-17 11:28:16 +02001152 if (!is_jack_detectable(codec, ext))
Takashi Iwai6c819492009-08-10 18:47:44 +02001153 return; /* no unsol support */
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001154 if (dock && !is_jack_detectable(codec, dock))
1155 return; /* no unsol support */
Takashi Iwai21268962011-07-07 15:01:13 +02001156
1157 /* check imux indices */
1158 spec->ext_mic_pin = ext;
1159 spec->int_mic_pin = fixed;
1160 spec->dock_mic_pin = dock;
1161
1162 spec->auto_mic = 1;
1163 if (!alc_auto_mic_check_imux(codec))
1164 return;
1165
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001166 snd_printdd("realtek: Enable auto-mic switch on NID 0x%x/0x%x/0x%x\n",
1167 ext, fixed, dock);
Takashi Iwai6c819492009-08-10 18:47:44 +02001168 spec->unsol_event = alc_sku_unsol_event;
1169}
1170
Takashi Iwai1d045db2011-07-07 18:23:21 +02001171/* check the availabilities of auto-mute and auto-mic switches */
1172static void alc_auto_check_switches(struct hda_codec *codec)
1173{
David Henningsson42cf0d02011-09-20 12:04:56 +02001174 alc_init_automute(codec);
Takashi Iwai1d045db2011-07-07 18:23:21 +02001175 alc_init_auto_mic(codec);
1176}
1177
1178/*
1179 * Realtek SSID verification
1180 */
1181
David Henningsson90622912010-10-14 14:50:18 +02001182/* Could be any non-zero and even value. When used as fixup, tells
1183 * the driver to ignore any present sku defines.
1184 */
1185#define ALC_FIXUP_SKU_IGNORE (2)
1186
Kailang Yangda00c242010-03-19 11:23:45 +01001187static int alc_auto_parse_customize_define(struct hda_codec *codec)
1188{
1189 unsigned int ass, tmp, i;
Takashi Iwai7fb56222010-03-22 17:09:47 +01001190 unsigned nid = 0;
Kailang Yangda00c242010-03-19 11:23:45 +01001191 struct alc_spec *spec = codec->spec;
1192
Takashi Iwaib6cbe512010-07-28 17:43:36 +02001193 spec->cdefine.enable_pcbeep = 1; /* assume always enabled */
1194
David Henningsson90622912010-10-14 14:50:18 +02001195 if (spec->cdefine.fixup) {
1196 ass = spec->cdefine.sku_cfg;
1197 if (ass == ALC_FIXUP_SKU_IGNORE)
1198 return -1;
1199 goto do_sku;
1200 }
1201
Kailang Yangda00c242010-03-19 11:23:45 +01001202 ass = codec->subsystem_id & 0xffff;
Takashi Iwaib6cbe512010-07-28 17:43:36 +02001203 if (ass != codec->bus->pci->subsystem_device && (ass & 1))
Kailang Yangda00c242010-03-19 11:23:45 +01001204 goto do_sku;
1205
1206 nid = 0x1d;
1207 if (codec->vendor_id == 0x10ec0260)
1208 nid = 0x17;
1209 ass = snd_hda_codec_get_pincfg(codec, nid);
1210
1211 if (!(ass & 1)) {
1212 printk(KERN_INFO "hda_codec: %s: SKU not ready 0x%08x\n",
1213 codec->chip_name, ass);
1214 return -1;
1215 }
1216
1217 /* check sum */
1218 tmp = 0;
1219 for (i = 1; i < 16; i++) {
1220 if ((ass >> i) & 1)
1221 tmp++;
1222 }
1223 if (((ass >> 16) & 0xf) != tmp)
1224 return -1;
1225
1226 spec->cdefine.port_connectivity = ass >> 30;
1227 spec->cdefine.enable_pcbeep = (ass & 0x100000) >> 20;
1228 spec->cdefine.check_sum = (ass >> 16) & 0xf;
1229 spec->cdefine.customization = ass >> 8;
1230do_sku:
1231 spec->cdefine.sku_cfg = ass;
1232 spec->cdefine.external_amp = (ass & 0x38) >> 3;
1233 spec->cdefine.platform_type = (ass & 0x4) >> 2;
1234 spec->cdefine.swap = (ass & 0x2) >> 1;
1235 spec->cdefine.override = ass & 0x1;
1236
1237 snd_printd("SKU: Nid=0x%x sku_cfg=0x%08x\n",
1238 nid, spec->cdefine.sku_cfg);
1239 snd_printd("SKU: port_connectivity=0x%x\n",
1240 spec->cdefine.port_connectivity);
1241 snd_printd("SKU: enable_pcbeep=0x%x\n", spec->cdefine.enable_pcbeep);
1242 snd_printd("SKU: check_sum=0x%08x\n", spec->cdefine.check_sum);
1243 snd_printd("SKU: customization=0x%08x\n", spec->cdefine.customization);
1244 snd_printd("SKU: external_amp=0x%x\n", spec->cdefine.external_amp);
1245 snd_printd("SKU: platform_type=0x%x\n", spec->cdefine.platform_type);
1246 snd_printd("SKU: swap=0x%x\n", spec->cdefine.swap);
1247 snd_printd("SKU: override=0x%x\n", spec->cdefine.override);
1248
1249 return 0;
1250}
1251
Takashi Iwai1d045db2011-07-07 18:23:21 +02001252/* return true if the given NID is found in the list */
Takashi Iwai3af9ee62011-06-27 12:34:01 +02001253static bool found_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
1254{
Takashi Iwai21268962011-07-07 15:01:13 +02001255 return find_idx_in_nid_list(nid, list, nums) >= 0;
Takashi Iwai3af9ee62011-06-27 12:34:01 +02001256}
1257
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001258/* check subsystem ID and set up device-specific initialization;
1259 * return 1 if initialized, 0 if invalid SSID
1260 */
1261/* 32-bit subsystem ID for BIOS loading in HD Audio codec.
1262 * 31 ~ 16 : Manufacture ID
1263 * 15 ~ 8 : SKU ID
1264 * 7 ~ 0 : Assembly ID
1265 * port-A --> pin 39/41, port-E --> pin 14/15, port-D --> pin 35/36
1266 */
1267static int alc_subsystem_id(struct hda_codec *codec,
1268 hda_nid_t porta, hda_nid_t porte,
Kailang Yang6227cdc2010-02-25 08:36:52 +01001269 hda_nid_t portd, hda_nid_t porti)
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001270{
1271 unsigned int ass, tmp, i;
1272 unsigned nid;
1273 struct alc_spec *spec = codec->spec;
1274
David Henningsson90622912010-10-14 14:50:18 +02001275 if (spec->cdefine.fixup) {
1276 ass = spec->cdefine.sku_cfg;
1277 if (ass == ALC_FIXUP_SKU_IGNORE)
1278 return 0;
1279 goto do_sku;
1280 }
1281
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001282 ass = codec->subsystem_id & 0xffff;
1283 if ((ass != codec->bus->pci->subsystem_device) && (ass & 1))
1284 goto do_sku;
1285
1286 /* invalid SSID, check the special NID pin defcfg instead */
1287 /*
Sasha Alexandrdef319f2009-06-16 16:00:15 -04001288 * 31~30 : port connectivity
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001289 * 29~21 : reserve
1290 * 20 : PCBEEP input
1291 * 19~16 : Check sum (15:1)
1292 * 15~1 : Custom
1293 * 0 : override
1294 */
1295 nid = 0x1d;
1296 if (codec->vendor_id == 0x10ec0260)
1297 nid = 0x17;
1298 ass = snd_hda_codec_get_pincfg(codec, nid);
1299 snd_printd("realtek: No valid SSID, "
1300 "checking pincfg 0x%08x for NID 0x%x\n",
Takashi Iwaicb6605c2009-04-28 13:03:19 +02001301 ass, nid);
Kailang Yang6227cdc2010-02-25 08:36:52 +01001302 if (!(ass & 1))
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001303 return 0;
1304 if ((ass >> 30) != 1) /* no physical connection */
1305 return 0;
1306
1307 /* check sum */
1308 tmp = 0;
1309 for (i = 1; i < 16; i++) {
1310 if ((ass >> i) & 1)
1311 tmp++;
1312 }
1313 if (((ass >> 16) & 0xf) != tmp)
1314 return 0;
1315do_sku:
1316 snd_printd("realtek: Enabling init ASM_ID=0x%04x CODEC_ID=%08x\n",
1317 ass & 0xffff, codec->vendor_id);
1318 /*
1319 * 0 : override
1320 * 1 : Swap Jack
1321 * 2 : 0 --> Desktop, 1 --> Laptop
1322 * 3~5 : External Amplifier control
1323 * 7~6 : Reserved
1324 */
1325 tmp = (ass & 0x38) >> 3; /* external Amp control */
1326 switch (tmp) {
1327 case 1:
1328 spec->init_amp = ALC_INIT_GPIO1;
1329 break;
1330 case 3:
1331 spec->init_amp = ALC_INIT_GPIO2;
1332 break;
1333 case 7:
1334 spec->init_amp = ALC_INIT_GPIO3;
1335 break;
1336 case 5:
Takashi Iwai5a8cfb42010-11-26 17:11:18 +01001337 default:
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001338 spec->init_amp = ALC_INIT_DEFAULT;
1339 break;
1340 }
1341
1342 /* is laptop or Desktop and enable the function "Mute internal speaker
1343 * when the external headphone out jack is plugged"
1344 */
1345 if (!(ass & 0x8000))
1346 return 1;
1347 /*
1348 * 10~8 : Jack location
1349 * 12~11: Headphone out -> 00: PortA, 01: PortE, 02: PortD, 03: Resvered
1350 * 14~13: Resvered
1351 * 15 : 1 --> enable the function "Mute internal speaker
1352 * when the external headphone out jack is plugged"
1353 */
Takashi Iwai5fe6e012011-09-26 10:41:21 +02001354 if (!spec->autocfg.hp_pins[0] &&
1355 !(spec->autocfg.line_out_pins[0] &&
1356 spec->autocfg.line_out_type == AUTO_PIN_HP_OUT)) {
Takashi Iwai01d48252009-10-06 13:21:54 +02001357 hda_nid_t nid;
Kailang Yangc9b58002007-10-16 14:30:01 +02001358 tmp = (ass >> 11) & 0x3; /* HP to chassis */
1359 if (tmp == 0)
Takashi Iwai01d48252009-10-06 13:21:54 +02001360 nid = porta;
Kailang Yangc9b58002007-10-16 14:30:01 +02001361 else if (tmp == 1)
Takashi Iwai01d48252009-10-06 13:21:54 +02001362 nid = porte;
Kailang Yangc9b58002007-10-16 14:30:01 +02001363 else if (tmp == 2)
Takashi Iwai01d48252009-10-06 13:21:54 +02001364 nid = portd;
Kailang Yang6227cdc2010-02-25 08:36:52 +01001365 else if (tmp == 3)
1366 nid = porti;
Kailang Yangc9b58002007-10-16 14:30:01 +02001367 else
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001368 return 1;
Takashi Iwai3af9ee62011-06-27 12:34:01 +02001369 if (found_in_nid_list(nid, spec->autocfg.line_out_pins,
1370 spec->autocfg.line_outs))
1371 return 1;
Takashi Iwai01d48252009-10-06 13:21:54 +02001372 spec->autocfg.hp_pins[0] = nid;
Kailang Yangc9b58002007-10-16 14:30:01 +02001373 }
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001374 return 1;
1375}
Kailang Yangea1fb292008-08-26 12:58:38 +02001376
Takashi Iwai3e6179b2011-07-08 16:55:13 +02001377/* Check the validity of ALC subsystem-id
1378 * ports contains an array of 4 pin NIDs for port-A, E, D and I */
1379static void alc_ssid_check(struct hda_codec *codec, const hda_nid_t *ports)
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001380{
Takashi Iwai3e6179b2011-07-08 16:55:13 +02001381 if (!alc_subsystem_id(codec, ports[0], ports[1], ports[2], ports[3])) {
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001382 struct alc_spec *spec = codec->spec;
1383 snd_printd("realtek: "
1384 "Enable default setup for auto mode as fallback\n");
1385 spec->init_amp = ALC_INIT_DEFAULT;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001386 }
Takashi Iwai21268962011-07-07 15:01:13 +02001387}
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001388
Takashi Iwai41e41f12005-06-08 14:48:49 +02001389/*
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02001390 * Fix-up pin default configurations and add default verbs
Takashi Iwaif95474e2007-07-10 00:47:43 +02001391 */
1392
1393struct alc_pincfg {
1394 hda_nid_t nid;
1395 u32 val;
1396};
1397
Todd Broche1eb5f12010-12-06 11:19:51 -08001398struct alc_model_fixup {
1399 const int id;
1400 const char *name;
1401};
1402
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02001403struct alc_fixup {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001404 int type;
Takashi Iwai361fe6e2011-01-14 09:55:32 +01001405 bool chained;
1406 int chain_id;
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001407 union {
1408 unsigned int sku;
1409 const struct alc_pincfg *pins;
1410 const struct hda_verb *verbs;
1411 void (*func)(struct hda_codec *codec,
1412 const struct alc_fixup *fix,
1413 int action);
1414 } v;
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02001415};
1416
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001417enum {
1418 ALC_FIXUP_INVALID,
1419 ALC_FIXUP_SKU,
1420 ALC_FIXUP_PINS,
1421 ALC_FIXUP_VERBS,
1422 ALC_FIXUP_FUNC,
1423};
Takashi Iwaif95474e2007-07-10 00:47:43 +02001424
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001425enum {
1426 ALC_FIXUP_ACT_PRE_PROBE,
1427 ALC_FIXUP_ACT_PROBE,
Takashi Iwai58701122011-01-13 15:41:45 +01001428 ALC_FIXUP_ACT_INIT,
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001429};
1430
1431static void alc_apply_fixup(struct hda_codec *codec, int action)
1432{
1433 struct alc_spec *spec = codec->spec;
1434 int id = spec->fixup_id;
Takashi Iwaiaa1d0c52011-01-19 17:27:58 +01001435#ifdef CONFIG_SND_DEBUG_VERBOSE
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001436 const char *modelname = spec->fixup_name;
Takashi Iwaiaa1d0c52011-01-19 17:27:58 +01001437#endif
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001438 int depth = 0;
1439
1440 if (!spec->fixup_list)
1441 return;
1442
1443 while (id >= 0) {
1444 const struct alc_fixup *fix = spec->fixup_list + id;
1445 const struct alc_pincfg *cfg;
1446
1447 switch (fix->type) {
1448 case ALC_FIXUP_SKU:
1449 if (action != ALC_FIXUP_ACT_PRE_PROBE || !fix->v.sku)
1450 break;;
1451 snd_printdd(KERN_INFO "hda_codec: %s: "
1452 "Apply sku override for %s\n",
1453 codec->chip_name, modelname);
1454 spec->cdefine.sku_cfg = fix->v.sku;
1455 spec->cdefine.fixup = 1;
1456 break;
1457 case ALC_FIXUP_PINS:
1458 cfg = fix->v.pins;
1459 if (action != ALC_FIXUP_ACT_PRE_PROBE || !cfg)
1460 break;
1461 snd_printdd(KERN_INFO "hda_codec: %s: "
1462 "Apply pincfg for %s\n",
1463 codec->chip_name, modelname);
1464 for (; cfg->nid; cfg++)
1465 snd_hda_codec_set_pincfg(codec, cfg->nid,
1466 cfg->val);
1467 break;
1468 case ALC_FIXUP_VERBS:
1469 if (action != ALC_FIXUP_ACT_PROBE || !fix->v.verbs)
1470 break;
1471 snd_printdd(KERN_INFO "hda_codec: %s: "
1472 "Apply fix-verbs for %s\n",
1473 codec->chip_name, modelname);
1474 add_verb(codec->spec, fix->v.verbs);
1475 break;
1476 case ALC_FIXUP_FUNC:
1477 if (!fix->v.func)
1478 break;
1479 snd_printdd(KERN_INFO "hda_codec: %s: "
1480 "Apply fix-func for %s\n",
1481 codec->chip_name, modelname);
1482 fix->v.func(codec, fix, action);
1483 break;
1484 default:
1485 snd_printk(KERN_ERR "hda_codec: %s: "
1486 "Invalid fixup type %d\n",
1487 codec->chip_name, fix->type);
1488 break;
1489 }
Takashi Iwai24af2b12011-05-02 13:55:36 +02001490 if (!fix->chained)
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001491 break;
1492 if (++depth > 10)
1493 break;
Takashi Iwai24af2b12011-05-02 13:55:36 +02001494 id = fix->chain_id;
Takashi Iwai9d578832010-11-22 13:29:19 +01001495 }
Takashi Iwaif95474e2007-07-10 00:47:43 +02001496}
1497
Todd Broche1eb5f12010-12-06 11:19:51 -08001498static void alc_pick_fixup(struct hda_codec *codec,
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001499 const struct alc_model_fixup *models,
1500 const struct snd_pci_quirk *quirk,
1501 const struct alc_fixup *fixlist)
Todd Broche1eb5f12010-12-06 11:19:51 -08001502{
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001503 struct alc_spec *spec = codec->spec;
1504 int id = -1;
1505 const char *name = NULL;
Todd Broche1eb5f12010-12-06 11:19:51 -08001506
Todd Broche1eb5f12010-12-06 11:19:51 -08001507 if (codec->modelname && models) {
1508 while (models->name) {
1509 if (!strcmp(codec->modelname, models->name)) {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001510 id = models->id;
1511 name = models->name;
Todd Broche1eb5f12010-12-06 11:19:51 -08001512 break;
1513 }
1514 models++;
1515 }
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001516 }
1517 if (id < 0) {
1518 quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk);
1519 if (quirk) {
1520 id = quirk->value;
1521#ifdef CONFIG_SND_DEBUG_VERBOSE
1522 name = quirk->name;
1523#endif
1524 }
1525 }
1526
1527 spec->fixup_id = id;
1528 if (id >= 0) {
1529 spec->fixup_list = fixlist;
1530 spec->fixup_name = name;
Todd Broche1eb5f12010-12-06 11:19:51 -08001531 }
Takashi Iwaif95474e2007-07-10 00:47:43 +02001532}
1533
Takashi Iwai1d045db2011-07-07 18:23:21 +02001534/*
1535 * COEF access helper functions
1536 */
Kailang Yang274693f2009-12-03 10:07:50 +01001537static int alc_read_coef_idx(struct hda_codec *codec,
1538 unsigned int coef_idx)
1539{
1540 unsigned int val;
1541 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX,
1542 coef_idx);
1543 val = snd_hda_codec_read(codec, 0x20, 0,
1544 AC_VERB_GET_PROC_COEF, 0);
1545 return val;
1546}
1547
Kailang Yang977ddd62010-09-15 10:02:29 +02001548static void alc_write_coef_idx(struct hda_codec *codec, unsigned int coef_idx,
1549 unsigned int coef_val)
1550{
1551 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX,
1552 coef_idx);
1553 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF,
1554 coef_val);
1555}
1556
Takashi Iwai1d045db2011-07-07 18:23:21 +02001557/*
1558 * Digital I/O handling
1559 */
1560
Takashi Iwai757899a2010-07-30 10:48:14 +02001561/* set right pin controls for digital I/O */
1562static void alc_auto_init_digital(struct hda_codec *codec)
1563{
1564 struct alc_spec *spec = codec->spec;
1565 int i;
Takashi Iwai1f0f4b82011-06-27 10:52:59 +02001566 hda_nid_t pin, dac;
Takashi Iwai757899a2010-07-30 10:48:14 +02001567
1568 for (i = 0; i < spec->autocfg.dig_outs; i++) {
1569 pin = spec->autocfg.dig_out_pins[i];
Takashi Iwai1f0f4b82011-06-27 10:52:59 +02001570 if (!pin)
1571 continue;
1572 snd_hda_codec_write(codec, pin, 0,
1573 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
1574 if (!i)
1575 dac = spec->multiout.dig_out_nid;
1576 else
1577 dac = spec->slave_dig_outs[i - 1];
1578 if (!dac || !(get_wcaps(codec, dac) & AC_WCAP_OUT_AMP))
1579 continue;
1580 snd_hda_codec_write(codec, dac, 0,
1581 AC_VERB_SET_AMP_GAIN_MUTE,
1582 AMP_OUT_UNMUTE);
Takashi Iwai757899a2010-07-30 10:48:14 +02001583 }
1584 pin = spec->autocfg.dig_in_pin;
1585 if (pin)
1586 snd_hda_codec_write(codec, pin, 0,
1587 AC_VERB_SET_PIN_WIDGET_CONTROL,
1588 PIN_IN);
1589}
1590
1591/* parse digital I/Os and set up NIDs in BIOS auto-parse mode */
1592static void alc_auto_parse_digital(struct hda_codec *codec)
1593{
1594 struct alc_spec *spec = codec->spec;
1595 int i, err;
1596 hda_nid_t dig_nid;
1597
1598 /* support multiple SPDIFs; the secondary is set up as a slave */
1599 for (i = 0; i < spec->autocfg.dig_outs; i++) {
Takashi Iwaia9267572011-07-07 15:12:55 +02001600 hda_nid_t conn[4];
Takashi Iwai757899a2010-07-30 10:48:14 +02001601 err = snd_hda_get_connections(codec,
1602 spec->autocfg.dig_out_pins[i],
Takashi Iwaia9267572011-07-07 15:12:55 +02001603 conn, ARRAY_SIZE(conn));
Takashi Iwai757899a2010-07-30 10:48:14 +02001604 if (err < 0)
1605 continue;
Takashi Iwaia9267572011-07-07 15:12:55 +02001606 dig_nid = conn[0]; /* assume the first element is audio-out */
Takashi Iwai757899a2010-07-30 10:48:14 +02001607 if (!i) {
1608 spec->multiout.dig_out_nid = dig_nid;
1609 spec->dig_out_type = spec->autocfg.dig_out_type[0];
1610 } else {
1611 spec->multiout.slave_dig_outs = spec->slave_dig_outs;
1612 if (i >= ARRAY_SIZE(spec->slave_dig_outs) - 1)
1613 break;
1614 spec->slave_dig_outs[i - 1] = dig_nid;
1615 }
1616 }
1617
1618 if (spec->autocfg.dig_in_pin) {
Takashi Iwai01fdf182010-09-24 09:09:42 +02001619 dig_nid = codec->start_nid;
1620 for (i = 0; i < codec->num_nodes; i++, dig_nid++) {
1621 unsigned int wcaps = get_wcaps(codec, dig_nid);
1622 if (get_wcaps_type(wcaps) != AC_WID_AUD_IN)
1623 continue;
1624 if (!(wcaps & AC_WCAP_DIGITAL))
1625 continue;
1626 if (!(wcaps & AC_WCAP_CONN_LIST))
1627 continue;
1628 err = get_connection_index(codec, dig_nid,
1629 spec->autocfg.dig_in_pin);
1630 if (err >= 0) {
1631 spec->dig_in_nid = dig_nid;
1632 break;
1633 }
1634 }
Takashi Iwai757899a2010-07-30 10:48:14 +02001635 }
1636}
1637
Takashi Iwaif95474e2007-07-10 00:47:43 +02001638/*
Takashi Iwai1d045db2011-07-07 18:23:21 +02001639 * capture mixer elements
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001640 */
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001641static int alc_cap_vol_info(struct snd_kcontrol *kcontrol,
1642 struct snd_ctl_elem_info *uinfo)
1643{
1644 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1645 struct alc_spec *spec = codec->spec;
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02001646 unsigned long val;
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001647 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001648
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001649 mutex_lock(&codec->control_mutex);
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02001650 if (spec->vol_in_capsrc)
1651 val = HDA_COMPOSE_AMP_VAL(spec->capsrc_nids[0], 3, 0, HDA_OUTPUT);
1652 else
1653 val = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0, HDA_INPUT);
1654 kcontrol->private_value = val;
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001655 err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001656 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001657 return err;
1658}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001660static int alc_cap_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
1661 unsigned int size, unsigned int __user *tlv)
1662{
1663 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1664 struct alc_spec *spec = codec->spec;
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02001665 unsigned long val;
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001666 int err;
1667
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001668 mutex_lock(&codec->control_mutex);
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02001669 if (spec->vol_in_capsrc)
1670 val = HDA_COMPOSE_AMP_VAL(spec->capsrc_nids[0], 3, 0, HDA_OUTPUT);
1671 else
1672 val = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0, HDA_INPUT);
1673 kcontrol->private_value = val;
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001674 err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001675 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001676 return err;
1677}
1678
1679typedef int (*getput_call_t)(struct snd_kcontrol *kcontrol,
1680 struct snd_ctl_elem_value *ucontrol);
1681
1682static int alc_cap_getput_caller(struct snd_kcontrol *kcontrol,
1683 struct snd_ctl_elem_value *ucontrol,
Takashi Iwai9c7a0832011-07-07 09:25:54 +02001684 getput_call_t func, bool check_adc_switch)
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001685{
1686 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1687 struct alc_spec *spec = codec->spec;
Takashi Iwai21268962011-07-07 15:01:13 +02001688 int i, err = 0;
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001689
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001690 mutex_lock(&codec->control_mutex);
Takashi Iwai21268962011-07-07 15:01:13 +02001691 if (check_adc_switch && spec->dyn_adc_switch) {
Takashi Iwai9c7a0832011-07-07 09:25:54 +02001692 for (i = 0; i < spec->num_adc_nids; i++) {
1693 kcontrol->private_value =
1694 HDA_COMPOSE_AMP_VAL(spec->adc_nids[i],
1695 3, 0, HDA_INPUT);
1696 err = func(kcontrol, ucontrol);
1697 if (err < 0)
1698 goto error;
1699 }
1700 } else {
1701 i = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02001702 if (spec->vol_in_capsrc)
1703 kcontrol->private_value =
1704 HDA_COMPOSE_AMP_VAL(spec->capsrc_nids[i],
1705 3, 0, HDA_OUTPUT);
1706 else
1707 kcontrol->private_value =
Takashi Iwai21268962011-07-07 15:01:13 +02001708 HDA_COMPOSE_AMP_VAL(spec->adc_nids[i],
1709 3, 0, HDA_INPUT);
Takashi Iwai9c7a0832011-07-07 09:25:54 +02001710 err = func(kcontrol, ucontrol);
1711 }
1712 error:
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001713 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001714 return err;
1715}
1716
1717static int alc_cap_vol_get(struct snd_kcontrol *kcontrol,
1718 struct snd_ctl_elem_value *ucontrol)
1719{
1720 return alc_cap_getput_caller(kcontrol, ucontrol,
Takashi Iwai9c7a0832011-07-07 09:25:54 +02001721 snd_hda_mixer_amp_volume_get, false);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001722}
1723
1724static int alc_cap_vol_put(struct snd_kcontrol *kcontrol,
1725 struct snd_ctl_elem_value *ucontrol)
1726{
1727 return alc_cap_getput_caller(kcontrol, ucontrol,
Takashi Iwai9c7a0832011-07-07 09:25:54 +02001728 snd_hda_mixer_amp_volume_put, true);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001729}
1730
1731/* capture mixer elements */
1732#define alc_cap_sw_info snd_ctl_boolean_stereo_info
1733
1734static int alc_cap_sw_get(struct snd_kcontrol *kcontrol,
1735 struct snd_ctl_elem_value *ucontrol)
1736{
1737 return alc_cap_getput_caller(kcontrol, ucontrol,
Takashi Iwai9c7a0832011-07-07 09:25:54 +02001738 snd_hda_mixer_amp_switch_get, false);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001739}
1740
1741static int alc_cap_sw_put(struct snd_kcontrol *kcontrol,
1742 struct snd_ctl_elem_value *ucontrol)
1743{
1744 return alc_cap_getput_caller(kcontrol, ucontrol,
Takashi Iwai9c7a0832011-07-07 09:25:54 +02001745 snd_hda_mixer_amp_switch_put, true);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001746}
1747
Takashi Iwaia23b6882009-03-23 15:21:36 +01001748#define _DEFINE_CAPMIX(num) \
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001749 { \
1750 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
1751 .name = "Capture Switch", \
1752 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
1753 .count = num, \
1754 .info = alc_cap_sw_info, \
1755 .get = alc_cap_sw_get, \
1756 .put = alc_cap_sw_put, \
1757 }, \
1758 { \
1759 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
1760 .name = "Capture Volume", \
1761 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | \
1762 SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
1763 SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK), \
1764 .count = num, \
1765 .info = alc_cap_vol_info, \
1766 .get = alc_cap_vol_get, \
1767 .put = alc_cap_vol_put, \
1768 .tlv = { .c = alc_cap_vol_tlv }, \
Takashi Iwaia23b6882009-03-23 15:21:36 +01001769 }
1770
1771#define _DEFINE_CAPSRC(num) \
Takashi Iwai3c3e9892008-10-31 17:48:56 +01001772 { \
1773 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
1774 /* .name = "Capture Source", */ \
1775 .name = "Input Source", \
1776 .count = num, \
1777 .info = alc_mux_enum_info, \
1778 .get = alc_mux_enum_get, \
1779 .put = alc_mux_enum_put, \
Takashi Iwaia23b6882009-03-23 15:21:36 +01001780 }
1781
1782#define DEFINE_CAPMIX(num) \
Takashi Iwaia9111322011-05-02 11:30:18 +02001783static const struct snd_kcontrol_new alc_capture_mixer ## num[] = { \
Takashi Iwaia23b6882009-03-23 15:21:36 +01001784 _DEFINE_CAPMIX(num), \
1785 _DEFINE_CAPSRC(num), \
1786 { } /* end */ \
1787}
1788
1789#define DEFINE_CAPMIX_NOSRC(num) \
Takashi Iwaia9111322011-05-02 11:30:18 +02001790static const struct snd_kcontrol_new alc_capture_mixer_nosrc ## num[] = { \
Takashi Iwaia23b6882009-03-23 15:21:36 +01001791 _DEFINE_CAPMIX(num), \
1792 { } /* end */ \
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001793}
1794
1795/* up to three ADCs */
1796DEFINE_CAPMIX(1);
1797DEFINE_CAPMIX(2);
1798DEFINE_CAPMIX(3);
Takashi Iwaia23b6882009-03-23 15:21:36 +01001799DEFINE_CAPMIX_NOSRC(1);
1800DEFINE_CAPMIX_NOSRC(2);
1801DEFINE_CAPMIX_NOSRC(3);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001802
1803/*
Takashi Iwai2134ea42008-01-10 16:53:55 +01001804 * virtual master controls
1805 */
1806
1807/*
1808 * slave controls for virtual master
1809 */
Takashi Iwaiea734962011-01-17 11:29:34 +01001810static const char * const alc_slave_vols[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01001811 "Front Playback Volume",
1812 "Surround Playback Volume",
1813 "Center Playback Volume",
1814 "LFE Playback Volume",
1815 "Side Playback Volume",
1816 "Headphone Playback Volume",
1817 "Speaker Playback Volume",
1818 "Mono Playback Volume",
Takashi Iwai2134ea42008-01-10 16:53:55 +01001819 "Line-Out Playback Volume",
Takashi Iwai3fe45ae2011-08-18 15:13:17 +02001820 "PCM Playback Volume",
Takashi Iwai2134ea42008-01-10 16:53:55 +01001821 NULL,
1822};
1823
Takashi Iwaiea734962011-01-17 11:29:34 +01001824static const char * const alc_slave_sws[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01001825 "Front Playback Switch",
1826 "Surround Playback Switch",
1827 "Center Playback Switch",
1828 "LFE Playback Switch",
1829 "Side Playback Switch",
1830 "Headphone Playback Switch",
1831 "Speaker Playback Switch",
1832 "Mono Playback Switch",
Takashi Iwaiedb54a52008-01-29 12:47:02 +01001833 "IEC958 Playback Switch",
Takashi Iwai23033b22009-12-08 12:36:52 +01001834 "Line-Out Playback Switch",
Takashi Iwai3fe45ae2011-08-18 15:13:17 +02001835 "PCM Playback Switch",
Takashi Iwai2134ea42008-01-10 16:53:55 +01001836 NULL,
1837};
1838
1839/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001840 * build control elements
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841 */
Takashi Iwai603c4012008-07-30 15:01:44 +02001842
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01001843#define NID_MAPPING (-1)
1844
1845#define SUBDEV_SPEAKER_ (0 << 6)
1846#define SUBDEV_HP_ (1 << 6)
1847#define SUBDEV_LINE_ (2 << 6)
1848#define SUBDEV_SPEAKER(x) (SUBDEV_SPEAKER_ | ((x) & 0x3f))
1849#define SUBDEV_HP(x) (SUBDEV_HP_ | ((x) & 0x3f))
1850#define SUBDEV_LINE(x) (SUBDEV_LINE_ | ((x) & 0x3f))
1851
Takashi Iwai603c4012008-07-30 15:01:44 +02001852static void alc_free_kctls(struct hda_codec *codec);
1853
Takashi Iwai67d634c2009-11-16 15:35:59 +01001854#ifdef CONFIG_SND_HDA_INPUT_BEEP
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01001855/* additional beep mixers; the actual parameters are overwritten at build */
Takashi Iwaia9111322011-05-02 11:30:18 +02001856static const struct snd_kcontrol_new alc_beep_mixer[] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01001857 HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_INPUT),
Jaroslav Kysela123c07a2009-10-21 14:48:23 +02001858 HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01001859 { } /* end */
1860};
Takashi Iwai67d634c2009-11-16 15:35:59 +01001861#endif
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01001862
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863static int alc_build_controls(struct hda_codec *codec)
1864{
1865 struct alc_spec *spec = codec->spec;
Takashi Iwai2f44f842010-06-22 11:12:32 +02001866 struct snd_kcontrol *kctl = NULL;
Takashi Iwaia9111322011-05-02 11:30:18 +02001867 const struct snd_kcontrol_new *knew;
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01001868 int i, j, err;
1869 unsigned int u;
1870 hda_nid_t nid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871
1872 for (i = 0; i < spec->num_mixers; i++) {
1873 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
1874 if (err < 0)
1875 return err;
1876 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001877 if (spec->cap_mixer) {
1878 err = snd_hda_add_new_ctls(codec, spec->cap_mixer);
1879 if (err < 0)
1880 return err;
1881 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001882 if (spec->multiout.dig_out_nid) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001883 err = snd_hda_create_spdif_out_ctls(codec,
Stephen Warren74b654c2011-06-01 11:14:18 -06001884 spec->multiout.dig_out_nid,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001885 spec->multiout.dig_out_nid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886 if (err < 0)
1887 return err;
Takashi Iwaie64f14f2009-01-20 18:32:55 +01001888 if (!spec->no_analog) {
1889 err = snd_hda_create_spdif_share_sw(codec,
1890 &spec->multiout);
1891 if (err < 0)
1892 return err;
1893 spec->multiout.share_spdif = 1;
1894 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895 }
1896 if (spec->dig_in_nid) {
1897 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
1898 if (err < 0)
1899 return err;
1900 }
Takashi Iwai2134ea42008-01-10 16:53:55 +01001901
Takashi Iwai67d634c2009-11-16 15:35:59 +01001902#ifdef CONFIG_SND_HDA_INPUT_BEEP
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01001903 /* create beep controls if needed */
1904 if (spec->beep_amp) {
Takashi Iwaia9111322011-05-02 11:30:18 +02001905 const struct snd_kcontrol_new *knew;
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01001906 for (knew = alc_beep_mixer; knew->name; knew++) {
1907 struct snd_kcontrol *kctl;
1908 kctl = snd_ctl_new1(knew, codec);
1909 if (!kctl)
1910 return -ENOMEM;
1911 kctl->private_value = spec->beep_amp;
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +01001912 err = snd_hda_ctl_add(codec, 0, kctl);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01001913 if (err < 0)
1914 return err;
1915 }
1916 }
Takashi Iwai67d634c2009-11-16 15:35:59 +01001917#endif
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01001918
Takashi Iwai2134ea42008-01-10 16:53:55 +01001919 /* if we have no master control, let's create it */
Takashi Iwaie64f14f2009-01-20 18:32:55 +01001920 if (!spec->no_analog &&
1921 !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001922 unsigned int vmaster_tlv[4];
Takashi Iwai2134ea42008-01-10 16:53:55 +01001923 snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001924 HDA_OUTPUT, vmaster_tlv);
Takashi Iwai2134ea42008-01-10 16:53:55 +01001925 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001926 vmaster_tlv, alc_slave_vols);
Takashi Iwai2134ea42008-01-10 16:53:55 +01001927 if (err < 0)
1928 return err;
1929 }
Takashi Iwaie64f14f2009-01-20 18:32:55 +01001930 if (!spec->no_analog &&
1931 !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
Takashi Iwai2134ea42008-01-10 16:53:55 +01001932 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
1933 NULL, alc_slave_sws);
1934 if (err < 0)
1935 return err;
1936 }
1937
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01001938 /* assign Capture Source enums to NID */
Takashi Iwaifbe618f2010-06-11 11:24:58 +02001939 if (spec->capsrc_nids || spec->adc_nids) {
1940 kctl = snd_hda_find_mixer_ctl(codec, "Capture Source");
1941 if (!kctl)
1942 kctl = snd_hda_find_mixer_ctl(codec, "Input Source");
1943 for (i = 0; kctl && i < kctl->count; i++) {
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02001944 const hda_nid_t *nids = spec->capsrc_nids;
Takashi Iwaifbe618f2010-06-11 11:24:58 +02001945 if (!nids)
1946 nids = spec->adc_nids;
1947 err = snd_hda_add_nid(codec, kctl, i, nids[i]);
1948 if (err < 0)
1949 return err;
1950 }
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01001951 }
Takashi Iwai60a6a842011-07-27 14:01:24 +02001952 if (spec->cap_mixer && spec->adc_nids) {
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01001953 const char *kname = kctl ? kctl->id.name : NULL;
1954 for (knew = spec->cap_mixer; knew->name; knew++) {
1955 if (kname && strcmp(knew->name, kname) == 0)
1956 continue;
1957 kctl = snd_hda_find_mixer_ctl(codec, knew->name);
1958 for (i = 0; kctl && i < kctl->count; i++) {
1959 err = snd_hda_add_nid(codec, kctl, i,
1960 spec->adc_nids[i]);
1961 if (err < 0)
1962 return err;
1963 }
1964 }
1965 }
1966
1967 /* other nid->control mapping */
1968 for (i = 0; i < spec->num_mixers; i++) {
1969 for (knew = spec->mixers[i]; knew->name; knew++) {
1970 if (knew->iface != NID_MAPPING)
1971 continue;
1972 kctl = snd_hda_find_mixer_ctl(codec, knew->name);
1973 if (kctl == NULL)
1974 continue;
1975 u = knew->subdevice;
1976 for (j = 0; j < 4; j++, u >>= 8) {
1977 nid = u & 0x3f;
1978 if (nid == 0)
1979 continue;
1980 switch (u & 0xc0) {
1981 case SUBDEV_SPEAKER_:
1982 nid = spec->autocfg.speaker_pins[nid];
1983 break;
1984 case SUBDEV_LINE_:
1985 nid = spec->autocfg.line_out_pins[nid];
1986 break;
1987 case SUBDEV_HP_:
1988 nid = spec->autocfg.hp_pins[nid];
1989 break;
1990 default:
1991 continue;
1992 }
1993 err = snd_hda_add_nid(codec, kctl, 0, nid);
1994 if (err < 0)
1995 return err;
1996 }
1997 u = knew->private_value;
1998 for (j = 0; j < 4; j++, u >>= 8) {
1999 nid = u & 0xff;
2000 if (nid == 0)
2001 continue;
2002 err = snd_hda_add_nid(codec, kctl, 0, nid);
2003 if (err < 0)
2004 return err;
2005 }
2006 }
2007 }
Takashi Iwaibae84e72010-03-22 08:30:20 +01002008
2009 alc_free_kctls(codec); /* no longer needed */
2010
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011 return 0;
2012}
2013
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002014
Linus Torvalds1da177e2005-04-16 15:20:36 -07002015/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002016 * Common callbacks
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002017 */
Takashi Iwai16ded522005-06-10 19:58:24 +02002018
Takashi Iwai584c0c42011-03-10 12:51:11 +01002019static void alc_init_special_input_src(struct hda_codec *codec);
2020
Linus Torvalds1da177e2005-04-16 15:20:36 -07002021static int alc_init(struct hda_codec *codec)
2022{
2023 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002024 unsigned int i;
2025
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02002026 alc_fix_pll(codec);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02002027 alc_auto_init_amp(codec, spec->init_amp);
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02002028
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002029 for (i = 0; i < spec->num_init_verbs; i++)
2030 snd_hda_sequence_write(codec, spec->init_verbs[i]);
Takashi Iwai584c0c42011-03-10 12:51:11 +01002031 alc_init_special_input_src(codec);
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002032
2033 if (spec->init_hook)
2034 spec->init_hook(codec);
2035
Takashi Iwai58701122011-01-13 15:41:45 +01002036 alc_apply_fixup(codec, ALC_FIXUP_ACT_INIT);
2037
Takashi Iwai9e5341b2010-09-21 09:57:06 +02002038 hda_call_check_power_status(codec, 0x01);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002039 return 0;
2040}
2041
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002042static void alc_unsol_event(struct hda_codec *codec, unsigned int res)
2043{
2044 struct alc_spec *spec = codec->spec;
2045
2046 if (spec->unsol_event)
2047 spec->unsol_event(codec, res);
2048}
2049
Takashi Iwaicb53c622007-08-10 17:21:45 +02002050#ifdef CONFIG_SND_HDA_POWER_SAVE
2051static int alc_check_power_status(struct hda_codec *codec, hda_nid_t nid)
2052{
2053 struct alc_spec *spec = codec->spec;
2054 return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
2055}
2056#endif
2057
Linus Torvalds1da177e2005-04-16 15:20:36 -07002058/*
2059 * Analog playback callbacks
2060 */
Takashi Iwaic2d986b2011-07-06 18:30:08 +02002061static int alc_playback_pcm_open(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002063 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064{
2065 struct alc_spec *spec = codec->spec;
Takashi Iwai9a081602008-02-12 18:37:26 +01002066 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
2067 hinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068}
2069
Takashi Iwaic2d986b2011-07-06 18:30:08 +02002070static int alc_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002071 struct hda_codec *codec,
2072 unsigned int stream_tag,
2073 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002074 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075{
2076 struct alc_spec *spec = codec->spec;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002077 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
2078 stream_tag, format, substream);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079}
2080
Takashi Iwaic2d986b2011-07-06 18:30:08 +02002081static int alc_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002082 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002083 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002084{
2085 struct alc_spec *spec = codec->spec;
2086 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
2087}
2088
2089/*
2090 * Digital out
2091 */
Takashi Iwaic2d986b2011-07-06 18:30:08 +02002092static int alc_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002093 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002094 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095{
2096 struct alc_spec *spec = codec->spec;
2097 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
2098}
2099
Takashi Iwaic2d986b2011-07-06 18:30:08 +02002100static int alc_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02002101 struct hda_codec *codec,
2102 unsigned int stream_tag,
2103 unsigned int format,
2104 struct snd_pcm_substream *substream)
2105{
2106 struct alc_spec *spec = codec->spec;
2107 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
2108 stream_tag, format, substream);
2109}
2110
Takashi Iwaic2d986b2011-07-06 18:30:08 +02002111static int alc_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
Takashi Iwai9b5f12e2009-02-13 11:47:37 +01002112 struct hda_codec *codec,
2113 struct snd_pcm_substream *substream)
2114{
2115 struct alc_spec *spec = codec->spec;
2116 return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
2117}
2118
Takashi Iwaic2d986b2011-07-06 18:30:08 +02002119static int alc_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002121 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122{
2123 struct alc_spec *spec = codec->spec;
2124 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
2125}
2126
2127/*
2128 * Analog capture
2129 */
Takashi Iwaic2d986b2011-07-06 18:30:08 +02002130static int alc_alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002131 struct hda_codec *codec,
2132 unsigned int stream_tag,
2133 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002134 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002135{
2136 struct alc_spec *spec = codec->spec;
2137
Takashi Iwai63300792008-01-24 15:31:36 +01002138 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1],
Linus Torvalds1da177e2005-04-16 15:20:36 -07002139 stream_tag, 0, format);
2140 return 0;
2141}
2142
Takashi Iwaic2d986b2011-07-06 18:30:08 +02002143static int alc_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002144 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002145 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002146{
2147 struct alc_spec *spec = codec->spec;
2148
Takashi Iwai888afa12008-03-18 09:57:50 +01002149 snd_hda_codec_cleanup_stream(codec,
2150 spec->adc_nids[substream->number + 1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002151 return 0;
2152}
2153
Takashi Iwai840b64c2010-07-13 22:49:01 +02002154/* analog capture with dynamic dual-adc changes */
Takashi Iwai21268962011-07-07 15:01:13 +02002155static int dyn_adc_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
Takashi Iwai840b64c2010-07-13 22:49:01 +02002156 struct hda_codec *codec,
2157 unsigned int stream_tag,
2158 unsigned int format,
2159 struct snd_pcm_substream *substream)
2160{
2161 struct alc_spec *spec = codec->spec;
Takashi Iwai21268962011-07-07 15:01:13 +02002162 spec->cur_adc = spec->adc_nids[spec->dyn_adc_idx[spec->cur_mux[0]]];
Takashi Iwai840b64c2010-07-13 22:49:01 +02002163 spec->cur_adc_stream_tag = stream_tag;
2164 spec->cur_adc_format = format;
2165 snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format);
2166 return 0;
2167}
2168
Takashi Iwai21268962011-07-07 15:01:13 +02002169static int dyn_adc_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
Takashi Iwai840b64c2010-07-13 22:49:01 +02002170 struct hda_codec *codec,
2171 struct snd_pcm_substream *substream)
2172{
2173 struct alc_spec *spec = codec->spec;
2174 snd_hda_codec_cleanup_stream(codec, spec->cur_adc);
2175 spec->cur_adc = 0;
2176 return 0;
2177}
2178
Takashi Iwai21268962011-07-07 15:01:13 +02002179static const struct hda_pcm_stream dyn_adc_pcm_analog_capture = {
Takashi Iwai840b64c2010-07-13 22:49:01 +02002180 .substreams = 1,
2181 .channels_min = 2,
2182 .channels_max = 2,
2183 .nid = 0, /* fill later */
2184 .ops = {
Takashi Iwai21268962011-07-07 15:01:13 +02002185 .prepare = dyn_adc_capture_pcm_prepare,
2186 .cleanup = dyn_adc_capture_pcm_cleanup
Takashi Iwai840b64c2010-07-13 22:49:01 +02002187 },
2188};
Linus Torvalds1da177e2005-04-16 15:20:36 -07002189
2190/*
2191 */
Takashi Iwaic2d986b2011-07-06 18:30:08 +02002192static const struct hda_pcm_stream alc_pcm_analog_playback = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002193 .substreams = 1,
2194 .channels_min = 2,
2195 .channels_max = 8,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002196 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002197 .ops = {
Takashi Iwaic2d986b2011-07-06 18:30:08 +02002198 .open = alc_playback_pcm_open,
2199 .prepare = alc_playback_pcm_prepare,
2200 .cleanup = alc_playback_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201 },
2202};
2203
Takashi Iwaic2d986b2011-07-06 18:30:08 +02002204static const struct hda_pcm_stream alc_pcm_analog_capture = {
Takashi Iwai63300792008-01-24 15:31:36 +01002205 .substreams = 1,
2206 .channels_min = 2,
2207 .channels_max = 2,
2208 /* NID is set in alc_build_pcms */
2209};
2210
Takashi Iwaic2d986b2011-07-06 18:30:08 +02002211static const struct hda_pcm_stream alc_pcm_analog_alt_playback = {
Takashi Iwai63300792008-01-24 15:31:36 +01002212 .substreams = 1,
2213 .channels_min = 2,
2214 .channels_max = 2,
2215 /* NID is set in alc_build_pcms */
2216};
2217
Takashi Iwaic2d986b2011-07-06 18:30:08 +02002218static const struct hda_pcm_stream alc_pcm_analog_alt_capture = {
Takashi Iwai63300792008-01-24 15:31:36 +01002219 .substreams = 2, /* can be overridden */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002220 .channels_min = 2,
2221 .channels_max = 2,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002222 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002223 .ops = {
Takashi Iwaic2d986b2011-07-06 18:30:08 +02002224 .prepare = alc_alt_capture_pcm_prepare,
2225 .cleanup = alc_alt_capture_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07002226 },
2227};
2228
Takashi Iwaic2d986b2011-07-06 18:30:08 +02002229static const struct hda_pcm_stream alc_pcm_digital_playback = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230 .substreams = 1,
2231 .channels_min = 2,
2232 .channels_max = 2,
2233 /* NID is set in alc_build_pcms */
2234 .ops = {
Takashi Iwaic2d986b2011-07-06 18:30:08 +02002235 .open = alc_dig_playback_pcm_open,
2236 .close = alc_dig_playback_pcm_close,
2237 .prepare = alc_dig_playback_pcm_prepare,
2238 .cleanup = alc_dig_playback_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07002239 },
2240};
2241
Takashi Iwaic2d986b2011-07-06 18:30:08 +02002242static const struct hda_pcm_stream alc_pcm_digital_capture = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243 .substreams = 1,
2244 .channels_min = 2,
2245 .channels_max = 2,
2246 /* NID is set in alc_build_pcms */
2247};
2248
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01002249/* Used by alc_build_pcms to flag that a PCM has no playback stream */
Takashi Iwaia9111322011-05-02 11:30:18 +02002250static const struct hda_pcm_stream alc_pcm_null_stream = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01002251 .substreams = 0,
2252 .channels_min = 0,
2253 .channels_max = 0,
2254};
2255
Linus Torvalds1da177e2005-04-16 15:20:36 -07002256static int alc_build_pcms(struct hda_codec *codec)
2257{
2258 struct alc_spec *spec = codec->spec;
2259 struct hda_pcm *info = spec->pcm_rec;
Takashi Iwaic2d986b2011-07-06 18:30:08 +02002260 const struct hda_pcm_stream *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002261 int i;
2262
2263 codec->num_pcms = 1;
2264 codec->pcm_info = info;
2265
Takashi Iwaie64f14f2009-01-20 18:32:55 +01002266 if (spec->no_analog)
2267 goto skip_analog;
2268
Takashi Iwai812a2cc2009-05-16 10:00:49 +02002269 snprintf(spec->stream_name_analog, sizeof(spec->stream_name_analog),
2270 "%s Analog", codec->chip_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002271 info->name = spec->stream_name_analog;
Kailang Yang274693f2009-12-03 10:07:50 +01002272
Takashi Iwaic2d986b2011-07-06 18:30:08 +02002273 if (spec->multiout.dac_nids > 0) {
2274 p = spec->stream_analog_playback;
2275 if (!p)
2276 p = &alc_pcm_analog_playback;
2277 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p;
Takashi Iwai4a471b72005-12-07 13:56:29 +01002278 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
2279 }
Takashi Iwaic2d986b2011-07-06 18:30:08 +02002280 if (spec->adc_nids) {
2281 p = spec->stream_analog_capture;
Takashi Iwai21268962011-07-07 15:01:13 +02002282 if (!p) {
2283 if (spec->dyn_adc_switch)
2284 p = &dyn_adc_pcm_analog_capture;
2285 else
2286 p = &alc_pcm_analog_capture;
2287 }
Takashi Iwaic2d986b2011-07-06 18:30:08 +02002288 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p;
Takashi Iwai4a471b72005-12-07 13:56:29 +01002289 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
2290 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002291
Takashi Iwai4a471b72005-12-07 13:56:29 +01002292 if (spec->channel_mode) {
2293 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0;
2294 for (i = 0; i < spec->num_channel_mode; i++) {
2295 if (spec->channel_mode[i].channels > info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max) {
2296 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->channel_mode[i].channels;
2297 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298 }
2299 }
2300
Takashi Iwaie64f14f2009-01-20 18:32:55 +01002301 skip_analog:
Takashi Iwaie08a0072006-09-07 17:52:14 +02002302 /* SPDIF for stream index #1 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
Takashi Iwai812a2cc2009-05-16 10:00:49 +02002304 snprintf(spec->stream_name_digital,
2305 sizeof(spec->stream_name_digital),
2306 "%s Digital", codec->chip_name);
Takashi Iwaie08a0072006-09-07 17:52:14 +02002307 codec->num_pcms = 2;
Wu Fengguangb25c9da2009-02-06 15:02:27 +08002308 codec->slave_dig_outs = spec->multiout.slave_dig_outs;
Takashi Iwaic06134d2006-10-11 18:49:13 +02002309 info = spec->pcm_rec + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310 info->name = spec->stream_name_digital;
Takashi Iwai8c441982009-01-20 18:30:20 +01002311 if (spec->dig_out_type)
2312 info->pcm_type = spec->dig_out_type;
2313 else
2314 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Takashi Iwaic2d986b2011-07-06 18:30:08 +02002315 if (spec->multiout.dig_out_nid) {
2316 p = spec->stream_digital_playback;
2317 if (!p)
2318 p = &alc_pcm_digital_playback;
2319 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002320 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
2321 }
Takashi Iwaic2d986b2011-07-06 18:30:08 +02002322 if (spec->dig_in_nid) {
2323 p = spec->stream_digital_capture;
2324 if (!p)
2325 p = &alc_pcm_digital_capture;
2326 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002327 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
2328 }
Takashi Iwai963f8032008-08-11 10:04:40 +02002329 /* FIXME: do we need this for all Realtek codec models? */
2330 codec->spdif_status_reset = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002331 }
2332
Takashi Iwaie64f14f2009-01-20 18:32:55 +01002333 if (spec->no_analog)
2334 return 0;
2335
Takashi Iwaie08a0072006-09-07 17:52:14 +02002336 /* If the use of more than one ADC is requested for the current
2337 * model, configure a second analog capture-only PCM.
2338 */
2339 /* Additional Analaog capture for index #2 */
Takashi Iwaic2d986b2011-07-06 18:30:08 +02002340 if (spec->alt_dac_nid || spec->num_adc_nids > 1) {
Takashi Iwaie08a0072006-09-07 17:52:14 +02002341 codec->num_pcms = 3;
Takashi Iwaic06134d2006-10-11 18:49:13 +02002342 info = spec->pcm_rec + 2;
Takashi Iwaie08a0072006-09-07 17:52:14 +02002343 info->name = spec->stream_name_analog;
Takashi Iwai63300792008-01-24 15:31:36 +01002344 if (spec->alt_dac_nid) {
Takashi Iwaic2d986b2011-07-06 18:30:08 +02002345 p = spec->stream_analog_alt_playback;
2346 if (!p)
2347 p = &alc_pcm_analog_alt_playback;
2348 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p;
Takashi Iwai63300792008-01-24 15:31:36 +01002349 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
2350 spec->alt_dac_nid;
2351 } else {
2352 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
2353 alc_pcm_null_stream;
2354 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
2355 }
Takashi Iwaic2d986b2011-07-06 18:30:08 +02002356 if (spec->num_adc_nids > 1) {
2357 p = spec->stream_analog_alt_capture;
2358 if (!p)
2359 p = &alc_pcm_analog_alt_capture;
2360 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p;
Takashi Iwai63300792008-01-24 15:31:36 +01002361 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
2362 spec->adc_nids[1];
2363 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams =
2364 spec->num_adc_nids - 1;
2365 } else {
2366 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
2367 alc_pcm_null_stream;
2368 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0;
Takashi Iwaie08a0072006-09-07 17:52:14 +02002369 }
2370 }
2371
Linus Torvalds1da177e2005-04-16 15:20:36 -07002372 return 0;
2373}
2374
Takashi Iwaia4e09aa2009-12-27 11:22:24 +01002375static inline void alc_shutup(struct hda_codec *codec)
2376{
Takashi Iwai1c7161532011-04-07 10:37:16 +02002377 struct alc_spec *spec = codec->spec;
2378
2379 if (spec && spec->shutup)
2380 spec->shutup(codec);
Takashi Iwaia4e09aa2009-12-27 11:22:24 +01002381 snd_hda_shutup_pins(codec);
2382}
2383
Takashi Iwai603c4012008-07-30 15:01:44 +02002384static void alc_free_kctls(struct hda_codec *codec)
2385{
2386 struct alc_spec *spec = codec->spec;
2387
2388 if (spec->kctls.list) {
2389 struct snd_kcontrol_new *kctl = spec->kctls.list;
2390 int i;
2391 for (i = 0; i < spec->kctls.used; i++)
2392 kfree(kctl[i].name);
2393 }
2394 snd_array_free(&spec->kctls);
2395}
2396
Takashi Iwai23c09b02011-08-19 09:05:35 +02002397static void alc_free_bind_ctls(struct hda_codec *codec)
2398{
2399 struct alc_spec *spec = codec->spec;
2400 if (spec->bind_ctls.list) {
2401 struct hda_bind_ctls **ctl = spec->bind_ctls.list;
2402 int i;
2403 for (i = 0; i < spec->bind_ctls.used; i++)
2404 kfree(ctl[i]);
2405 }
2406 snd_array_free(&spec->bind_ctls);
2407}
2408
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409static void alc_free(struct hda_codec *codec)
2410{
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002411 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002412
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002413 if (!spec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002414 return;
2415
Takashi Iwaia4e09aa2009-12-27 11:22:24 +01002416 alc_shutup(codec);
Takashi Iwaicd372fb2011-03-03 14:40:14 +01002417 snd_hda_input_jack_free(codec);
Takashi Iwai603c4012008-07-30 15:01:44 +02002418 alc_free_kctls(codec);
Takashi Iwai23c09b02011-08-19 09:05:35 +02002419 alc_free_bind_ctls(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002420 kfree(spec);
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09002421 snd_hda_detach_beep_device(codec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422}
2423
Hector Martinf5de24b2009-12-20 22:51:31 +01002424#ifdef CONFIG_SND_HDA_POWER_SAVE
Daniel T Chenc97259d2009-12-27 18:52:08 -05002425static void alc_power_eapd(struct hda_codec *codec)
2426{
Takashi Iwai691f1fc2011-04-07 10:31:43 +02002427 alc_auto_setup_eapd(codec, false);
Daniel T Chenc97259d2009-12-27 18:52:08 -05002428}
2429
Hector Martinf5de24b2009-12-20 22:51:31 +01002430static int alc_suspend(struct hda_codec *codec, pm_message_t state)
2431{
2432 struct alc_spec *spec = codec->spec;
Takashi Iwaia4e09aa2009-12-27 11:22:24 +01002433 alc_shutup(codec);
Hector Martinf5de24b2009-12-20 22:51:31 +01002434 if (spec && spec->power_hook)
Daniel T Chenc97259d2009-12-27 18:52:08 -05002435 spec->power_hook(codec);
Hector Martinf5de24b2009-12-20 22:51:31 +01002436 return 0;
2437}
2438#endif
2439
Takashi Iwai2a439522011-07-26 09:52:50 +02002440#ifdef CONFIG_PM
Takashi Iwaie044c392008-10-27 16:56:24 +01002441static int alc_resume(struct hda_codec *codec)
2442{
Takashi Iwai1c7161532011-04-07 10:37:16 +02002443 msleep(150); /* to avoid pop noise */
Takashi Iwaie044c392008-10-27 16:56:24 +01002444 codec->patch_ops.init(codec);
2445 snd_hda_codec_resume_amp(codec);
2446 snd_hda_codec_resume_cache(codec);
Takashi Iwai9e5341b2010-09-21 09:57:06 +02002447 hda_call_check_power_status(codec, 0x01);
Takashi Iwaie044c392008-10-27 16:56:24 +01002448 return 0;
2449}
Takashi Iwaie044c392008-10-27 16:56:24 +01002450#endif
2451
Linus Torvalds1da177e2005-04-16 15:20:36 -07002452/*
2453 */
Takashi Iwaia9111322011-05-02 11:30:18 +02002454static const struct hda_codec_ops alc_patch_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002455 .build_controls = alc_build_controls,
2456 .build_pcms = alc_build_pcms,
2457 .init = alc_init,
2458 .free = alc_free,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002459 .unsol_event = alc_unsol_event,
Takashi Iwai2a439522011-07-26 09:52:50 +02002460#ifdef CONFIG_PM
Takashi Iwaie044c392008-10-27 16:56:24 +01002461 .resume = alc_resume,
2462#endif
Takashi Iwaicb53c622007-08-10 17:21:45 +02002463#ifdef CONFIG_SND_HDA_POWER_SAVE
Hector Martinf5de24b2009-12-20 22:51:31 +01002464 .suspend = alc_suspend,
Takashi Iwaicb53c622007-08-10 17:21:45 +02002465 .check_power_status = alc_check_power_status,
2466#endif
Daniel T Chenc97259d2009-12-27 18:52:08 -05002467 .reboot_notify = alc_shutup,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002468};
2469
Kailang Yangc027ddc2010-03-19 11:33:06 +01002470/* replace the codec chip_name with the given string */
2471static int alc_codec_rename(struct hda_codec *codec, const char *name)
2472{
2473 kfree(codec->chip_name);
2474 codec->chip_name = kstrdup(name, GFP_KERNEL);
2475 if (!codec->chip_name) {
2476 alc_free(codec);
2477 return -ENOMEM;
2478 }
2479 return 0;
2480}
2481
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002482/*
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02002483 * Rename codecs appropriately from COEF value
2484 */
2485struct alc_codec_rename_table {
2486 unsigned int vendor_id;
2487 unsigned short coef_mask;
2488 unsigned short coef_bits;
2489 const char *name;
2490};
2491
2492static struct alc_codec_rename_table rename_tbl[] = {
2493 { 0x10ec0269, 0xfff0, 0x3010, "ALC277" },
2494 { 0x10ec0269, 0xf0f0, 0x2010, "ALC259" },
2495 { 0x10ec0269, 0xf0f0, 0x3010, "ALC258" },
2496 { 0x10ec0269, 0x00f0, 0x0010, "ALC269VB" },
2497 { 0x10ec0269, 0xffff, 0xa023, "ALC259" },
2498 { 0x10ec0269, 0xffff, 0x6023, "ALC281X" },
2499 { 0x10ec0269, 0x00f0, 0x0020, "ALC269VC" },
2500 { 0x10ec0887, 0x00f0, 0x0030, "ALC887-VD" },
2501 { 0x10ec0888, 0x00f0, 0x0030, "ALC888-VD" },
2502 { 0x10ec0888, 0xf0f0, 0x3020, "ALC886" },
2503 { 0x10ec0899, 0x2000, 0x2000, "ALC899" },
2504 { 0x10ec0892, 0xffff, 0x8020, "ALC661" },
2505 { 0x10ec0892, 0xffff, 0x8011, "ALC661" },
2506 { 0x10ec0892, 0xffff, 0x4011, "ALC656" },
2507 { } /* terminator */
2508};
2509
2510static int alc_codec_rename_from_preset(struct hda_codec *codec)
2511{
2512 const struct alc_codec_rename_table *p;
2513 unsigned short coef;
2514
2515 for (p = rename_tbl; p->vendor_id; p++) {
2516 if (p->vendor_id != codec->vendor_id)
2517 continue;
2518 coef = alc_read_coef_idx(codec, 0);
2519 if ((coef & p->coef_mask) == p->coef_bits)
2520 return alc_codec_rename(codec, p->name);
2521 }
2522 return 0;
2523}
2524
2525/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002526 * Automatic parse of I/O pins from the BIOS configuration
2527 */
2528
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002529enum {
2530 ALC_CTL_WIDGET_VOL,
2531 ALC_CTL_WIDGET_MUTE,
2532 ALC_CTL_BIND_MUTE,
Takashi Iwai23c09b02011-08-19 09:05:35 +02002533 ALC_CTL_BIND_VOL,
2534 ALC_CTL_BIND_SW,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002535};
Takashi Iwai1d045db2011-07-07 18:23:21 +02002536static const struct snd_kcontrol_new alc_control_templates[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002537 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
2538 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Takashi Iwai985be542005-11-02 18:26:49 +01002539 HDA_BIND_MUTE(NULL, 0, 0, 0),
Takashi Iwai23c09b02011-08-19 09:05:35 +02002540 HDA_BIND_VOL(NULL, 0),
2541 HDA_BIND_SW(NULL, 0),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002542};
2543
2544/* add dynamic controls */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002545static int add_control(struct alc_spec *spec, int type, const char *name,
Takashi Iwai66ceeb62010-08-30 13:05:52 +02002546 int cidx, unsigned long val)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002547{
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002548 struct snd_kcontrol_new *knew;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002549
Takashi Iwaice764ab2011-04-27 16:35:23 +02002550 knew = alc_kcontrol_new(spec);
Takashi Iwai603c4012008-07-30 15:01:44 +02002551 if (!knew)
2552 return -ENOMEM;
Takashi Iwai1d045db2011-07-07 18:23:21 +02002553 *knew = alc_control_templates[type];
Paulo Marques543537b2005-06-23 00:09:02 -07002554 knew->name = kstrdup(name, GFP_KERNEL);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002555 if (!knew->name)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002556 return -ENOMEM;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02002557 knew->index = cidx;
Jaroslav Kysela4d02d1b2009-11-12 10:15:48 +01002558 if (get_amp_nid_(val))
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +01002559 knew->subdevice = HDA_SUBDEV_AMP_FLAG;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002560 knew->private_value = val;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002561 return 0;
2562}
2563
Takashi Iwai0afe5f82009-10-02 09:20:00 +02002564static int add_control_with_pfx(struct alc_spec *spec, int type,
2565 const char *pfx, const char *dir,
Takashi Iwai66ceeb62010-08-30 13:05:52 +02002566 const char *sfx, int cidx, unsigned long val)
Takashi Iwai0afe5f82009-10-02 09:20:00 +02002567{
2568 char name[32];
2569 snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx);
Takashi Iwai66ceeb62010-08-30 13:05:52 +02002570 return add_control(spec, type, name, cidx, val);
Takashi Iwai0afe5f82009-10-02 09:20:00 +02002571}
2572
Takashi Iwai66ceeb62010-08-30 13:05:52 +02002573#define add_pb_vol_ctrl(spec, type, pfx, val) \
2574 add_control_with_pfx(spec, type, pfx, "Playback", "Volume", 0, val)
2575#define add_pb_sw_ctrl(spec, type, pfx, val) \
2576 add_control_with_pfx(spec, type, pfx, "Playback", "Switch", 0, val)
2577#define __add_pb_vol_ctrl(spec, type, pfx, cidx, val) \
2578 add_control_with_pfx(spec, type, pfx, "Playback", "Volume", cidx, val)
2579#define __add_pb_sw_ctrl(spec, type, pfx, cidx, val) \
2580 add_control_with_pfx(spec, type, pfx, "Playback", "Switch", cidx, val)
Takashi Iwai0afe5f82009-10-02 09:20:00 +02002581
Takashi Iwai23c09b02011-08-19 09:05:35 +02002582static const char * const channel_name[4] = {
2583 "Front", "Surround", "CLFE", "Side"
2584};
2585
Takashi Iwai6843ca12011-06-24 11:03:58 +02002586static const char *alc_get_line_out_pfx(struct alc_spec *spec, int ch,
2587 bool can_be_master, int *index)
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01002588{
Takashi Iwaice764ab2011-04-27 16:35:23 +02002589 struct auto_pin_cfg *cfg = &spec->autocfg;
2590
Takashi Iwai6843ca12011-06-24 11:03:58 +02002591 *index = 0;
Takashi Iwaice764ab2011-04-27 16:35:23 +02002592 if (cfg->line_outs == 1 && !spec->multi_ios &&
2593 !cfg->hp_outs && !cfg->speaker_outs && can_be_master)
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01002594 return "Master";
2595
2596 switch (cfg->line_out_type) {
2597 case AUTO_PIN_SPEAKER_OUT:
David Henningssonebbeb3d2011-03-04 14:08:30 +01002598 if (cfg->line_outs == 1)
2599 return "Speaker";
2600 break;
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01002601 case AUTO_PIN_HP_OUT:
Takashi Iwai6843ca12011-06-24 11:03:58 +02002602 /* for multi-io case, only the primary out */
2603 if (ch && spec->multi_ios)
2604 break;
2605 *index = ch;
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01002606 return "Headphone";
2607 default:
Takashi Iwaice764ab2011-04-27 16:35:23 +02002608 if (cfg->line_outs == 1 && !spec->multi_ios)
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01002609 return "PCM";
2610 break;
2611 }
Takashi Iwai23c09b02011-08-19 09:05:35 +02002612 if (snd_BUG_ON(ch >= ARRAY_SIZE(channel_name)))
2613 return "PCM";
2614
2615 return channel_name[ch];
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01002616}
2617
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002618/* create input playback/capture controls for the given pin */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002619static int new_analog_input(struct alc_spec *spec, hda_nid_t pin,
Takashi Iwai66ceeb62010-08-30 13:05:52 +02002620 const char *ctlname, int ctlidx,
Kailang Yangdf694da2005-12-05 19:42:22 +01002621 int idx, hda_nid_t mix_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002622{
Kailang Yangdf694da2005-12-05 19:42:22 +01002623 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002624
Takashi Iwai66ceeb62010-08-30 13:05:52 +02002625 err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname, ctlidx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002626 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
2627 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002628 return err;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02002629 err = __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname, ctlidx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002630 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
2631 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002632 return err;
2633 return 0;
2634}
2635
Takashi Iwai05f5f472009-08-25 13:10:18 +02002636static int alc_is_input_pin(struct hda_codec *codec, hda_nid_t nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002637{
Takashi Iwai05f5f472009-08-25 13:10:18 +02002638 unsigned int pincap = snd_hda_query_pin_caps(codec, nid);
2639 return (pincap & AC_PINCAP_IN) != 0;
2640}
2641
Takashi Iwai1d045db2011-07-07 18:23:21 +02002642/* Parse the codec tree and retrieve ADCs and corresponding capsrc MUXs */
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02002643static int alc_auto_fill_adc_caps(struct hda_codec *codec)
Takashi Iwaib7821702011-07-06 15:12:46 +02002644{
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02002645 struct alc_spec *spec = codec->spec;
Takashi Iwaib7821702011-07-06 15:12:46 +02002646 hda_nid_t nid;
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02002647 hda_nid_t *adc_nids = spec->private_adc_nids;
2648 hda_nid_t *cap_nids = spec->private_capsrc_nids;
2649 int max_nums = ARRAY_SIZE(spec->private_adc_nids);
2650 bool indep_capsrc = false;
Takashi Iwaib7821702011-07-06 15:12:46 +02002651 int i, nums = 0;
2652
2653 nid = codec->start_nid;
2654 for (i = 0; i < codec->num_nodes; i++, nid++) {
2655 hda_nid_t src;
2656 const hda_nid_t *list;
2657 unsigned int caps = get_wcaps(codec, nid);
2658 int type = get_wcaps_type(caps);
2659
2660 if (type != AC_WID_AUD_IN || (caps & AC_WCAP_DIGITAL))
2661 continue;
2662 adc_nids[nums] = nid;
2663 cap_nids[nums] = nid;
2664 src = nid;
2665 for (;;) {
2666 int n;
2667 type = get_wcaps_type(get_wcaps(codec, src));
2668 if (type == AC_WID_PIN)
2669 break;
2670 if (type == AC_WID_AUD_SEL) {
2671 cap_nids[nums] = src;
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02002672 indep_capsrc = true;
Takashi Iwaib7821702011-07-06 15:12:46 +02002673 break;
2674 }
2675 n = snd_hda_get_conn_list(codec, src, &list);
2676 if (n > 1) {
2677 cap_nids[nums] = src;
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02002678 indep_capsrc = true;
Takashi Iwaib7821702011-07-06 15:12:46 +02002679 break;
2680 } else if (n != 1)
2681 break;
2682 src = *list;
2683 }
2684 if (++nums >= max_nums)
2685 break;
2686 }
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02002687 spec->adc_nids = spec->private_adc_nids;
Takashi Iwai21268962011-07-07 15:01:13 +02002688 spec->capsrc_nids = spec->private_capsrc_nids;
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02002689 spec->num_adc_nids = nums;
Takashi Iwaib7821702011-07-06 15:12:46 +02002690 return nums;
2691}
2692
Takashi Iwai05f5f472009-08-25 13:10:18 +02002693/* create playback/capture controls for input pins */
Takashi Iwaib7821702011-07-06 15:12:46 +02002694static int alc_auto_create_input_ctls(struct hda_codec *codec)
Takashi Iwai05f5f472009-08-25 13:10:18 +02002695{
2696 struct alc_spec *spec = codec->spec;
Takashi Iwaib7821702011-07-06 15:12:46 +02002697 const struct auto_pin_cfg *cfg = &spec->autocfg;
2698 hda_nid_t mixer = spec->mixer_nid;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02002699 struct hda_input_mux *imux = &spec->private_imux[0];
Takashi Iwaib7821702011-07-06 15:12:46 +02002700 int num_adcs;
Takashi Iwaib7821702011-07-06 15:12:46 +02002701 int i, c, err, idx, type_idx = 0;
David Henningsson5322bf22011-01-05 11:03:56 +01002702 const char *prev_label = NULL;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002703
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02002704 num_adcs = alc_auto_fill_adc_caps(codec);
Takashi Iwaib7821702011-07-06 15:12:46 +02002705 if (num_adcs < 0)
2706 return 0;
2707
Takashi Iwai66ceeb62010-08-30 13:05:52 +02002708 for (i = 0; i < cfg->num_inputs; i++) {
Takashi Iwai05f5f472009-08-25 13:10:18 +02002709 hda_nid_t pin;
Takashi Iwai10a20af2010-09-09 16:28:02 +02002710 const char *label;
Takashi Iwai05f5f472009-08-25 13:10:18 +02002711
Takashi Iwai66ceeb62010-08-30 13:05:52 +02002712 pin = cfg->inputs[i].pin;
Takashi Iwai05f5f472009-08-25 13:10:18 +02002713 if (!alc_is_input_pin(codec, pin))
2714 continue;
2715
David Henningsson5322bf22011-01-05 11:03:56 +01002716 label = hda_get_autocfg_input_label(codec, cfg, i);
2717 if (prev_label && !strcmp(label, prev_label))
Takashi Iwai66ceeb62010-08-30 13:05:52 +02002718 type_idx++;
2719 else
2720 type_idx = 0;
David Henningsson5322bf22011-01-05 11:03:56 +01002721 prev_label = label;
2722
Takashi Iwai05f5f472009-08-25 13:10:18 +02002723 if (mixer) {
2724 idx = get_connection_index(codec, mixer, pin);
2725 if (idx >= 0) {
2726 err = new_analog_input(spec, pin,
Takashi Iwai10a20af2010-09-09 16:28:02 +02002727 label, type_idx,
2728 idx, mixer);
Takashi Iwai05f5f472009-08-25 13:10:18 +02002729 if (err < 0)
2730 return err;
2731 }
2732 }
2733
Takashi Iwaib7821702011-07-06 15:12:46 +02002734 for (c = 0; c < num_adcs; c++) {
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02002735 hda_nid_t cap = spec->capsrc_nids ?
2736 spec->capsrc_nids[c] : spec->adc_nids[c];
2737 idx = get_connection_index(codec, cap, pin);
Takashi Iwaib7821702011-07-06 15:12:46 +02002738 if (idx >= 0) {
Takashi Iwai21268962011-07-07 15:01:13 +02002739 spec->imux_pins[imux->num_items] = pin;
Takashi Iwaib7821702011-07-06 15:12:46 +02002740 snd_hda_add_imux_item(imux, label, idx, NULL);
2741 break;
2742 }
2743 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002744 }
Takashi Iwai21268962011-07-07 15:01:13 +02002745
2746 spec->num_mux_defs = 1;
2747 spec->input_mux = imux;
2748
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002749 return 0;
2750}
2751
Takashi Iwaif6c7e542008-02-12 18:32:23 +01002752static void alc_set_pin_output(struct hda_codec *codec, hda_nid_t nid,
2753 unsigned int pin_type)
2754{
2755 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
2756 pin_type);
2757 /* unmute pin */
Takashi Iwai44c02402011-07-08 15:14:19 +02002758 if (nid_has_mute(codec, nid, HDA_OUTPUT))
2759 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwaid260cdf2008-02-13 17:19:35 +01002760 AMP_OUT_UNMUTE);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01002761}
2762
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02002763static int get_pin_type(int line_out_type)
2764{
2765 if (line_out_type == AUTO_PIN_HP_OUT)
2766 return PIN_HP;
2767 else
2768 return PIN_OUT;
2769}
2770
Takashi Iwai0a7f5322011-07-06 15:15:12 +02002771static void alc_auto_init_analog_input(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002772{
2773 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02002774 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002775 int i;
2776
Takashi Iwai66ceeb62010-08-30 13:05:52 +02002777 for (i = 0; i < cfg->num_inputs; i++) {
2778 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai05f5f472009-08-25 13:10:18 +02002779 if (alc_is_input_pin(codec, nid)) {
Takashi Iwai30ea0982010-09-16 18:47:56 +02002780 alc_set_input_pin(codec, nid, cfg->inputs[i].type);
Takashi Iwai1f0f4b82011-06-27 10:52:59 +02002781 if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002782 snd_hda_codec_write(codec, nid, 0,
2783 AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002784 AMP_OUT_MUTE);
2785 }
2786 }
Takashi Iwai1f0f4b82011-06-27 10:52:59 +02002787
2788 /* mute all loopback inputs */
2789 if (spec->mixer_nid) {
2790 int nums = snd_hda_get_conn_list(codec, spec->mixer_nid, NULL);
2791 for (i = 0; i < nums; i++)
2792 snd_hda_codec_write(codec, spec->mixer_nid, 0,
2793 AC_VERB_SET_AMP_GAIN_MUTE,
2794 AMP_IN_MUTE(i));
2795 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002796}
2797
Takashi Iwai7085ec12009-10-02 09:03:58 +02002798/* convert from MIX nid to DAC */
Takashi Iwai604401a2011-04-27 15:14:23 +02002799static hda_nid_t alc_auto_mix_to_dac(struct hda_codec *codec, hda_nid_t nid)
Takashi Iwai7085ec12009-10-02 09:03:58 +02002800{
Takashi Iwai604401a2011-04-27 15:14:23 +02002801 hda_nid_t list[5];
Takashi Iwai1304ac82011-04-06 15:16:21 +02002802 int i, num;
2803
Takashi Iwaiafcd5512011-07-08 11:07:59 +02002804 if (get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_AUD_OUT)
2805 return nid;
Takashi Iwai1304ac82011-04-06 15:16:21 +02002806 num = snd_hda_get_connections(codec, nid, list, ARRAY_SIZE(list));
2807 for (i = 0; i < num; i++) {
2808 if (get_wcaps_type(get_wcaps(codec, list[i])) == AC_WID_AUD_OUT)
2809 return list[i];
2810 }
2811 return 0;
Takashi Iwai7085ec12009-10-02 09:03:58 +02002812}
2813
Takashi Iwai604401a2011-04-27 15:14:23 +02002814/* go down to the selector widget before the mixer */
2815static hda_nid_t alc_go_down_to_selector(struct hda_codec *codec, hda_nid_t pin)
2816{
2817 hda_nid_t srcs[5];
2818 int num = snd_hda_get_connections(codec, pin, srcs,
2819 ARRAY_SIZE(srcs));
2820 if (num != 1 ||
2821 get_wcaps_type(get_wcaps(codec, srcs[0])) != AC_WID_AUD_SEL)
2822 return pin;
2823 return srcs[0];
2824}
2825
Takashi Iwai7085ec12009-10-02 09:03:58 +02002826/* get MIX nid connected to the given pin targeted to DAC */
Takashi Iwai604401a2011-04-27 15:14:23 +02002827static hda_nid_t alc_auto_dac_to_mix(struct hda_codec *codec, hda_nid_t pin,
Takashi Iwai7085ec12009-10-02 09:03:58 +02002828 hda_nid_t dac)
2829{
David Henningssoncc1c4522010-11-24 14:17:47 +01002830 hda_nid_t mix[5];
Takashi Iwai7085ec12009-10-02 09:03:58 +02002831 int i, num;
2832
Takashi Iwai604401a2011-04-27 15:14:23 +02002833 pin = alc_go_down_to_selector(codec, pin);
Takashi Iwai7085ec12009-10-02 09:03:58 +02002834 num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix));
2835 for (i = 0; i < num; i++) {
Takashi Iwai604401a2011-04-27 15:14:23 +02002836 if (alc_auto_mix_to_dac(codec, mix[i]) == dac)
Takashi Iwai7085ec12009-10-02 09:03:58 +02002837 return mix[i];
2838 }
2839 return 0;
2840}
2841
Takashi Iwaice764ab2011-04-27 16:35:23 +02002842/* select the connection from pin to DAC if needed */
2843static int alc_auto_select_dac(struct hda_codec *codec, hda_nid_t pin,
2844 hda_nid_t dac)
2845{
2846 hda_nid_t mix[5];
2847 int i, num;
2848
2849 pin = alc_go_down_to_selector(codec, pin);
2850 num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix));
2851 if (num < 2)
2852 return 0;
2853 for (i = 0; i < num; i++) {
2854 if (alc_auto_mix_to_dac(codec, mix[i]) == dac) {
2855 snd_hda_codec_update_cache(codec, pin, 0,
2856 AC_VERB_SET_CONNECT_SEL, i);
2857 return 0;
2858 }
2859 }
2860 return 0;
2861}
2862
Takashi Iwai7085ec12009-10-02 09:03:58 +02002863/* look for an empty DAC slot */
Takashi Iwai604401a2011-04-27 15:14:23 +02002864static hda_nid_t alc_auto_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
Takashi Iwai7085ec12009-10-02 09:03:58 +02002865{
2866 struct alc_spec *spec = codec->spec;
2867 hda_nid_t srcs[5];
Takashi Iwai3af9ee62011-06-27 12:34:01 +02002868 int i, num;
Takashi Iwai7085ec12009-10-02 09:03:58 +02002869
Takashi Iwai604401a2011-04-27 15:14:23 +02002870 pin = alc_go_down_to_selector(codec, pin);
Takashi Iwai7085ec12009-10-02 09:03:58 +02002871 num = snd_hda_get_connections(codec, pin, srcs, ARRAY_SIZE(srcs));
Takashi Iwai7085ec12009-10-02 09:03:58 +02002872 for (i = 0; i < num; i++) {
Takashi Iwai604401a2011-04-27 15:14:23 +02002873 hda_nid_t nid = alc_auto_mix_to_dac(codec, srcs[i]);
Takashi Iwai7085ec12009-10-02 09:03:58 +02002874 if (!nid)
2875 continue;
Takashi Iwai3af9ee62011-06-27 12:34:01 +02002876 if (found_in_nid_list(nid, spec->multiout.dac_nids,
2877 spec->multiout.num_dacs))
2878 continue;
Takashi Iwaic2674682011-08-24 17:57:44 +02002879 if (found_in_nid_list(nid, spec->multiout.hp_out_nid,
2880 ARRAY_SIZE(spec->multiout.hp_out_nid)))
2881 continue;
Takashi Iwai3af9ee62011-06-27 12:34:01 +02002882 if (found_in_nid_list(nid, spec->multiout.extra_out_nid,
2883 ARRAY_SIZE(spec->multiout.extra_out_nid)))
2884 continue;
2885 return nid;
Takashi Iwai7085ec12009-10-02 09:03:58 +02002886 }
2887 return 0;
2888}
2889
Takashi Iwai3af9ee62011-06-27 12:34:01 +02002890static hda_nid_t get_dac_if_single(struct hda_codec *codec, hda_nid_t pin)
2891{
2892 hda_nid_t sel = alc_go_down_to_selector(codec, pin);
2893 if (snd_hda_get_conn_list(codec, sel, NULL) == 1)
2894 return alc_auto_look_for_dac(codec, pin);
2895 return 0;
2896}
2897
Takashi Iwaic2674682011-08-24 17:57:44 +02002898static int alc_auto_fill_extra_dacs(struct hda_codec *codec, int num_outs,
2899 const hda_nid_t *pins, hda_nid_t *dacs)
2900{
2901 int i;
2902
2903 if (num_outs && !dacs[0]) {
2904 dacs[0] = alc_auto_look_for_dac(codec, pins[0]);
2905 if (!dacs[0])
2906 return 0;
2907 }
2908
2909 for (i = 1; i < num_outs; i++)
2910 dacs[i] = get_dac_if_single(codec, pins[i]);
2911 for (i = 1; i < num_outs; i++) {
2912 if (!dacs[i])
2913 dacs[i] = alc_auto_look_for_dac(codec, pins[i]);
2914 }
2915 return 0;
2916}
2917
2918static int alc_auto_fill_multi_ios(struct hda_codec *codec,
2919 unsigned int location);
2920
Takashi Iwai7085ec12009-10-02 09:03:58 +02002921/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwai343a04b2011-07-06 14:28:39 +02002922static int alc_auto_fill_dac_nids(struct hda_codec *codec)
Takashi Iwai7085ec12009-10-02 09:03:58 +02002923{
2924 struct alc_spec *spec = codec->spec;
Takashi Iwaicb053a82011-06-27 11:32:07 +02002925 const struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwai350434e2011-06-30 21:29:12 +02002926 bool redone = false;
Takashi Iwai7085ec12009-10-02 09:03:58 +02002927 int i;
Takashi Iwai7085ec12009-10-02 09:03:58 +02002928
Takashi Iwai3af9ee62011-06-27 12:34:01 +02002929 again:
Takashi Iwai8f398ae2011-07-23 18:57:11 +02002930 /* set num_dacs once to full for alc_auto_look_for_dac() */
2931 spec->multiout.num_dacs = cfg->line_outs;
Takashi Iwaie23832a2011-08-23 18:16:56 +02002932 spec->multiout.hp_out_nid[0] = 0;
Takashi Iwai3af9ee62011-06-27 12:34:01 +02002933 spec->multiout.extra_out_nid[0] = 0;
2934 memset(spec->private_dac_nids, 0, sizeof(spec->private_dac_nids));
2935 spec->multiout.dac_nids = spec->private_dac_nids;
2936
2937 /* fill hard-wired DACs first */
2938 if (!redone) {
2939 for (i = 0; i < cfg->line_outs; i++)
2940 spec->private_dac_nids[i] =
2941 get_dac_if_single(codec, cfg->line_out_pins[i]);
2942 if (cfg->hp_outs)
Takashi Iwaie23832a2011-08-23 18:16:56 +02002943 spec->multiout.hp_out_nid[0] =
Takashi Iwai3af9ee62011-06-27 12:34:01 +02002944 get_dac_if_single(codec, cfg->hp_pins[0]);
2945 if (cfg->speaker_outs)
2946 spec->multiout.extra_out_nid[0] =
2947 get_dac_if_single(codec, cfg->speaker_pins[0]);
Takashi Iwai7085ec12009-10-02 09:03:58 +02002948 }
Takashi Iwai3af9ee62011-06-27 12:34:01 +02002949
2950 for (i = 0; i < cfg->line_outs; i++) {
2951 hda_nid_t pin = cfg->line_out_pins[i];
2952 if (spec->private_dac_nids[i])
2953 continue;
2954 spec->private_dac_nids[i] = alc_auto_look_for_dac(codec, pin);
2955 if (!spec->private_dac_nids[i] && !redone) {
2956 /* if we can't find primary DACs, re-probe without
2957 * checking the hard-wired DACs
2958 */
2959 redone = true;
2960 goto again;
2961 }
2962 }
2963
Takashi Iwai8f398ae2011-07-23 18:57:11 +02002964 /* re-count num_dacs and squash invalid entries */
2965 spec->multiout.num_dacs = 0;
Takashi Iwai3af9ee62011-06-27 12:34:01 +02002966 for (i = 0; i < cfg->line_outs; i++) {
2967 if (spec->private_dac_nids[i])
2968 spec->multiout.num_dacs++;
2969 else
2970 memmove(spec->private_dac_nids + i,
2971 spec->private_dac_nids + i + 1,
2972 sizeof(hda_nid_t) * (cfg->line_outs - i - 1));
2973 }
2974
Takashi Iwaic2674682011-08-24 17:57:44 +02002975 if (cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
2976 /* try to fill multi-io first */
2977 unsigned int location, defcfg;
2978 int num_pins;
Takashi Iwaibb8bf4d2011-07-06 13:07:54 +02002979
Takashi Iwaic2674682011-08-24 17:57:44 +02002980 defcfg = snd_hda_codec_get_pincfg(codec, cfg->line_out_pins[0]);
2981 location = get_defcfg_location(defcfg);
Takashi Iwai7085ec12009-10-02 09:03:58 +02002982
Takashi Iwaic2674682011-08-24 17:57:44 +02002983 num_pins = alc_auto_fill_multi_ios(codec, location);
2984 if (num_pins > 0) {
2985 spec->multi_ios = num_pins;
2986 spec->ext_channel_count = 2;
2987 spec->multiout.num_dacs = num_pins + 1;
2988 }
Takashi Iwai23c09b02011-08-19 09:05:35 +02002989 }
Takashi Iwaic2674682011-08-24 17:57:44 +02002990
2991 alc_auto_fill_extra_dacs(codec, cfg->hp_outs, cfg->hp_pins,
2992 spec->multiout.hp_out_nid);
2993 alc_auto_fill_extra_dacs(codec, cfg->speaker_outs, cfg->speaker_pins,
2994 spec->multiout.extra_out_nid);
2995
Takashi Iwai23c09b02011-08-19 09:05:35 +02002996 return 0;
2997}
2998
Takashi Iwai343a04b2011-07-06 14:28:39 +02002999static int alc_auto_add_vol_ctl(struct hda_codec *codec,
Takashi Iwai97aaab72011-07-06 14:02:55 +02003000 const char *pfx, int cidx,
3001 hda_nid_t nid, unsigned int chs)
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003002{
Takashi Iwaiafcd5512011-07-08 11:07:59 +02003003 if (!nid)
3004 return 0;
Takashi Iwai97aaab72011-07-06 14:02:55 +02003005 return __add_pb_vol_ctrl(codec->spec, ALC_CTL_WIDGET_VOL, pfx, cidx,
3006 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
Takashi Iwai7085ec12009-10-02 09:03:58 +02003007}
3008
Takashi Iwai343a04b2011-07-06 14:28:39 +02003009#define alc_auto_add_stereo_vol(codec, pfx, cidx, nid) \
3010 alc_auto_add_vol_ctl(codec, pfx, cidx, nid, 3)
Takashi Iwai97aaab72011-07-06 14:02:55 +02003011
3012/* create a mute-switch for the given mixer widget;
3013 * if it has multiple sources (e.g. DAC and loopback), create a bind-mute
3014 */
Takashi Iwai343a04b2011-07-06 14:28:39 +02003015static int alc_auto_add_sw_ctl(struct hda_codec *codec,
Takashi Iwai97aaab72011-07-06 14:02:55 +02003016 const char *pfx, int cidx,
3017 hda_nid_t nid, unsigned int chs)
Takashi Iwai7085ec12009-10-02 09:03:58 +02003018{
Takashi Iwaiafcd5512011-07-08 11:07:59 +02003019 int wid_type;
Takashi Iwai97aaab72011-07-06 14:02:55 +02003020 int type;
3021 unsigned long val;
Takashi Iwaiafcd5512011-07-08 11:07:59 +02003022 if (!nid)
3023 return 0;
3024 wid_type = get_wcaps_type(get_wcaps(codec, nid));
3025 if (wid_type == AC_WID_PIN || wid_type == AC_WID_AUD_OUT) {
3026 type = ALC_CTL_WIDGET_MUTE;
3027 val = HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT);
3028 } else if (snd_hda_get_conn_list(codec, nid, NULL) == 1) {
Takashi Iwai97aaab72011-07-06 14:02:55 +02003029 type = ALC_CTL_WIDGET_MUTE;
3030 val = HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_INPUT);
3031 } else {
3032 type = ALC_CTL_BIND_MUTE;
3033 val = HDA_COMPOSE_AMP_VAL(nid, chs, 2, HDA_INPUT);
3034 }
3035 return __add_pb_sw_ctrl(codec->spec, type, pfx, cidx, val);
Takashi Iwai7085ec12009-10-02 09:03:58 +02003036}
3037
Takashi Iwai343a04b2011-07-06 14:28:39 +02003038#define alc_auto_add_stereo_sw(codec, pfx, cidx, nid) \
3039 alc_auto_add_sw_ctl(codec, pfx, cidx, nid, 3)
Takashi Iwai7085ec12009-10-02 09:03:58 +02003040
Takashi Iwaiafcd5512011-07-08 11:07:59 +02003041static hda_nid_t alc_look_for_out_mute_nid(struct hda_codec *codec,
3042 hda_nid_t pin, hda_nid_t dac)
3043{
3044 hda_nid_t mix = alc_auto_dac_to_mix(codec, pin, dac);
3045 if (nid_has_mute(codec, pin, HDA_OUTPUT))
3046 return pin;
3047 else if (mix && nid_has_mute(codec, mix, HDA_INPUT))
3048 return mix;
3049 else if (nid_has_mute(codec, dac, HDA_OUTPUT))
3050 return dac;
3051 return 0;
3052}
3053
3054static hda_nid_t alc_look_for_out_vol_nid(struct hda_codec *codec,
3055 hda_nid_t pin, hda_nid_t dac)
3056{
3057 hda_nid_t mix = alc_auto_dac_to_mix(codec, pin, dac);
3058 if (nid_has_volume(codec, dac, HDA_OUTPUT))
3059 return dac;
3060 else if (nid_has_volume(codec, mix, HDA_OUTPUT))
3061 return mix;
3062 else if (nid_has_volume(codec, pin, HDA_OUTPUT))
3063 return pin;
3064 return 0;
3065}
3066
Takashi Iwai7085ec12009-10-02 09:03:58 +02003067/* add playback controls from the parsed DAC table */
Takashi Iwai343a04b2011-07-06 14:28:39 +02003068static int alc_auto_create_multi_out_ctls(struct hda_codec *codec,
Takashi Iwai7085ec12009-10-02 09:03:58 +02003069 const struct auto_pin_cfg *cfg)
3070{
3071 struct alc_spec *spec = codec->spec;
Takashi Iwaice764ab2011-04-27 16:35:23 +02003072 int i, err, noutputs;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003073
Takashi Iwaice764ab2011-04-27 16:35:23 +02003074 noutputs = cfg->line_outs;
3075 if (spec->multi_ios > 0)
3076 noutputs += spec->multi_ios;
3077
3078 for (i = 0; i < noutputs; i++) {
Takashi Iwai6843ca12011-06-24 11:03:58 +02003079 const char *name;
3080 int index;
Takashi Iwaiafcd5512011-07-08 11:07:59 +02003081 hda_nid_t dac, pin;
3082 hda_nid_t sw, vol;
3083
3084 dac = spec->multiout.dac_nids[i];
3085 if (!dac)
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003086 continue;
Takashi Iwaice764ab2011-04-27 16:35:23 +02003087 if (i >= cfg->line_outs)
3088 pin = spec->multi_io[i - 1].pin;
3089 else
3090 pin = cfg->line_out_pins[i];
Takashi Iwaiafcd5512011-07-08 11:07:59 +02003091
3092 sw = alc_look_for_out_mute_nid(codec, pin, dac);
3093 vol = alc_look_for_out_vol_nid(codec, pin, dac);
Takashi Iwai6843ca12011-06-24 11:03:58 +02003094 name = alc_get_line_out_pfx(spec, i, true, &index);
Takashi Iwai9c4e84d2011-08-24 17:27:52 +02003095 if (!name || !strcmp(name, "CLFE")) {
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003096 /* Center/LFE */
Takashi Iwaiafcd5512011-07-08 11:07:59 +02003097 err = alc_auto_add_vol_ctl(codec, "Center", 0, vol, 1);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003098 if (err < 0)
3099 return err;
Takashi Iwaiafcd5512011-07-08 11:07:59 +02003100 err = alc_auto_add_vol_ctl(codec, "LFE", 0, vol, 2);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003101 if (err < 0)
3102 return err;
Takashi Iwaiafcd5512011-07-08 11:07:59 +02003103 err = alc_auto_add_sw_ctl(codec, "Center", 0, sw, 1);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003104 if (err < 0)
3105 return err;
Takashi Iwaiafcd5512011-07-08 11:07:59 +02003106 err = alc_auto_add_sw_ctl(codec, "LFE", 0, sw, 2);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003107 if (err < 0)
3108 return err;
3109 } else {
Takashi Iwaiafcd5512011-07-08 11:07:59 +02003110 err = alc_auto_add_stereo_vol(codec, name, index, vol);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003111 if (err < 0)
3112 return err;
Takashi Iwaiafcd5512011-07-08 11:07:59 +02003113 err = alc_auto_add_stereo_sw(codec, name, index, sw);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003114 if (err < 0)
3115 return err;
3116 }
3117 }
3118 return 0;
3119}
3120
Takashi Iwai343a04b2011-07-06 14:28:39 +02003121static int alc_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
Takashi Iwai23c09b02011-08-19 09:05:35 +02003122 hda_nid_t dac, const char *pfx)
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003123{
Takashi Iwai7085ec12009-10-02 09:03:58 +02003124 struct alc_spec *spec = codec->spec;
Takashi Iwaiafcd5512011-07-08 11:07:59 +02003125 hda_nid_t sw, vol;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003126 int err;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003127
Takashi Iwai3af9ee62011-06-27 12:34:01 +02003128 if (!dac) {
Takashi Iwai7085ec12009-10-02 09:03:58 +02003129 /* the corresponding DAC is already occupied */
3130 if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP))
3131 return 0; /* no way */
3132 /* create a switch only */
Takashi Iwai0afe5f82009-10-02 09:20:00 +02003133 return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +02003134 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
3135 }
3136
Takashi Iwaiafcd5512011-07-08 11:07:59 +02003137 sw = alc_look_for_out_mute_nid(codec, pin, dac);
3138 vol = alc_look_for_out_vol_nid(codec, pin, dac);
3139 err = alc_auto_add_stereo_vol(codec, pfx, 0, vol);
Takashi Iwai7085ec12009-10-02 09:03:58 +02003140 if (err < 0)
Takashi Iwai24fb9172008-09-02 14:48:20 +02003141 return err;
Takashi Iwaiafcd5512011-07-08 11:07:59 +02003142 err = alc_auto_add_stereo_sw(codec, pfx, 0, sw);
Takashi Iwai7085ec12009-10-02 09:03:58 +02003143 if (err < 0)
3144 return err;
Takashi Iwai3af9ee62011-06-27 12:34:01 +02003145 return 0;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003146}
3147
Takashi Iwai23c09b02011-08-19 09:05:35 +02003148static struct hda_bind_ctls *new_bind_ctl(struct hda_codec *codec,
3149 unsigned int nums,
3150 struct hda_ctl_ops *ops)
3151{
3152 struct alc_spec *spec = codec->spec;
3153 struct hda_bind_ctls **ctlp, *ctl;
3154 snd_array_init(&spec->bind_ctls, sizeof(ctl), 8);
3155 ctlp = snd_array_new(&spec->bind_ctls);
3156 if (!ctlp)
3157 return NULL;
3158 ctl = kzalloc(sizeof(*ctl) + sizeof(long) * (nums + 1), GFP_KERNEL);
3159 *ctlp = ctl;
3160 if (ctl)
3161 ctl->ops = ops;
3162 return ctl;
3163}
3164
3165/* add playback controls for speaker and HP outputs */
3166static int alc_auto_create_extra_outs(struct hda_codec *codec, int num_pins,
3167 const hda_nid_t *pins,
3168 const hda_nid_t *dacs,
3169 const char *pfx)
3170{
3171 struct alc_spec *spec = codec->spec;
3172 struct hda_bind_ctls *ctl;
3173 char name[32];
3174 int i, n, err;
3175
3176 if (!num_pins || !pins[0])
3177 return 0;
3178
3179 if (num_pins == 1)
3180 return alc_auto_create_extra_out(codec, *pins, *dacs, pfx);
3181
3182 if (dacs[num_pins - 1]) {
3183 /* OK, we have a multi-output system with individual volumes */
3184 for (i = 0; i < num_pins; i++) {
3185 snprintf(name, sizeof(name), "%s %s",
3186 pfx, channel_name[i]);
3187 err = alc_auto_create_extra_out(codec, pins[i], dacs[i],
3188 name);
3189 if (err < 0)
3190 return err;
3191 }
3192 return 0;
3193 }
3194
3195 /* Let's create a bind-controls */
3196 ctl = new_bind_ctl(codec, num_pins, &snd_hda_bind_sw);
3197 if (!ctl)
3198 return -ENOMEM;
3199 n = 0;
3200 for (i = 0; i < num_pins; i++) {
3201 if (get_wcaps(codec, pins[i]) & AC_WCAP_OUT_AMP)
3202 ctl->values[n++] =
3203 HDA_COMPOSE_AMP_VAL(pins[i], 3, 0, HDA_OUTPUT);
3204 }
3205 if (n) {
3206 snprintf(name, sizeof(name), "%s Playback Switch", pfx);
3207 err = add_control(spec, ALC_CTL_BIND_SW, name, 0, (long)ctl);
3208 if (err < 0)
3209 return err;
3210 }
3211
3212 ctl = new_bind_ctl(codec, num_pins, &snd_hda_bind_vol);
3213 if (!ctl)
3214 return -ENOMEM;
3215 n = 0;
3216 for (i = 0; i < num_pins; i++) {
3217 hda_nid_t vol;
3218 if (!pins[i] || !dacs[i])
3219 continue;
3220 vol = alc_look_for_out_vol_nid(codec, pins[i], dacs[i]);
3221 if (vol)
3222 ctl->values[n++] =
3223 HDA_COMPOSE_AMP_VAL(vol, 3, 0, HDA_OUTPUT);
3224 }
3225 if (n) {
3226 snprintf(name, sizeof(name), "%s Playback Volume", pfx);
3227 err = add_control(spec, ALC_CTL_BIND_VOL, name, 0, (long)ctl);
3228 if (err < 0)
3229 return err;
3230 }
3231 return 0;
3232}
3233
Takashi Iwai343a04b2011-07-06 14:28:39 +02003234static int alc_auto_create_hp_out(struct hda_codec *codec)
3235{
3236 struct alc_spec *spec = codec->spec;
Takashi Iwaie23832a2011-08-23 18:16:56 +02003237 return alc_auto_create_extra_outs(codec, spec->autocfg.hp_outs,
3238 spec->autocfg.hp_pins,
3239 spec->multiout.hp_out_nid,
3240 "Headphone");
Takashi Iwai343a04b2011-07-06 14:28:39 +02003241}
3242
3243static int alc_auto_create_speaker_out(struct hda_codec *codec)
3244{
3245 struct alc_spec *spec = codec->spec;
Takashi Iwai23c09b02011-08-19 09:05:35 +02003246 return alc_auto_create_extra_outs(codec, spec->autocfg.speaker_outs,
3247 spec->autocfg.speaker_pins,
3248 spec->multiout.extra_out_nid,
3249 "Speaker");
Takashi Iwai343a04b2011-07-06 14:28:39 +02003250}
3251
Takashi Iwai343a04b2011-07-06 14:28:39 +02003252static void alc_auto_set_output_and_unmute(struct hda_codec *codec,
Takashi Iwaiafcd5512011-07-08 11:07:59 +02003253 hda_nid_t pin, int pin_type,
Takashi Iwai7085ec12009-10-02 09:03:58 +02003254 hda_nid_t dac)
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003255{
Takashi Iwai7085ec12009-10-02 09:03:58 +02003256 int i, num;
Takashi Iwaiafcd5512011-07-08 11:07:59 +02003257 hda_nid_t nid, mix = 0;
Takashi Iwaice503f32010-07-30 10:37:29 +02003258 hda_nid_t srcs[HDA_MAX_CONNECTIONS];
Takashi Iwai7085ec12009-10-02 09:03:58 +02003259
Takashi Iwaiafcd5512011-07-08 11:07:59 +02003260 alc_set_pin_output(codec, pin, pin_type);
3261 nid = alc_go_down_to_selector(codec, pin);
Takashi Iwai7085ec12009-10-02 09:03:58 +02003262 num = snd_hda_get_connections(codec, nid, srcs, ARRAY_SIZE(srcs));
Takashi Iwai7085ec12009-10-02 09:03:58 +02003263 for (i = 0; i < num; i++) {
Takashi Iwai604401a2011-04-27 15:14:23 +02003264 if (alc_auto_mix_to_dac(codec, srcs[i]) != dac)
Takashi Iwai7085ec12009-10-02 09:03:58 +02003265 continue;
Takashi Iwaicd511552011-07-06 13:10:42 +02003266 mix = srcs[i];
3267 break;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003268 }
Takashi Iwaicd511552011-07-06 13:10:42 +02003269 if (!mix)
3270 return;
3271
3272 /* need the manual connection? */
3273 if (num > 1)
3274 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, i);
3275 /* unmute mixer widget inputs */
Takashi Iwaiafcd5512011-07-08 11:07:59 +02003276 if (nid_has_mute(codec, mix, HDA_INPUT)) {
3277 snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwaicd511552011-07-06 13:10:42 +02003278 AMP_IN_UNMUTE(0));
Takashi Iwaiafcd5512011-07-08 11:07:59 +02003279 snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwaicd511552011-07-06 13:10:42 +02003280 AMP_IN_UNMUTE(1));
Takashi Iwaiafcd5512011-07-08 11:07:59 +02003281 }
Takashi Iwaicd511552011-07-06 13:10:42 +02003282 /* initialize volume */
Takashi Iwaiafcd5512011-07-08 11:07:59 +02003283 nid = alc_look_for_out_vol_nid(codec, pin, dac);
3284 if (nid)
3285 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
3286 AMP_OUT_ZERO);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003287}
3288
Takashi Iwai343a04b2011-07-06 14:28:39 +02003289static void alc_auto_init_multi_out(struct hda_codec *codec)
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003290{
3291 struct alc_spec *spec = codec->spec;
Takashi Iwai7085ec12009-10-02 09:03:58 +02003292 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003293 int i;
3294
3295 for (i = 0; i <= HDA_SIDE; i++) {
3296 hda_nid_t nid = spec->autocfg.line_out_pins[i];
3297 if (nid)
Takashi Iwai343a04b2011-07-06 14:28:39 +02003298 alc_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwai7085ec12009-10-02 09:03:58 +02003299 spec->multiout.dac_nids[i]);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003300 }
3301}
3302
Takashi Iwai343a04b2011-07-06 14:28:39 +02003303static void alc_auto_init_extra_out(struct hda_codec *codec)
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003304{
3305 struct alc_spec *spec = codec->spec;
Takashi Iwai8cd07752011-08-23 15:16:22 +02003306 int i;
Takashi Iwai675c1aa2011-08-23 12:36:28 +02003307 hda_nid_t pin, dac;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003308
David Henningsson636030e2011-10-12 19:26:03 +02003309 for (i = 0; i < spec->autocfg.hp_outs; i++) {
Takashi Iwaie23832a2011-08-23 18:16:56 +02003310 pin = spec->autocfg.hp_pins[i];
3311 if (!pin)
3312 break;
3313 dac = spec->multiout.hp_out_nid[i];
3314 if (!dac) {
3315 if (i > 0 && spec->multiout.hp_out_nid[0])
3316 dac = spec->multiout.hp_out_nid[0];
3317 else
3318 dac = spec->multiout.dac_nids[0];
3319 }
Takashi Iwai675c1aa2011-08-23 12:36:28 +02003320 alc_auto_set_output_and_unmute(codec, pin, PIN_HP, dac);
3321 }
Takashi Iwai8cd07752011-08-23 15:16:22 +02003322 for (i = 0; i < spec->autocfg.speaker_outs; i++) {
3323 pin = spec->autocfg.speaker_pins[i];
3324 if (!pin)
3325 break;
3326 dac = spec->multiout.extra_out_nid[i];
3327 if (!dac) {
3328 if (i > 0 && spec->multiout.extra_out_nid[0])
3329 dac = spec->multiout.extra_out_nid[0];
3330 else
3331 dac = spec->multiout.dac_nids[0];
3332 }
Takashi Iwai675c1aa2011-08-23 12:36:28 +02003333 alc_auto_set_output_and_unmute(codec, pin, PIN_OUT, dac);
3334 }
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003335}
3336
Takashi Iwaice764ab2011-04-27 16:35:23 +02003337/*
3338 * multi-io helper
3339 */
3340static int alc_auto_fill_multi_ios(struct hda_codec *codec,
3341 unsigned int location)
3342{
3343 struct alc_spec *spec = codec->spec;
3344 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwaic2674682011-08-24 17:57:44 +02003345 hda_nid_t prime_dac = spec->private_dac_nids[0];
Takashi Iwaice764ab2011-04-27 16:35:23 +02003346 int type, i, num_pins = 0;
3347
3348 for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) {
3349 for (i = 0; i < cfg->num_inputs; i++) {
3350 hda_nid_t nid = cfg->inputs[i].pin;
3351 hda_nid_t dac;
3352 unsigned int defcfg, caps;
3353 if (cfg->inputs[i].type != type)
3354 continue;
3355 defcfg = snd_hda_codec_get_pincfg(codec, nid);
3356 if (get_defcfg_connect(defcfg) != AC_JACK_PORT_COMPLEX)
3357 continue;
3358 if (location && get_defcfg_location(defcfg) != location)
3359 continue;
3360 caps = snd_hda_query_pin_caps(codec, nid);
3361 if (!(caps & AC_PINCAP_OUT))
3362 continue;
3363 dac = alc_auto_look_for_dac(codec, nid);
3364 if (!dac)
3365 continue;
3366 spec->multi_io[num_pins].pin = nid;
3367 spec->multi_io[num_pins].dac = dac;
3368 num_pins++;
Takashi Iwaidda14412011-05-02 11:29:30 +02003369 spec->private_dac_nids[spec->multiout.num_dacs++] = dac;
Takashi Iwaice764ab2011-04-27 16:35:23 +02003370 }
3371 }
3372 spec->multiout.num_dacs = 1;
Takashi Iwaic2674682011-08-24 17:57:44 +02003373 if (num_pins < 2) {
3374 /* clear up again */
3375 memset(spec->private_dac_nids, 0,
3376 sizeof(spec->private_dac_nids));
3377 spec->private_dac_nids[0] = prime_dac;
Takashi Iwaice764ab2011-04-27 16:35:23 +02003378 return 0;
Takashi Iwaic2674682011-08-24 17:57:44 +02003379 }
Takashi Iwaice764ab2011-04-27 16:35:23 +02003380 return num_pins;
3381}
3382
3383static int alc_auto_ch_mode_info(struct snd_kcontrol *kcontrol,
3384 struct snd_ctl_elem_info *uinfo)
3385{
3386 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3387 struct alc_spec *spec = codec->spec;
3388
3389 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
3390 uinfo->count = 1;
3391 uinfo->value.enumerated.items = spec->multi_ios + 1;
3392 if (uinfo->value.enumerated.item > spec->multi_ios)
3393 uinfo->value.enumerated.item = spec->multi_ios;
3394 sprintf(uinfo->value.enumerated.name, "%dch",
3395 (uinfo->value.enumerated.item + 1) * 2);
3396 return 0;
3397}
3398
3399static int alc_auto_ch_mode_get(struct snd_kcontrol *kcontrol,
3400 struct snd_ctl_elem_value *ucontrol)
3401{
3402 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3403 struct alc_spec *spec = codec->spec;
3404 ucontrol->value.enumerated.item[0] = (spec->ext_channel_count - 1) / 2;
3405 return 0;
3406}
3407
3408static int alc_set_multi_io(struct hda_codec *codec, int idx, bool output)
3409{
3410 struct alc_spec *spec = codec->spec;
3411 hda_nid_t nid = spec->multi_io[idx].pin;
3412
3413 if (!spec->multi_io[idx].ctl_in)
3414 spec->multi_io[idx].ctl_in =
3415 snd_hda_codec_read(codec, nid, 0,
3416 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
3417 if (output) {
3418 snd_hda_codec_update_cache(codec, nid, 0,
3419 AC_VERB_SET_PIN_WIDGET_CONTROL,
3420 PIN_OUT);
3421 if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
3422 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
3423 HDA_AMP_MUTE, 0);
3424 alc_auto_select_dac(codec, nid, spec->multi_io[idx].dac);
3425 } else {
3426 if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
3427 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
3428 HDA_AMP_MUTE, HDA_AMP_MUTE);
3429 snd_hda_codec_update_cache(codec, nid, 0,
3430 AC_VERB_SET_PIN_WIDGET_CONTROL,
3431 spec->multi_io[idx].ctl_in);
3432 }
3433 return 0;
3434}
3435
3436static int alc_auto_ch_mode_put(struct snd_kcontrol *kcontrol,
3437 struct snd_ctl_elem_value *ucontrol)
3438{
3439 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3440 struct alc_spec *spec = codec->spec;
3441 int i, ch;
3442
3443 ch = ucontrol->value.enumerated.item[0];
3444 if (ch < 0 || ch > spec->multi_ios)
3445 return -EINVAL;
3446 if (ch == (spec->ext_channel_count - 1) / 2)
3447 return 0;
3448 spec->ext_channel_count = (ch + 1) * 2;
3449 for (i = 0; i < spec->multi_ios; i++)
3450 alc_set_multi_io(codec, i, i < ch);
3451 spec->multiout.max_channels = spec->ext_channel_count;
Takashi Iwai7b1655f2011-07-14 15:31:21 +02003452 if (spec->need_dac_fix && !spec->const_channel_count)
3453 spec->multiout.num_dacs = spec->multiout.max_channels / 2;
Takashi Iwaice764ab2011-04-27 16:35:23 +02003454 return 1;
3455}
3456
Takashi Iwaia9111322011-05-02 11:30:18 +02003457static const struct snd_kcontrol_new alc_auto_channel_mode_enum = {
Takashi Iwaice764ab2011-04-27 16:35:23 +02003458 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3459 .name = "Channel Mode",
3460 .info = alc_auto_ch_mode_info,
3461 .get = alc_auto_ch_mode_get,
3462 .put = alc_auto_ch_mode_put,
3463};
3464
Takashi Iwai23c09b02011-08-19 09:05:35 +02003465static int alc_auto_add_multi_channel_mode(struct hda_codec *codec)
Takashi Iwaice764ab2011-04-27 16:35:23 +02003466{
3467 struct alc_spec *spec = codec->spec;
Takashi Iwaice764ab2011-04-27 16:35:23 +02003468
Takashi Iwaic2674682011-08-24 17:57:44 +02003469 if (spec->multi_ios > 0) {
Takashi Iwaice764ab2011-04-27 16:35:23 +02003470 struct snd_kcontrol_new *knew;
3471
3472 knew = alc_kcontrol_new(spec);
3473 if (!knew)
3474 return -ENOMEM;
3475 *knew = alc_auto_channel_mode_enum;
3476 knew->name = kstrdup("Channel Mode", GFP_KERNEL);
3477 if (!knew->name)
3478 return -ENOMEM;
Takashi Iwaice764ab2011-04-27 16:35:23 +02003479 }
3480 return 0;
3481}
3482
Takashi Iwai1d045db2011-07-07 18:23:21 +02003483/* filter out invalid adc_nids (and capsrc_nids) that don't give all
3484 * active input pins
3485 */
3486static void alc_remove_invalid_adc_nids(struct hda_codec *codec)
3487{
3488 struct alc_spec *spec = codec->spec;
3489 const struct hda_input_mux *imux;
3490 hda_nid_t adc_nids[ARRAY_SIZE(spec->private_adc_nids)];
3491 hda_nid_t capsrc_nids[ARRAY_SIZE(spec->private_adc_nids)];
3492 int i, n, nums;
3493
3494 imux = spec->input_mux;
3495 if (!imux)
3496 return;
3497 if (spec->dyn_adc_switch)
3498 return;
3499
3500 nums = 0;
3501 for (n = 0; n < spec->num_adc_nids; n++) {
3502 hda_nid_t cap = spec->private_capsrc_nids[n];
3503 int num_conns = snd_hda_get_conn_list(codec, cap, NULL);
3504 for (i = 0; i < imux->num_items; i++) {
3505 hda_nid_t pin = spec->imux_pins[i];
3506 if (pin) {
3507 if (get_connection_index(codec, cap, pin) < 0)
3508 break;
3509 } else if (num_conns <= imux->items[i].index)
3510 break;
3511 }
3512 if (i >= imux->num_items) {
3513 adc_nids[nums] = spec->private_adc_nids[n];
3514 capsrc_nids[nums++] = cap;
3515 }
3516 }
3517 if (!nums) {
3518 /* check whether ADC-switch is possible */
3519 if (!alc_check_dyn_adc_switch(codec)) {
3520 printk(KERN_WARNING "hda_codec: %s: no valid ADC found;"
3521 " using fallback 0x%x\n",
3522 codec->chip_name, spec->private_adc_nids[0]);
3523 spec->num_adc_nids = 1;
3524 spec->auto_mic = 0;
3525 return;
3526 }
3527 } else if (nums != spec->num_adc_nids) {
3528 memcpy(spec->private_adc_nids, adc_nids,
3529 nums * sizeof(hda_nid_t));
3530 memcpy(spec->private_capsrc_nids, capsrc_nids,
3531 nums * sizeof(hda_nid_t));
3532 spec->num_adc_nids = nums;
3533 }
3534
3535 if (spec->auto_mic)
3536 alc_auto_mic_check_imux(codec); /* check auto-mic setups */
3537 else if (spec->input_mux->num_items == 1)
3538 spec->num_adc_nids = 1; /* reduce to a single ADC */
3539}
3540
3541/*
3542 * initialize ADC paths
3543 */
3544static void alc_auto_init_adc(struct hda_codec *codec, int adc_idx)
3545{
3546 struct alc_spec *spec = codec->spec;
3547 hda_nid_t nid;
3548
3549 nid = spec->adc_nids[adc_idx];
3550 /* mute ADC */
Takashi Iwai44c02402011-07-08 15:14:19 +02003551 if (nid_has_mute(codec, nid, HDA_INPUT)) {
Takashi Iwai1d045db2011-07-07 18:23:21 +02003552 snd_hda_codec_write(codec, nid, 0,
3553 AC_VERB_SET_AMP_GAIN_MUTE,
3554 AMP_IN_MUTE(0));
3555 return;
3556 }
3557 if (!spec->capsrc_nids)
3558 return;
3559 nid = spec->capsrc_nids[adc_idx];
Takashi Iwai44c02402011-07-08 15:14:19 +02003560 if (nid_has_mute(codec, nid, HDA_OUTPUT))
Takashi Iwai1d045db2011-07-07 18:23:21 +02003561 snd_hda_codec_write(codec, nid, 0,
3562 AC_VERB_SET_AMP_GAIN_MUTE,
3563 AMP_OUT_MUTE);
3564}
3565
3566static void alc_auto_init_input_src(struct hda_codec *codec)
3567{
3568 struct alc_spec *spec = codec->spec;
3569 int c, nums;
3570
3571 for (c = 0; c < spec->num_adc_nids; c++)
3572 alc_auto_init_adc(codec, c);
3573 if (spec->dyn_adc_switch)
3574 nums = 1;
3575 else
3576 nums = spec->num_adc_nids;
3577 for (c = 0; c < nums; c++)
3578 alc_mux_select(codec, 0, spec->cur_mux[c], true);
3579}
3580
3581/* add mic boosts if needed */
3582static int alc_auto_add_mic_boost(struct hda_codec *codec)
3583{
3584 struct alc_spec *spec = codec->spec;
3585 struct auto_pin_cfg *cfg = &spec->autocfg;
3586 int i, err;
3587 int type_idx = 0;
3588 hda_nid_t nid;
3589 const char *prev_label = NULL;
3590
3591 for (i = 0; i < cfg->num_inputs; i++) {
3592 if (cfg->inputs[i].type > AUTO_PIN_MIC)
3593 break;
3594 nid = cfg->inputs[i].pin;
3595 if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) {
3596 const char *label;
3597 char boost_label[32];
3598
3599 label = hda_get_autocfg_input_label(codec, cfg, i);
3600 if (prev_label && !strcmp(label, prev_label))
3601 type_idx++;
3602 else
3603 type_idx = 0;
3604 prev_label = label;
3605
3606 snprintf(boost_label, sizeof(boost_label),
3607 "%s Boost Volume", label);
3608 err = add_control(spec, ALC_CTL_WIDGET_VOL,
3609 boost_label, type_idx,
3610 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
3611 if (err < 0)
3612 return err;
3613 }
3614 }
3615 return 0;
3616}
3617
3618/* select or unmute the given capsrc route */
3619static void select_or_unmute_capsrc(struct hda_codec *codec, hda_nid_t cap,
3620 int idx)
3621{
3622 if (get_wcaps_type(get_wcaps(codec, cap)) == AC_WID_AUD_MIX) {
3623 snd_hda_codec_amp_stereo(codec, cap, HDA_INPUT, idx,
3624 HDA_AMP_MUTE, 0);
3625 } else if (snd_hda_get_conn_list(codec, cap, NULL) > 1) {
3626 snd_hda_codec_write_cache(codec, cap, 0,
3627 AC_VERB_SET_CONNECT_SEL, idx);
3628 }
3629}
3630
3631/* set the default connection to that pin */
3632static int init_capsrc_for_pin(struct hda_codec *codec, hda_nid_t pin)
3633{
3634 struct alc_spec *spec = codec->spec;
3635 int i;
3636
3637 if (!pin)
3638 return 0;
3639 for (i = 0; i < spec->num_adc_nids; i++) {
3640 hda_nid_t cap = spec->capsrc_nids ?
3641 spec->capsrc_nids[i] : spec->adc_nids[i];
3642 int idx;
3643
3644 idx = get_connection_index(codec, cap, pin);
3645 if (idx < 0)
3646 continue;
3647 select_or_unmute_capsrc(codec, cap, idx);
3648 return i; /* return the found index */
3649 }
3650 return -1; /* not found */
3651}
3652
3653/* initialize some special cases for input sources */
3654static void alc_init_special_input_src(struct hda_codec *codec)
3655{
3656 struct alc_spec *spec = codec->spec;
3657 int i;
3658
3659 for (i = 0; i < spec->autocfg.num_inputs; i++)
3660 init_capsrc_for_pin(codec, spec->autocfg.inputs[i].pin);
3661}
3662
3663/* assign appropriate capture mixers */
3664static void set_capture_mixer(struct hda_codec *codec)
3665{
3666 struct alc_spec *spec = codec->spec;
3667 static const struct snd_kcontrol_new *caps[2][3] = {
3668 { alc_capture_mixer_nosrc1,
3669 alc_capture_mixer_nosrc2,
3670 alc_capture_mixer_nosrc3 },
3671 { alc_capture_mixer1,
3672 alc_capture_mixer2,
3673 alc_capture_mixer3 },
3674 };
3675
3676 /* check whether either of ADC or MUX has a volume control */
Takashi Iwai44c02402011-07-08 15:14:19 +02003677 if (!nid_has_volume(codec, spec->adc_nids[0], HDA_INPUT)) {
Takashi Iwai1d045db2011-07-07 18:23:21 +02003678 if (!spec->capsrc_nids)
3679 return; /* no volume */
Takashi Iwai44c02402011-07-08 15:14:19 +02003680 if (!nid_has_volume(codec, spec->capsrc_nids[0], HDA_OUTPUT))
Takashi Iwai1d045db2011-07-07 18:23:21 +02003681 return; /* no volume in capsrc, too */
3682 spec->vol_in_capsrc = 1;
3683 }
3684
3685 if (spec->num_adc_nids > 0) {
3686 int mux = 0;
3687 int num_adcs = 0;
3688
3689 if (spec->input_mux && spec->input_mux->num_items > 1)
3690 mux = 1;
3691 if (spec->auto_mic) {
3692 num_adcs = 1;
3693 mux = 0;
3694 } else if (spec->dyn_adc_switch)
3695 num_adcs = 1;
3696 if (!num_adcs) {
3697 if (spec->num_adc_nids > 3)
3698 spec->num_adc_nids = 3;
3699 else if (!spec->num_adc_nids)
3700 return;
3701 num_adcs = spec->num_adc_nids;
3702 }
3703 spec->cap_mixer = caps[mux][num_adcs - 1];
3704 }
3705}
3706
3707/*
Takashi Iwaie4770622011-07-08 11:11:35 +02003708 * standard auto-parser initializations
3709 */
3710static void alc_auto_init_std(struct hda_codec *codec)
3711{
3712 struct alc_spec *spec = codec->spec;
3713 alc_auto_init_multi_out(codec);
3714 alc_auto_init_extra_out(codec);
3715 alc_auto_init_analog_input(codec);
3716 alc_auto_init_input_src(codec);
3717 alc_auto_init_digital(codec);
3718 if (spec->unsol_event)
3719 alc_inithook(codec);
3720}
3721
3722/*
Takashi Iwai1d045db2011-07-07 18:23:21 +02003723 * Digital-beep handlers
3724 */
3725#ifdef CONFIG_SND_HDA_INPUT_BEEP
3726#define set_beep_amp(spec, nid, idx, dir) \
3727 ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir))
3728
3729static const struct snd_pci_quirk beep_white_list[] = {
3730 SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1),
3731 SND_PCI_QUIRK(0x1043, 0x83ce, "EeePC", 1),
3732 SND_PCI_QUIRK(0x1043, 0x831a, "EeePC", 1),
3733 SND_PCI_QUIRK(0x1043, 0x834a, "EeePC", 1),
3734 SND_PCI_QUIRK(0x8086, 0xd613, "Intel", 1),
3735 {}
3736};
3737
3738static inline int has_cdefine_beep(struct hda_codec *codec)
3739{
3740 struct alc_spec *spec = codec->spec;
3741 const struct snd_pci_quirk *q;
3742 q = snd_pci_quirk_lookup(codec->bus->pci, beep_white_list);
3743 if (q)
3744 return q->value;
3745 return spec->cdefine.enable_pcbeep;
3746}
3747#else
3748#define set_beep_amp(spec, nid, idx, dir) /* NOP */
3749#define has_cdefine_beep(codec) 0
3750#endif
3751
3752/* parse the BIOS configuration and set up the alc_spec */
3753/* return 1 if successful, 0 if the proper config is not found,
3754 * or a negative error code
3755 */
Takashi Iwai3e6179b2011-07-08 16:55:13 +02003756static int alc_parse_auto_config(struct hda_codec *codec,
3757 const hda_nid_t *ignore_nids,
3758 const hda_nid_t *ssid_nids)
Takashi Iwai1d045db2011-07-07 18:23:21 +02003759{
3760 struct alc_spec *spec = codec->spec;
Takashi Iwai23c09b02011-08-19 09:05:35 +02003761 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwai1d045db2011-07-07 18:23:21 +02003762 int err;
Takashi Iwai1d045db2011-07-07 18:23:21 +02003763
Takashi Iwai53c334a2011-08-23 18:27:14 +02003764 err = snd_hda_parse_pin_defcfg(codec, cfg, ignore_nids,
3765 spec->parse_flags);
Takashi Iwai1d045db2011-07-07 18:23:21 +02003766 if (err < 0)
3767 return err;
Takashi Iwai23c09b02011-08-19 09:05:35 +02003768 if (!cfg->line_outs) {
3769 if (cfg->dig_outs || cfg->dig_in_pin) {
Takashi Iwai3e6179b2011-07-08 16:55:13 +02003770 spec->multiout.max_channels = 2;
3771 spec->no_analog = 1;
3772 goto dig_only;
3773 }
Takashi Iwai1d045db2011-07-07 18:23:21 +02003774 return 0; /* can't find valid BIOS pin config */
Takashi Iwai3e6179b2011-07-08 16:55:13 +02003775 }
Takashi Iwai23c09b02011-08-19 09:05:35 +02003776
Takashi Iwai06503672011-10-06 08:27:19 +02003777 if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT &&
3778 cfg->line_outs <= cfg->hp_outs) {
Takashi Iwai23c09b02011-08-19 09:05:35 +02003779 /* use HP as primary out */
3780 cfg->speaker_outs = cfg->line_outs;
3781 memcpy(cfg->speaker_pins, cfg->line_out_pins,
3782 sizeof(cfg->speaker_pins));
3783 cfg->line_outs = cfg->hp_outs;
3784 memcpy(cfg->line_out_pins, cfg->hp_pins, sizeof(cfg->hp_pins));
3785 cfg->hp_outs = 0;
3786 memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins));
3787 cfg->line_out_type = AUTO_PIN_HP_OUT;
3788 }
3789
Takashi Iwai1d045db2011-07-07 18:23:21 +02003790 err = alc_auto_fill_dac_nids(codec);
3791 if (err < 0)
3792 return err;
Takashi Iwai23c09b02011-08-19 09:05:35 +02003793 err = alc_auto_add_multi_channel_mode(codec);
Takashi Iwai3e6179b2011-07-08 16:55:13 +02003794 if (err < 0)
3795 return err;
Takashi Iwai23c09b02011-08-19 09:05:35 +02003796 err = alc_auto_create_multi_out_ctls(codec, cfg);
Takashi Iwai1d045db2011-07-07 18:23:21 +02003797 if (err < 0)
3798 return err;
3799 err = alc_auto_create_hp_out(codec);
3800 if (err < 0)
3801 return err;
3802 err = alc_auto_create_speaker_out(codec);
3803 if (err < 0)
3804 return err;
3805 err = alc_auto_create_input_ctls(codec);
3806 if (err < 0)
3807 return err;
3808
3809 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
3810
Takashi Iwai3e6179b2011-07-08 16:55:13 +02003811 dig_only:
Takashi Iwai1d045db2011-07-07 18:23:21 +02003812 alc_auto_parse_digital(codec);
3813
Takashi Iwai3e6179b2011-07-08 16:55:13 +02003814 if (!spec->no_analog)
3815 alc_remove_invalid_adc_nids(codec);
3816
3817 if (ssid_nids)
3818 alc_ssid_check(codec, ssid_nids);
3819
3820 if (!spec->no_analog) {
3821 alc_auto_check_switches(codec);
3822 err = alc_auto_add_mic_boost(codec);
3823 if (err < 0)
3824 return err;
3825 }
3826
Takashi Iwai1d045db2011-07-07 18:23:21 +02003827 if (spec->kctls.list)
3828 add_mixer(spec, spec->kctls.list);
3829
Takashi Iwai1d045db2011-07-07 18:23:21 +02003830 return 1;
3831}
3832
Takashi Iwai3e6179b2011-07-08 16:55:13 +02003833static int alc880_parse_auto_config(struct hda_codec *codec)
3834{
3835 static const hda_nid_t alc880_ignore[] = { 0x1d, 0 };
3836 static const hda_nid_t alc880_ssids[] = { 0x15, 0x1b, 0x14, 0 };
3837 return alc_parse_auto_config(codec, alc880_ignore, alc880_ssids);
3838}
3839
Takashi Iwai1d045db2011-07-07 18:23:21 +02003840#ifdef CONFIG_SND_HDA_POWER_SAVE
3841static const struct hda_amp_list alc880_loopbacks[] = {
3842 { 0x0b, HDA_INPUT, 0 },
3843 { 0x0b, HDA_INPUT, 1 },
3844 { 0x0b, HDA_INPUT, 2 },
3845 { 0x0b, HDA_INPUT, 3 },
3846 { 0x0b, HDA_INPUT, 4 },
3847 { } /* end */
3848};
3849#endif
3850
3851/*
3852 * board setups
3853 */
3854#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
3855#define alc_board_config \
3856 snd_hda_check_board_config
3857#define alc_board_codec_sid_config \
3858 snd_hda_check_board_codec_sid_config
3859#include "alc_quirks.c"
3860#else
3861#define alc_board_config(codec, nums, models, tbl) -1
3862#define alc_board_codec_sid_config(codec, nums, models, tbl) -1
3863#define setup_preset(codec, x) /* NOP */
3864#endif
3865
3866/*
3867 * OK, here we have finally the patch for ALC880
3868 */
3869#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
3870#include "alc880_quirks.c"
3871#endif
3872
3873static int patch_alc880(struct hda_codec *codec)
3874{
3875 struct alc_spec *spec;
3876 int board_config;
3877 int err;
3878
3879 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3880 if (spec == NULL)
3881 return -ENOMEM;
3882
3883 codec->spec = spec;
3884
3885 spec->mixer_nid = 0x0b;
Takashi Iwai7b1655f2011-07-14 15:31:21 +02003886 spec->need_dac_fix = 1;
Takashi Iwai1d045db2011-07-07 18:23:21 +02003887
3888 board_config = alc_board_config(codec, ALC880_MODEL_LAST,
3889 alc880_models, alc880_cfg_tbl);
3890 if (board_config < 0) {
3891 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
3892 codec->chip_name);
3893 board_config = ALC_MODEL_AUTO;
3894 }
3895
3896 if (board_config == ALC_MODEL_AUTO) {
3897 /* automatic parse from the BIOS config */
3898 err = alc880_parse_auto_config(codec);
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02003899 if (err < 0)
3900 goto error;
Takashi Iwai1d045db2011-07-07 18:23:21 +02003901#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
3902 else if (!err) {
3903 printk(KERN_INFO
3904 "hda_codec: Cannot set up configuration "
3905 "from BIOS. Using 3-stack mode...\n");
3906 board_config = ALC880_3ST;
3907 }
3908#endif
3909 }
3910
Takashi Iwai1d045db2011-07-07 18:23:21 +02003911 if (board_config != ALC_MODEL_AUTO)
3912 setup_preset(codec, &alc880_presets[board_config]);
3913
Takashi Iwai60a6a842011-07-27 14:01:24 +02003914 if (!spec->no_analog && !spec->adc_nids) {
Takashi Iwai1d045db2011-07-07 18:23:21 +02003915 alc_auto_fill_adc_caps(codec);
3916 alc_rebuild_imux_for_auto_mic(codec);
3917 alc_remove_invalid_adc_nids(codec);
3918 }
Takashi Iwai3e6179b2011-07-08 16:55:13 +02003919
3920 if (!spec->no_analog && !spec->cap_mixer)
3921 set_capture_mixer(codec);
3922
3923 if (!spec->no_analog) {
3924 err = snd_hda_attach_beep_device(codec, 0x1);
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02003925 if (err < 0)
3926 goto error;
Takashi Iwai3e6179b2011-07-08 16:55:13 +02003927 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
3928 }
Takashi Iwai1d045db2011-07-07 18:23:21 +02003929
3930 spec->vmaster_nid = 0x0c;
3931
3932 codec->patch_ops = alc_patch_ops;
3933 if (board_config == ALC_MODEL_AUTO)
Takashi Iwaie4770622011-07-08 11:11:35 +02003934 spec->init_hook = alc_auto_init_std;
Takashi Iwai1d045db2011-07-07 18:23:21 +02003935#ifdef CONFIG_SND_HDA_POWER_SAVE
3936 if (!spec->loopback.amplist)
3937 spec->loopback.amplist = alc880_loopbacks;
3938#endif
3939
3940 return 0;
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02003941
3942 error:
3943 alc_free(codec);
3944 return err;
Takashi Iwai1d045db2011-07-07 18:23:21 +02003945}
3946
3947
3948/*
3949 * ALC260 support
3950 */
Takashi Iwai1d045db2011-07-07 18:23:21 +02003951static int alc260_parse_auto_config(struct hda_codec *codec)
3952{
Takashi Iwai1d045db2011-07-07 18:23:21 +02003953 static const hda_nid_t alc260_ignore[] = { 0x17, 0 };
Takashi Iwai3e6179b2011-07-08 16:55:13 +02003954 static const hda_nid_t alc260_ssids[] = { 0x10, 0x15, 0x0f, 0 };
3955 return alc_parse_auto_config(codec, alc260_ignore, alc260_ssids);
Takashi Iwai1d045db2011-07-07 18:23:21 +02003956}
3957
Takashi Iwai1d045db2011-07-07 18:23:21 +02003958#ifdef CONFIG_SND_HDA_POWER_SAVE
3959static const struct hda_amp_list alc260_loopbacks[] = {
3960 { 0x07, HDA_INPUT, 0 },
3961 { 0x07, HDA_INPUT, 1 },
3962 { 0x07, HDA_INPUT, 2 },
3963 { 0x07, HDA_INPUT, 3 },
3964 { 0x07, HDA_INPUT, 4 },
3965 { } /* end */
3966};
3967#endif
3968
3969/*
3970 * Pin config fixes
3971 */
3972enum {
3973 PINFIX_HP_DC5750,
3974};
3975
3976static const struct alc_fixup alc260_fixups[] = {
3977 [PINFIX_HP_DC5750] = {
3978 .type = ALC_FIXUP_PINS,
3979 .v.pins = (const struct alc_pincfg[]) {
3980 { 0x11, 0x90130110 }, /* speaker */
3981 { }
3982 }
3983 },
3984};
3985
3986static const struct snd_pci_quirk alc260_fixup_tbl[] = {
3987 SND_PCI_QUIRK(0x103c, 0x280a, "HP dc5750", PINFIX_HP_DC5750),
3988 {}
3989};
3990
3991/*
3992 */
3993#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
3994#include "alc260_quirks.c"
3995#endif
3996
3997static int patch_alc260(struct hda_codec *codec)
3998{
3999 struct alc_spec *spec;
4000 int err, board_config;
4001
4002 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4003 if (spec == NULL)
4004 return -ENOMEM;
4005
4006 codec->spec = spec;
4007
4008 spec->mixer_nid = 0x07;
4009
4010 board_config = alc_board_config(codec, ALC260_MODEL_LAST,
4011 alc260_models, alc260_cfg_tbl);
4012 if (board_config < 0) {
4013 snd_printd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
4014 codec->chip_name);
4015 board_config = ALC_MODEL_AUTO;
4016 }
4017
4018 if (board_config == ALC_MODEL_AUTO) {
4019 alc_pick_fixup(codec, NULL, alc260_fixup_tbl, alc260_fixups);
4020 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
4021 }
4022
4023 if (board_config == ALC_MODEL_AUTO) {
4024 /* automatic parse from the BIOS config */
4025 err = alc260_parse_auto_config(codec);
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02004026 if (err < 0)
4027 goto error;
Takashi Iwai1d045db2011-07-07 18:23:21 +02004028#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
4029 else if (!err) {
4030 printk(KERN_INFO
4031 "hda_codec: Cannot set up configuration "
4032 "from BIOS. Using base mode...\n");
4033 board_config = ALC260_BASIC;
4034 }
4035#endif
4036 }
4037
Takashi Iwai1d045db2011-07-07 18:23:21 +02004038 if (board_config != ALC_MODEL_AUTO)
4039 setup_preset(codec, &alc260_presets[board_config]);
4040
Takashi Iwai60a6a842011-07-27 14:01:24 +02004041 if (!spec->no_analog && !spec->adc_nids) {
Takashi Iwai1d045db2011-07-07 18:23:21 +02004042 alc_auto_fill_adc_caps(codec);
4043 alc_rebuild_imux_for_auto_mic(codec);
4044 alc_remove_invalid_adc_nids(codec);
4045 }
Takashi Iwai3e6179b2011-07-08 16:55:13 +02004046
4047 if (!spec->no_analog && !spec->cap_mixer)
4048 set_capture_mixer(codec);
4049
4050 if (!spec->no_analog) {
4051 err = snd_hda_attach_beep_device(codec, 0x1);
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02004052 if (err < 0)
4053 goto error;
Takashi Iwai3e6179b2011-07-08 16:55:13 +02004054 set_beep_amp(spec, 0x07, 0x05, HDA_INPUT);
4055 }
Takashi Iwai1d045db2011-07-07 18:23:21 +02004056
4057 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
4058
4059 spec->vmaster_nid = 0x08;
4060
4061 codec->patch_ops = alc_patch_ops;
4062 if (board_config == ALC_MODEL_AUTO)
Takashi Iwai8452a982011-07-08 16:19:48 +02004063 spec->init_hook = alc_auto_init_std;
Takashi Iwai1d045db2011-07-07 18:23:21 +02004064 spec->shutup = alc_eapd_shutup;
4065#ifdef CONFIG_SND_HDA_POWER_SAVE
4066 if (!spec->loopback.amplist)
4067 spec->loopback.amplist = alc260_loopbacks;
4068#endif
4069
4070 return 0;
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02004071
4072 error:
4073 alc_free(codec);
4074 return err;
Takashi Iwai1d045db2011-07-07 18:23:21 +02004075}
4076
4077
4078/*
4079 * ALC882/883/885/888/889 support
4080 *
4081 * ALC882 is almost identical with ALC880 but has cleaner and more flexible
4082 * configuration. Each pin widget can choose any input DACs and a mixer.
4083 * Each ADC is connected from a mixer of all inputs. This makes possible
4084 * 6-channel independent captures.
4085 *
4086 * In addition, an independent DAC for the multi-playback (not used in this
4087 * driver yet).
4088 */
4089#ifdef CONFIG_SND_HDA_POWER_SAVE
4090#define alc882_loopbacks alc880_loopbacks
4091#endif
4092
4093/*
4094 * Pin config fixes
4095 */
4096enum {
4097 PINFIX_ABIT_AW9D_MAX,
4098 PINFIX_LENOVO_Y530,
4099 PINFIX_PB_M5210,
4100 PINFIX_ACER_ASPIRE_7736,
4101};
4102
4103static const struct alc_fixup alc882_fixups[] = {
4104 [PINFIX_ABIT_AW9D_MAX] = {
4105 .type = ALC_FIXUP_PINS,
4106 .v.pins = (const struct alc_pincfg[]) {
4107 { 0x15, 0x01080104 }, /* side */
4108 { 0x16, 0x01011012 }, /* rear */
4109 { 0x17, 0x01016011 }, /* clfe */
4110 { }
4111 }
4112 },
4113 [PINFIX_LENOVO_Y530] = {
4114 .type = ALC_FIXUP_PINS,
4115 .v.pins = (const struct alc_pincfg[]) {
4116 { 0x15, 0x99130112 }, /* rear int speakers */
4117 { 0x16, 0x99130111 }, /* subwoofer */
4118 { }
4119 }
4120 },
4121 [PINFIX_PB_M5210] = {
4122 .type = ALC_FIXUP_VERBS,
4123 .v.verbs = (const struct hda_verb[]) {
4124 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 },
4125 {}
4126 }
4127 },
4128 [PINFIX_ACER_ASPIRE_7736] = {
4129 .type = ALC_FIXUP_SKU,
4130 .v.sku = ALC_FIXUP_SKU_IGNORE,
4131 },
4132};
4133
4134static const struct snd_pci_quirk alc882_fixup_tbl[] = {
4135 SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", PINFIX_PB_M5210),
4136 SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Y530", PINFIX_LENOVO_Y530),
4137 SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
4138 SND_PCI_QUIRK(0x1025, 0x0296, "Acer Aspire 7736z", PINFIX_ACER_ASPIRE_7736),
4139 {}
4140};
4141
4142/*
4143 * BIOS auto configuration
4144 */
4145/* almost identical with ALC880 parser... */
4146static int alc882_parse_auto_config(struct hda_codec *codec)
4147{
Takashi Iwai1d045db2011-07-07 18:23:21 +02004148 static const hda_nid_t alc882_ignore[] = { 0x1d, 0 };
Takashi Iwai3e6179b2011-07-08 16:55:13 +02004149 static const hda_nid_t alc882_ssids[] = { 0x15, 0x1b, 0x14, 0 };
4150 return alc_parse_auto_config(codec, alc882_ignore, alc882_ssids);
Takashi Iwai1d045db2011-07-07 18:23:21 +02004151}
4152
Takashi Iwai1d045db2011-07-07 18:23:21 +02004153/*
4154 */
4155#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
4156#include "alc882_quirks.c"
4157#endif
4158
4159static int patch_alc882(struct hda_codec *codec)
4160{
4161 struct alc_spec *spec;
4162 int err, board_config;
4163
4164 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4165 if (spec == NULL)
4166 return -ENOMEM;
4167
4168 codec->spec = spec;
4169
4170 spec->mixer_nid = 0x0b;
4171
4172 switch (codec->vendor_id) {
4173 case 0x10ec0882:
4174 case 0x10ec0885:
4175 break;
4176 default:
4177 /* ALC883 and variants */
4178 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
4179 break;
4180 }
4181
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02004182 err = alc_codec_rename_from_preset(codec);
4183 if (err < 0)
4184 goto error;
4185
Takashi Iwai1d045db2011-07-07 18:23:21 +02004186 board_config = alc_board_config(codec, ALC882_MODEL_LAST,
4187 alc882_models, alc882_cfg_tbl);
4188
4189 if (board_config < 0)
4190 board_config = alc_board_codec_sid_config(codec,
4191 ALC882_MODEL_LAST, alc882_models, alc882_ssid_cfg_tbl);
4192
4193 if (board_config < 0) {
4194 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
4195 codec->chip_name);
4196 board_config = ALC_MODEL_AUTO;
4197 }
4198
4199 if (board_config == ALC_MODEL_AUTO) {
4200 alc_pick_fixup(codec, NULL, alc882_fixup_tbl, alc882_fixups);
4201 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
4202 }
4203
4204 alc_auto_parse_customize_define(codec);
4205
4206 if (board_config == ALC_MODEL_AUTO) {
4207 /* automatic parse from the BIOS config */
4208 err = alc882_parse_auto_config(codec);
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02004209 if (err < 0)
4210 goto error;
Takashi Iwai1d045db2011-07-07 18:23:21 +02004211#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
4212 else if (!err) {
4213 printk(KERN_INFO
4214 "hda_codec: Cannot set up configuration "
4215 "from BIOS. Using base mode...\n");
4216 board_config = ALC882_3ST_DIG;
4217 }
4218#endif
4219 }
4220
Takashi Iwai1d045db2011-07-07 18:23:21 +02004221 if (board_config != ALC_MODEL_AUTO)
4222 setup_preset(codec, &alc882_presets[board_config]);
4223
Takashi Iwai60a6a842011-07-27 14:01:24 +02004224 if (!spec->no_analog && !spec->adc_nids) {
Takashi Iwai1d045db2011-07-07 18:23:21 +02004225 alc_auto_fill_adc_caps(codec);
4226 alc_rebuild_imux_for_auto_mic(codec);
4227 alc_remove_invalid_adc_nids(codec);
4228 }
4229
Takashi Iwai3e6179b2011-07-08 16:55:13 +02004230 if (!spec->no_analog && !spec->cap_mixer)
4231 set_capture_mixer(codec);
Takashi Iwai1d045db2011-07-07 18:23:21 +02004232
Takashi Iwai3e6179b2011-07-08 16:55:13 +02004233 if (!spec->no_analog && has_cdefine_beep(codec)) {
4234 err = snd_hda_attach_beep_device(codec, 0x1);
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02004235 if (err < 0)
4236 goto error;
Takashi Iwai1d045db2011-07-07 18:23:21 +02004237 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Takashi Iwai3e6179b2011-07-08 16:55:13 +02004238 }
Takashi Iwai1d045db2011-07-07 18:23:21 +02004239
4240 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
4241
4242 spec->vmaster_nid = 0x0c;
4243
4244 codec->patch_ops = alc_patch_ops;
4245 if (board_config == ALC_MODEL_AUTO)
Takashi Iwaie4770622011-07-08 11:11:35 +02004246 spec->init_hook = alc_auto_init_std;
Takashi Iwai1d045db2011-07-07 18:23:21 +02004247
4248 alc_init_jacks(codec);
4249#ifdef CONFIG_SND_HDA_POWER_SAVE
4250 if (!spec->loopback.amplist)
4251 spec->loopback.amplist = alc882_loopbacks;
4252#endif
4253
4254 return 0;
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02004255
4256 error:
4257 alc_free(codec);
4258 return err;
Takashi Iwai1d045db2011-07-07 18:23:21 +02004259}
4260
4261
4262/*
4263 * ALC262 support
4264 */
Takashi Iwai1d045db2011-07-07 18:23:21 +02004265static int alc262_parse_auto_config(struct hda_codec *codec)
4266{
Takashi Iwai1d045db2011-07-07 18:23:21 +02004267 static const hda_nid_t alc262_ignore[] = { 0x1d, 0 };
Takashi Iwai3e6179b2011-07-08 16:55:13 +02004268 static const hda_nid_t alc262_ssids[] = { 0x15, 0x1b, 0x14, 0 };
4269 return alc_parse_auto_config(codec, alc262_ignore, alc262_ssids);
Takashi Iwai1d045db2011-07-07 18:23:21 +02004270}
4271
4272/*
4273 * Pin config fixes
4274 */
4275enum {
4276 PINFIX_FSC_H270,
4277 PINFIX_HP_Z200,
4278};
4279
4280static const struct alc_fixup alc262_fixups[] = {
4281 [PINFIX_FSC_H270] = {
4282 .type = ALC_FIXUP_PINS,
4283 .v.pins = (const struct alc_pincfg[]) {
4284 { 0x14, 0x99130110 }, /* speaker */
4285 { 0x15, 0x0221142f }, /* front HP */
4286 { 0x1b, 0x0121141f }, /* rear HP */
4287 { }
4288 }
4289 },
4290 [PINFIX_HP_Z200] = {
4291 .type = ALC_FIXUP_PINS,
4292 .v.pins = (const struct alc_pincfg[]) {
4293 { 0x16, 0x99130120 }, /* internal speaker */
4294 { }
4295 }
4296 },
4297};
4298
4299static const struct snd_pci_quirk alc262_fixup_tbl[] = {
4300 SND_PCI_QUIRK(0x103c, 0x170b, "HP Z200", PINFIX_HP_Z200),
4301 SND_PCI_QUIRK(0x1734, 0x1147, "FSC Celsius H270", PINFIX_FSC_H270),
4302 {}
4303};
4304
4305
4306#ifdef CONFIG_SND_HDA_POWER_SAVE
4307#define alc262_loopbacks alc880_loopbacks
4308#endif
4309
Takashi Iwai1d045db2011-07-07 18:23:21 +02004310/*
4311 */
4312#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
4313#include "alc262_quirks.c"
4314#endif
4315
4316static int patch_alc262(struct hda_codec *codec)
4317{
4318 struct alc_spec *spec;
4319 int board_config;
4320 int err;
4321
4322 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4323 if (spec == NULL)
4324 return -ENOMEM;
4325
4326 codec->spec = spec;
4327
4328 spec->mixer_nid = 0x0b;
4329
4330#if 0
4331 /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is
4332 * under-run
4333 */
4334 {
4335 int tmp;
4336 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
4337 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
4338 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
4339 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80);
4340 }
4341#endif
4342 alc_auto_parse_customize_define(codec);
4343
4344 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
4345
4346 board_config = alc_board_config(codec, ALC262_MODEL_LAST,
4347 alc262_models, alc262_cfg_tbl);
4348
4349 if (board_config < 0) {
4350 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
4351 codec->chip_name);
4352 board_config = ALC_MODEL_AUTO;
4353 }
4354
4355 if (board_config == ALC_MODEL_AUTO) {
4356 alc_pick_fixup(codec, NULL, alc262_fixup_tbl, alc262_fixups);
4357 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
4358 }
4359
4360 if (board_config == ALC_MODEL_AUTO) {
4361 /* automatic parse from the BIOS config */
4362 err = alc262_parse_auto_config(codec);
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02004363 if (err < 0)
4364 goto error;
Takashi Iwai1d045db2011-07-07 18:23:21 +02004365#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
4366 else if (!err) {
4367 printk(KERN_INFO
4368 "hda_codec: Cannot set up configuration "
4369 "from BIOS. Using base mode...\n");
4370 board_config = ALC262_BASIC;
4371 }
4372#endif
4373 }
4374
Takashi Iwai3e6179b2011-07-08 16:55:13 +02004375 if (board_config != ALC_MODEL_AUTO)
4376 setup_preset(codec, &alc262_presets[board_config]);
4377
Takashi Iwai60a6a842011-07-27 14:01:24 +02004378 if (!spec->no_analog && !spec->adc_nids) {
Takashi Iwai3e6179b2011-07-08 16:55:13 +02004379 alc_auto_fill_adc_caps(codec);
4380 alc_rebuild_imux_for_auto_mic(codec);
4381 alc_remove_invalid_adc_nids(codec);
4382 }
4383
4384 if (!spec->no_analog && !spec->cap_mixer)
4385 set_capture_mixer(codec);
4386
Takashi Iwai1d045db2011-07-07 18:23:21 +02004387 if (!spec->no_analog && has_cdefine_beep(codec)) {
4388 err = snd_hda_attach_beep_device(codec, 0x1);
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02004389 if (err < 0)
4390 goto error;
Takashi Iwai1d045db2011-07-07 18:23:21 +02004391 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Takashi Iwai3e6179b2011-07-08 16:55:13 +02004392 }
Takashi Iwai1d045db2011-07-07 18:23:21 +02004393
4394 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
4395
4396 spec->vmaster_nid = 0x0c;
4397
4398 codec->patch_ops = alc_patch_ops;
4399 if (board_config == ALC_MODEL_AUTO)
Takashi Iwaie4770622011-07-08 11:11:35 +02004400 spec->init_hook = alc_auto_init_std;
Takashi Iwai1d045db2011-07-07 18:23:21 +02004401 spec->shutup = alc_eapd_shutup;
4402
4403 alc_init_jacks(codec);
4404#ifdef CONFIG_SND_HDA_POWER_SAVE
4405 if (!spec->loopback.amplist)
4406 spec->loopback.amplist = alc262_loopbacks;
4407#endif
4408
4409 return 0;
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02004410
4411 error:
4412 alc_free(codec);
4413 return err;
Takashi Iwai1d045db2011-07-07 18:23:21 +02004414}
4415
4416/*
4417 * ALC268
4418 */
Takashi Iwai1d045db2011-07-07 18:23:21 +02004419/* bind Beep switches of both NID 0x0f and 0x10 */
4420static const struct hda_bind_ctls alc268_bind_beep_sw = {
4421 .ops = &snd_hda_bind_sw,
4422 .values = {
4423 HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT),
4424 HDA_COMPOSE_AMP_VAL(0x10, 3, 1, HDA_INPUT),
4425 0
4426 },
4427};
4428
4429static const struct snd_kcontrol_new alc268_beep_mixer[] = {
4430 HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT),
4431 HDA_BIND_SW("Beep Playback Switch", &alc268_bind_beep_sw),
4432 { }
4433};
4434
4435/* set PCBEEP vol = 0, mute connections */
4436static const struct hda_verb alc268_beep_init_verbs[] = {
4437 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4438 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4439 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4440 { }
4441};
4442
4443/*
4444 * BIOS auto configuration
4445 */
4446static int alc268_parse_auto_config(struct hda_codec *codec)
4447{
Takashi Iwai3e6179b2011-07-08 16:55:13 +02004448 static const hda_nid_t alc268_ssids[] = { 0x15, 0x1b, 0x14, 0 };
Takashi Iwai1d045db2011-07-07 18:23:21 +02004449 struct alc_spec *spec = codec->spec;
Takashi Iwai3e6179b2011-07-08 16:55:13 +02004450 int err = alc_parse_auto_config(codec, NULL, alc268_ssids);
4451 if (err > 0) {
4452 if (!spec->no_analog && spec->autocfg.speaker_pins[0] != 0x1d) {
4453 add_mixer(spec, alc268_beep_mixer);
4454 add_verb(spec, alc268_beep_init_verbs);
Takashi Iwai1d045db2011-07-07 18:23:21 +02004455 }
Takashi Iwai1d045db2011-07-07 18:23:21 +02004456 }
Takashi Iwai3e6179b2011-07-08 16:55:13 +02004457 return err;
Takashi Iwai1d045db2011-07-07 18:23:21 +02004458}
4459
Takashi Iwai1d045db2011-07-07 18:23:21 +02004460/*
4461 */
Takashi Iwai1d045db2011-07-07 18:23:21 +02004462static int patch_alc268(struct hda_codec *codec)
4463{
4464 struct alc_spec *spec;
Takashi Iwai1d045db2011-07-07 18:23:21 +02004465 int i, has_beep, err;
4466
4467 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4468 if (spec == NULL)
4469 return -ENOMEM;
4470
4471 codec->spec = spec;
4472
4473 /* ALC268 has no aa-loopback mixer */
4474
Takashi Iwai6ebb8052011-08-16 15:15:40 +02004475 /* automatic parse from the BIOS config */
4476 err = alc268_parse_auto_config(codec);
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02004477 if (err < 0)
4478 goto error;
Takashi Iwai1d045db2011-07-07 18:23:21 +02004479
Takashi Iwai1d045db2011-07-07 18:23:21 +02004480 has_beep = 0;
4481 for (i = 0; i < spec->num_mixers; i++) {
4482 if (spec->mixers[i] == alc268_beep_mixer) {
4483 has_beep = 1;
4484 break;
4485 }
4486 }
4487
4488 if (has_beep) {
4489 err = snd_hda_attach_beep_device(codec, 0x1);
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02004490 if (err < 0)
4491 goto error;
Takashi Iwai1d045db2011-07-07 18:23:21 +02004492 if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
4493 /* override the amp caps for beep generator */
4494 snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT,
4495 (0x0c << AC_AMPCAP_OFFSET_SHIFT) |
4496 (0x0c << AC_AMPCAP_NUM_STEPS_SHIFT) |
4497 (0x07 << AC_AMPCAP_STEP_SIZE_SHIFT) |
4498 (0 << AC_AMPCAP_MUTE_SHIFT));
4499 }
4500
Takashi Iwai60a6a842011-07-27 14:01:24 +02004501 if (!spec->no_analog && !spec->adc_nids) {
Takashi Iwai1d045db2011-07-07 18:23:21 +02004502 alc_auto_fill_adc_caps(codec);
4503 alc_rebuild_imux_for_auto_mic(codec);
4504 alc_remove_invalid_adc_nids(codec);
4505 }
4506
Takashi Iwai3e6179b2011-07-08 16:55:13 +02004507 if (!spec->no_analog && !spec->cap_mixer)
Takashi Iwai1d045db2011-07-07 18:23:21 +02004508 set_capture_mixer(codec);
4509
4510 spec->vmaster_nid = 0x02;
4511
4512 codec->patch_ops = alc_patch_ops;
Takashi Iwai6ebb8052011-08-16 15:15:40 +02004513 spec->init_hook = alc_auto_init_std;
Takashi Iwai1d045db2011-07-07 18:23:21 +02004514 spec->shutup = alc_eapd_shutup;
4515
4516 alc_init_jacks(codec);
4517
4518 return 0;
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02004519
4520 error:
4521 alc_free(codec);
4522 return err;
Takashi Iwai1d045db2011-07-07 18:23:21 +02004523}
4524
4525/*
4526 * ALC269
4527 */
Takashi Iwai1d045db2011-07-07 18:23:21 +02004528#ifdef CONFIG_SND_HDA_POWER_SAVE
4529#define alc269_loopbacks alc880_loopbacks
4530#endif
4531
4532static const struct hda_pcm_stream alc269_44k_pcm_analog_playback = {
4533 .substreams = 1,
4534 .channels_min = 2,
4535 .channels_max = 8,
4536 .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
4537 /* NID is set in alc_build_pcms */
4538 .ops = {
4539 .open = alc_playback_pcm_open,
4540 .prepare = alc_playback_pcm_prepare,
4541 .cleanup = alc_playback_pcm_cleanup
4542 },
4543};
4544
4545static const struct hda_pcm_stream alc269_44k_pcm_analog_capture = {
4546 .substreams = 1,
4547 .channels_min = 2,
4548 .channels_max = 2,
4549 .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
4550 /* NID is set in alc_build_pcms */
4551};
4552
4553#ifdef CONFIG_SND_HDA_POWER_SAVE
4554static int alc269_mic2_for_mute_led(struct hda_codec *codec)
4555{
4556 switch (codec->subsystem_id) {
4557 case 0x103c1586:
4558 return 1;
4559 }
4560 return 0;
4561}
4562
4563static int alc269_mic2_mute_check_ps(struct hda_codec *codec, hda_nid_t nid)
4564{
4565 /* update mute-LED according to the speaker mute state */
4566 if (nid == 0x01 || nid == 0x14) {
4567 int pinval;
4568 if (snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0) &
4569 HDA_AMP_MUTE)
4570 pinval = 0x24;
4571 else
4572 pinval = 0x20;
4573 /* mic2 vref pin is used for mute LED control */
4574 snd_hda_codec_update_cache(codec, 0x19, 0,
4575 AC_VERB_SET_PIN_WIDGET_CONTROL,
4576 pinval);
4577 }
4578 return alc_check_power_status(codec, nid);
4579}
4580#endif /* CONFIG_SND_HDA_POWER_SAVE */
4581
4582/* different alc269-variants */
4583enum {
4584 ALC269_TYPE_ALC269VA,
4585 ALC269_TYPE_ALC269VB,
4586 ALC269_TYPE_ALC269VC,
4587};
4588
4589/*
4590 * BIOS auto configuration
4591 */
4592static int alc269_parse_auto_config(struct hda_codec *codec)
4593{
Takashi Iwai1d045db2011-07-07 18:23:21 +02004594 static const hda_nid_t alc269_ignore[] = { 0x1d, 0 };
Takashi Iwai3e6179b2011-07-08 16:55:13 +02004595 static const hda_nid_t alc269_ssids[] = { 0, 0x1b, 0x14, 0x21 };
4596 static const hda_nid_t alc269va_ssids[] = { 0x15, 0x1b, 0x14, 0 };
4597 struct alc_spec *spec = codec->spec;
4598 const hda_nid_t *ssids = spec->codec_variant == ALC269_TYPE_ALC269VA ?
4599 alc269va_ssids : alc269_ssids;
Takashi Iwai1d045db2011-07-07 18:23:21 +02004600
Takashi Iwai3e6179b2011-07-08 16:55:13 +02004601 return alc_parse_auto_config(codec, alc269_ignore, ssids);
Takashi Iwai1d045db2011-07-07 18:23:21 +02004602}
4603
Takashi Iwai1d045db2011-07-07 18:23:21 +02004604static void alc269_toggle_power_output(struct hda_codec *codec, int power_up)
4605{
4606 int val = alc_read_coef_idx(codec, 0x04);
4607 if (power_up)
4608 val |= 1 << 11;
4609 else
4610 val &= ~(1 << 11);
4611 alc_write_coef_idx(codec, 0x04, val);
4612}
4613
4614static void alc269_shutup(struct hda_codec *codec)
4615{
4616 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017)
4617 alc269_toggle_power_output(codec, 0);
4618 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
4619 alc269_toggle_power_output(codec, 0);
4620 msleep(150);
4621 }
4622}
4623
Takashi Iwai2a439522011-07-26 09:52:50 +02004624#ifdef CONFIG_PM
Takashi Iwai1d045db2011-07-07 18:23:21 +02004625static int alc269_resume(struct hda_codec *codec)
4626{
4627 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
4628 alc269_toggle_power_output(codec, 0);
4629 msleep(150);
4630 }
4631
4632 codec->patch_ops.init(codec);
4633
4634 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) {
4635 alc269_toggle_power_output(codec, 1);
4636 msleep(200);
4637 }
4638
4639 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018)
4640 alc269_toggle_power_output(codec, 1);
4641
4642 snd_hda_codec_resume_amp(codec);
4643 snd_hda_codec_resume_cache(codec);
4644 hda_call_check_power_status(codec, 0x01);
4645 return 0;
4646}
Takashi Iwai2a439522011-07-26 09:52:50 +02004647#endif /* CONFIG_PM */
Takashi Iwai1d045db2011-07-07 18:23:21 +02004648
4649static void alc269_fixup_hweq(struct hda_codec *codec,
4650 const struct alc_fixup *fix, int action)
4651{
4652 int coef;
4653
4654 if (action != ALC_FIXUP_ACT_INIT)
4655 return;
4656 coef = alc_read_coef_idx(codec, 0x1e);
4657 alc_write_coef_idx(codec, 0x1e, coef | 0x80);
4658}
4659
4660static void alc271_fixup_dmic(struct hda_codec *codec,
4661 const struct alc_fixup *fix, int action)
4662{
4663 static const struct hda_verb verbs[] = {
4664 {0x20, AC_VERB_SET_COEF_INDEX, 0x0d},
4665 {0x20, AC_VERB_SET_PROC_COEF, 0x4000},
4666 {}
4667 };
4668 unsigned int cfg;
4669
4670 if (strcmp(codec->chip_name, "ALC271X"))
4671 return;
4672 cfg = snd_hda_codec_get_pincfg(codec, 0x12);
4673 if (get_defcfg_connect(cfg) == AC_JACK_PORT_FIXED)
4674 snd_hda_sequence_write(codec, verbs);
4675}
4676
Takashi Iwai017f2a12011-07-09 14:42:25 +02004677static void alc269_fixup_pcm_44k(struct hda_codec *codec,
4678 const struct alc_fixup *fix, int action)
4679{
4680 struct alc_spec *spec = codec->spec;
4681
4682 if (action != ALC_FIXUP_ACT_PROBE)
4683 return;
4684
4685 /* Due to a hardware problem on Lenovo Ideadpad, we need to
4686 * fix the sample rate of analog I/O to 44.1kHz
4687 */
4688 spec->stream_analog_playback = &alc269_44k_pcm_analog_playback;
4689 spec->stream_analog_capture = &alc269_44k_pcm_analog_capture;
4690}
4691
Takashi Iwaiadabb3e2011-08-03 07:48:37 +02004692static void alc269_fixup_stereo_dmic(struct hda_codec *codec,
4693 const struct alc_fixup *fix, int action)
4694{
4695 int coef;
4696
4697 if (action != ALC_FIXUP_ACT_INIT)
4698 return;
4699 /* The digital-mic unit sends PDM (differential signal) instead of
4700 * the standard PCM, thus you can't record a valid mono stream as is.
4701 * Below is a workaround specific to ALC269 to control the dmic
4702 * signal source as mono.
4703 */
4704 coef = alc_read_coef_idx(codec, 0x07);
4705 alc_write_coef_idx(codec, 0x07, coef | 0x80);
4706}
4707
Takashi Iwai24519912011-08-16 15:08:49 +02004708static void alc269_quanta_automute(struct hda_codec *codec)
4709{
David Henningsson42cf0d02011-09-20 12:04:56 +02004710 update_outputs(codec);
Takashi Iwai24519912011-08-16 15:08:49 +02004711
4712 snd_hda_codec_write(codec, 0x20, 0,
4713 AC_VERB_SET_COEF_INDEX, 0x0c);
4714 snd_hda_codec_write(codec, 0x20, 0,
4715 AC_VERB_SET_PROC_COEF, 0x680);
4716
4717 snd_hda_codec_write(codec, 0x20, 0,
4718 AC_VERB_SET_COEF_INDEX, 0x0c);
4719 snd_hda_codec_write(codec, 0x20, 0,
4720 AC_VERB_SET_PROC_COEF, 0x480);
4721}
4722
4723static void alc269_fixup_quanta_mute(struct hda_codec *codec,
4724 const struct alc_fixup *fix, int action)
4725{
4726 struct alc_spec *spec = codec->spec;
4727 if (action != ALC_FIXUP_ACT_PROBE)
4728 return;
4729 spec->automute_hook = alc269_quanta_automute;
4730}
4731
Takashi Iwai1d045db2011-07-07 18:23:21 +02004732enum {
4733 ALC269_FIXUP_SONY_VAIO,
4734 ALC275_FIXUP_SONY_VAIO_GPIO2,
4735 ALC269_FIXUP_DELL_M101Z,
4736 ALC269_FIXUP_SKU_IGNORE,
4737 ALC269_FIXUP_ASUS_G73JW,
4738 ALC269_FIXUP_LENOVO_EAPD,
4739 ALC275_FIXUP_SONY_HWEQ,
4740 ALC271_FIXUP_DMIC,
Takashi Iwai017f2a12011-07-09 14:42:25 +02004741 ALC269_FIXUP_PCM_44K,
Takashi Iwaiadabb3e2011-08-03 07:48:37 +02004742 ALC269_FIXUP_STEREO_DMIC,
Takashi Iwai24519912011-08-16 15:08:49 +02004743 ALC269_FIXUP_QUANTA_MUTE,
4744 ALC269_FIXUP_LIFEBOOK,
Takashi Iwaia4297b52011-08-23 18:40:12 +02004745 ALC269_FIXUP_AMIC,
4746 ALC269_FIXUP_DMIC,
4747 ALC269VB_FIXUP_AMIC,
4748 ALC269VB_FIXUP_DMIC,
Takashi Iwai1d045db2011-07-07 18:23:21 +02004749};
4750
4751static const struct alc_fixup alc269_fixups[] = {
4752 [ALC269_FIXUP_SONY_VAIO] = {
4753 .type = ALC_FIXUP_VERBS,
4754 .v.verbs = (const struct hda_verb[]) {
4755 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREFGRD},
4756 {}
4757 }
4758 },
4759 [ALC275_FIXUP_SONY_VAIO_GPIO2] = {
4760 .type = ALC_FIXUP_VERBS,
4761 .v.verbs = (const struct hda_verb[]) {
4762 {0x01, AC_VERB_SET_GPIO_MASK, 0x04},
4763 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x04},
4764 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
4765 { }
4766 },
4767 .chained = true,
4768 .chain_id = ALC269_FIXUP_SONY_VAIO
4769 },
4770 [ALC269_FIXUP_DELL_M101Z] = {
4771 .type = ALC_FIXUP_VERBS,
4772 .v.verbs = (const struct hda_verb[]) {
4773 /* Enables internal speaker */
4774 {0x20, AC_VERB_SET_COEF_INDEX, 13},
4775 {0x20, AC_VERB_SET_PROC_COEF, 0x4040},
4776 {}
4777 }
4778 },
4779 [ALC269_FIXUP_SKU_IGNORE] = {
4780 .type = ALC_FIXUP_SKU,
4781 .v.sku = ALC_FIXUP_SKU_IGNORE,
4782 },
4783 [ALC269_FIXUP_ASUS_G73JW] = {
4784 .type = ALC_FIXUP_PINS,
4785 .v.pins = (const struct alc_pincfg[]) {
4786 { 0x17, 0x99130111 }, /* subwoofer */
4787 { }
4788 }
4789 },
4790 [ALC269_FIXUP_LENOVO_EAPD] = {
4791 .type = ALC_FIXUP_VERBS,
4792 .v.verbs = (const struct hda_verb[]) {
4793 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 0},
4794 {}
4795 }
4796 },
4797 [ALC275_FIXUP_SONY_HWEQ] = {
4798 .type = ALC_FIXUP_FUNC,
4799 .v.func = alc269_fixup_hweq,
4800 .chained = true,
4801 .chain_id = ALC275_FIXUP_SONY_VAIO_GPIO2
4802 },
4803 [ALC271_FIXUP_DMIC] = {
4804 .type = ALC_FIXUP_FUNC,
4805 .v.func = alc271_fixup_dmic,
4806 },
Takashi Iwai017f2a12011-07-09 14:42:25 +02004807 [ALC269_FIXUP_PCM_44K] = {
4808 .type = ALC_FIXUP_FUNC,
4809 .v.func = alc269_fixup_pcm_44k,
4810 },
Takashi Iwaiadabb3e2011-08-03 07:48:37 +02004811 [ALC269_FIXUP_STEREO_DMIC] = {
4812 .type = ALC_FIXUP_FUNC,
4813 .v.func = alc269_fixup_stereo_dmic,
4814 },
Takashi Iwai24519912011-08-16 15:08:49 +02004815 [ALC269_FIXUP_QUANTA_MUTE] = {
4816 .type = ALC_FIXUP_FUNC,
4817 .v.func = alc269_fixup_quanta_mute,
4818 },
4819 [ALC269_FIXUP_LIFEBOOK] = {
4820 .type = ALC_FIXUP_PINS,
4821 .v.pins = (const struct alc_pincfg[]) {
4822 { 0x1a, 0x2101103f }, /* dock line-out */
4823 { 0x1b, 0x23a11040 }, /* dock mic-in */
4824 { }
4825 },
4826 .chained = true,
4827 .chain_id = ALC269_FIXUP_QUANTA_MUTE
4828 },
Takashi Iwaia4297b52011-08-23 18:40:12 +02004829 [ALC269_FIXUP_AMIC] = {
4830 .type = ALC_FIXUP_PINS,
4831 .v.pins = (const struct alc_pincfg[]) {
4832 { 0x14, 0x99130110 }, /* speaker */
4833 { 0x15, 0x0121401f }, /* HP out */
4834 { 0x18, 0x01a19c20 }, /* mic */
4835 { 0x19, 0x99a3092f }, /* int-mic */
4836 { }
4837 },
4838 },
4839 [ALC269_FIXUP_DMIC] = {
4840 .type = ALC_FIXUP_PINS,
4841 .v.pins = (const struct alc_pincfg[]) {
4842 { 0x12, 0x99a3092f }, /* int-mic */
4843 { 0x14, 0x99130110 }, /* speaker */
4844 { 0x15, 0x0121401f }, /* HP out */
4845 { 0x18, 0x01a19c20 }, /* mic */
4846 { }
4847 },
4848 },
4849 [ALC269VB_FIXUP_AMIC] = {
4850 .type = ALC_FIXUP_PINS,
4851 .v.pins = (const struct alc_pincfg[]) {
4852 { 0x14, 0x99130110 }, /* speaker */
4853 { 0x18, 0x01a19c20 }, /* mic */
4854 { 0x19, 0x99a3092f }, /* int-mic */
4855 { 0x21, 0x0121401f }, /* HP out */
4856 { }
4857 },
4858 },
4859 [ALC269_FIXUP_DMIC] = {
4860 .type = ALC_FIXUP_PINS,
4861 .v.pins = (const struct alc_pincfg[]) {
4862 { 0x12, 0x99a3092f }, /* int-mic */
4863 { 0x14, 0x99130110 }, /* speaker */
4864 { 0x18, 0x01a19c20 }, /* mic */
4865 { 0x21, 0x0121401f }, /* HP out */
4866 { }
4867 },
4868 },
Takashi Iwai1d045db2011-07-07 18:23:21 +02004869};
4870
4871static const struct snd_pci_quirk alc269_fixup_tbl[] = {
Takashi Iwai017f2a12011-07-09 14:42:25 +02004872 SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW),
Takashi Iwaiadabb3e2011-08-03 07:48:37 +02004873 SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_FIXUP_STEREO_DMIC),
4874 SND_PCI_QUIRK(0x1043, 0x831a, "ASUS P901", ALC269_FIXUP_STEREO_DMIC),
4875 SND_PCI_QUIRK(0x1043, 0x834a, "ASUS S101", ALC269_FIXUP_STEREO_DMIC),
4876 SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005", ALC269_FIXUP_STEREO_DMIC),
4877 SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005", ALC269_FIXUP_STEREO_DMIC),
Takashi Iwai1d045db2011-07-07 18:23:21 +02004878 SND_PCI_QUIRK(0x104d, 0x9073, "Sony VAIO", ALC275_FIXUP_SONY_VAIO_GPIO2),
4879 SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
4880 SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
4881 SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO),
4882 SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z),
4883 SND_PCI_QUIRK_VENDOR(0x1025, "Acer Aspire", ALC271_FIXUP_DMIC),
Takashi Iwai24519912011-08-16 15:08:49 +02004884 SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook", ALC269_FIXUP_LIFEBOOK),
Takashi Iwai1d045db2011-07-07 18:23:21 +02004885 SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE),
4886 SND_PCI_QUIRK(0x17aa, 0x215e, "Thinkpad L512", ALC269_FIXUP_SKU_IGNORE),
4887 SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE),
4888 SND_PCI_QUIRK(0x17aa, 0x21ca, "Thinkpad L412", ALC269_FIXUP_SKU_IGNORE),
4889 SND_PCI_QUIRK(0x17aa, 0x21e9, "Thinkpad Edge 15", ALC269_FIXUP_SKU_IGNORE),
Takashi Iwai24519912011-08-16 15:08:49 +02004890 SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_QUANTA_MUTE),
Takashi Iwai017f2a12011-07-09 14:42:25 +02004891 SND_PCI_QUIRK(0x17aa, 0x3bf8, "Lenovo Ideapd", ALC269_FIXUP_PCM_44K),
Takashi Iwai1d045db2011-07-07 18:23:21 +02004892 SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
Takashi Iwaia4297b52011-08-23 18:40:12 +02004893
4894#if 1
4895 /* Below is a quirk table taken from the old code.
4896 * Basically the device should work as is without the fixup table.
4897 * If BIOS doesn't give a proper info, enable the corresponding
4898 * fixup entry.
4899 */
4900 SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A",
4901 ALC269_FIXUP_AMIC),
4902 SND_PCI_QUIRK(0x1043, 0x1013, "ASUS N61Da", ALC269_FIXUP_AMIC),
4903 SND_PCI_QUIRK(0x1043, 0x1113, "ASUS N63Jn", ALC269_FIXUP_AMIC),
4904 SND_PCI_QUIRK(0x1043, 0x1143, "ASUS B53f", ALC269_FIXUP_AMIC),
4905 SND_PCI_QUIRK(0x1043, 0x1133, "ASUS UJ20ft", ALC269_FIXUP_AMIC),
4906 SND_PCI_QUIRK(0x1043, 0x1183, "ASUS K72DR", ALC269_FIXUP_AMIC),
4907 SND_PCI_QUIRK(0x1043, 0x11b3, "ASUS K52DR", ALC269_FIXUP_AMIC),
4908 SND_PCI_QUIRK(0x1043, 0x11e3, "ASUS U33Jc", ALC269_FIXUP_AMIC),
4909 SND_PCI_QUIRK(0x1043, 0x1273, "ASUS UL80Jt", ALC269_FIXUP_AMIC),
4910 SND_PCI_QUIRK(0x1043, 0x1283, "ASUS U53Jc", ALC269_FIXUP_AMIC),
4911 SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS N82JV", ALC269_FIXUP_AMIC),
4912 SND_PCI_QUIRK(0x1043, 0x12d3, "ASUS N61Jv", ALC269_FIXUP_AMIC),
4913 SND_PCI_QUIRK(0x1043, 0x13a3, "ASUS UL30Vt", ALC269_FIXUP_AMIC),
4914 SND_PCI_QUIRK(0x1043, 0x1373, "ASUS G73JX", ALC269_FIXUP_AMIC),
4915 SND_PCI_QUIRK(0x1043, 0x1383, "ASUS UJ30Jc", ALC269_FIXUP_AMIC),
4916 SND_PCI_QUIRK(0x1043, 0x13d3, "ASUS N61JA", ALC269_FIXUP_AMIC),
4917 SND_PCI_QUIRK(0x1043, 0x1413, "ASUS UL50", ALC269_FIXUP_AMIC),
4918 SND_PCI_QUIRK(0x1043, 0x1443, "ASUS UL30", ALC269_FIXUP_AMIC),
4919 SND_PCI_QUIRK(0x1043, 0x1453, "ASUS M60Jv", ALC269_FIXUP_AMIC),
4920 SND_PCI_QUIRK(0x1043, 0x1483, "ASUS UL80", ALC269_FIXUP_AMIC),
4921 SND_PCI_QUIRK(0x1043, 0x14f3, "ASUS F83Vf", ALC269_FIXUP_AMIC),
4922 SND_PCI_QUIRK(0x1043, 0x14e3, "ASUS UL20", ALC269_FIXUP_AMIC),
4923 SND_PCI_QUIRK(0x1043, 0x1513, "ASUS UX30", ALC269_FIXUP_AMIC),
4924 SND_PCI_QUIRK(0x1043, 0x1593, "ASUS N51Vn", ALC269_FIXUP_AMIC),
4925 SND_PCI_QUIRK(0x1043, 0x15a3, "ASUS N60Jv", ALC269_FIXUP_AMIC),
4926 SND_PCI_QUIRK(0x1043, 0x15b3, "ASUS N60Dp", ALC269_FIXUP_AMIC),
4927 SND_PCI_QUIRK(0x1043, 0x15c3, "ASUS N70De", ALC269_FIXUP_AMIC),
4928 SND_PCI_QUIRK(0x1043, 0x15e3, "ASUS F83T", ALC269_FIXUP_AMIC),
4929 SND_PCI_QUIRK(0x1043, 0x1643, "ASUS M60J", ALC269_FIXUP_AMIC),
4930 SND_PCI_QUIRK(0x1043, 0x1653, "ASUS U50", ALC269_FIXUP_AMIC),
4931 SND_PCI_QUIRK(0x1043, 0x1693, "ASUS F50N", ALC269_FIXUP_AMIC),
4932 SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS F5Q", ALC269_FIXUP_AMIC),
4933 SND_PCI_QUIRK(0x1043, 0x1723, "ASUS P80", ALC269_FIXUP_AMIC),
4934 SND_PCI_QUIRK(0x1043, 0x1743, "ASUS U80", ALC269_FIXUP_AMIC),
4935 SND_PCI_QUIRK(0x1043, 0x1773, "ASUS U20A", ALC269_FIXUP_AMIC),
4936 SND_PCI_QUIRK(0x1043, 0x1883, "ASUS F81Se", ALC269_FIXUP_AMIC),
4937 SND_PCI_QUIRK(0x152d, 0x1778, "Quanta ON1", ALC269_FIXUP_DMIC),
4938 SND_PCI_QUIRK(0x17aa, 0x3be9, "Quanta Wistron", ALC269_FIXUP_AMIC),
4939 SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_AMIC),
4940 SND_PCI_QUIRK(0x17ff, 0x059a, "Quanta EL3", ALC269_FIXUP_DMIC),
4941 SND_PCI_QUIRK(0x17ff, 0x059b, "Quanta JR1", ALC269_FIXUP_DMIC),
4942#endif
4943 {}
4944};
4945
4946static const struct alc_model_fixup alc269_fixup_models[] = {
4947 {.id = ALC269_FIXUP_AMIC, .name = "laptop-amic"},
4948 {.id = ALC269_FIXUP_DMIC, .name = "laptop-dmic"},
Takashi Iwai1d045db2011-07-07 18:23:21 +02004949 {}
4950};
4951
4952
4953static int alc269_fill_coef(struct hda_codec *codec)
4954{
4955 int val;
4956
4957 if ((alc_read_coef_idx(codec, 0) & 0x00ff) < 0x015) {
4958 alc_write_coef_idx(codec, 0xf, 0x960b);
4959 alc_write_coef_idx(codec, 0xe, 0x8817);
4960 }
4961
4962 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x016) {
4963 alc_write_coef_idx(codec, 0xf, 0x960b);
4964 alc_write_coef_idx(codec, 0xe, 0x8814);
4965 }
4966
4967 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) {
4968 val = alc_read_coef_idx(codec, 0x04);
4969 /* Power up output pin */
4970 alc_write_coef_idx(codec, 0x04, val | (1<<11));
4971 }
4972
4973 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
4974 val = alc_read_coef_idx(codec, 0xd);
4975 if ((val & 0x0c00) >> 10 != 0x1) {
4976 /* Capless ramp up clock control */
4977 alc_write_coef_idx(codec, 0xd, val | (1<<10));
4978 }
4979 val = alc_read_coef_idx(codec, 0x17);
4980 if ((val & 0x01c0) >> 6 != 0x4) {
4981 /* Class D power on reset */
4982 alc_write_coef_idx(codec, 0x17, val | (1<<7));
4983 }
4984 }
4985
4986 val = alc_read_coef_idx(codec, 0xd); /* Class D */
4987 alc_write_coef_idx(codec, 0xd, val | (1<<14));
4988
4989 val = alc_read_coef_idx(codec, 0x4); /* HP */
4990 alc_write_coef_idx(codec, 0x4, val | (1<<11));
4991
4992 return 0;
4993}
4994
4995/*
4996 */
Takashi Iwai1d045db2011-07-07 18:23:21 +02004997static int patch_alc269(struct hda_codec *codec)
4998{
4999 struct alc_spec *spec;
Takashi Iwai20ca0c32011-10-17 16:00:35 +02005000 int err = 0;
Takashi Iwai1d045db2011-07-07 18:23:21 +02005001
5002 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
5003 if (spec == NULL)
5004 return -ENOMEM;
5005
5006 codec->spec = spec;
5007
5008 spec->mixer_nid = 0x0b;
5009
5010 alc_auto_parse_customize_define(codec);
5011
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02005012 err = alc_codec_rename_from_preset(codec);
5013 if (err < 0)
5014 goto error;
5015
Takashi Iwai1d045db2011-07-07 18:23:21 +02005016 if (codec->vendor_id == 0x10ec0269) {
Takashi Iwaia4297b52011-08-23 18:40:12 +02005017 unsigned int coef;
Takashi Iwai1d045db2011-07-07 18:23:21 +02005018 spec->codec_variant = ALC269_TYPE_ALC269VA;
5019 coef = alc_read_coef_idx(codec, 0);
5020 if ((coef & 0x00f0) == 0x0010) {
5021 if (codec->bus->pci->subsystem_vendor == 0x1025 &&
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02005022 spec->cdefine.platform_type == 1)
Takashi Iwai20ca0c32011-10-17 16:00:35 +02005023 err = alc_codec_rename(codec, "ALC271X");
Takashi Iwai1d045db2011-07-07 18:23:21 +02005024 spec->codec_variant = ALC269_TYPE_ALC269VB;
5025 } else if ((coef & 0x00f0) == 0x0020) {
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02005026 if (codec->bus->pci->subsystem_vendor == 0x17aa &&
5027 codec->bus->pci->subsystem_device == 0x21f3)
Takashi Iwai20ca0c32011-10-17 16:00:35 +02005028 err = alc_codec_rename(codec, "ALC3202");
Takashi Iwai1d045db2011-07-07 18:23:21 +02005029 spec->codec_variant = ALC269_TYPE_ALC269VC;
5030 } else
5031 alc_fix_pll_init(codec, 0x20, 0x04, 15);
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02005032 if (err < 0)
5033 goto error;
Takashi Iwai1d045db2011-07-07 18:23:21 +02005034 alc269_fill_coef(codec);
5035 }
5036
Takashi Iwaia4297b52011-08-23 18:40:12 +02005037 alc_pick_fixup(codec, alc269_fixup_models,
5038 alc269_fixup_tbl, alc269_fixups);
5039 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
Takashi Iwai1d045db2011-07-07 18:23:21 +02005040
Takashi Iwaia4297b52011-08-23 18:40:12 +02005041 /* automatic parse from the BIOS config */
5042 err = alc269_parse_auto_config(codec);
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02005043 if (err < 0)
5044 goto error;
Takashi Iwai1d045db2011-07-07 18:23:21 +02005045
Takashi Iwai60a6a842011-07-27 14:01:24 +02005046 if (!spec->no_analog && !spec->adc_nids) {
Takashi Iwai1d045db2011-07-07 18:23:21 +02005047 alc_auto_fill_adc_caps(codec);
5048 alc_rebuild_imux_for_auto_mic(codec);
5049 alc_remove_invalid_adc_nids(codec);
5050 }
5051
Takashi Iwai3e6179b2011-07-08 16:55:13 +02005052 if (!spec->no_analog && !spec->cap_mixer)
Takashi Iwai1d045db2011-07-07 18:23:21 +02005053 set_capture_mixer(codec);
Takashi Iwai3e6179b2011-07-08 16:55:13 +02005054
5055 if (!spec->no_analog && has_cdefine_beep(codec)) {
5056 err = snd_hda_attach_beep_device(codec, 0x1);
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02005057 if (err < 0)
5058 goto error;
Takashi Iwai1d045db2011-07-07 18:23:21 +02005059 set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
Takashi Iwai3e6179b2011-07-08 16:55:13 +02005060 }
Takashi Iwai1d045db2011-07-07 18:23:21 +02005061
5062 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
5063
5064 spec->vmaster_nid = 0x02;
5065
5066 codec->patch_ops = alc_patch_ops;
Takashi Iwai2a439522011-07-26 09:52:50 +02005067#ifdef CONFIG_PM
Takashi Iwai1d045db2011-07-07 18:23:21 +02005068 codec->patch_ops.resume = alc269_resume;
5069#endif
Takashi Iwaia4297b52011-08-23 18:40:12 +02005070 spec->init_hook = alc_auto_init_std;
Takashi Iwai1d045db2011-07-07 18:23:21 +02005071 spec->shutup = alc269_shutup;
5072
5073 alc_init_jacks(codec);
5074#ifdef CONFIG_SND_HDA_POWER_SAVE
5075 if (!spec->loopback.amplist)
5076 spec->loopback.amplist = alc269_loopbacks;
5077 if (alc269_mic2_for_mute_led(codec))
5078 codec->patch_ops.check_power_status = alc269_mic2_mute_check_ps;
5079#endif
5080
5081 return 0;
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02005082
5083 error:
5084 alc_free(codec);
5085 return err;
Takashi Iwai1d045db2011-07-07 18:23:21 +02005086}
5087
5088/*
5089 * ALC861
5090 */
5091
Takashi Iwai1d045db2011-07-07 18:23:21 +02005092static int alc861_parse_auto_config(struct hda_codec *codec)
5093{
Takashi Iwai1d045db2011-07-07 18:23:21 +02005094 static const hda_nid_t alc861_ignore[] = { 0x1d, 0 };
Takashi Iwai3e6179b2011-07-08 16:55:13 +02005095 static const hda_nid_t alc861_ssids[] = { 0x0e, 0x0f, 0x0b, 0 };
5096 return alc_parse_auto_config(codec, alc861_ignore, alc861_ssids);
Takashi Iwai1d045db2011-07-07 18:23:21 +02005097}
5098
Takashi Iwai1d045db2011-07-07 18:23:21 +02005099#ifdef CONFIG_SND_HDA_POWER_SAVE
5100static const struct hda_amp_list alc861_loopbacks[] = {
5101 { 0x15, HDA_INPUT, 0 },
5102 { 0x15, HDA_INPUT, 1 },
5103 { 0x15, HDA_INPUT, 2 },
5104 { 0x15, HDA_INPUT, 3 },
5105 { } /* end */
5106};
5107#endif
5108
5109
5110/* Pin config fixes */
5111enum {
5112 PINFIX_FSC_AMILO_PI1505,
5113};
5114
5115static const struct alc_fixup alc861_fixups[] = {
5116 [PINFIX_FSC_AMILO_PI1505] = {
5117 .type = ALC_FIXUP_PINS,
5118 .v.pins = (const struct alc_pincfg[]) {
5119 { 0x0b, 0x0221101f }, /* HP */
5120 { 0x0f, 0x90170310 }, /* speaker */
5121 { }
5122 }
5123 },
5124};
5125
5126static const struct snd_pci_quirk alc861_fixup_tbl[] = {
5127 SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", PINFIX_FSC_AMILO_PI1505),
5128 {}
5129};
5130
5131/*
5132 */
Takashi Iwai1d045db2011-07-07 18:23:21 +02005133static int patch_alc861(struct hda_codec *codec)
5134{
5135 struct alc_spec *spec;
Takashi Iwai1d045db2011-07-07 18:23:21 +02005136 int err;
5137
5138 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
5139 if (spec == NULL)
5140 return -ENOMEM;
5141
5142 codec->spec = spec;
5143
5144 spec->mixer_nid = 0x15;
5145
Takashi Iwaicb4e4822011-08-23 17:34:25 +02005146 alc_pick_fixup(codec, NULL, alc861_fixup_tbl, alc861_fixups);
5147 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
Takashi Iwai1d045db2011-07-07 18:23:21 +02005148
Takashi Iwaicb4e4822011-08-23 17:34:25 +02005149 /* automatic parse from the BIOS config */
5150 err = alc861_parse_auto_config(codec);
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02005151 if (err < 0)
5152 goto error;
Takashi Iwai1d045db2011-07-07 18:23:21 +02005153
Takashi Iwai60a6a842011-07-27 14:01:24 +02005154 if (!spec->no_analog && !spec->adc_nids) {
Takashi Iwai1d045db2011-07-07 18:23:21 +02005155 alc_auto_fill_adc_caps(codec);
5156 alc_rebuild_imux_for_auto_mic(codec);
5157 alc_remove_invalid_adc_nids(codec);
5158 }
5159
Takashi Iwai3e6179b2011-07-08 16:55:13 +02005160 if (!spec->no_analog && !spec->cap_mixer)
Takashi Iwai1d045db2011-07-07 18:23:21 +02005161 set_capture_mixer(codec);
Takashi Iwai3e6179b2011-07-08 16:55:13 +02005162
5163 if (!spec->no_analog) {
5164 err = snd_hda_attach_beep_device(codec, 0x23);
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02005165 if (err < 0)
5166 goto error;
Takashi Iwai3e6179b2011-07-08 16:55:13 +02005167 set_beep_amp(spec, 0x23, 0, HDA_OUTPUT);
5168 }
Takashi Iwai1d045db2011-07-07 18:23:21 +02005169
5170 spec->vmaster_nid = 0x03;
5171
5172 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
5173
5174 codec->patch_ops = alc_patch_ops;
Takashi Iwaicb4e4822011-08-23 17:34:25 +02005175 spec->init_hook = alc_auto_init_std;
Takashi Iwai1d045db2011-07-07 18:23:21 +02005176#ifdef CONFIG_SND_HDA_POWER_SAVE
Takashi Iwaicb4e4822011-08-23 17:34:25 +02005177 spec->power_hook = alc_power_eapd;
Takashi Iwai1d045db2011-07-07 18:23:21 +02005178 if (!spec->loopback.amplist)
5179 spec->loopback.amplist = alc861_loopbacks;
5180#endif
5181
5182 return 0;
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02005183
5184 error:
5185 alc_free(codec);
5186 return err;
Takashi Iwai1d045db2011-07-07 18:23:21 +02005187}
5188
5189/*
5190 * ALC861-VD support
5191 *
5192 * Based on ALC882
5193 *
5194 * In addition, an independent DAC
5195 */
5196#ifdef CONFIG_SND_HDA_POWER_SAVE
5197#define alc861vd_loopbacks alc880_loopbacks
5198#endif
5199
Takashi Iwai1d045db2011-07-07 18:23:21 +02005200static int alc861vd_parse_auto_config(struct hda_codec *codec)
5201{
Takashi Iwai1d045db2011-07-07 18:23:21 +02005202 static const hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
Takashi Iwai3e6179b2011-07-08 16:55:13 +02005203 static const hda_nid_t alc861vd_ssids[] = { 0x15, 0x1b, 0x14, 0 };
5204 return alc_parse_auto_config(codec, alc861vd_ignore, alc861vd_ssids);
Takashi Iwai1d045db2011-07-07 18:23:21 +02005205}
5206
Takashi Iwai1d045db2011-07-07 18:23:21 +02005207enum {
Takashi Iwai8fdcb6f2011-08-23 17:28:55 +02005208 ALC660VD_FIX_ASUS_GPIO1,
5209 ALC861VD_FIX_DALLAS,
Takashi Iwai1d045db2011-07-07 18:23:21 +02005210};
5211
Takashi Iwai8fdcb6f2011-08-23 17:28:55 +02005212/* exclude VREF80 */
5213static void alc861vd_fixup_dallas(struct hda_codec *codec,
5214 const struct alc_fixup *fix, int action)
5215{
5216 if (action == ALC_FIXUP_ACT_PRE_PROBE) {
5217 snd_hda_override_pin_caps(codec, 0x18, 0x00001714);
5218 snd_hda_override_pin_caps(codec, 0x19, 0x0000171c);
5219 }
5220}
5221
Takashi Iwai1d045db2011-07-07 18:23:21 +02005222static const struct alc_fixup alc861vd_fixups[] = {
5223 [ALC660VD_FIX_ASUS_GPIO1] = {
5224 .type = ALC_FIXUP_VERBS,
5225 .v.verbs = (const struct hda_verb[]) {
Takashi Iwai8fdcb6f2011-08-23 17:28:55 +02005226 /* reset GPIO1 */
Takashi Iwai1d045db2011-07-07 18:23:21 +02005227 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
5228 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
5229 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
5230 { }
5231 }
5232 },
Takashi Iwai8fdcb6f2011-08-23 17:28:55 +02005233 [ALC861VD_FIX_DALLAS] = {
5234 .type = ALC_FIXUP_FUNC,
5235 .v.func = alc861vd_fixup_dallas,
5236 },
Takashi Iwai1d045db2011-07-07 18:23:21 +02005237};
5238
5239static const struct snd_pci_quirk alc861vd_fixup_tbl[] = {
Takashi Iwai8fdcb6f2011-08-23 17:28:55 +02005240 SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_FIX_DALLAS),
Takashi Iwai1d045db2011-07-07 18:23:21 +02005241 SND_PCI_QUIRK(0x1043, 0x1339, "ASUS A7-K", ALC660VD_FIX_ASUS_GPIO1),
Takashi Iwai8fdcb6f2011-08-23 17:28:55 +02005242 SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_FIX_DALLAS),
Takashi Iwai1d045db2011-07-07 18:23:21 +02005243 {}
5244};
5245
5246static const struct hda_verb alc660vd_eapd_verbs[] = {
5247 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
5248 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
5249 { }
5250};
5251
5252/*
5253 */
Takashi Iwai1d045db2011-07-07 18:23:21 +02005254static int patch_alc861vd(struct hda_codec *codec)
5255{
5256 struct alc_spec *spec;
Takashi Iwaicb4e4822011-08-23 17:34:25 +02005257 int err;
Takashi Iwai1d045db2011-07-07 18:23:21 +02005258
5259 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
5260 if (spec == NULL)
5261 return -ENOMEM;
5262
5263 codec->spec = spec;
5264
5265 spec->mixer_nid = 0x0b;
5266
Takashi Iwaicb4e4822011-08-23 17:34:25 +02005267 alc_pick_fixup(codec, NULL, alc861vd_fixup_tbl, alc861vd_fixups);
5268 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
Takashi Iwai1d045db2011-07-07 18:23:21 +02005269
Takashi Iwaicb4e4822011-08-23 17:34:25 +02005270 /* automatic parse from the BIOS config */
5271 err = alc861vd_parse_auto_config(codec);
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02005272 if (err < 0)
5273 goto error;
Takashi Iwai1d045db2011-07-07 18:23:21 +02005274
Takashi Iwai1d045db2011-07-07 18:23:21 +02005275 if (codec->vendor_id == 0x10ec0660) {
5276 /* always turn on EAPD */
5277 add_verb(spec, alc660vd_eapd_verbs);
5278 }
5279
Takashi Iwai60a6a842011-07-27 14:01:24 +02005280 if (!spec->no_analog && !spec->adc_nids) {
Takashi Iwai1d045db2011-07-07 18:23:21 +02005281 alc_auto_fill_adc_caps(codec);
5282 alc_rebuild_imux_for_auto_mic(codec);
5283 alc_remove_invalid_adc_nids(codec);
5284 }
5285
Takashi Iwai3e6179b2011-07-08 16:55:13 +02005286 if (!spec->no_analog && !spec->cap_mixer)
5287 set_capture_mixer(codec);
5288
5289 if (!spec->no_analog) {
5290 err = snd_hda_attach_beep_device(codec, 0x23);
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02005291 if (err < 0)
5292 goto error;
Takashi Iwai3e6179b2011-07-08 16:55:13 +02005293 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
5294 }
Takashi Iwai1d045db2011-07-07 18:23:21 +02005295
5296 spec->vmaster_nid = 0x02;
5297
5298 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
5299
5300 codec->patch_ops = alc_patch_ops;
5301
Takashi Iwaicb4e4822011-08-23 17:34:25 +02005302 spec->init_hook = alc_auto_init_std;
Takashi Iwai1d045db2011-07-07 18:23:21 +02005303 spec->shutup = alc_eapd_shutup;
5304#ifdef CONFIG_SND_HDA_POWER_SAVE
5305 if (!spec->loopback.amplist)
5306 spec->loopback.amplist = alc861vd_loopbacks;
5307#endif
5308
5309 return 0;
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02005310
5311 error:
5312 alc_free(codec);
5313 return err;
Takashi Iwai1d045db2011-07-07 18:23:21 +02005314}
5315
5316/*
5317 * ALC662 support
5318 *
5319 * ALC662 is almost identical with ALC880 but has cleaner and more flexible
5320 * configuration. Each pin widget can choose any input DACs and a mixer.
5321 * Each ADC is connected from a mixer of all inputs. This makes possible
5322 * 6-channel independent captures.
5323 *
5324 * In addition, an independent DAC for the multi-playback (not used in this
5325 * driver yet).
5326 */
5327#ifdef CONFIG_SND_HDA_POWER_SAVE
5328#define alc662_loopbacks alc880_loopbacks
5329#endif
5330
5331/*
5332 * BIOS auto configuration
5333 */
5334
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005335static int alc662_parse_auto_config(struct hda_codec *codec)
5336{
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02005337 static const hda_nid_t alc662_ignore[] = { 0x1d, 0 };
Takashi Iwai3e6179b2011-07-08 16:55:13 +02005338 static const hda_nid_t alc663_ssids[] = { 0x15, 0x1b, 0x14, 0x21 };
5339 static const hda_nid_t alc662_ssids[] = { 0x15, 0x1b, 0x14, 0 };
5340 const hda_nid_t *ssids;
Takashi Iwaiee979a142008-09-02 15:42:20 +02005341
Kailang Yang6227cdc2010-02-25 08:36:52 +01005342 if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 ||
5343 codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670)
Takashi Iwai3e6179b2011-07-08 16:55:13 +02005344 ssids = alc663_ssids;
Kailang Yang6227cdc2010-02-25 08:36:52 +01005345 else
Takashi Iwai3e6179b2011-07-08 16:55:13 +02005346 ssids = alc662_ssids;
5347 return alc_parse_auto_config(codec, alc662_ignore, ssids);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005348}
5349
Todd Broch6be79482010-12-07 16:51:05 -08005350static void alc272_fixup_mario(struct hda_codec *codec,
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01005351 const struct alc_fixup *fix, int action)
Takashi Iwai6fc398c2011-01-13 14:36:37 +01005352{
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01005353 if (action != ALC_FIXUP_ACT_PROBE)
Takashi Iwai6fc398c2011-01-13 14:36:37 +01005354 return;
Todd Broch6be79482010-12-07 16:51:05 -08005355 if (snd_hda_override_amp_caps(codec, 0x2, HDA_OUTPUT,
5356 (0x3b << AC_AMPCAP_OFFSET_SHIFT) |
5357 (0x3b << AC_AMPCAP_NUM_STEPS_SHIFT) |
5358 (0x03 << AC_AMPCAP_STEP_SIZE_SHIFT) |
5359 (0 << AC_AMPCAP_MUTE_SHIFT)))
5360 printk(KERN_WARNING
5361 "hda_codec: failed to override amp caps for NID 0x2\n");
5362}
5363
David Henningsson6cb3b702010-09-09 08:51:44 +02005364enum {
Daniel T Chen2df03512010-10-10 22:39:28 -04005365 ALC662_FIXUP_ASPIRE,
David Henningsson6cb3b702010-09-09 08:51:44 +02005366 ALC662_FIXUP_IDEAPAD,
Todd Broch6be79482010-12-07 16:51:05 -08005367 ALC272_FIXUP_MARIO,
Anisse Astierd2ebd472011-01-20 12:36:21 +01005368 ALC662_FIXUP_CZC_P10T,
David Henningsson94024cd2011-04-29 14:10:55 +02005369 ALC662_FIXUP_SKU_IGNORE,
Takashi Iwaie59ea3e2011-06-29 17:21:00 +02005370 ALC662_FIXUP_HP_RP5800,
Takashi Iwai53c334a2011-08-23 18:27:14 +02005371 ALC662_FIXUP_ASUS_MODE1,
5372 ALC662_FIXUP_ASUS_MODE2,
5373 ALC662_FIXUP_ASUS_MODE3,
5374 ALC662_FIXUP_ASUS_MODE4,
5375 ALC662_FIXUP_ASUS_MODE5,
5376 ALC662_FIXUP_ASUS_MODE6,
5377 ALC662_FIXUP_ASUS_MODE7,
5378 ALC662_FIXUP_ASUS_MODE8,
David Henningsson6cb3b702010-09-09 08:51:44 +02005379};
5380
5381static const struct alc_fixup alc662_fixups[] = {
Daniel T Chen2df03512010-10-10 22:39:28 -04005382 [ALC662_FIXUP_ASPIRE] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01005383 .type = ALC_FIXUP_PINS,
5384 .v.pins = (const struct alc_pincfg[]) {
Daniel T Chen2df03512010-10-10 22:39:28 -04005385 { 0x15, 0x99130112 }, /* subwoofer */
5386 { }
5387 }
5388 },
David Henningsson6cb3b702010-09-09 08:51:44 +02005389 [ALC662_FIXUP_IDEAPAD] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01005390 .type = ALC_FIXUP_PINS,
5391 .v.pins = (const struct alc_pincfg[]) {
David Henningsson6cb3b702010-09-09 08:51:44 +02005392 { 0x17, 0x99130112 }, /* subwoofer */
5393 { }
5394 }
5395 },
Todd Broch6be79482010-12-07 16:51:05 -08005396 [ALC272_FIXUP_MARIO] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01005397 .type = ALC_FIXUP_FUNC,
5398 .v.func = alc272_fixup_mario,
Anisse Astierd2ebd472011-01-20 12:36:21 +01005399 },
5400 [ALC662_FIXUP_CZC_P10T] = {
5401 .type = ALC_FIXUP_VERBS,
5402 .v.verbs = (const struct hda_verb[]) {
5403 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 0},
5404 {}
5405 }
5406 },
David Henningsson94024cd2011-04-29 14:10:55 +02005407 [ALC662_FIXUP_SKU_IGNORE] = {
5408 .type = ALC_FIXUP_SKU,
5409 .v.sku = ALC_FIXUP_SKU_IGNORE,
Takashi Iwaic6b35872011-03-28 12:05:31 +02005410 },
Takashi Iwaie59ea3e2011-06-29 17:21:00 +02005411 [ALC662_FIXUP_HP_RP5800] = {
5412 .type = ALC_FIXUP_PINS,
5413 .v.pins = (const struct alc_pincfg[]) {
5414 { 0x14, 0x0221201f }, /* HP out */
5415 { }
5416 },
5417 .chained = true,
5418 .chain_id = ALC662_FIXUP_SKU_IGNORE
5419 },
Takashi Iwai53c334a2011-08-23 18:27:14 +02005420 [ALC662_FIXUP_ASUS_MODE1] = {
5421 .type = ALC_FIXUP_PINS,
5422 .v.pins = (const struct alc_pincfg[]) {
5423 { 0x14, 0x99130110 }, /* speaker */
5424 { 0x18, 0x01a19c20 }, /* mic */
5425 { 0x19, 0x99a3092f }, /* int-mic */
5426 { 0x21, 0x0121401f }, /* HP out */
5427 { }
5428 },
5429 .chained = true,
5430 .chain_id = ALC662_FIXUP_SKU_IGNORE
5431 },
5432 [ALC662_FIXUP_ASUS_MODE2] = {
Takashi Iwai2996bdb2011-08-18 16:02:24 +02005433 .type = ALC_FIXUP_PINS,
5434 .v.pins = (const struct alc_pincfg[]) {
5435 { 0x14, 0x99130110 }, /* speaker */
5436 { 0x18, 0x01a19820 }, /* mic */
5437 { 0x19, 0x99a3092f }, /* int-mic */
5438 { 0x1b, 0x0121401f }, /* HP out */
5439 { }
5440 },
Takashi Iwai53c334a2011-08-23 18:27:14 +02005441 .chained = true,
5442 .chain_id = ALC662_FIXUP_SKU_IGNORE
5443 },
5444 [ALC662_FIXUP_ASUS_MODE3] = {
5445 .type = ALC_FIXUP_PINS,
5446 .v.pins = (const struct alc_pincfg[]) {
5447 { 0x14, 0x99130110 }, /* speaker */
5448 { 0x15, 0x0121441f }, /* HP */
5449 { 0x18, 0x01a19840 }, /* mic */
5450 { 0x19, 0x99a3094f }, /* int-mic */
5451 { 0x21, 0x01211420 }, /* HP2 */
5452 { }
5453 },
5454 .chained = true,
5455 .chain_id = ALC662_FIXUP_SKU_IGNORE
5456 },
5457 [ALC662_FIXUP_ASUS_MODE4] = {
5458 .type = ALC_FIXUP_PINS,
5459 .v.pins = (const struct alc_pincfg[]) {
5460 { 0x14, 0x99130110 }, /* speaker */
5461 { 0x16, 0x99130111 }, /* speaker */
5462 { 0x18, 0x01a19840 }, /* mic */
5463 { 0x19, 0x99a3094f }, /* int-mic */
5464 { 0x21, 0x0121441f }, /* HP */
5465 { }
5466 },
5467 .chained = true,
5468 .chain_id = ALC662_FIXUP_SKU_IGNORE
5469 },
5470 [ALC662_FIXUP_ASUS_MODE5] = {
5471 .type = ALC_FIXUP_PINS,
5472 .v.pins = (const struct alc_pincfg[]) {
5473 { 0x14, 0x99130110 }, /* speaker */
5474 { 0x15, 0x0121441f }, /* HP */
5475 { 0x16, 0x99130111 }, /* speaker */
5476 { 0x18, 0x01a19840 }, /* mic */
5477 { 0x19, 0x99a3094f }, /* int-mic */
5478 { }
5479 },
5480 .chained = true,
5481 .chain_id = ALC662_FIXUP_SKU_IGNORE
5482 },
5483 [ALC662_FIXUP_ASUS_MODE6] = {
5484 .type = ALC_FIXUP_PINS,
5485 .v.pins = (const struct alc_pincfg[]) {
5486 { 0x14, 0x99130110 }, /* speaker */
5487 { 0x15, 0x01211420 }, /* HP2 */
5488 { 0x18, 0x01a19840 }, /* mic */
5489 { 0x19, 0x99a3094f }, /* int-mic */
5490 { 0x1b, 0x0121441f }, /* HP */
5491 { }
5492 },
5493 .chained = true,
5494 .chain_id = ALC662_FIXUP_SKU_IGNORE
5495 },
5496 [ALC662_FIXUP_ASUS_MODE7] = {
5497 .type = ALC_FIXUP_PINS,
5498 .v.pins = (const struct alc_pincfg[]) {
5499 { 0x14, 0x99130110 }, /* speaker */
5500 { 0x17, 0x99130111 }, /* speaker */
5501 { 0x18, 0x01a19840 }, /* mic */
5502 { 0x19, 0x99a3094f }, /* int-mic */
5503 { 0x1b, 0x01214020 }, /* HP */
5504 { 0x21, 0x0121401f }, /* HP */
5505 { }
5506 },
5507 .chained = true,
5508 .chain_id = ALC662_FIXUP_SKU_IGNORE
5509 },
5510 [ALC662_FIXUP_ASUS_MODE8] = {
5511 .type = ALC_FIXUP_PINS,
5512 .v.pins = (const struct alc_pincfg[]) {
5513 { 0x14, 0x99130110 }, /* speaker */
5514 { 0x12, 0x99a30970 }, /* int-mic */
5515 { 0x15, 0x01214020 }, /* HP */
5516 { 0x17, 0x99130111 }, /* speaker */
5517 { 0x18, 0x01a19840 }, /* mic */
5518 { 0x21, 0x0121401f }, /* HP */
5519 { }
5520 },
5521 .chained = true,
5522 .chain_id = ALC662_FIXUP_SKU_IGNORE
Takashi Iwai2996bdb2011-08-18 16:02:24 +02005523 },
David Henningsson6cb3b702010-09-09 08:51:44 +02005524};
5525
Takashi Iwaia9111322011-05-02 11:30:18 +02005526static const struct snd_pci_quirk alc662_fixup_tbl[] = {
Takashi Iwai53c334a2011-08-23 18:27:14 +02005527 SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_FIXUP_ASUS_MODE2),
David Henningssona6c47a82011-02-10 15:39:19 +01005528 SND_PCI_QUIRK(0x1025, 0x0308, "Acer Aspire 8942G", ALC662_FIXUP_ASPIRE),
David Henningsson94024cd2011-04-29 14:10:55 +02005529 SND_PCI_QUIRK(0x1025, 0x031c, "Gateway NV79", ALC662_FIXUP_SKU_IGNORE),
Daniel T Chen2df03512010-10-10 22:39:28 -04005530 SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE),
Takashi Iwaie59ea3e2011-06-29 17:21:00 +02005531 SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800),
Takashi Iwai53c334a2011-08-23 18:27:14 +02005532 SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_FIXUP_ASUS_MODE2),
Daniel T Chena0e90ac2010-11-20 10:20:35 -05005533 SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD),
Valentine Sinitsynd4118582010-10-01 22:24:08 +06005534 SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD),
David Henningsson6cb3b702010-09-09 08:51:44 +02005535 SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD),
Anisse Astierd2ebd472011-01-20 12:36:21 +01005536 SND_PCI_QUIRK(0x1b35, 0x2206, "CZC P10T", ALC662_FIXUP_CZC_P10T),
Takashi Iwai53c334a2011-08-23 18:27:14 +02005537
5538#if 0
5539 /* Below is a quirk table taken from the old code.
5540 * Basically the device should work as is without the fixup table.
5541 * If BIOS doesn't give a proper info, enable the corresponding
5542 * fixup entry.
5543 */
5544 SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC662_FIXUP_ASUS_MODE1),
5545 SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC662_FIXUP_ASUS_MODE3),
5546 SND_PCI_QUIRK(0x1043, 0x1173, "ASUS K73Jn", ALC662_FIXUP_ASUS_MODE1),
5547 SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC662_FIXUP_ASUS_MODE3),
5548 SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC662_FIXUP_ASUS_MODE1),
5549 SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
5550 SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC662_FIXUP_ASUS_MODE1),
5551 SND_PCI_QUIRK(0x1043, 0x1303, "ASUS G60J", ALC662_FIXUP_ASUS_MODE1),
5552 SND_PCI_QUIRK(0x1043, 0x1333, "ASUS G60Jx", ALC662_FIXUP_ASUS_MODE1),
5553 SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
5554 SND_PCI_QUIRK(0x1043, 0x13e3, "ASUS N71JA", ALC662_FIXUP_ASUS_MODE7),
5555 SND_PCI_QUIRK(0x1043, 0x1463, "ASUS N71", ALC662_FIXUP_ASUS_MODE7),
5556 SND_PCI_QUIRK(0x1043, 0x14d3, "ASUS G72", ALC662_FIXUP_ASUS_MODE8),
5557 SND_PCI_QUIRK(0x1043, 0x1563, "ASUS N90", ALC662_FIXUP_ASUS_MODE3),
5558 SND_PCI_QUIRK(0x1043, 0x15d3, "ASUS N50SF F50SF", ALC662_FIXUP_ASUS_MODE1),
5559 SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
5560 SND_PCI_QUIRK(0x1043, 0x16f3, "ASUS K40C K50C", ALC662_FIXUP_ASUS_MODE2),
5561 SND_PCI_QUIRK(0x1043, 0x1733, "ASUS N81De", ALC662_FIXUP_ASUS_MODE1),
5562 SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
5563 SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC662_FIXUP_ASUS_MODE6),
5564 SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC662_FIXUP_ASUS_MODE6),
5565 SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
5566 SND_PCI_QUIRK(0x1043, 0x1793, "ASUS F50GX", ALC662_FIXUP_ASUS_MODE1),
5567 SND_PCI_QUIRK(0x1043, 0x17b3, "ASUS F70SL", ALC662_FIXUP_ASUS_MODE3),
5568 SND_PCI_QUIRK(0x1043, 0x17f3, "ASUS X58LE", ALC662_FIXUP_ASUS_MODE2),
5569 SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
5570 SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC662_FIXUP_ASUS_MODE5),
5571 SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC662_FIXUP_ASUS_MODE6),
5572 SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
5573 SND_PCI_QUIRK(0x1043, 0x1853, "ASUS F50Z", ALC662_FIXUP_ASUS_MODE1),
5574 SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
5575 SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
5576 SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC662_FIXUP_ASUS_MODE3),
5577 SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC662_FIXUP_ASUS_MODE3),
5578 SND_PCI_QUIRK(0x1043, 0x18b3, "ASUS N80Vc", ALC662_FIXUP_ASUS_MODE1),
5579 SND_PCI_QUIRK(0x1043, 0x18c3, "ASUS VX5", ALC662_FIXUP_ASUS_MODE1),
5580 SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS N81Te", ALC662_FIXUP_ASUS_MODE1),
5581 SND_PCI_QUIRK(0x1043, 0x18f3, "ASUS N505Tp", ALC662_FIXUP_ASUS_MODE1),
5582 SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC662_FIXUP_ASUS_MODE1),
5583 SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
5584 SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_FIXUP_ASUS_MODE2),
5585 SND_PCI_QUIRK(0x1043, 0x1943, "ASUS Vx3V", ALC662_FIXUP_ASUS_MODE1),
5586 SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC662_FIXUP_ASUS_MODE1),
5587 SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC662_FIXUP_ASUS_MODE3),
5588 SND_PCI_QUIRK(0x1043, 0x1983, "ASUS N5051A", ALC662_FIXUP_ASUS_MODE1),
5589 SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC662_FIXUP_ASUS_MODE1),
5590 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC662_FIXUP_ASUS_MODE1),
5591 SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_FIXUP_ASUS_MODE2),
5592 SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC662_FIXUP_ASUS_MODE1),
5593 SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC662_FIXUP_ASUS_MODE4),
5594#endif
David Henningsson6cb3b702010-09-09 08:51:44 +02005595 {}
5596};
5597
Todd Broch6be79482010-12-07 16:51:05 -08005598static const struct alc_model_fixup alc662_fixup_models[] = {
5599 {.id = ALC272_FIXUP_MARIO, .name = "mario"},
Takashi Iwai53c334a2011-08-23 18:27:14 +02005600 {.id = ALC662_FIXUP_ASUS_MODE1, .name = "asus-mode1"},
5601 {.id = ALC662_FIXUP_ASUS_MODE2, .name = "asus-mode2"},
5602 {.id = ALC662_FIXUP_ASUS_MODE3, .name = "asus-mode3"},
5603 {.id = ALC662_FIXUP_ASUS_MODE4, .name = "asus-mode4"},
5604 {.id = ALC662_FIXUP_ASUS_MODE5, .name = "asus-mode5"},
5605 {.id = ALC662_FIXUP_ASUS_MODE6, .name = "asus-mode6"},
5606 {.id = ALC662_FIXUP_ASUS_MODE7, .name = "asus-mode7"},
5607 {.id = ALC662_FIXUP_ASUS_MODE8, .name = "asus-mode8"},
Todd Broch6be79482010-12-07 16:51:05 -08005608 {}
5609};
David Henningsson6cb3b702010-09-09 08:51:44 +02005610
5611
Takashi Iwai1d045db2011-07-07 18:23:21 +02005612/*
5613 */
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005614static int patch_alc662(struct hda_codec *codec)
5615{
5616 struct alc_spec *spec;
Takashi Iwai20ca0c32011-10-17 16:00:35 +02005617 int err = 0;
Kailang Yang693194f2010-10-21 08:51:48 +02005618 int coef;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005619
5620 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
5621 if (!spec)
5622 return -ENOMEM;
5623
5624 codec->spec = spec;
5625
Takashi Iwai1f0f4b82011-06-27 10:52:59 +02005626 spec->mixer_nid = 0x0b;
5627
Takashi Iwai53c334a2011-08-23 18:27:14 +02005628 /* handle multiple HPs as is */
5629 spec->parse_flags = HDA_PINCFG_NO_HP_FIXUP;
5630
Kailang Yangda00c242010-03-19 11:23:45 +01005631 alc_auto_parse_customize_define(codec);
5632
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02005633 alc_fix_pll_init(codec, 0x20, 0x04, 15);
5634
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02005635 err = alc_codec_rename_from_preset(codec);
5636 if (err < 0)
5637 goto error;
5638
Kailang Yang693194f2010-10-21 08:51:48 +02005639 coef = alc_read_coef_idx(codec, 0);
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02005640 if (coef & (1 << 14) &&
5641 codec->bus->pci->subsystem_vendor == 0x1025 &&
5642 spec->cdefine.platform_type == 1) {
5643 if (alc_codec_rename(codec, "ALC272X") < 0)
5644 goto error;
Takashi Iwai20ca0c32011-10-17 16:00:35 +02005645 }
Kailang Yang274693f2009-12-03 10:07:50 +01005646
Takashi Iwaib9c51062011-08-24 18:08:07 +02005647 alc_pick_fixup(codec, alc662_fixup_models,
5648 alc662_fixup_tbl, alc662_fixups);
5649 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
5650 /* automatic parse from the BIOS config */
5651 err = alc662_parse_auto_config(codec);
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02005652 if (err < 0)
5653 goto error;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005654
Takashi Iwai60a6a842011-07-27 14:01:24 +02005655 if (!spec->no_analog && !spec->adc_nids) {
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02005656 alc_auto_fill_adc_caps(codec);
Takashi Iwai21268962011-07-07 15:01:13 +02005657 alc_rebuild_imux_for_auto_mic(codec);
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02005658 alc_remove_invalid_adc_nids(codec);
Takashi Iwaidd704692009-08-11 08:45:11 +02005659 }
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005660
Takashi Iwai3e6179b2011-07-08 16:55:13 +02005661 if (!spec->no_analog && !spec->cap_mixer)
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005662 set_capture_mixer(codec);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005663
Takashi Iwai3e6179b2011-07-08 16:55:13 +02005664 if (!spec->no_analog && has_cdefine_beep(codec)) {
5665 err = snd_hda_attach_beep_device(codec, 0x1);
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02005666 if (err < 0)
5667 goto error;
Kailang Yangda00c242010-03-19 11:23:45 +01005668 switch (codec->vendor_id) {
5669 case 0x10ec0662:
5670 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
5671 break;
5672 case 0x10ec0272:
5673 case 0x10ec0663:
5674 case 0x10ec0665:
5675 set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
5676 break;
5677 case 0x10ec0273:
5678 set_beep_amp(spec, 0x0b, 0x03, HDA_INPUT);
5679 break;
5680 }
Kailang Yangcec27c82010-02-04 14:18:18 +01005681 }
Takashi Iwai2134ea42008-01-10 16:53:55 +01005682 spec->vmaster_nid = 0x02;
5683
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01005684 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
5685
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005686 codec->patch_ops = alc_patch_ops;
Takashi Iwaib9c51062011-08-24 18:08:07 +02005687 spec->init_hook = alc_auto_init_std;
Takashi Iwai1c7161532011-04-07 10:37:16 +02005688 spec->shutup = alc_eapd_shutup;
David Henningsson6cb3b702010-09-09 08:51:44 +02005689
Kailang Yangbf1b0222010-10-21 08:49:56 +02005690 alc_init_jacks(codec);
5691
Takashi Iwaicb53c622007-08-10 17:21:45 +02005692#ifdef CONFIG_SND_HDA_POWER_SAVE
5693 if (!spec->loopback.amplist)
5694 spec->loopback.amplist = alc662_loopbacks;
5695#endif
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005696
5697 return 0;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005698
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02005699 error:
5700 alc_free(codec);
5701 return err;
Kailang Yangb478b992011-05-18 11:51:15 +02005702}
5703
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005704/*
Kailang Yangd1eb57f2010-06-23 16:25:26 +02005705 * ALC680 support
5706 */
Kailang Yangd1eb57f2010-06-23 16:25:26 +02005707
Kailang Yangd1eb57f2010-06-23 16:25:26 +02005708static int alc680_parse_auto_config(struct hda_codec *codec)
5709{
Takashi Iwai3e6179b2011-07-08 16:55:13 +02005710 return alc_parse_auto_config(codec, NULL, NULL);
Kailang Yangd1eb57f2010-06-23 16:25:26 +02005711}
5712
Kailang Yangd1eb57f2010-06-23 16:25:26 +02005713/*
Kailang Yangd1eb57f2010-06-23 16:25:26 +02005714 */
Kailang Yangd1eb57f2010-06-23 16:25:26 +02005715static int patch_alc680(struct hda_codec *codec)
5716{
5717 struct alc_spec *spec;
Kailang Yangd1eb57f2010-06-23 16:25:26 +02005718 int err;
5719
5720 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
5721 if (spec == NULL)
5722 return -ENOMEM;
5723
5724 codec->spec = spec;
5725
Takashi Iwai1f0f4b82011-06-27 10:52:59 +02005726 /* ALC680 has no aa-loopback mixer */
5727
Takashi Iwai1ebec5f2011-08-15 13:21:48 +02005728 /* automatic parse from the BIOS config */
5729 err = alc680_parse_auto_config(codec);
5730 if (err < 0) {
5731 alc_free(codec);
5732 return err;
Kailang Yangd1eb57f2010-06-23 16:25:26 +02005733 }
5734
Takashi Iwai3e6179b2011-07-08 16:55:13 +02005735 if (!spec->no_analog && !spec->cap_mixer)
Kailang Yangd1eb57f2010-06-23 16:25:26 +02005736 set_capture_mixer(codec);
5737
5738 spec->vmaster_nid = 0x02;
5739
5740 codec->patch_ops = alc_patch_ops;
Takashi Iwai1ebec5f2011-08-15 13:21:48 +02005741 spec->init_hook = alc_auto_init_std;
Kailang Yangd1eb57f2010-06-23 16:25:26 +02005742
5743 return 0;
5744}
5745
5746/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07005747 * patch entries
5748 */
Takashi Iwaia9111322011-05-02 11:30:18 +02005749static const struct hda_codec_preset snd_hda_preset_realtek[] = {
Kailang Yang296f0332011-05-18 11:52:36 +02005750 { .id = 0x10ec0221, .name = "ALC221", .patch = patch_alc269 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07005751 { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
Kailang Yangdf694da2005-12-05 19:42:22 +01005752 { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
Kailang Yangf6a92242007-12-13 16:52:54 +01005753 { .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 },
Kailang Yanga361d842007-06-05 12:30:55 +02005754 { .id = 0x10ec0268, .name = "ALC268", .patch = patch_alc268 },
Kailang Yangf6a92242007-12-13 16:52:54 +01005755 { .id = 0x10ec0269, .name = "ALC269", .patch = patch_alc269 },
Kailang Yangebb83ee2009-12-17 12:23:00 +01005756 { .id = 0x10ec0270, .name = "ALC270", .patch = patch_alc269 },
Kailang Yang01afd412008-10-15 11:22:09 +02005757 { .id = 0x10ec0272, .name = "ALC272", .patch = patch_alc662 },
Kailang Yangebb83ee2009-12-17 12:23:00 +01005758 { .id = 0x10ec0275, .name = "ALC275", .patch = patch_alc269 },
Kailang Yang296f0332011-05-18 11:52:36 +02005759 { .id = 0x10ec0276, .name = "ALC276", .patch = patch_alc269 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +01005760 { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005761 .patch = patch_alc861 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +01005762 { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
5763 { .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 },
5764 { .id = 0x10ec0862, .name = "ALC861-VD", .patch = patch_alc861vd },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005765 { .id = 0x10ec0662, .rev = 0x100002, .name = "ALC662 rev2",
Takashi Iwai4953550a2009-06-30 15:28:30 +02005766 .patch = patch_alc882 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005767 { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1",
5768 .patch = patch_alc662 },
Kailang Yang6dda9f42008-05-27 12:05:31 +02005769 { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 },
Kailang Yangcec27c82010-02-04 14:18:18 +01005770 { .id = 0x10ec0665, .name = "ALC665", .patch = patch_alc662 },
Kailang Yang6227cdc2010-02-25 08:36:52 +01005771 { .id = 0x10ec0670, .name = "ALC670", .patch = patch_alc662 },
Kailang Yangd1eb57f2010-06-23 16:25:26 +02005772 { .id = 0x10ec0680, .name = "ALC680", .patch = patch_alc680 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +01005773 { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07005774 { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
Takashi Iwai4953550a2009-06-30 15:28:30 +02005775 { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc882 },
Clive Messer669faba2008-09-30 15:49:13 +02005776 { .id = 0x10ec0885, .rev = 0x100101, .name = "ALC889A",
Takashi Iwai4953550a2009-06-30 15:28:30 +02005777 .patch = patch_alc882 },
Takashi Iwaicb308f92008-04-16 14:13:29 +02005778 { .id = 0x10ec0885, .rev = 0x100103, .name = "ALC889A",
Takashi Iwai4953550a2009-06-30 15:28:30 +02005779 .patch = patch_alc882 },
Kailang Yangdf694da2005-12-05 19:42:22 +01005780 { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02005781 { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc882 },
Kailang Yang44426082008-10-15 11:18:05 +02005782 { .id = 0x10ec0888, .rev = 0x100101, .name = "ALC1200",
Takashi Iwai4953550a2009-06-30 15:28:30 +02005783 .patch = patch_alc882 },
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02005784 { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc882 },
Takashi Iwai4953550a2009-06-30 15:28:30 +02005785 { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc882 },
Kailang Yang274693f2009-12-03 10:07:50 +01005786 { .id = 0x10ec0892, .name = "ALC892", .patch = patch_alc662 },
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02005787 { .id = 0x10ec0899, .name = "ALC898", .patch = patch_alc882 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07005788 {} /* terminator */
5789};
Takashi Iwai1289e9e2008-11-27 15:47:11 +01005790
5791MODULE_ALIAS("snd-hda-codec-id:10ec*");
5792
5793MODULE_LICENSE("GPL");
5794MODULE_DESCRIPTION("Realtek HD-audio codec");
5795
5796static struct hda_codec_preset_list realtek_list = {
5797 .preset = snd_hda_preset_realtek,
5798 .owner = THIS_MODULE,
5799};
5800
5801static int __init patch_realtek_init(void)
5802{
5803 return snd_hda_add_codec_preset(&realtek_list);
5804}
5805
5806static void __exit patch_realtek_exit(void)
5807{
5808 snd_hda_delete_codec_preset(&realtek_list);
5809}
5810
5811module_init(patch_realtek_init)
5812module_exit(patch_realtek_exit)