blob: ddbed9705ef49bbae108c643b37dc417bd0b862f [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 Woithe7cf51e42006-02-09 12:01:26 +01009 * Jonathan Woithe <jwoithe@physics.adelaide.edu.au>
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 *
11 * This driver is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This driver is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <linux/init.h>
27#include <linux/delay.h>
28#include <linux/slab.h>
29#include <linux/pci.h>
Paul Gortmakerda155d52011-07-15 12:38:28 -040030#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031#include <sound/core.h>
Kailang Yang9ad0e492010-09-14 23:22:00 +020032#include <sound/jack.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include "hda_codec.h"
34#include "hda_local.h"
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090035#include "hda_beep.h"
Takashi Iwai1835a0f2011-10-27 22:12:46 +020036#include "hda_jack.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070037
Takashi Iwai1d045db2011-07-07 18:23:21 +020038/* unsol event tags */
39#define ALC_FRONT_EVENT 0x01
40#define ALC_DCVOL_EVENT 0x02
41#define ALC_HP_EVENT 0x04
42#define ALC_MIC_EVENT 0x08
Takashi Iwaid4a86d82010-06-23 17:51:26 +020043
Kailang Yangdf694da2005-12-05 19:42:22 +010044/* for GPIO Poll */
45#define GPIO_MASK 0x03
46
Takashi Iwai4a79ba32009-04-22 16:31:35 +020047/* extra amp-initialization sequence types */
48enum {
49 ALC_INIT_NONE,
50 ALC_INIT_DEFAULT,
51 ALC_INIT_GPIO1,
52 ALC_INIT_GPIO2,
53 ALC_INIT_GPIO3,
54};
55
Kailang Yangda00c242010-03-19 11:23:45 +010056struct alc_customize_define {
57 unsigned int sku_cfg;
58 unsigned char port_connectivity;
59 unsigned char check_sum;
60 unsigned char customization;
61 unsigned char external_amp;
62 unsigned int enable_pcbeep:1;
63 unsigned int platform_type:1;
64 unsigned int swap:1;
65 unsigned int override:1;
David Henningsson90622912010-10-14 14:50:18 +020066 unsigned int fixup:1; /* Means that this sku is set by driver, not read from hw */
Kailang Yangda00c242010-03-19 11:23:45 +010067};
68
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010069struct alc_fixup;
70
Takashi Iwaice764ab2011-04-27 16:35:23 +020071struct alc_multi_io {
72 hda_nid_t pin; /* multi-io widget pin NID */
73 hda_nid_t dac; /* DAC to be connected */
74 unsigned int ctl_in; /* cached input-pin control value */
75};
76
Takashi Iwaid922b512011-04-28 12:18:53 +020077enum {
Takashi Iwai3b8510c2011-04-28 14:03:24 +020078 ALC_AUTOMUTE_PIN, /* change the pin control */
79 ALC_AUTOMUTE_AMP, /* mute/unmute the pin AMP */
80 ALC_AUTOMUTE_MIXER, /* mute/unmute mixer widget AMP */
Takashi Iwaid922b512011-04-28 12:18:53 +020081};
82
Linus Torvalds1da177e2005-04-16 15:20:36 -070083struct alc_spec {
84 /* codec parameterization */
Takashi Iwaia9111322011-05-02 11:30:18 +020085 const struct snd_kcontrol_new *mixers[5]; /* mixer arrays */
Linus Torvalds1da177e2005-04-16 15:20:36 -070086 unsigned int num_mixers;
Takashi Iwaia9111322011-05-02 11:30:18 +020087 const struct snd_kcontrol_new *cap_mixer; /* capture mixer */
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010088 unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */
Linus Torvalds1da177e2005-04-16 15:20:36 -070089
Takashi Iwai2d9c6482009-10-13 08:06:55 +020090 const struct hda_verb *init_verbs[10]; /* initialization verbs
Takashi Iwai9c7f8522006-06-28 15:08:22 +020091 * don't forget NULL
92 * termination!
Takashi Iwaie9edcee2005-06-13 14:16:38 +020093 */
94 unsigned int num_init_verbs;
Linus Torvalds1da177e2005-04-16 15:20:36 -070095
Takashi Iwaiaa563af2009-07-31 10:05:11 +020096 char stream_name_analog[32]; /* analog PCM stream */
Takashi Iwaia9111322011-05-02 11:30:18 +020097 const struct hda_pcm_stream *stream_analog_playback;
98 const struct hda_pcm_stream *stream_analog_capture;
99 const struct hda_pcm_stream *stream_analog_alt_playback;
100 const struct hda_pcm_stream *stream_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101
Takashi Iwaiaa563af2009-07-31 10:05:11 +0200102 char stream_name_digital[32]; /* digital PCM stream */
Takashi Iwaia9111322011-05-02 11:30:18 +0200103 const struct hda_pcm_stream *stream_digital_playback;
104 const struct hda_pcm_stream *stream_digital_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105
106 /* playback */
Takashi Iwai16ded522005-06-10 19:58:24 +0200107 struct hda_multi_out multiout; /* playback set-up
108 * max_channels, dacs must be set
109 * dig_out_nid and hp_nid are optional
110 */
Takashi Iwai63300792008-01-24 15:31:36 +0100111 hda_nid_t alt_dac_nid;
Takashi Iwai6a05ac42009-02-13 11:19:09 +0100112 hda_nid_t slave_dig_outs[3]; /* optional - for auto-parsing */
Takashi Iwai8c441982009-01-20 18:30:20 +0100113 int dig_out_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114
115 /* capture */
116 unsigned int num_adc_nids;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +0200117 const hda_nid_t *adc_nids;
118 const hda_nid_t *capsrc_nids;
Takashi Iwai16ded522005-06-10 19:58:24 +0200119 hda_nid_t dig_in_nid; /* digital-in NID; optional */
Takashi Iwai1f0f4b82011-06-27 10:52:59 +0200120 hda_nid_t mixer_nid; /* analog-mixer NID */
Takashi Iwai527e4d72011-10-27 16:33:27 +0200121 DECLARE_BITMAP(vol_ctls, 0x20 << 1);
122 DECLARE_BITMAP(sw_ctls, 0x20 << 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123
Takashi Iwai840b64c2010-07-13 22:49:01 +0200124 /* capture setup for dynamic dual-adc switch */
Takashi Iwai840b64c2010-07-13 22:49:01 +0200125 hda_nid_t cur_adc;
126 unsigned int cur_adc_stream_tag;
127 unsigned int cur_adc_format;
128
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129 /* capture source */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200130 unsigned int num_mux_defs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131 const struct hda_input_mux *input_mux;
132 unsigned int cur_mux[3];
Takashi Iwai21268962011-07-07 15:01:13 +0200133 hda_nid_t ext_mic_pin;
134 hda_nid_t dock_mic_pin;
135 hda_nid_t int_mic_pin;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136
137 /* channel model */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100138 const struct hda_channel_mode *channel_mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139 int num_channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200140 int need_dac_fix;
Hector Martin3b315d72009-06-02 10:54:19 +0200141 int const_channel_count;
142 int ext_channel_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143
144 /* PCM information */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100145 struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */
Takashi Iwai41e41f12005-06-08 14:48:49 +0200146
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200147 /* dynamic controls, init_verbs and input_mux */
148 struct auto_pin_cfg autocfg;
Kailang Yangda00c242010-03-19 11:23:45 +0100149 struct alc_customize_define cdefine;
Takashi Iwai603c4012008-07-30 15:01:44 +0200150 struct snd_array kctls;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -0200151 struct hda_input_mux private_imux[3];
Takashi Iwai41923e42007-10-22 17:20:10 +0200152 hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
Takashi Iwai4953550a2009-06-30 15:28:30 +0200153 hda_nid_t private_adc_nids[AUTO_CFG_MAX_OUTS];
154 hda_nid_t private_capsrc_nids[AUTO_CFG_MAX_OUTS];
Takashi Iwai21268962011-07-07 15:01:13 +0200155 hda_nid_t imux_pins[HDA_MAX_NUM_INPUTS];
156 unsigned int dyn_adc_idx[HDA_MAX_NUM_INPUTS];
157 int int_mic_idx, ext_mic_idx, dock_mic_idx; /* for auto-mic */
Takashi Iwai834be882006-03-01 14:16:17 +0100158
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100159 /* hooks */
160 void (*init_hook)(struct hda_codec *codec);
161 void (*unsol_event)(struct hda_codec *codec, unsigned int res);
Hector Martinf5de24b2009-12-20 22:51:31 +0100162#ifdef CONFIG_SND_HDA_POWER_SAVE
Daniel T Chenc97259d2009-12-27 18:52:08 -0500163 void (*power_hook)(struct hda_codec *codec);
Hector Martinf5de24b2009-12-20 22:51:31 +0100164#endif
Takashi Iwai1c716152011-04-07 10:37:16 +0200165 void (*shutup)(struct hda_codec *codec);
Takashi Iwai24519912011-08-16 15:08:49 +0200166 void (*automute_hook)(struct hda_codec *codec);
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100167
Takashi Iwai834be882006-03-01 14:16:17 +0100168 /* for pin sensing */
David Henningsson42cf0d02011-09-20 12:04:56 +0200169 unsigned int hp_jack_present:1;
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200170 unsigned int line_jack_present:1;
Takashi Iwaie9427962011-04-28 15:46:07 +0200171 unsigned int master_mute:1;
Takashi Iwai6c819492009-08-10 18:47:44 +0200172 unsigned int auto_mic:1;
Takashi Iwai21268962011-07-07 15:01:13 +0200173 unsigned int auto_mic_valid_imux:1; /* valid imux for auto-mic */
David Henningsson42cf0d02011-09-20 12:04:56 +0200174 unsigned int automute_speaker:1; /* automute speaker outputs */
175 unsigned int automute_lo:1; /* automute LO outputs */
176 unsigned int detect_hp:1; /* Headphone detection enabled */
177 unsigned int detect_lo:1; /* Line-out detection enabled */
178 unsigned int automute_speaker_possible:1; /* there are speakers and either LO or HP */
179 unsigned int automute_lo_possible:1; /* there are line outs and HP */
Takashi Iwaicb53c622007-08-10 17:21:45 +0200180
Takashi Iwaie64f14f2009-01-20 18:32:55 +0100181 /* other flags */
182 unsigned int no_analog :1; /* digital I/O only */
Takashi Iwai21268962011-07-07 15:01:13 +0200183 unsigned int dyn_adc_switch:1; /* switch ADCs (for ALC275) */
Takashi Iwai584c0c42011-03-10 12:51:11 +0100184 unsigned int single_input_src:1;
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +0200185 unsigned int vol_in_capsrc:1; /* use capsrc volume (ADC has no vol) */
Takashi Iwai53c334a2011-08-23 18:27:14 +0200186 unsigned int parse_flags; /* passed to snd_hda_parse_pin_defcfg() */
Takashi Iwai24de1832011-11-07 17:13:39 +0100187 unsigned int shared_mic_hp:1; /* HP/Mic-in sharing */
Takashi Iwaid922b512011-04-28 12:18:53 +0200188
189 /* auto-mute control */
190 int automute_mode;
Takashi Iwai3b8510c2011-04-28 14:03:24 +0200191 hda_nid_t automute_mixer_nid[AUTO_CFG_MAX_OUTS];
Takashi Iwaid922b512011-04-28 12:18:53 +0200192
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200193 int init_amp;
Takashi Iwaid433a672010-09-20 15:11:54 +0200194 int codec_variant; /* flag for other variants */
Takashi Iwaie64f14f2009-01-20 18:32:55 +0100195
Takashi Iwai2134ea42008-01-10 16:53:55 +0100196 /* for virtual master */
197 hda_nid_t vmaster_nid;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200198#ifdef CONFIG_SND_HDA_POWER_SAVE
199 struct hda_loopback_check loopback;
200#endif
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +0200201
202 /* for PLL fix */
203 hda_nid_t pll_nid;
204 unsigned int pll_coef_idx, pll_coef_bit;
Takashi Iwai1bb7e432011-10-17 16:50:59 +0200205 unsigned int coef0;
Takashi Iwaib5bfbc62011-01-13 14:22:32 +0100206
207 /* fix-up list */
208 int fixup_id;
209 const struct alc_fixup *fixup_list;
210 const char *fixup_name;
Takashi Iwaice764ab2011-04-27 16:35:23 +0200211
212 /* multi-io */
213 int multi_ios;
214 struct alc_multi_io multi_io[4];
Takashi Iwai23c09b02011-08-19 09:05:35 +0200215
216 /* bind volumes */
217 struct snd_array bind_ctls;
Kailang Yangdf694da2005-12-05 19:42:22 +0100218};
219
Takashi Iwai1d045db2011-07-07 18:23:21 +0200220#define ALC_MODEL_AUTO 0 /* common for all chips */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221
Takashi Iwai44c02402011-07-08 15:14:19 +0200222static bool check_amp_caps(struct hda_codec *codec, hda_nid_t nid,
223 int dir, unsigned int bits)
224{
225 if (!nid)
226 return false;
227 if (get_wcaps(codec, nid) & (1 << (dir + 1)))
228 if (query_amp_caps(codec, nid, dir) & bits)
229 return true;
230 return false;
231}
232
233#define nid_has_mute(codec, nid, dir) \
234 check_amp_caps(codec, nid, dir, AC_AMPCAP_MUTE)
235#define nid_has_volume(codec, nid, dir) \
236 check_amp_caps(codec, nid, dir, AC_AMPCAP_NUM_STEPS)
237
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238/*
239 * input MUX handling
240 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200241static int alc_mux_enum_info(struct snd_kcontrol *kcontrol,
242 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243{
244 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
245 struct alc_spec *spec = codec->spec;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200246 unsigned int mux_idx = snd_ctl_get_ioffidx(kcontrol, &uinfo->id);
247 if (mux_idx >= spec->num_mux_defs)
248 mux_idx = 0;
Takashi Iwai53111142010-03-08 12:13:07 +0100249 if (!spec->input_mux[mux_idx].num_items && mux_idx > 0)
250 mux_idx = 0;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200251 return snd_hda_input_mux_info(&spec->input_mux[mux_idx], uinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252}
253
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200254static int alc_mux_enum_get(struct snd_kcontrol *kcontrol,
255 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256{
257 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
258 struct alc_spec *spec = codec->spec;
259 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
260
261 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
262 return 0;
263}
264
Takashi Iwai21268962011-07-07 15:01:13 +0200265static bool alc_dyn_adc_pcm_resetup(struct hda_codec *codec, int cur)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266{
Takashi Iwai21268962011-07-07 15:01:13 +0200267 struct alc_spec *spec = codec->spec;
268 hda_nid_t new_adc = spec->adc_nids[spec->dyn_adc_idx[cur]];
269
270 if (spec->cur_adc && spec->cur_adc != new_adc) {
271 /* stream is running, let's swap the current ADC */
272 __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1);
273 spec->cur_adc = new_adc;
274 snd_hda_codec_setup_stream(codec, new_adc,
275 spec->cur_adc_stream_tag, 0,
276 spec->cur_adc_format);
277 return true;
278 }
279 return false;
280}
281
Takashi Iwai61071592011-11-23 07:52:15 +0100282static inline hda_nid_t get_capsrc(struct alc_spec *spec, int idx)
283{
284 return spec->capsrc_nids ?
285 spec->capsrc_nids[idx] : spec->adc_nids[idx];
286}
287
Takashi Iwai24de1832011-11-07 17:13:39 +0100288static void call_update_outputs(struct hda_codec *codec);
289
Takashi Iwai21268962011-07-07 15:01:13 +0200290/* select the given imux item; either unmute exclusively or select the route */
291static int alc_mux_select(struct hda_codec *codec, unsigned int adc_idx,
292 unsigned int idx, bool force)
293{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 struct alc_spec *spec = codec->spec;
Takashi Iwaicd896c32008-11-18 12:36:33 +0100295 const struct hda_input_mux *imux;
Takashi Iwaicd896c32008-11-18 12:36:33 +0100296 unsigned int mux_idx;
Takashi Iwaidccc1812011-11-08 07:52:19 +0100297 int i, type, num_conns;
Takashi Iwai21268962011-07-07 15:01:13 +0200298 hda_nid_t nid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299
Takashi Iwaicd896c32008-11-18 12:36:33 +0100300 mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx;
301 imux = &spec->input_mux[mux_idx];
Takashi Iwai53111142010-03-08 12:13:07 +0100302 if (!imux->num_items && mux_idx > 0)
303 imux = &spec->input_mux[0];
Takashi Iwaicce4aa32011-12-02 15:29:12 +0100304 if (!imux->num_items)
305 return 0;
Takashi Iwaicd896c32008-11-18 12:36:33 +0100306
Takashi Iwai21268962011-07-07 15:01:13 +0200307 if (idx >= imux->num_items)
308 idx = imux->num_items - 1;
309 if (spec->cur_mux[adc_idx] == idx && !force)
310 return 0;
311 spec->cur_mux[adc_idx] = idx;
312
Takashi Iwai24de1832011-11-07 17:13:39 +0100313 /* for shared I/O, change the pin-control accordingly */
314 if (spec->shared_mic_hp) {
315 /* NOTE: this assumes that there are only two inputs, the
316 * first is the real internal mic and the second is HP jack.
317 */
318 snd_hda_codec_write(codec, spec->autocfg.inputs[1].pin, 0,
319 AC_VERB_SET_PIN_WIDGET_CONTROL,
320 spec->cur_mux[adc_idx] ?
321 PIN_VREF80 : PIN_HP);
322 spec->automute_speaker = !spec->cur_mux[adc_idx];
323 call_update_outputs(codec);
324 }
325
Takashi Iwai21268962011-07-07 15:01:13 +0200326 if (spec->dyn_adc_switch) {
327 alc_dyn_adc_pcm_resetup(codec, idx);
328 adc_idx = spec->dyn_adc_idx[idx];
329 }
330
Takashi Iwai61071592011-11-23 07:52:15 +0100331 nid = get_capsrc(spec, adc_idx);
Takashi Iwai21268962011-07-07 15:01:13 +0200332
333 /* no selection? */
Takashi Iwaidccc1812011-11-08 07:52:19 +0100334 num_conns = snd_hda_get_conn_list(codec, nid, NULL);
335 if (num_conns <= 1)
Takashi Iwai21268962011-07-07 15:01:13 +0200336 return 1;
337
Takashi Iwaia22d5432009-07-27 12:54:26 +0200338 type = get_wcaps_type(get_wcaps(codec, nid));
Takashi Iwai0169b6b2009-06-22 10:50:19 +0200339 if (type == AC_WID_AUD_MIX) {
Takashi Iwai54cbc9a2008-10-31 15:24:04 +0100340 /* Matrix-mixer style (e.g. ALC882) */
Takashi Iwaidccc1812011-11-08 07:52:19 +0100341 int active = imux->items[idx].index;
342 for (i = 0; i < num_conns; i++) {
343 unsigned int v = (i == active) ? 0 : HDA_AMP_MUTE;
344 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, i,
Takashi Iwai54cbc9a2008-10-31 15:24:04 +0100345 HDA_AMP_MUTE, v);
346 }
Takashi Iwai54cbc9a2008-10-31 15:24:04 +0100347 } else {
348 /* MUX style (e.g. ALC880) */
Takashi Iwai21268962011-07-07 15:01:13 +0200349 snd_hda_codec_write_cache(codec, nid, 0,
350 AC_VERB_SET_CONNECT_SEL,
351 imux->items[idx].index);
Takashi Iwai54cbc9a2008-10-31 15:24:04 +0100352 }
Takashi Iwai21268962011-07-07 15:01:13 +0200353 return 1;
354}
355
356static int alc_mux_enum_put(struct snd_kcontrol *kcontrol,
357 struct snd_ctl_elem_value *ucontrol)
358{
359 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
360 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
361 return alc_mux_select(codec, adc_idx,
362 ucontrol->value.enumerated.item[0], false);
Takashi Iwai54cbc9a2008-10-31 15:24:04 +0100363}
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200364
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365/*
Takashi Iwai23f0c042009-02-26 13:03:58 +0100366 * set up the input pin config (depending on the given auto-pin type)
367 */
368static void alc_set_input_pin(struct hda_codec *codec, hda_nid_t nid,
369 int auto_pin_type)
370{
371 unsigned int val = PIN_IN;
372
Takashi Iwai86e29592010-09-09 14:50:17 +0200373 if (auto_pin_type == AUTO_PIN_MIC) {
Takashi Iwai23f0c042009-02-26 13:03:58 +0100374 unsigned int pincap;
Takashi Iwai954a29c2010-07-30 10:55:44 +0200375 unsigned int oldval;
376 oldval = snd_hda_codec_read(codec, nid, 0,
377 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
Takashi Iwai1327a322009-03-23 13:07:47 +0100378 pincap = snd_hda_query_pin_caps(codec, nid);
Takashi Iwai23f0c042009-02-26 13:03:58 +0100379 pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
Takashi Iwai954a29c2010-07-30 10:55:44 +0200380 /* if the default pin setup is vref50, we give it priority */
381 if ((pincap & AC_PINCAP_VREF_80) && oldval != PIN_VREF50)
Takashi Iwai23f0c042009-02-26 13:03:58 +0100382 val = PIN_VREF80;
Takashi Iwai461c6c32009-05-25 08:06:02 +0200383 else if (pincap & AC_PINCAP_VREF_50)
384 val = PIN_VREF50;
385 else if (pincap & AC_PINCAP_VREF_100)
386 val = PIN_VREF100;
387 else if (pincap & AC_PINCAP_VREF_GRD)
388 val = PIN_VREFGRD;
Takashi Iwai23f0c042009-02-26 13:03:58 +0100389 }
390 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, val);
391}
392
393/*
Takashi Iwai1d045db2011-07-07 18:23:21 +0200394 * Append the given mixer and verb elements for the later use
395 * The mixer array is referred in build_controls(), and init_verbs are
396 * called in init().
Takashi Iwaid88897e2008-10-31 15:01:37 +0100397 */
Takashi Iwaia9111322011-05-02 11:30:18 +0200398static void add_mixer(struct alc_spec *spec, const struct snd_kcontrol_new *mix)
Takashi Iwaid88897e2008-10-31 15:01:37 +0100399{
400 if (snd_BUG_ON(spec->num_mixers >= ARRAY_SIZE(spec->mixers)))
401 return;
402 spec->mixers[spec->num_mixers++] = mix;
403}
404
405static void add_verb(struct alc_spec *spec, const struct hda_verb *verb)
406{
407 if (snd_BUG_ON(spec->num_init_verbs >= ARRAY_SIZE(spec->init_verbs)))
408 return;
409 spec->init_verbs[spec->num_init_verbs++] = verb;
410}
411
412/*
Takashi Iwai1d045db2011-07-07 18:23:21 +0200413 * GPIO setup tables, used in initialization
Kailang Yangdf694da2005-12-05 19:42:22 +0100414 */
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200415/* Enable GPIO mask and set output */
Takashi Iwaia9111322011-05-02 11:30:18 +0200416static const struct hda_verb alc_gpio1_init_verbs[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200417 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
418 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
419 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
420 { }
421};
422
Takashi Iwaia9111322011-05-02 11:30:18 +0200423static const struct hda_verb alc_gpio2_init_verbs[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200424 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
425 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
426 {0x01, AC_VERB_SET_GPIO_DATA, 0x02},
427 { }
428};
429
Takashi Iwaia9111322011-05-02 11:30:18 +0200430static const struct hda_verb alc_gpio3_init_verbs[] = {
Kailang Yangbdd148a2007-05-08 15:19:08 +0200431 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
432 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
433 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
434 { }
435};
436
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +0200437/*
438 * Fix hardware PLL issue
439 * On some codecs, the analog PLL gating control must be off while
440 * the default value is 1.
441 */
442static void alc_fix_pll(struct hda_codec *codec)
443{
444 struct alc_spec *spec = codec->spec;
445 unsigned int val;
446
447 if (!spec->pll_nid)
448 return;
449 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
450 spec->pll_coef_idx);
451 val = snd_hda_codec_read(codec, spec->pll_nid, 0,
452 AC_VERB_GET_PROC_COEF, 0);
453 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
454 spec->pll_coef_idx);
455 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_PROC_COEF,
456 val & ~(1 << spec->pll_coef_bit));
457}
458
459static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
460 unsigned int coef_idx, unsigned int coef_bit)
461{
462 struct alc_spec *spec = codec->spec;
463 spec->pll_nid = nid;
464 spec->pll_coef_idx = coef_idx;
465 spec->pll_coef_bit = coef_bit;
466 alc_fix_pll(codec);
467}
468
Takashi Iwai1d045db2011-07-07 18:23:21 +0200469/*
Takashi Iwai1d045db2011-07-07 18:23:21 +0200470 * Jack detections for HP auto-mute and mic-switch
471 */
472
473/* check each pin in the given array; returns true if any of them is plugged */
474static bool detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins)
Kailang Yangc9b58002007-10-16 14:30:01 +0200475{
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200476 int i, present = 0;
Kailang Yangc9b58002007-10-16 14:30:01 +0200477
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200478 for (i = 0; i < num_pins; i++) {
479 hda_nid_t nid = pins[i];
Takashi Iwaibb35feb2010-09-08 15:30:49 +0200480 if (!nid)
481 break;
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200482 present |= snd_hda_jack_detect(codec, nid);
Takashi Iwaibb35feb2010-09-08 15:30:49 +0200483 }
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200484 return present;
485}
Takashi Iwaibb35feb2010-09-08 15:30:49 +0200486
Takashi Iwai1d045db2011-07-07 18:23:21 +0200487/* standard HP/line-out auto-mute helper */
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200488static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins,
Takashi Iwaie9427962011-04-28 15:46:07 +0200489 bool mute, bool hp_out)
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200490{
491 struct alc_spec *spec = codec->spec;
492 unsigned int mute_bits = mute ? HDA_AMP_MUTE : 0;
Takashi Iwaie9427962011-04-28 15:46:07 +0200493 unsigned int pin_bits = mute ? 0 : (hp_out ? PIN_HP : PIN_OUT);
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200494 int i;
495
496 for (i = 0; i < num_pins; i++) {
497 hda_nid_t nid = pins[i];
Takashi Iwaia9fd4f32009-05-08 15:57:59 +0200498 if (!nid)
499 break;
Takashi Iwai3b8510c2011-04-28 14:03:24 +0200500 switch (spec->automute_mode) {
501 case ALC_AUTOMUTE_PIN:
Takashi Iwaibb35feb2010-09-08 15:30:49 +0200502 snd_hda_codec_write(codec, nid, 0,
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200503 AC_VERB_SET_PIN_WIDGET_CONTROL,
504 pin_bits);
Takashi Iwai3b8510c2011-04-28 14:03:24 +0200505 break;
506 case ALC_AUTOMUTE_AMP:
Takashi Iwaibb35feb2010-09-08 15:30:49 +0200507 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200508 HDA_AMP_MUTE, mute_bits);
Takashi Iwai3b8510c2011-04-28 14:03:24 +0200509 break;
510 case ALC_AUTOMUTE_MIXER:
511 nid = spec->automute_mixer_nid[i];
512 if (!nid)
513 break;
514 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200515 HDA_AMP_MUTE, mute_bits);
Takashi Iwai3b8510c2011-04-28 14:03:24 +0200516 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 1,
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200517 HDA_AMP_MUTE, mute_bits);
Takashi Iwai3b8510c2011-04-28 14:03:24 +0200518 break;
Takashi Iwaibb35feb2010-09-08 15:30:49 +0200519 }
Takashi Iwaia9fd4f32009-05-08 15:57:59 +0200520 }
Kailang Yangc9b58002007-10-16 14:30:01 +0200521}
522
David Henningsson42cf0d02011-09-20 12:04:56 +0200523/* Toggle outputs muting */
524static void update_outputs(struct hda_codec *codec)
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200525{
526 struct alc_spec *spec = codec->spec;
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200527 int on;
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200528
Takashi Iwaic0a20262011-06-10 15:28:15 +0200529 /* Control HP pins/amps depending on master_mute state;
530 * in general, HP pins/amps control should be enabled in all cases,
531 * but currently set only for master_mute, just to be safe
532 */
Takashi Iwai24de1832011-11-07 17:13:39 +0100533 if (!spec->shared_mic_hp) /* don't change HP-pin when shared with mic */
534 do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins),
Takashi Iwaic0a20262011-06-10 15:28:15 +0200535 spec->autocfg.hp_pins, spec->master_mute, true);
536
David Henningsson42cf0d02011-09-20 12:04:56 +0200537 if (!spec->automute_speaker)
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200538 on = 0;
539 else
David Henningsson42cf0d02011-09-20 12:04:56 +0200540 on = spec->hp_jack_present | spec->line_jack_present;
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200541 on |= spec->master_mute;
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200542 do_automute(codec, ARRAY_SIZE(spec->autocfg.speaker_pins),
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200543 spec->autocfg.speaker_pins, on, false);
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200544
545 /* toggle line-out mutes if needed, too */
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200546 /* if LO is a copy of either HP or Speaker, don't need to handle it */
547 if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0] ||
548 spec->autocfg.line_out_pins[0] == spec->autocfg.speaker_pins[0])
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200549 return;
David Henningsson42cf0d02011-09-20 12:04:56 +0200550 if (!spec->automute_lo)
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200551 on = 0;
552 else
David Henningsson42cf0d02011-09-20 12:04:56 +0200553 on = spec->hp_jack_present;
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200554 on |= spec->master_mute;
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200555 do_automute(codec, ARRAY_SIZE(spec->autocfg.line_out_pins),
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200556 spec->autocfg.line_out_pins, on, false);
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200557}
558
David Henningsson42cf0d02011-09-20 12:04:56 +0200559static void call_update_outputs(struct hda_codec *codec)
Takashi Iwai24519912011-08-16 15:08:49 +0200560{
561 struct alc_spec *spec = codec->spec;
562 if (spec->automute_hook)
563 spec->automute_hook(codec);
564 else
David Henningsson42cf0d02011-09-20 12:04:56 +0200565 update_outputs(codec);
Takashi Iwai24519912011-08-16 15:08:49 +0200566}
567
Takashi Iwai1d045db2011-07-07 18:23:21 +0200568/* standard HP-automute helper */
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200569static void alc_hp_automute(struct hda_codec *codec)
570{
571 struct alc_spec *spec = codec->spec;
572
David Henningsson42cf0d02011-09-20 12:04:56 +0200573 spec->hp_jack_present =
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200574 detect_jacks(codec, ARRAY_SIZE(spec->autocfg.hp_pins),
575 spec->autocfg.hp_pins);
David Henningsson42cf0d02011-09-20 12:04:56 +0200576 if (!spec->detect_hp || (!spec->automute_speaker && !spec->automute_lo))
Takashi Iwai3c715a92011-08-23 12:41:09 +0200577 return;
David Henningsson42cf0d02011-09-20 12:04:56 +0200578 call_update_outputs(codec);
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200579}
580
Takashi Iwai1d045db2011-07-07 18:23:21 +0200581/* standard line-out-automute helper */
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200582static void alc_line_automute(struct hda_codec *codec)
583{
584 struct alc_spec *spec = codec->spec;
585
Takashi Iwaie0d32e32011-09-26 15:19:55 +0200586 /* check LO jack only when it's different from HP */
587 if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0])
588 return;
589
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200590 spec->line_jack_present =
591 detect_jacks(codec, ARRAY_SIZE(spec->autocfg.line_out_pins),
592 spec->autocfg.line_out_pins);
David Henningsson42cf0d02011-09-20 12:04:56 +0200593 if (!spec->automute_speaker || !spec->detect_lo)
Takashi Iwai3c715a92011-08-23 12:41:09 +0200594 return;
David Henningsson42cf0d02011-09-20 12:04:56 +0200595 call_update_outputs(codec);
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200596}
597
Takashi Iwai8d087c72011-06-28 12:45:47 +0200598#define get_connection_index(codec, mux, nid) \
599 snd_hda_get_conn_index(codec, mux, nid, 0)
Takashi Iwai6c819492009-08-10 18:47:44 +0200600
Takashi Iwai1d045db2011-07-07 18:23:21 +0200601/* standard mic auto-switch helper */
Kailang Yang7fb0d782008-10-15 11:12:35 +0200602static void alc_mic_automute(struct hda_codec *codec)
603{
604 struct alc_spec *spec = codec->spec;
Takashi Iwai21268962011-07-07 15:01:13 +0200605 hda_nid_t *pins = spec->imux_pins;
Kailang Yang7fb0d782008-10-15 11:12:35 +0200606
Takashi Iwai21268962011-07-07 15:01:13 +0200607 if (!spec->auto_mic || !spec->auto_mic_valid_imux)
Takashi Iwai6c819492009-08-10 18:47:44 +0200608 return;
609 if (snd_BUG_ON(!spec->adc_nids))
610 return;
Takashi Iwai21268962011-07-07 15:01:13 +0200611 if (snd_BUG_ON(spec->int_mic_idx < 0 || spec->ext_mic_idx < 0))
Takashi Iwai840b64c2010-07-13 22:49:01 +0200612 return;
Takashi Iwai840b64c2010-07-13 22:49:01 +0200613
Takashi Iwai21268962011-07-07 15:01:13 +0200614 if (snd_hda_jack_detect(codec, pins[spec->ext_mic_idx]))
615 alc_mux_select(codec, 0, spec->ext_mic_idx, false);
616 else if (spec->dock_mic_idx >= 0 &&
617 snd_hda_jack_detect(codec, pins[spec->dock_mic_idx]))
618 alc_mux_select(codec, 0, spec->dock_mic_idx, false);
619 else
620 alc_mux_select(codec, 0, spec->int_mic_idx, false);
Kailang Yang7fb0d782008-10-15 11:12:35 +0200621}
622
Takashi Iwaif21d78e2012-01-19 12:10:29 +0100623/* handle the specified unsol action (ALC_XXX_EVENT) */
624static void alc_exec_unsol_event(struct hda_codec *codec, int action)
Kailang Yangc9b58002007-10-16 14:30:01 +0200625{
Takashi Iwaif21d78e2012-01-19 12:10:29 +0100626 switch (action) {
Takashi Iwai1d045db2011-07-07 18:23:21 +0200627 case ALC_HP_EVENT:
Takashi Iwaid922b512011-04-28 12:18:53 +0200628 alc_hp_automute(codec);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +0200629 break;
Takashi Iwai1d045db2011-07-07 18:23:21 +0200630 case ALC_FRONT_EVENT:
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200631 alc_line_automute(codec);
632 break;
Takashi Iwai1d045db2011-07-07 18:23:21 +0200633 case ALC_MIC_EVENT:
Kailang Yang7fb0d782008-10-15 11:12:35 +0200634 alc_mic_automute(codec);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +0200635 break;
636 }
Takashi Iwai01a61e12011-10-28 00:03:22 +0200637 snd_hda_jack_report_sync(codec);
Kailang Yang7fb0d782008-10-15 11:12:35 +0200638}
639
Takashi Iwaif21d78e2012-01-19 12:10:29 +0100640/* unsolicited event for HP jack sensing */
641static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res)
642{
643 struct alc_spec *spec = codec->spec;
644 if (codec->vendor_id == 0x10ec0880)
645 res >>= 28;
646 else
647 res >>= 26;
Takashi Iwaia7309792012-01-19 15:03:48 +0100648 res = snd_hda_jack_get_action(codec, res);
Takashi Iwaif21d78e2012-01-19 12:10:29 +0100649 alc_exec_unsol_event(codec, res);
650}
651
Takashi Iwai1d045db2011-07-07 18:23:21 +0200652/* call init functions of standard auto-mute helpers */
Kailang Yang7fb0d782008-10-15 11:12:35 +0200653static void alc_inithook(struct hda_codec *codec)
654{
Takashi Iwaid922b512011-04-28 12:18:53 +0200655 alc_hp_automute(codec);
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200656 alc_line_automute(codec);
Kailang Yang7fb0d782008-10-15 11:12:35 +0200657 alc_mic_automute(codec);
Kailang Yangc9b58002007-10-16 14:30:01 +0200658}
659
Kailang Yangf9423e72008-05-27 12:32:25 +0200660/* additional initialization for ALC888 variants */
661static void alc888_coef_init(struct hda_codec *codec)
662{
663 unsigned int tmp;
664
665 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0);
666 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
667 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
Takashi Iwai37db6232009-03-05 09:40:16 +0100668 if ((tmp & 0xf0) == 0x20)
Kailang Yangf9423e72008-05-27 12:32:25 +0200669 /* alc888S-VC */
670 snd_hda_codec_read(codec, 0x20, 0,
671 AC_VERB_SET_PROC_COEF, 0x830);
672 else
673 /* alc888-VB */
674 snd_hda_codec_read(codec, 0x20, 0,
675 AC_VERB_SET_PROC_COEF, 0x3030);
676}
677
Takashi Iwai1d045db2011-07-07 18:23:21 +0200678/* additional initialization for ALC889 variants */
Jaroslav Kysela87a8c372009-07-23 10:58:29 +0200679static void alc889_coef_init(struct hda_codec *codec)
680{
681 unsigned int tmp;
682
683 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
684 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
685 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
686 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF, tmp|0x2010);
687}
688
Takashi Iwai3fb4a502010-01-19 15:46:37 +0100689/* turn on/off EAPD control (only if available) */
690static void set_eapd(struct hda_codec *codec, hda_nid_t nid, int on)
691{
692 if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
693 return;
694 if (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)
695 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
696 on ? 2 : 0);
697}
698
Takashi Iwai691f1fc2011-04-07 10:31:43 +0200699/* turn on/off EAPD controls of the codec */
700static void alc_auto_setup_eapd(struct hda_codec *codec, bool on)
701{
702 /* We currently only handle front, HP */
Takashi Iwai39fa84e2011-06-27 15:28:57 +0200703 static hda_nid_t pins[] = {
704 0x0f, 0x10, 0x14, 0x15, 0
705 };
706 hda_nid_t *p;
707 for (p = pins; *p; p++)
708 set_eapd(codec, *p, on);
Takashi Iwai691f1fc2011-04-07 10:31:43 +0200709}
710
Takashi Iwai1c716152011-04-07 10:37:16 +0200711/* generic shutup callback;
712 * just turning off EPAD and a little pause for avoiding pop-noise
713 */
714static void alc_eapd_shutup(struct hda_codec *codec)
715{
716 alc_auto_setup_eapd(codec, false);
717 msleep(200);
718}
719
Takashi Iwai1d045db2011-07-07 18:23:21 +0200720/* generic EAPD initialization */
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200721static void alc_auto_init_amp(struct hda_codec *codec, int type)
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200722{
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200723 unsigned int tmp;
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200724
Takashi Iwai39fa84e2011-06-27 15:28:57 +0200725 alc_auto_setup_eapd(codec, true);
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200726 switch (type) {
727 case ALC_INIT_GPIO1:
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200728 snd_hda_sequence_write(codec, alc_gpio1_init_verbs);
729 break;
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200730 case ALC_INIT_GPIO2:
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200731 snd_hda_sequence_write(codec, alc_gpio2_init_verbs);
732 break;
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200733 case ALC_INIT_GPIO3:
Kailang Yangbdd148a2007-05-08 15:19:08 +0200734 snd_hda_sequence_write(codec, alc_gpio3_init_verbs);
735 break;
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200736 case ALC_INIT_DEFAULT:
Kailang Yangc9b58002007-10-16 14:30:01 +0200737 switch (codec->vendor_id) {
738 case 0x10ec0260:
739 snd_hda_codec_write(codec, 0x1a, 0,
740 AC_VERB_SET_COEF_INDEX, 7);
741 tmp = snd_hda_codec_read(codec, 0x1a, 0,
742 AC_VERB_GET_PROC_COEF, 0);
743 snd_hda_codec_write(codec, 0x1a, 0,
744 AC_VERB_SET_COEF_INDEX, 7);
745 snd_hda_codec_write(codec, 0x1a, 0,
746 AC_VERB_SET_PROC_COEF,
747 tmp | 0x2010);
748 break;
749 case 0x10ec0262:
750 case 0x10ec0880:
751 case 0x10ec0882:
752 case 0x10ec0883:
753 case 0x10ec0885:
Takashi Iwai4a5a4c52009-02-06 12:46:59 +0100754 case 0x10ec0887:
Takashi Iwai20b67dd2011-03-23 22:54:32 +0100755 /*case 0x10ec0889:*/ /* this causes an SPDIF problem */
Jaroslav Kysela87a8c372009-07-23 10:58:29 +0200756 alc889_coef_init(codec);
Kailang Yangc9b58002007-10-16 14:30:01 +0200757 break;
Kailang Yangf9423e72008-05-27 12:32:25 +0200758 case 0x10ec0888:
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200759 alc888_coef_init(codec);
Kailang Yangf9423e72008-05-27 12:32:25 +0200760 break;
Takashi Iwai0aea7782010-01-25 15:44:11 +0100761#if 0 /* XXX: This may cause the silent output on speaker on some machines */
Kailang Yangc9b58002007-10-16 14:30:01 +0200762 case 0x10ec0267:
763 case 0x10ec0268:
764 snd_hda_codec_write(codec, 0x20, 0,
765 AC_VERB_SET_COEF_INDEX, 7);
766 tmp = snd_hda_codec_read(codec, 0x20, 0,
767 AC_VERB_GET_PROC_COEF, 0);
768 snd_hda_codec_write(codec, 0x20, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +0200769 AC_VERB_SET_COEF_INDEX, 7);
Kailang Yangc9b58002007-10-16 14:30:01 +0200770 snd_hda_codec_write(codec, 0x20, 0,
771 AC_VERB_SET_PROC_COEF,
772 tmp | 0x3000);
773 break;
Takashi Iwai0aea7782010-01-25 15:44:11 +0100774#endif /* XXX */
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200775 }
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200776 break;
777 }
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200778}
Kailang Yangea1fb292008-08-26 12:58:38 +0200779
Takashi Iwai1d045db2011-07-07 18:23:21 +0200780/*
781 * Auto-Mute mode mixer enum support
782 */
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200783static int alc_automute_mode_info(struct snd_kcontrol *kcontrol,
784 struct snd_ctl_elem_info *uinfo)
785{
Takashi Iwaiae8a60a2011-04-28 18:09:52 +0200786 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
787 struct alc_spec *spec = codec->spec;
788 static const char * const texts2[] = {
789 "Disabled", "Enabled"
790 };
791 static const char * const texts3[] = {
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200792 "Disabled", "Speaker Only", "Line-Out+Speaker"
793 };
Takashi Iwaiae8a60a2011-04-28 18:09:52 +0200794 const char * const *texts;
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200795
796 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
797 uinfo->count = 1;
David Henningsson42cf0d02011-09-20 12:04:56 +0200798 if (spec->automute_speaker_possible && spec->automute_lo_possible) {
Takashi Iwaiae8a60a2011-04-28 18:09:52 +0200799 uinfo->value.enumerated.items = 3;
800 texts = texts3;
801 } else {
802 uinfo->value.enumerated.items = 2;
803 texts = texts2;
804 }
805 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
806 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200807 strcpy(uinfo->value.enumerated.name,
808 texts[uinfo->value.enumerated.item]);
809 return 0;
810}
811
812static int alc_automute_mode_get(struct snd_kcontrol *kcontrol,
813 struct snd_ctl_elem_value *ucontrol)
814{
815 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
816 struct alc_spec *spec = codec->spec;
David Henningsson42cf0d02011-09-20 12:04:56 +0200817 unsigned int val = 0;
818 if (spec->automute_speaker)
819 val++;
820 if (spec->automute_lo)
821 val++;
822
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200823 ucontrol->value.enumerated.item[0] = val;
824 return 0;
825}
826
827static int alc_automute_mode_put(struct snd_kcontrol *kcontrol,
828 struct snd_ctl_elem_value *ucontrol)
829{
830 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
831 struct alc_spec *spec = codec->spec;
832
833 switch (ucontrol->value.enumerated.item[0]) {
834 case 0:
David Henningsson42cf0d02011-09-20 12:04:56 +0200835 if (!spec->automute_speaker && !spec->automute_lo)
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200836 return 0;
David Henningsson42cf0d02011-09-20 12:04:56 +0200837 spec->automute_speaker = 0;
838 spec->automute_lo = 0;
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200839 break;
840 case 1:
David Henningsson42cf0d02011-09-20 12:04:56 +0200841 if (spec->automute_speaker_possible) {
842 if (!spec->automute_lo && spec->automute_speaker)
843 return 0;
844 spec->automute_speaker = 1;
845 spec->automute_lo = 0;
846 } else if (spec->automute_lo_possible) {
847 if (spec->automute_lo)
848 return 0;
849 spec->automute_lo = 1;
850 } else
851 return -EINVAL;
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200852 break;
853 case 2:
David Henningsson42cf0d02011-09-20 12:04:56 +0200854 if (!spec->automute_lo_possible || !spec->automute_speaker_possible)
Takashi Iwaiae8a60a2011-04-28 18:09:52 +0200855 return -EINVAL;
David Henningsson42cf0d02011-09-20 12:04:56 +0200856 if (spec->automute_speaker && spec->automute_lo)
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200857 return 0;
David Henningsson42cf0d02011-09-20 12:04:56 +0200858 spec->automute_speaker = 1;
859 spec->automute_lo = 1;
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200860 break;
861 default:
862 return -EINVAL;
863 }
David Henningsson42cf0d02011-09-20 12:04:56 +0200864 call_update_outputs(codec);
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200865 return 1;
866}
867
Takashi Iwaia9111322011-05-02 11:30:18 +0200868static const struct snd_kcontrol_new alc_automute_mode_enum = {
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200869 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
870 .name = "Auto-Mute Mode",
871 .info = alc_automute_mode_info,
872 .get = alc_automute_mode_get,
873 .put = alc_automute_mode_put,
874};
875
Takashi Iwai1d045db2011-07-07 18:23:21 +0200876static struct snd_kcontrol_new *alc_kcontrol_new(struct alc_spec *spec)
877{
878 snd_array_init(&spec->kctls, sizeof(struct snd_kcontrol_new), 32);
879 return snd_array_new(&spec->kctls);
880}
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200881
882static int alc_add_automute_mode_enum(struct hda_codec *codec)
883{
884 struct alc_spec *spec = codec->spec;
885 struct snd_kcontrol_new *knew;
886
887 knew = alc_kcontrol_new(spec);
888 if (!knew)
889 return -ENOMEM;
890 *knew = alc_automute_mode_enum;
891 knew->name = kstrdup("Auto-Mute Mode", GFP_KERNEL);
892 if (!knew->name)
893 return -ENOMEM;
894 return 0;
895}
896
Takashi Iwai1d045db2011-07-07 18:23:21 +0200897/*
898 * Check the availability of HP/line-out auto-mute;
899 * Set up appropriately if really supported
900 */
David Henningsson42cf0d02011-09-20 12:04:56 +0200901static void alc_init_automute(struct hda_codec *codec)
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200902{
903 struct alc_spec *spec = codec->spec;
Takashi Iwaibb35feb2010-09-08 15:30:49 +0200904 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwai1daf5f42011-04-28 17:57:46 +0200905 int present = 0;
Takashi Iwaibb35feb2010-09-08 15:30:49 +0200906 int i;
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200907
Takashi Iwai1daf5f42011-04-28 17:57:46 +0200908 if (cfg->hp_pins[0])
909 present++;
910 if (cfg->line_out_pins[0])
911 present++;
912 if (cfg->speaker_pins[0])
913 present++;
914 if (present < 2) /* need two different output types */
915 return;
Kailang Yangc9b58002007-10-16 14:30:01 +0200916
Takashi Iwaic48a8fb2011-07-27 16:41:57 +0200917 if (!cfg->speaker_pins[0] &&
918 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
Takashi Iwaibb35feb2010-09-08 15:30:49 +0200919 memcpy(cfg->speaker_pins, cfg->line_out_pins,
920 sizeof(cfg->speaker_pins));
921 cfg->speaker_outs = cfg->line_outs;
922 }
923
Takashi Iwaic48a8fb2011-07-27 16:41:57 +0200924 if (!cfg->hp_pins[0] &&
925 cfg->line_out_type == AUTO_PIN_HP_OUT) {
Takashi Iwaibb35feb2010-09-08 15:30:49 +0200926 memcpy(cfg->hp_pins, cfg->line_out_pins,
927 sizeof(cfg->hp_pins));
928 cfg->hp_outs = cfg->line_outs;
929 }
930
David Henningsson42cf0d02011-09-20 12:04:56 +0200931 spec->automute_mode = ALC_AUTOMUTE_PIN;
932
Takashi Iwaibb35feb2010-09-08 15:30:49 +0200933 for (i = 0; i < cfg->hp_outs; i++) {
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200934 hda_nid_t nid = cfg->hp_pins[i];
Takashi Iwai06dec222011-05-17 10:00:16 +0200935 if (!is_jack_detectable(codec, nid))
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200936 continue;
Takashi Iwaibb35feb2010-09-08 15:30:49 +0200937 snd_printdd("realtek: Enable HP auto-muting on NID 0x%x\n",
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200938 nid);
Takashi Iwai1835a0f2011-10-27 22:12:46 +0200939 snd_hda_jack_detect_enable(codec, nid, ALC_HP_EVENT);
David Henningsson42cf0d02011-09-20 12:04:56 +0200940 spec->detect_hp = 1;
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200941 }
Takashi Iwaiae8a60a2011-04-28 18:09:52 +0200942
David Henningsson42cf0d02011-09-20 12:04:56 +0200943 if (cfg->line_out_type == AUTO_PIN_LINE_OUT && cfg->line_outs) {
944 if (cfg->speaker_outs)
945 for (i = 0; i < cfg->line_outs; i++) {
946 hda_nid_t nid = cfg->line_out_pins[i];
947 if (!is_jack_detectable(codec, nid))
948 continue;
949 snd_printdd("realtek: Enable Line-Out "
950 "auto-muting on NID 0x%x\n", nid);
Takashi Iwai1835a0f2011-10-27 22:12:46 +0200951 snd_hda_jack_detect_enable(codec, nid,
952 ALC_FRONT_EVENT);
David Henningsson42cf0d02011-09-20 12:04:56 +0200953 spec->detect_lo = 1;
954 }
955 spec->automute_lo_possible = spec->detect_hp;
956 }
957
958 spec->automute_speaker_possible = cfg->speaker_outs &&
959 (spec->detect_hp || spec->detect_lo);
960
961 spec->automute_lo = spec->automute_lo_possible;
962 spec->automute_speaker = spec->automute_speaker_possible;
963
964 if (spec->automute_speaker_possible || spec->automute_lo_possible) {
Takashi Iwaiae8a60a2011-04-28 18:09:52 +0200965 /* create a control for automute mode */
966 alc_add_automute_mode_enum(codec);
967 spec->unsol_event = alc_sku_unsol_event;
968 }
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200969}
970
Takashi Iwai1d045db2011-07-07 18:23:21 +0200971/* return the position of NID in the list, or -1 if not found */
Takashi Iwai21268962011-07-07 15:01:13 +0200972static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
973{
974 int i;
975 for (i = 0; i < nums; i++)
976 if (list[i] == nid)
977 return i;
978 return -1;
979}
980
Takashi Iwai1d045db2011-07-07 18:23:21 +0200981/* check whether dynamic ADC-switching is available */
982static bool alc_check_dyn_adc_switch(struct hda_codec *codec)
983{
984 struct alc_spec *spec = codec->spec;
985 struct hda_input_mux *imux = &spec->private_imux[0];
986 int i, n, idx;
987 hda_nid_t cap, pin;
988
989 if (imux != spec->input_mux) /* no dynamic imux? */
990 return false;
991
992 for (n = 0; n < spec->num_adc_nids; n++) {
993 cap = spec->private_capsrc_nids[n];
994 for (i = 0; i < imux->num_items; i++) {
995 pin = spec->imux_pins[i];
996 if (!pin)
997 return false;
998 if (get_connection_index(codec, cap, pin) < 0)
999 break;
1000 }
1001 if (i >= imux->num_items)
Takashi Iwai268ff6f2011-07-08 14:37:35 +02001002 return true; /* no ADC-switch is needed */
Takashi Iwai1d045db2011-07-07 18:23:21 +02001003 }
1004
1005 for (i = 0; i < imux->num_items; i++) {
1006 pin = spec->imux_pins[i];
1007 for (n = 0; n < spec->num_adc_nids; n++) {
1008 cap = spec->private_capsrc_nids[n];
1009 idx = get_connection_index(codec, cap, pin);
1010 if (idx >= 0) {
1011 imux->items[i].index = idx;
1012 spec->dyn_adc_idx[i] = n;
1013 break;
1014 }
1015 }
1016 }
1017
1018 snd_printdd("realtek: enabling ADC switching\n");
1019 spec->dyn_adc_switch = 1;
1020 return true;
1021}
Takashi Iwai21268962011-07-07 15:01:13 +02001022
1023/* rebuild imux for matching with the given auto-mic pins (if not yet) */
1024static bool alc_rebuild_imux_for_auto_mic(struct hda_codec *codec)
1025{
1026 struct alc_spec *spec = codec->spec;
1027 struct hda_input_mux *imux;
1028 static char * const texts[3] = {
1029 "Mic", "Internal Mic", "Dock Mic"
1030 };
1031 int i;
1032
1033 if (!spec->auto_mic)
1034 return false;
1035 imux = &spec->private_imux[0];
1036 if (spec->input_mux == imux)
1037 return true;
1038 spec->imux_pins[0] = spec->ext_mic_pin;
1039 spec->imux_pins[1] = spec->int_mic_pin;
1040 spec->imux_pins[2] = spec->dock_mic_pin;
1041 for (i = 0; i < 3; i++) {
1042 strcpy(imux->items[i].label, texts[i]);
Takashi Iwai6759dc32011-11-23 07:38:59 +01001043 if (spec->imux_pins[i]) {
1044 hda_nid_t pin = spec->imux_pins[i];
1045 int c;
1046 for (c = 0; c < spec->num_adc_nids; c++) {
Takashi Iwai61071592011-11-23 07:52:15 +01001047 hda_nid_t cap = get_capsrc(spec, c);
Takashi Iwai6759dc32011-11-23 07:38:59 +01001048 int idx = get_connection_index(codec, cap, pin);
1049 if (idx >= 0) {
1050 imux->items[i].index = idx;
1051 break;
1052 }
1053 }
Takashi Iwai21268962011-07-07 15:01:13 +02001054 imux->num_items = i + 1;
Takashi Iwai6759dc32011-11-23 07:38:59 +01001055 }
Takashi Iwai21268962011-07-07 15:01:13 +02001056 }
1057 spec->num_mux_defs = 1;
1058 spec->input_mux = imux;
1059 return true;
1060}
1061
1062/* check whether all auto-mic pins are valid; setup indices if OK */
1063static bool alc_auto_mic_check_imux(struct hda_codec *codec)
1064{
1065 struct alc_spec *spec = codec->spec;
1066 const struct hda_input_mux *imux;
1067
1068 if (!spec->auto_mic)
1069 return false;
1070 if (spec->auto_mic_valid_imux)
1071 return true; /* already checked */
1072
1073 /* fill up imux indices */
1074 if (!alc_check_dyn_adc_switch(codec)) {
1075 spec->auto_mic = 0;
1076 return false;
1077 }
1078
1079 imux = spec->input_mux;
1080 spec->ext_mic_idx = find_idx_in_nid_list(spec->ext_mic_pin,
1081 spec->imux_pins, imux->num_items);
1082 spec->int_mic_idx = find_idx_in_nid_list(spec->int_mic_pin,
1083 spec->imux_pins, imux->num_items);
1084 spec->dock_mic_idx = find_idx_in_nid_list(spec->dock_mic_pin,
1085 spec->imux_pins, imux->num_items);
1086 if (spec->ext_mic_idx < 0 || spec->int_mic_idx < 0) {
1087 spec->auto_mic = 0;
1088 return false; /* no corresponding imux */
1089 }
1090
Takashi Iwai1835a0f2011-10-27 22:12:46 +02001091 snd_hda_jack_detect_enable(codec, spec->ext_mic_pin, ALC_MIC_EVENT);
Takashi Iwai21268962011-07-07 15:01:13 +02001092 if (spec->dock_mic_pin)
Takashi Iwai1835a0f2011-10-27 22:12:46 +02001093 snd_hda_jack_detect_enable(codec, spec->dock_mic_pin,
1094 ALC_MIC_EVENT);
Takashi Iwai21268962011-07-07 15:01:13 +02001095
1096 spec->auto_mic_valid_imux = 1;
1097 spec->auto_mic = 1;
1098 return true;
1099}
1100
Takashi Iwai1d045db2011-07-07 18:23:21 +02001101/*
1102 * Check the availability of auto-mic switch;
1103 * Set up if really supported
1104 */
Takashi Iwai6c819492009-08-10 18:47:44 +02001105static void alc_init_auto_mic(struct hda_codec *codec)
1106{
1107 struct alc_spec *spec = codec->spec;
1108 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001109 hda_nid_t fixed, ext, dock;
Takashi Iwai6c819492009-08-10 18:47:44 +02001110 int i;
1111
Takashi Iwai24de1832011-11-07 17:13:39 +01001112 if (spec->shared_mic_hp)
1113 return; /* no auto-mic for the shared I/O */
1114
Takashi Iwai21268962011-07-07 15:01:13 +02001115 spec->ext_mic_idx = spec->int_mic_idx = spec->dock_mic_idx = -1;
1116
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001117 fixed = ext = dock = 0;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02001118 for (i = 0; i < cfg->num_inputs; i++) {
1119 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai6c819492009-08-10 18:47:44 +02001120 unsigned int defcfg;
Takashi Iwai6c819492009-08-10 18:47:44 +02001121 defcfg = snd_hda_codec_get_pincfg(codec, nid);
Takashi Iwai99ae28b2010-09-17 14:42:34 +02001122 switch (snd_hda_get_input_pin_attr(defcfg)) {
1123 case INPUT_PIN_ATTR_INT:
Takashi Iwai6c819492009-08-10 18:47:44 +02001124 if (fixed)
1125 return; /* already occupied */
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001126 if (cfg->inputs[i].type != AUTO_PIN_MIC)
1127 return; /* invalid type */
Takashi Iwai6c819492009-08-10 18:47:44 +02001128 fixed = nid;
1129 break;
Takashi Iwai99ae28b2010-09-17 14:42:34 +02001130 case INPUT_PIN_ATTR_UNUSED:
1131 return; /* invalid entry */
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001132 case INPUT_PIN_ATTR_DOCK:
1133 if (dock)
1134 return; /* already occupied */
1135 if (cfg->inputs[i].type > AUTO_PIN_LINE_IN)
1136 return; /* invalid type */
1137 dock = nid;
1138 break;
Takashi Iwai99ae28b2010-09-17 14:42:34 +02001139 default:
Takashi Iwai6c819492009-08-10 18:47:44 +02001140 if (ext)
1141 return; /* already occupied */
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001142 if (cfg->inputs[i].type != AUTO_PIN_MIC)
1143 return; /* invalid type */
Takashi Iwai6c819492009-08-10 18:47:44 +02001144 ext = nid;
1145 break;
Takashi Iwai6c819492009-08-10 18:47:44 +02001146 }
1147 }
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001148 if (!ext && dock) {
1149 ext = dock;
1150 dock = 0;
1151 }
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01001152 if (!ext || !fixed)
1153 return;
Takashi Iwaie35d9d62011-05-17 11:28:16 +02001154 if (!is_jack_detectable(codec, ext))
Takashi Iwai6c819492009-08-10 18:47:44 +02001155 return; /* no unsol support */
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001156 if (dock && !is_jack_detectable(codec, dock))
1157 return; /* no unsol support */
Takashi Iwai21268962011-07-07 15:01:13 +02001158
1159 /* check imux indices */
1160 spec->ext_mic_pin = ext;
1161 spec->int_mic_pin = fixed;
1162 spec->dock_mic_pin = dock;
1163
1164 spec->auto_mic = 1;
1165 if (!alc_auto_mic_check_imux(codec))
1166 return;
1167
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001168 snd_printdd("realtek: Enable auto-mic switch on NID 0x%x/0x%x/0x%x\n",
1169 ext, fixed, dock);
Takashi Iwai6c819492009-08-10 18:47:44 +02001170 spec->unsol_event = alc_sku_unsol_event;
1171}
1172
Takashi Iwai1d045db2011-07-07 18:23:21 +02001173/* check the availabilities of auto-mute and auto-mic switches */
1174static void alc_auto_check_switches(struct hda_codec *codec)
1175{
David Henningsson42cf0d02011-09-20 12:04:56 +02001176 alc_init_automute(codec);
Takashi Iwai1d045db2011-07-07 18:23:21 +02001177 alc_init_auto_mic(codec);
1178}
1179
1180/*
1181 * Realtek SSID verification
1182 */
1183
David Henningsson90622912010-10-14 14:50:18 +02001184/* Could be any non-zero and even value. When used as fixup, tells
1185 * the driver to ignore any present sku defines.
1186 */
1187#define ALC_FIXUP_SKU_IGNORE (2)
1188
Kailang Yangda00c242010-03-19 11:23:45 +01001189static int alc_auto_parse_customize_define(struct hda_codec *codec)
1190{
1191 unsigned int ass, tmp, i;
Takashi Iwai7fb56222010-03-22 17:09:47 +01001192 unsigned nid = 0;
Kailang Yangda00c242010-03-19 11:23:45 +01001193 struct alc_spec *spec = codec->spec;
1194
Takashi Iwaib6cbe512010-07-28 17:43:36 +02001195 spec->cdefine.enable_pcbeep = 1; /* assume always enabled */
1196
David Henningsson90622912010-10-14 14:50:18 +02001197 if (spec->cdefine.fixup) {
1198 ass = spec->cdefine.sku_cfg;
1199 if (ass == ALC_FIXUP_SKU_IGNORE)
1200 return -1;
1201 goto do_sku;
1202 }
1203
Kailang Yangda00c242010-03-19 11:23:45 +01001204 ass = codec->subsystem_id & 0xffff;
Takashi Iwaib6cbe512010-07-28 17:43:36 +02001205 if (ass != codec->bus->pci->subsystem_device && (ass & 1))
Kailang Yangda00c242010-03-19 11:23:45 +01001206 goto do_sku;
1207
1208 nid = 0x1d;
1209 if (codec->vendor_id == 0x10ec0260)
1210 nid = 0x17;
1211 ass = snd_hda_codec_get_pincfg(codec, nid);
1212
1213 if (!(ass & 1)) {
1214 printk(KERN_INFO "hda_codec: %s: SKU not ready 0x%08x\n",
1215 codec->chip_name, ass);
1216 return -1;
1217 }
1218
1219 /* check sum */
1220 tmp = 0;
1221 for (i = 1; i < 16; i++) {
1222 if ((ass >> i) & 1)
1223 tmp++;
1224 }
1225 if (((ass >> 16) & 0xf) != tmp)
1226 return -1;
1227
1228 spec->cdefine.port_connectivity = ass >> 30;
1229 spec->cdefine.enable_pcbeep = (ass & 0x100000) >> 20;
1230 spec->cdefine.check_sum = (ass >> 16) & 0xf;
1231 spec->cdefine.customization = ass >> 8;
1232do_sku:
1233 spec->cdefine.sku_cfg = ass;
1234 spec->cdefine.external_amp = (ass & 0x38) >> 3;
1235 spec->cdefine.platform_type = (ass & 0x4) >> 2;
1236 spec->cdefine.swap = (ass & 0x2) >> 1;
1237 spec->cdefine.override = ass & 0x1;
1238
1239 snd_printd("SKU: Nid=0x%x sku_cfg=0x%08x\n",
1240 nid, spec->cdefine.sku_cfg);
1241 snd_printd("SKU: port_connectivity=0x%x\n",
1242 spec->cdefine.port_connectivity);
1243 snd_printd("SKU: enable_pcbeep=0x%x\n", spec->cdefine.enable_pcbeep);
1244 snd_printd("SKU: check_sum=0x%08x\n", spec->cdefine.check_sum);
1245 snd_printd("SKU: customization=0x%08x\n", spec->cdefine.customization);
1246 snd_printd("SKU: external_amp=0x%x\n", spec->cdefine.external_amp);
1247 snd_printd("SKU: platform_type=0x%x\n", spec->cdefine.platform_type);
1248 snd_printd("SKU: swap=0x%x\n", spec->cdefine.swap);
1249 snd_printd("SKU: override=0x%x\n", spec->cdefine.override);
1250
1251 return 0;
1252}
1253
Takashi Iwai1d045db2011-07-07 18:23:21 +02001254/* return true if the given NID is found in the list */
Takashi Iwai3af9ee62011-06-27 12:34:01 +02001255static bool found_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
1256{
Takashi Iwai21268962011-07-07 15:01:13 +02001257 return find_idx_in_nid_list(nid, list, nums) >= 0;
Takashi Iwai3af9ee62011-06-27 12:34:01 +02001258}
1259
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001260/* check subsystem ID and set up device-specific initialization;
1261 * return 1 if initialized, 0 if invalid SSID
1262 */
1263/* 32-bit subsystem ID for BIOS loading in HD Audio codec.
1264 * 31 ~ 16 : Manufacture ID
1265 * 15 ~ 8 : SKU ID
1266 * 7 ~ 0 : Assembly ID
1267 * port-A --> pin 39/41, port-E --> pin 14/15, port-D --> pin 35/36
1268 */
1269static int alc_subsystem_id(struct hda_codec *codec,
1270 hda_nid_t porta, hda_nid_t porte,
Kailang Yang6227cdc2010-02-25 08:36:52 +01001271 hda_nid_t portd, hda_nid_t porti)
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001272{
1273 unsigned int ass, tmp, i;
1274 unsigned nid;
1275 struct alc_spec *spec = codec->spec;
1276
David Henningsson90622912010-10-14 14:50:18 +02001277 if (spec->cdefine.fixup) {
1278 ass = spec->cdefine.sku_cfg;
1279 if (ass == ALC_FIXUP_SKU_IGNORE)
1280 return 0;
1281 goto do_sku;
1282 }
1283
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001284 ass = codec->subsystem_id & 0xffff;
1285 if ((ass != codec->bus->pci->subsystem_device) && (ass & 1))
1286 goto do_sku;
1287
1288 /* invalid SSID, check the special NID pin defcfg instead */
1289 /*
Sasha Alexandrdef319f2009-06-16 16:00:15 -04001290 * 31~30 : port connectivity
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001291 * 29~21 : reserve
1292 * 20 : PCBEEP input
1293 * 19~16 : Check sum (15:1)
1294 * 15~1 : Custom
1295 * 0 : override
1296 */
1297 nid = 0x1d;
1298 if (codec->vendor_id == 0x10ec0260)
1299 nid = 0x17;
1300 ass = snd_hda_codec_get_pincfg(codec, nid);
1301 snd_printd("realtek: No valid SSID, "
1302 "checking pincfg 0x%08x for NID 0x%x\n",
Takashi Iwaicb6605c2009-04-28 13:03:19 +02001303 ass, nid);
Kailang Yang6227cdc2010-02-25 08:36:52 +01001304 if (!(ass & 1))
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001305 return 0;
1306 if ((ass >> 30) != 1) /* no physical connection */
1307 return 0;
1308
1309 /* check sum */
1310 tmp = 0;
1311 for (i = 1; i < 16; i++) {
1312 if ((ass >> i) & 1)
1313 tmp++;
1314 }
1315 if (((ass >> 16) & 0xf) != tmp)
1316 return 0;
1317do_sku:
1318 snd_printd("realtek: Enabling init ASM_ID=0x%04x CODEC_ID=%08x\n",
1319 ass & 0xffff, codec->vendor_id);
1320 /*
1321 * 0 : override
1322 * 1 : Swap Jack
1323 * 2 : 0 --> Desktop, 1 --> Laptop
1324 * 3~5 : External Amplifier control
1325 * 7~6 : Reserved
1326 */
1327 tmp = (ass & 0x38) >> 3; /* external Amp control */
1328 switch (tmp) {
1329 case 1:
1330 spec->init_amp = ALC_INIT_GPIO1;
1331 break;
1332 case 3:
1333 spec->init_amp = ALC_INIT_GPIO2;
1334 break;
1335 case 7:
1336 spec->init_amp = ALC_INIT_GPIO3;
1337 break;
1338 case 5:
Takashi Iwai5a8cfb42010-11-26 17:11:18 +01001339 default:
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001340 spec->init_amp = ALC_INIT_DEFAULT;
1341 break;
1342 }
1343
1344 /* is laptop or Desktop and enable the function "Mute internal speaker
1345 * when the external headphone out jack is plugged"
1346 */
1347 if (!(ass & 0x8000))
1348 return 1;
1349 /*
1350 * 10~8 : Jack location
1351 * 12~11: Headphone out -> 00: PortA, 01: PortE, 02: PortD, 03: Resvered
1352 * 14~13: Resvered
1353 * 15 : 1 --> enable the function "Mute internal speaker
1354 * when the external headphone out jack is plugged"
1355 */
Takashi Iwai5fe6e012011-09-26 10:41:21 +02001356 if (!spec->autocfg.hp_pins[0] &&
1357 !(spec->autocfg.line_out_pins[0] &&
1358 spec->autocfg.line_out_type == AUTO_PIN_HP_OUT)) {
Takashi Iwai01d48252009-10-06 13:21:54 +02001359 hda_nid_t nid;
Kailang Yangc9b58002007-10-16 14:30:01 +02001360 tmp = (ass >> 11) & 0x3; /* HP to chassis */
1361 if (tmp == 0)
Takashi Iwai01d48252009-10-06 13:21:54 +02001362 nid = porta;
Kailang Yangc9b58002007-10-16 14:30:01 +02001363 else if (tmp == 1)
Takashi Iwai01d48252009-10-06 13:21:54 +02001364 nid = porte;
Kailang Yangc9b58002007-10-16 14:30:01 +02001365 else if (tmp == 2)
Takashi Iwai01d48252009-10-06 13:21:54 +02001366 nid = portd;
Kailang Yang6227cdc2010-02-25 08:36:52 +01001367 else if (tmp == 3)
1368 nid = porti;
Kailang Yangc9b58002007-10-16 14:30:01 +02001369 else
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001370 return 1;
Takashi Iwai3af9ee62011-06-27 12:34:01 +02001371 if (found_in_nid_list(nid, spec->autocfg.line_out_pins,
1372 spec->autocfg.line_outs))
1373 return 1;
Takashi Iwai01d48252009-10-06 13:21:54 +02001374 spec->autocfg.hp_pins[0] = nid;
Kailang Yangc9b58002007-10-16 14:30:01 +02001375 }
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001376 return 1;
1377}
Kailang Yangea1fb292008-08-26 12:58:38 +02001378
Takashi Iwai3e6179b2011-07-08 16:55:13 +02001379/* Check the validity of ALC subsystem-id
1380 * ports contains an array of 4 pin NIDs for port-A, E, D and I */
1381static void alc_ssid_check(struct hda_codec *codec, const hda_nid_t *ports)
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001382{
Takashi Iwai3e6179b2011-07-08 16:55:13 +02001383 if (!alc_subsystem_id(codec, ports[0], ports[1], ports[2], ports[3])) {
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001384 struct alc_spec *spec = codec->spec;
1385 snd_printd("realtek: "
1386 "Enable default setup for auto mode as fallback\n");
1387 spec->init_amp = ALC_INIT_DEFAULT;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001388 }
Takashi Iwai21268962011-07-07 15:01:13 +02001389}
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001390
Takashi Iwai41e41f12005-06-08 14:48:49 +02001391/*
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02001392 * Fix-up pin default configurations and add default verbs
Takashi Iwaif95474e2007-07-10 00:47:43 +02001393 */
1394
1395struct alc_pincfg {
1396 hda_nid_t nid;
1397 u32 val;
1398};
1399
Todd Broche1eb5f12010-12-06 11:19:51 -08001400struct alc_model_fixup {
1401 const int id;
1402 const char *name;
1403};
1404
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02001405struct alc_fixup {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001406 int type;
Takashi Iwai361fe6e2011-01-14 09:55:32 +01001407 bool chained;
1408 int chain_id;
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001409 union {
1410 unsigned int sku;
1411 const struct alc_pincfg *pins;
1412 const struct hda_verb *verbs;
1413 void (*func)(struct hda_codec *codec,
1414 const struct alc_fixup *fix,
1415 int action);
1416 } v;
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02001417};
1418
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001419enum {
1420 ALC_FIXUP_INVALID,
1421 ALC_FIXUP_SKU,
1422 ALC_FIXUP_PINS,
1423 ALC_FIXUP_VERBS,
1424 ALC_FIXUP_FUNC,
1425};
Takashi Iwaif95474e2007-07-10 00:47:43 +02001426
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001427enum {
1428 ALC_FIXUP_ACT_PRE_PROBE,
1429 ALC_FIXUP_ACT_PROBE,
Takashi Iwai58701122011-01-13 15:41:45 +01001430 ALC_FIXUP_ACT_INIT,
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001431};
1432
1433static void alc_apply_fixup(struct hda_codec *codec, int action)
1434{
1435 struct alc_spec *spec = codec->spec;
1436 int id = spec->fixup_id;
Takashi Iwaiaa1d0c52011-01-19 17:27:58 +01001437#ifdef CONFIG_SND_DEBUG_VERBOSE
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001438 const char *modelname = spec->fixup_name;
Takashi Iwaiaa1d0c52011-01-19 17:27:58 +01001439#endif
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001440 int depth = 0;
1441
1442 if (!spec->fixup_list)
1443 return;
1444
1445 while (id >= 0) {
1446 const struct alc_fixup *fix = spec->fixup_list + id;
1447 const struct alc_pincfg *cfg;
1448
1449 switch (fix->type) {
1450 case ALC_FIXUP_SKU:
1451 if (action != ALC_FIXUP_ACT_PRE_PROBE || !fix->v.sku)
Jesper Juhle53de8f2011-11-13 23:11:50 +01001452 break;
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001453 snd_printdd(KERN_INFO "hda_codec: %s: "
1454 "Apply sku override for %s\n",
1455 codec->chip_name, modelname);
1456 spec->cdefine.sku_cfg = fix->v.sku;
1457 spec->cdefine.fixup = 1;
1458 break;
1459 case ALC_FIXUP_PINS:
1460 cfg = fix->v.pins;
1461 if (action != ALC_FIXUP_ACT_PRE_PROBE || !cfg)
1462 break;
1463 snd_printdd(KERN_INFO "hda_codec: %s: "
1464 "Apply pincfg for %s\n",
1465 codec->chip_name, modelname);
1466 for (; cfg->nid; cfg++)
1467 snd_hda_codec_set_pincfg(codec, cfg->nid,
1468 cfg->val);
1469 break;
1470 case ALC_FIXUP_VERBS:
1471 if (action != ALC_FIXUP_ACT_PROBE || !fix->v.verbs)
1472 break;
1473 snd_printdd(KERN_INFO "hda_codec: %s: "
1474 "Apply fix-verbs for %s\n",
1475 codec->chip_name, modelname);
1476 add_verb(codec->spec, fix->v.verbs);
1477 break;
1478 case ALC_FIXUP_FUNC:
1479 if (!fix->v.func)
1480 break;
1481 snd_printdd(KERN_INFO "hda_codec: %s: "
1482 "Apply fix-func for %s\n",
1483 codec->chip_name, modelname);
1484 fix->v.func(codec, fix, action);
1485 break;
1486 default:
1487 snd_printk(KERN_ERR "hda_codec: %s: "
1488 "Invalid fixup type %d\n",
1489 codec->chip_name, fix->type);
1490 break;
1491 }
Takashi Iwai24af2b12011-05-02 13:55:36 +02001492 if (!fix->chained)
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001493 break;
1494 if (++depth > 10)
1495 break;
Takashi Iwai24af2b12011-05-02 13:55:36 +02001496 id = fix->chain_id;
Takashi Iwai9d578832010-11-22 13:29:19 +01001497 }
Takashi Iwaif95474e2007-07-10 00:47:43 +02001498}
1499
Todd Broche1eb5f12010-12-06 11:19:51 -08001500static void alc_pick_fixup(struct hda_codec *codec,
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001501 const struct alc_model_fixup *models,
1502 const struct snd_pci_quirk *quirk,
1503 const struct alc_fixup *fixlist)
Todd Broche1eb5f12010-12-06 11:19:51 -08001504{
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001505 struct alc_spec *spec = codec->spec;
Takashi Iwai596830e2011-11-09 15:06:45 +01001506 const struct snd_pci_quirk *q;
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001507 int id = -1;
1508 const char *name = NULL;
Todd Broche1eb5f12010-12-06 11:19:51 -08001509
Todd Broche1eb5f12010-12-06 11:19:51 -08001510 if (codec->modelname && models) {
1511 while (models->name) {
1512 if (!strcmp(codec->modelname, models->name)) {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001513 id = models->id;
1514 name = models->name;
Todd Broche1eb5f12010-12-06 11:19:51 -08001515 break;
1516 }
1517 models++;
1518 }
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001519 }
1520 if (id < 0) {
Takashi Iwai596830e2011-11-09 15:06:45 +01001521 q = snd_pci_quirk_lookup(codec->bus->pci, quirk);
1522 if (q) {
1523 id = q->value;
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001524#ifdef CONFIG_SND_DEBUG_VERBOSE
Takashi Iwai596830e2011-11-09 15:06:45 +01001525 name = q->name;
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001526#endif
1527 }
1528 }
Takashi Iwai596830e2011-11-09 15:06:45 +01001529 if (id < 0) {
1530 for (q = quirk; q->subvendor; q++) {
1531 unsigned int vendorid =
1532 q->subdevice | (q->subvendor << 16);
1533 if (vendorid == codec->subsystem_id) {
1534 id = q->value;
1535#ifdef CONFIG_SND_DEBUG_VERBOSE
1536 name = q->name;
1537#endif
1538 break;
1539 }
1540 }
1541 }
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001542
1543 spec->fixup_id = id;
1544 if (id >= 0) {
1545 spec->fixup_list = fixlist;
1546 spec->fixup_name = name;
Todd Broche1eb5f12010-12-06 11:19:51 -08001547 }
Takashi Iwaif95474e2007-07-10 00:47:43 +02001548}
1549
Takashi Iwai1d045db2011-07-07 18:23:21 +02001550/*
1551 * COEF access helper functions
1552 */
Kailang Yang274693f2009-12-03 10:07:50 +01001553static int alc_read_coef_idx(struct hda_codec *codec,
1554 unsigned int coef_idx)
1555{
1556 unsigned int val;
1557 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX,
1558 coef_idx);
1559 val = snd_hda_codec_read(codec, 0x20, 0,
1560 AC_VERB_GET_PROC_COEF, 0);
1561 return val;
1562}
1563
Kailang Yang977ddd62010-09-15 10:02:29 +02001564static void alc_write_coef_idx(struct hda_codec *codec, unsigned int coef_idx,
1565 unsigned int coef_val)
1566{
1567 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX,
1568 coef_idx);
1569 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF,
1570 coef_val);
1571}
1572
Takashi Iwai1bb7e432011-10-17 16:50:59 +02001573/* a special bypass for COEF 0; read the cached value at the second time */
1574static unsigned int alc_get_coef0(struct hda_codec *codec)
1575{
1576 struct alc_spec *spec = codec->spec;
1577 if (!spec->coef0)
1578 spec->coef0 = alc_read_coef_idx(codec, 0);
1579 return spec->coef0;
1580}
1581
Takashi Iwai1d045db2011-07-07 18:23:21 +02001582/*
1583 * Digital I/O handling
1584 */
1585
Takashi Iwai757899a2010-07-30 10:48:14 +02001586/* set right pin controls for digital I/O */
1587static void alc_auto_init_digital(struct hda_codec *codec)
1588{
1589 struct alc_spec *spec = codec->spec;
1590 int i;
Takashi Iwai1f0f4b82011-06-27 10:52:59 +02001591 hda_nid_t pin, dac;
Takashi Iwai757899a2010-07-30 10:48:14 +02001592
1593 for (i = 0; i < spec->autocfg.dig_outs; i++) {
1594 pin = spec->autocfg.dig_out_pins[i];
Takashi Iwai1f0f4b82011-06-27 10:52:59 +02001595 if (!pin)
1596 continue;
1597 snd_hda_codec_write(codec, pin, 0,
1598 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
1599 if (!i)
1600 dac = spec->multiout.dig_out_nid;
1601 else
1602 dac = spec->slave_dig_outs[i - 1];
1603 if (!dac || !(get_wcaps(codec, dac) & AC_WCAP_OUT_AMP))
1604 continue;
1605 snd_hda_codec_write(codec, dac, 0,
1606 AC_VERB_SET_AMP_GAIN_MUTE,
1607 AMP_OUT_UNMUTE);
Takashi Iwai757899a2010-07-30 10:48:14 +02001608 }
1609 pin = spec->autocfg.dig_in_pin;
1610 if (pin)
1611 snd_hda_codec_write(codec, pin, 0,
1612 AC_VERB_SET_PIN_WIDGET_CONTROL,
1613 PIN_IN);
1614}
1615
1616/* parse digital I/Os and set up NIDs in BIOS auto-parse mode */
1617static void alc_auto_parse_digital(struct hda_codec *codec)
1618{
1619 struct alc_spec *spec = codec->spec;
Takashi Iwai51e41522011-11-03 16:54:06 +01001620 int i, err, nums;
Takashi Iwai757899a2010-07-30 10:48:14 +02001621 hda_nid_t dig_nid;
1622
1623 /* support multiple SPDIFs; the secondary is set up as a slave */
Takashi Iwai51e41522011-11-03 16:54:06 +01001624 nums = 0;
Takashi Iwai757899a2010-07-30 10:48:14 +02001625 for (i = 0; i < spec->autocfg.dig_outs; i++) {
Takashi Iwaia9267572011-07-07 15:12:55 +02001626 hda_nid_t conn[4];
Takashi Iwai757899a2010-07-30 10:48:14 +02001627 err = snd_hda_get_connections(codec,
1628 spec->autocfg.dig_out_pins[i],
Takashi Iwaia9267572011-07-07 15:12:55 +02001629 conn, ARRAY_SIZE(conn));
Takashi Iwai51e41522011-11-03 16:54:06 +01001630 if (err <= 0)
Takashi Iwai757899a2010-07-30 10:48:14 +02001631 continue;
Takashi Iwaia9267572011-07-07 15:12:55 +02001632 dig_nid = conn[0]; /* assume the first element is audio-out */
Takashi Iwai51e41522011-11-03 16:54:06 +01001633 if (!nums) {
Takashi Iwai757899a2010-07-30 10:48:14 +02001634 spec->multiout.dig_out_nid = dig_nid;
1635 spec->dig_out_type = spec->autocfg.dig_out_type[0];
1636 } else {
1637 spec->multiout.slave_dig_outs = spec->slave_dig_outs;
Takashi Iwai51e41522011-11-03 16:54:06 +01001638 if (nums >= ARRAY_SIZE(spec->slave_dig_outs) - 1)
Takashi Iwai757899a2010-07-30 10:48:14 +02001639 break;
Takashi Iwai51e41522011-11-03 16:54:06 +01001640 spec->slave_dig_outs[nums - 1] = dig_nid;
Takashi Iwai757899a2010-07-30 10:48:14 +02001641 }
Takashi Iwai51e41522011-11-03 16:54:06 +01001642 nums++;
Takashi Iwai757899a2010-07-30 10:48:14 +02001643 }
1644
1645 if (spec->autocfg.dig_in_pin) {
Takashi Iwai01fdf182010-09-24 09:09:42 +02001646 dig_nid = codec->start_nid;
1647 for (i = 0; i < codec->num_nodes; i++, dig_nid++) {
1648 unsigned int wcaps = get_wcaps(codec, dig_nid);
1649 if (get_wcaps_type(wcaps) != AC_WID_AUD_IN)
1650 continue;
1651 if (!(wcaps & AC_WCAP_DIGITAL))
1652 continue;
1653 if (!(wcaps & AC_WCAP_CONN_LIST))
1654 continue;
1655 err = get_connection_index(codec, dig_nid,
1656 spec->autocfg.dig_in_pin);
1657 if (err >= 0) {
1658 spec->dig_in_nid = dig_nid;
1659 break;
1660 }
1661 }
Takashi Iwai757899a2010-07-30 10:48:14 +02001662 }
1663}
1664
Takashi Iwaif95474e2007-07-10 00:47:43 +02001665/*
Takashi Iwai1d045db2011-07-07 18:23:21 +02001666 * capture mixer elements
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001667 */
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001668static int alc_cap_vol_info(struct snd_kcontrol *kcontrol,
1669 struct snd_ctl_elem_info *uinfo)
1670{
1671 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1672 struct alc_spec *spec = codec->spec;
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02001673 unsigned long val;
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001674 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001675
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001676 mutex_lock(&codec->control_mutex);
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02001677 if (spec->vol_in_capsrc)
1678 val = HDA_COMPOSE_AMP_VAL(spec->capsrc_nids[0], 3, 0, HDA_OUTPUT);
1679 else
1680 val = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0, HDA_INPUT);
1681 kcontrol->private_value = val;
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001682 err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001683 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001684 return err;
1685}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001687static int alc_cap_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
1688 unsigned int size, unsigned int __user *tlv)
1689{
1690 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1691 struct alc_spec *spec = codec->spec;
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02001692 unsigned long val;
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001693 int err;
1694
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001695 mutex_lock(&codec->control_mutex);
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02001696 if (spec->vol_in_capsrc)
1697 val = HDA_COMPOSE_AMP_VAL(spec->capsrc_nids[0], 3, 0, HDA_OUTPUT);
1698 else
1699 val = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0, HDA_INPUT);
1700 kcontrol->private_value = val;
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001701 err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001702 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001703 return err;
1704}
1705
1706typedef int (*getput_call_t)(struct snd_kcontrol *kcontrol,
1707 struct snd_ctl_elem_value *ucontrol);
1708
1709static int alc_cap_getput_caller(struct snd_kcontrol *kcontrol,
1710 struct snd_ctl_elem_value *ucontrol,
Takashi Iwai9c7a0832011-07-07 09:25:54 +02001711 getput_call_t func, bool check_adc_switch)
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001712{
1713 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1714 struct alc_spec *spec = codec->spec;
Takashi Iwai21268962011-07-07 15:01:13 +02001715 int i, err = 0;
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001716
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001717 mutex_lock(&codec->control_mutex);
Takashi Iwai21268962011-07-07 15:01:13 +02001718 if (check_adc_switch && spec->dyn_adc_switch) {
Takashi Iwai9c7a0832011-07-07 09:25:54 +02001719 for (i = 0; i < spec->num_adc_nids; i++) {
1720 kcontrol->private_value =
1721 HDA_COMPOSE_AMP_VAL(spec->adc_nids[i],
1722 3, 0, HDA_INPUT);
1723 err = func(kcontrol, ucontrol);
1724 if (err < 0)
1725 goto error;
1726 }
1727 } else {
1728 i = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02001729 if (spec->vol_in_capsrc)
1730 kcontrol->private_value =
1731 HDA_COMPOSE_AMP_VAL(spec->capsrc_nids[i],
1732 3, 0, HDA_OUTPUT);
1733 else
1734 kcontrol->private_value =
Takashi Iwai21268962011-07-07 15:01:13 +02001735 HDA_COMPOSE_AMP_VAL(spec->adc_nids[i],
1736 3, 0, HDA_INPUT);
Takashi Iwai9c7a0832011-07-07 09:25:54 +02001737 err = func(kcontrol, ucontrol);
1738 }
1739 error:
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001740 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001741 return err;
1742}
1743
1744static int alc_cap_vol_get(struct snd_kcontrol *kcontrol,
1745 struct snd_ctl_elem_value *ucontrol)
1746{
1747 return alc_cap_getput_caller(kcontrol, ucontrol,
Takashi Iwai9c7a0832011-07-07 09:25:54 +02001748 snd_hda_mixer_amp_volume_get, false);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001749}
1750
1751static int alc_cap_vol_put(struct snd_kcontrol *kcontrol,
1752 struct snd_ctl_elem_value *ucontrol)
1753{
1754 return alc_cap_getput_caller(kcontrol, ucontrol,
Takashi Iwai9c7a0832011-07-07 09:25:54 +02001755 snd_hda_mixer_amp_volume_put, true);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001756}
1757
1758/* capture mixer elements */
1759#define alc_cap_sw_info snd_ctl_boolean_stereo_info
1760
1761static int alc_cap_sw_get(struct snd_kcontrol *kcontrol,
1762 struct snd_ctl_elem_value *ucontrol)
1763{
1764 return alc_cap_getput_caller(kcontrol, ucontrol,
Takashi Iwai9c7a0832011-07-07 09:25:54 +02001765 snd_hda_mixer_amp_switch_get, false);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001766}
1767
1768static int alc_cap_sw_put(struct snd_kcontrol *kcontrol,
1769 struct snd_ctl_elem_value *ucontrol)
1770{
1771 return alc_cap_getput_caller(kcontrol, ucontrol,
Takashi Iwai9c7a0832011-07-07 09:25:54 +02001772 snd_hda_mixer_amp_switch_put, true);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001773}
1774
Takashi Iwaia23b6882009-03-23 15:21:36 +01001775#define _DEFINE_CAPMIX(num) \
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001776 { \
1777 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
1778 .name = "Capture Switch", \
1779 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
1780 .count = num, \
1781 .info = alc_cap_sw_info, \
1782 .get = alc_cap_sw_get, \
1783 .put = alc_cap_sw_put, \
1784 }, \
1785 { \
1786 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
1787 .name = "Capture Volume", \
1788 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | \
1789 SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
1790 SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK), \
1791 .count = num, \
1792 .info = alc_cap_vol_info, \
1793 .get = alc_cap_vol_get, \
1794 .put = alc_cap_vol_put, \
1795 .tlv = { .c = alc_cap_vol_tlv }, \
Takashi Iwaia23b6882009-03-23 15:21:36 +01001796 }
1797
1798#define _DEFINE_CAPSRC(num) \
Takashi Iwai3c3e9892008-10-31 17:48:56 +01001799 { \
1800 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
1801 /* .name = "Capture Source", */ \
1802 .name = "Input Source", \
1803 .count = num, \
1804 .info = alc_mux_enum_info, \
1805 .get = alc_mux_enum_get, \
1806 .put = alc_mux_enum_put, \
Takashi Iwaia23b6882009-03-23 15:21:36 +01001807 }
1808
1809#define DEFINE_CAPMIX(num) \
Takashi Iwaia9111322011-05-02 11:30:18 +02001810static const struct snd_kcontrol_new alc_capture_mixer ## num[] = { \
Takashi Iwaia23b6882009-03-23 15:21:36 +01001811 _DEFINE_CAPMIX(num), \
1812 _DEFINE_CAPSRC(num), \
1813 { } /* end */ \
1814}
1815
1816#define DEFINE_CAPMIX_NOSRC(num) \
Takashi Iwaia9111322011-05-02 11:30:18 +02001817static const struct snd_kcontrol_new alc_capture_mixer_nosrc ## num[] = { \
Takashi Iwaia23b6882009-03-23 15:21:36 +01001818 _DEFINE_CAPMIX(num), \
1819 { } /* end */ \
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001820}
1821
1822/* up to three ADCs */
1823DEFINE_CAPMIX(1);
1824DEFINE_CAPMIX(2);
1825DEFINE_CAPMIX(3);
Takashi Iwaia23b6882009-03-23 15:21:36 +01001826DEFINE_CAPMIX_NOSRC(1);
1827DEFINE_CAPMIX_NOSRC(2);
1828DEFINE_CAPMIX_NOSRC(3);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001829
1830/*
Takashi Iwai2134ea42008-01-10 16:53:55 +01001831 * virtual master controls
1832 */
1833
1834/*
1835 * slave controls for virtual master
1836 */
Takashi Iwaiea734962011-01-17 11:29:34 +01001837static const char * const alc_slave_vols[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01001838 "Front Playback Volume",
1839 "Surround Playback Volume",
1840 "Center Playback Volume",
1841 "LFE Playback Volume",
1842 "Side Playback Volume",
1843 "Headphone Playback Volume",
1844 "Speaker Playback Volume",
1845 "Mono Playback Volume",
Takashi Iwai2134ea42008-01-10 16:53:55 +01001846 "Line-Out Playback Volume",
Takashi Iwai3fe45ae2011-08-18 15:13:17 +02001847 "PCM Playback Volume",
Takashi Iwai2134ea42008-01-10 16:53:55 +01001848 NULL,
1849};
1850
Takashi Iwaiea734962011-01-17 11:29:34 +01001851static const char * const alc_slave_sws[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01001852 "Front Playback Switch",
1853 "Surround Playback Switch",
1854 "Center Playback Switch",
1855 "LFE Playback Switch",
1856 "Side Playback Switch",
1857 "Headphone Playback Switch",
1858 "Speaker Playback Switch",
1859 "Mono Playback Switch",
Takashi Iwaiedb54a52008-01-29 12:47:02 +01001860 "IEC958 Playback Switch",
Takashi Iwai23033b22009-12-08 12:36:52 +01001861 "Line-Out Playback Switch",
Takashi Iwai3fe45ae2011-08-18 15:13:17 +02001862 "PCM Playback Switch",
Takashi Iwai2134ea42008-01-10 16:53:55 +01001863 NULL,
1864};
1865
1866/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001867 * build control elements
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868 */
Takashi Iwai603c4012008-07-30 15:01:44 +02001869
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01001870#define NID_MAPPING (-1)
1871
1872#define SUBDEV_SPEAKER_ (0 << 6)
1873#define SUBDEV_HP_ (1 << 6)
1874#define SUBDEV_LINE_ (2 << 6)
1875#define SUBDEV_SPEAKER(x) (SUBDEV_SPEAKER_ | ((x) & 0x3f))
1876#define SUBDEV_HP(x) (SUBDEV_HP_ | ((x) & 0x3f))
1877#define SUBDEV_LINE(x) (SUBDEV_LINE_ | ((x) & 0x3f))
1878
Takashi Iwai603c4012008-07-30 15:01:44 +02001879static void alc_free_kctls(struct hda_codec *codec);
1880
Takashi Iwai67d634c2009-11-16 15:35:59 +01001881#ifdef CONFIG_SND_HDA_INPUT_BEEP
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01001882/* additional beep mixers; the actual parameters are overwritten at build */
Takashi Iwaia9111322011-05-02 11:30:18 +02001883static const struct snd_kcontrol_new alc_beep_mixer[] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01001884 HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_INPUT),
Jaroslav Kysela123c07a2009-10-21 14:48:23 +02001885 HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01001886 { } /* end */
1887};
Takashi Iwai67d634c2009-11-16 15:35:59 +01001888#endif
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01001889
Takashi Iwaif21d78e2012-01-19 12:10:29 +01001890static int __alc_build_controls(struct hda_codec *codec)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891{
1892 struct alc_spec *spec = codec->spec;
Takashi Iwai2f44f842010-06-22 11:12:32 +02001893 struct snd_kcontrol *kctl = NULL;
Takashi Iwaia9111322011-05-02 11:30:18 +02001894 const struct snd_kcontrol_new *knew;
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01001895 int i, j, err;
1896 unsigned int u;
1897 hda_nid_t nid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898
1899 for (i = 0; i < spec->num_mixers; i++) {
1900 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
1901 if (err < 0)
1902 return err;
1903 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001904 if (spec->cap_mixer) {
1905 err = snd_hda_add_new_ctls(codec, spec->cap_mixer);
1906 if (err < 0)
1907 return err;
1908 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909 if (spec->multiout.dig_out_nid) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001910 err = snd_hda_create_spdif_out_ctls(codec,
Stephen Warren74b654c2011-06-01 11:14:18 -06001911 spec->multiout.dig_out_nid,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001912 spec->multiout.dig_out_nid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001913 if (err < 0)
1914 return err;
Takashi Iwaie64f14f2009-01-20 18:32:55 +01001915 if (!spec->no_analog) {
1916 err = snd_hda_create_spdif_share_sw(codec,
1917 &spec->multiout);
1918 if (err < 0)
1919 return err;
1920 spec->multiout.share_spdif = 1;
1921 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922 }
1923 if (spec->dig_in_nid) {
1924 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
1925 if (err < 0)
1926 return err;
1927 }
Takashi Iwai2134ea42008-01-10 16:53:55 +01001928
Takashi Iwai67d634c2009-11-16 15:35:59 +01001929#ifdef CONFIG_SND_HDA_INPUT_BEEP
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01001930 /* create beep controls if needed */
1931 if (spec->beep_amp) {
Takashi Iwaia9111322011-05-02 11:30:18 +02001932 const struct snd_kcontrol_new *knew;
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01001933 for (knew = alc_beep_mixer; knew->name; knew++) {
1934 struct snd_kcontrol *kctl;
1935 kctl = snd_ctl_new1(knew, codec);
1936 if (!kctl)
1937 return -ENOMEM;
1938 kctl->private_value = spec->beep_amp;
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +01001939 err = snd_hda_ctl_add(codec, 0, kctl);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01001940 if (err < 0)
1941 return err;
1942 }
1943 }
Takashi Iwai67d634c2009-11-16 15:35:59 +01001944#endif
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01001945
Takashi Iwai2134ea42008-01-10 16:53:55 +01001946 /* if we have no master control, let's create it */
Takashi Iwaie64f14f2009-01-20 18:32:55 +01001947 if (!spec->no_analog &&
1948 !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001949 unsigned int vmaster_tlv[4];
Takashi Iwai2134ea42008-01-10 16:53:55 +01001950 snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001951 HDA_OUTPUT, vmaster_tlv);
Takashi Iwai2134ea42008-01-10 16:53:55 +01001952 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001953 vmaster_tlv, alc_slave_vols);
Takashi Iwai2134ea42008-01-10 16:53:55 +01001954 if (err < 0)
1955 return err;
1956 }
Takashi Iwaie64f14f2009-01-20 18:32:55 +01001957 if (!spec->no_analog &&
1958 !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
Takashi Iwai2134ea42008-01-10 16:53:55 +01001959 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
1960 NULL, alc_slave_sws);
1961 if (err < 0)
1962 return err;
1963 }
1964
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01001965 /* assign Capture Source enums to NID */
Takashi Iwaifbe618f2010-06-11 11:24:58 +02001966 if (spec->capsrc_nids || spec->adc_nids) {
1967 kctl = snd_hda_find_mixer_ctl(codec, "Capture Source");
1968 if (!kctl)
1969 kctl = snd_hda_find_mixer_ctl(codec, "Input Source");
1970 for (i = 0; kctl && i < kctl->count; i++) {
Takashi Iwai61071592011-11-23 07:52:15 +01001971 err = snd_hda_add_nid(codec, kctl, i,
1972 get_capsrc(spec, i));
Takashi Iwaifbe618f2010-06-11 11:24:58 +02001973 if (err < 0)
1974 return err;
1975 }
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01001976 }
Takashi Iwai60a6a842011-07-27 14:01:24 +02001977 if (spec->cap_mixer && spec->adc_nids) {
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01001978 const char *kname = kctl ? kctl->id.name : NULL;
1979 for (knew = spec->cap_mixer; knew->name; knew++) {
1980 if (kname && strcmp(knew->name, kname) == 0)
1981 continue;
1982 kctl = snd_hda_find_mixer_ctl(codec, knew->name);
1983 for (i = 0; kctl && i < kctl->count; i++) {
1984 err = snd_hda_add_nid(codec, kctl, i,
1985 spec->adc_nids[i]);
1986 if (err < 0)
1987 return err;
1988 }
1989 }
1990 }
1991
1992 /* other nid->control mapping */
1993 for (i = 0; i < spec->num_mixers; i++) {
1994 for (knew = spec->mixers[i]; knew->name; knew++) {
1995 if (knew->iface != NID_MAPPING)
1996 continue;
1997 kctl = snd_hda_find_mixer_ctl(codec, knew->name);
1998 if (kctl == NULL)
1999 continue;
2000 u = knew->subdevice;
2001 for (j = 0; j < 4; j++, u >>= 8) {
2002 nid = u & 0x3f;
2003 if (nid == 0)
2004 continue;
2005 switch (u & 0xc0) {
2006 case SUBDEV_SPEAKER_:
2007 nid = spec->autocfg.speaker_pins[nid];
2008 break;
2009 case SUBDEV_LINE_:
2010 nid = spec->autocfg.line_out_pins[nid];
2011 break;
2012 case SUBDEV_HP_:
2013 nid = spec->autocfg.hp_pins[nid];
2014 break;
2015 default:
2016 continue;
2017 }
2018 err = snd_hda_add_nid(codec, kctl, 0, nid);
2019 if (err < 0)
2020 return err;
2021 }
2022 u = knew->private_value;
2023 for (j = 0; j < 4; j++, u >>= 8) {
2024 nid = u & 0xff;
2025 if (nid == 0)
2026 continue;
2027 err = snd_hda_add_nid(codec, kctl, 0, nid);
2028 if (err < 0)
2029 return err;
2030 }
2031 }
2032 }
Takashi Iwaibae84e72010-03-22 08:30:20 +01002033
2034 alc_free_kctls(codec); /* no longer needed */
2035
Takashi Iwaif21d78e2012-01-19 12:10:29 +01002036 return 0;
2037}
2038
2039static int alc_build_controls(struct hda_codec *codec)
2040{
2041 struct alc_spec *spec = codec->spec;
2042 int err = __alc_build_controls(codec);
Takashi Iwai01a61e12011-10-28 00:03:22 +02002043 if (err < 0)
2044 return err;
Takashi Iwaif21d78e2012-01-19 12:10:29 +01002045 return snd_hda_jack_add_kctls(codec, &spec->autocfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002046}
2047
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002048
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002050 * Common callbacks
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002051 */
Takashi Iwai16ded522005-06-10 19:58:24 +02002052
Takashi Iwai584c0c42011-03-10 12:51:11 +01002053static void alc_init_special_input_src(struct hda_codec *codec);
2054
Linus Torvalds1da177e2005-04-16 15:20:36 -07002055static int alc_init(struct hda_codec *codec)
2056{
2057 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002058 unsigned int i;
2059
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02002060 alc_fix_pll(codec);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02002061 alc_auto_init_amp(codec, spec->init_amp);
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02002062
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002063 for (i = 0; i < spec->num_init_verbs; i++)
2064 snd_hda_sequence_write(codec, spec->init_verbs[i]);
Takashi Iwai584c0c42011-03-10 12:51:11 +01002065 alc_init_special_input_src(codec);
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002066
2067 if (spec->init_hook)
2068 spec->init_hook(codec);
2069
Takashi Iwai58701122011-01-13 15:41:45 +01002070 alc_apply_fixup(codec, ALC_FIXUP_ACT_INIT);
2071
Takashi Iwai01a61e12011-10-28 00:03:22 +02002072 snd_hda_jack_report_sync(codec);
2073
Takashi Iwai9e5341b2010-09-21 09:57:06 +02002074 hda_call_check_power_status(codec, 0x01);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075 return 0;
2076}
2077
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002078static void alc_unsol_event(struct hda_codec *codec, unsigned int res)
2079{
2080 struct alc_spec *spec = codec->spec;
2081
2082 if (spec->unsol_event)
2083 spec->unsol_event(codec, res);
2084}
2085
Takashi Iwaicb53c622007-08-10 17:21:45 +02002086#ifdef CONFIG_SND_HDA_POWER_SAVE
2087static int alc_check_power_status(struct hda_codec *codec, hda_nid_t nid)
2088{
2089 struct alc_spec *spec = codec->spec;
2090 return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
2091}
2092#endif
2093
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094/*
2095 * Analog playback callbacks
2096 */
Takashi Iwaic2d986b2011-07-06 18:30:08 +02002097static int alc_playback_pcm_open(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002098 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002099 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100{
2101 struct alc_spec *spec = codec->spec;
Takashi Iwai9a081602008-02-12 18:37:26 +01002102 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
2103 hinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002104}
2105
Takashi Iwaic2d986b2011-07-06 18:30:08 +02002106static int alc_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002107 struct hda_codec *codec,
2108 unsigned int stream_tag,
2109 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002110 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002111{
2112 struct alc_spec *spec = codec->spec;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002113 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
2114 stream_tag, format, substream);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115}
2116
Takashi Iwaic2d986b2011-07-06 18:30:08 +02002117static int alc_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002119 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120{
2121 struct alc_spec *spec = codec->spec;
2122 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
2123}
2124
2125/*
2126 * Digital out
2127 */
Takashi Iwaic2d986b2011-07-06 18:30:08 +02002128static int alc_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002129 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002130 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002131{
2132 struct alc_spec *spec = codec->spec;
2133 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
2134}
2135
Takashi Iwaic2d986b2011-07-06 18:30:08 +02002136static int alc_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02002137 struct hda_codec *codec,
2138 unsigned int stream_tag,
2139 unsigned int format,
2140 struct snd_pcm_substream *substream)
2141{
2142 struct alc_spec *spec = codec->spec;
2143 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
2144 stream_tag, format, substream);
2145}
2146
Takashi Iwaic2d986b2011-07-06 18:30:08 +02002147static int alc_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
Takashi Iwai9b5f12e2009-02-13 11:47:37 +01002148 struct hda_codec *codec,
2149 struct snd_pcm_substream *substream)
2150{
2151 struct alc_spec *spec = codec->spec;
2152 return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
2153}
2154
Takashi Iwaic2d986b2011-07-06 18:30:08 +02002155static int alc_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002156 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002157 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158{
2159 struct alc_spec *spec = codec->spec;
2160 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
2161}
2162
2163/*
2164 * Analog capture
2165 */
Takashi Iwaic2d986b2011-07-06 18:30:08 +02002166static int alc_alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002167 struct hda_codec *codec,
2168 unsigned int stream_tag,
2169 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002170 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002171{
2172 struct alc_spec *spec = codec->spec;
2173
Takashi Iwai63300792008-01-24 15:31:36 +01002174 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1],
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175 stream_tag, 0, format);
2176 return 0;
2177}
2178
Takashi Iwaic2d986b2011-07-06 18:30:08 +02002179static int alc_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002180 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002181 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182{
2183 struct alc_spec *spec = codec->spec;
2184
Takashi Iwai888afa12008-03-18 09:57:50 +01002185 snd_hda_codec_cleanup_stream(codec,
2186 spec->adc_nids[substream->number + 1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002187 return 0;
2188}
2189
Takashi Iwai840b64c2010-07-13 22:49:01 +02002190/* analog capture with dynamic dual-adc changes */
Takashi Iwai21268962011-07-07 15:01:13 +02002191static int dyn_adc_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
Takashi Iwai840b64c2010-07-13 22:49:01 +02002192 struct hda_codec *codec,
2193 unsigned int stream_tag,
2194 unsigned int format,
2195 struct snd_pcm_substream *substream)
2196{
2197 struct alc_spec *spec = codec->spec;
Takashi Iwai21268962011-07-07 15:01:13 +02002198 spec->cur_adc = spec->adc_nids[spec->dyn_adc_idx[spec->cur_mux[0]]];
Takashi Iwai840b64c2010-07-13 22:49:01 +02002199 spec->cur_adc_stream_tag = stream_tag;
2200 spec->cur_adc_format = format;
2201 snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format);
2202 return 0;
2203}
2204
Takashi Iwai21268962011-07-07 15:01:13 +02002205static int dyn_adc_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
Takashi Iwai840b64c2010-07-13 22:49:01 +02002206 struct hda_codec *codec,
2207 struct snd_pcm_substream *substream)
2208{
2209 struct alc_spec *spec = codec->spec;
2210 snd_hda_codec_cleanup_stream(codec, spec->cur_adc);
2211 spec->cur_adc = 0;
2212 return 0;
2213}
2214
Takashi Iwai21268962011-07-07 15:01:13 +02002215static const struct hda_pcm_stream dyn_adc_pcm_analog_capture = {
Takashi Iwai840b64c2010-07-13 22:49:01 +02002216 .substreams = 1,
2217 .channels_min = 2,
2218 .channels_max = 2,
2219 .nid = 0, /* fill later */
2220 .ops = {
Takashi Iwai21268962011-07-07 15:01:13 +02002221 .prepare = dyn_adc_capture_pcm_prepare,
2222 .cleanup = dyn_adc_capture_pcm_cleanup
Takashi Iwai840b64c2010-07-13 22:49:01 +02002223 },
2224};
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225
2226/*
2227 */
Takashi Iwaic2d986b2011-07-06 18:30:08 +02002228static const struct hda_pcm_stream alc_pcm_analog_playback = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002229 .substreams = 1,
2230 .channels_min = 2,
2231 .channels_max = 8,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002232 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002233 .ops = {
Takashi Iwaic2d986b2011-07-06 18:30:08 +02002234 .open = alc_playback_pcm_open,
2235 .prepare = alc_playback_pcm_prepare,
2236 .cleanup = alc_playback_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237 },
2238};
2239
Takashi Iwaic2d986b2011-07-06 18:30:08 +02002240static const struct hda_pcm_stream alc_pcm_analog_capture = {
Takashi Iwai63300792008-01-24 15:31:36 +01002241 .substreams = 1,
2242 .channels_min = 2,
2243 .channels_max = 2,
2244 /* NID is set in alc_build_pcms */
2245};
2246
Takashi Iwaic2d986b2011-07-06 18:30:08 +02002247static const struct hda_pcm_stream alc_pcm_analog_alt_playback = {
Takashi Iwai63300792008-01-24 15:31:36 +01002248 .substreams = 1,
2249 .channels_min = 2,
2250 .channels_max = 2,
2251 /* NID is set in alc_build_pcms */
2252};
2253
Takashi Iwaic2d986b2011-07-06 18:30:08 +02002254static const struct hda_pcm_stream alc_pcm_analog_alt_capture = {
Takashi Iwai63300792008-01-24 15:31:36 +01002255 .substreams = 2, /* can be overridden */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002256 .channels_min = 2,
2257 .channels_max = 2,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002258 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259 .ops = {
Takashi Iwaic2d986b2011-07-06 18:30:08 +02002260 .prepare = alc_alt_capture_pcm_prepare,
2261 .cleanup = alc_alt_capture_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07002262 },
2263};
2264
Takashi Iwaic2d986b2011-07-06 18:30:08 +02002265static const struct hda_pcm_stream alc_pcm_digital_playback = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266 .substreams = 1,
2267 .channels_min = 2,
2268 .channels_max = 2,
2269 /* NID is set in alc_build_pcms */
2270 .ops = {
Takashi Iwaic2d986b2011-07-06 18:30:08 +02002271 .open = alc_dig_playback_pcm_open,
2272 .close = alc_dig_playback_pcm_close,
2273 .prepare = alc_dig_playback_pcm_prepare,
2274 .cleanup = alc_dig_playback_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07002275 },
2276};
2277
Takashi Iwaic2d986b2011-07-06 18:30:08 +02002278static const struct hda_pcm_stream alc_pcm_digital_capture = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002279 .substreams = 1,
2280 .channels_min = 2,
2281 .channels_max = 2,
2282 /* NID is set in alc_build_pcms */
2283};
2284
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01002285/* Used by alc_build_pcms to flag that a PCM has no playback stream */
Takashi Iwaia9111322011-05-02 11:30:18 +02002286static const struct hda_pcm_stream alc_pcm_null_stream = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01002287 .substreams = 0,
2288 .channels_min = 0,
2289 .channels_max = 0,
2290};
2291
Linus Torvalds1da177e2005-04-16 15:20:36 -07002292static int alc_build_pcms(struct hda_codec *codec)
2293{
2294 struct alc_spec *spec = codec->spec;
2295 struct hda_pcm *info = spec->pcm_rec;
Takashi Iwaic2d986b2011-07-06 18:30:08 +02002296 const struct hda_pcm_stream *p;
Takashi Iwai1fa17572011-11-02 21:30:51 +01002297 bool have_multi_adcs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298 int i;
2299
2300 codec->num_pcms = 1;
2301 codec->pcm_info = info;
2302
Takashi Iwaie64f14f2009-01-20 18:32:55 +01002303 if (spec->no_analog)
2304 goto skip_analog;
2305
Takashi Iwai812a2cc2009-05-16 10:00:49 +02002306 snprintf(spec->stream_name_analog, sizeof(spec->stream_name_analog),
2307 "%s Analog", codec->chip_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308 info->name = spec->stream_name_analog;
Kailang Yang274693f2009-12-03 10:07:50 +01002309
Takashi Iwaic2d986b2011-07-06 18:30:08 +02002310 if (spec->multiout.dac_nids > 0) {
2311 p = spec->stream_analog_playback;
2312 if (!p)
2313 p = &alc_pcm_analog_playback;
2314 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p;
Takashi Iwai4a471b72005-12-07 13:56:29 +01002315 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
2316 }
Takashi Iwaic2d986b2011-07-06 18:30:08 +02002317 if (spec->adc_nids) {
2318 p = spec->stream_analog_capture;
Takashi Iwai21268962011-07-07 15:01:13 +02002319 if (!p) {
2320 if (spec->dyn_adc_switch)
2321 p = &dyn_adc_pcm_analog_capture;
2322 else
2323 p = &alc_pcm_analog_capture;
2324 }
Takashi Iwaic2d986b2011-07-06 18:30:08 +02002325 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p;
Takashi Iwai4a471b72005-12-07 13:56:29 +01002326 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
2327 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002328
Takashi Iwai4a471b72005-12-07 13:56:29 +01002329 if (spec->channel_mode) {
2330 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0;
2331 for (i = 0; i < spec->num_channel_mode; i++) {
2332 if (spec->channel_mode[i].channels > info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max) {
2333 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->channel_mode[i].channels;
2334 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002335 }
2336 }
2337
Takashi Iwaie64f14f2009-01-20 18:32:55 +01002338 skip_analog:
Takashi Iwaie08a0072006-09-07 17:52:14 +02002339 /* SPDIF for stream index #1 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002340 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
Takashi Iwai812a2cc2009-05-16 10:00:49 +02002341 snprintf(spec->stream_name_digital,
2342 sizeof(spec->stream_name_digital),
2343 "%s Digital", codec->chip_name);
Takashi Iwaie08a0072006-09-07 17:52:14 +02002344 codec->num_pcms = 2;
Wu Fengguangb25c9da2009-02-06 15:02:27 +08002345 codec->slave_dig_outs = spec->multiout.slave_dig_outs;
Takashi Iwaic06134d2006-10-11 18:49:13 +02002346 info = spec->pcm_rec + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002347 info->name = spec->stream_name_digital;
Takashi Iwai8c441982009-01-20 18:30:20 +01002348 if (spec->dig_out_type)
2349 info->pcm_type = spec->dig_out_type;
2350 else
2351 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Takashi Iwaic2d986b2011-07-06 18:30:08 +02002352 if (spec->multiout.dig_out_nid) {
2353 p = spec->stream_digital_playback;
2354 if (!p)
2355 p = &alc_pcm_digital_playback;
2356 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002357 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
2358 }
Takashi Iwaic2d986b2011-07-06 18:30:08 +02002359 if (spec->dig_in_nid) {
2360 p = spec->stream_digital_capture;
2361 if (!p)
2362 p = &alc_pcm_digital_capture;
2363 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002364 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
2365 }
Takashi Iwai963f8032008-08-11 10:04:40 +02002366 /* FIXME: do we need this for all Realtek codec models? */
2367 codec->spdif_status_reset = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002368 }
2369
Takashi Iwaie64f14f2009-01-20 18:32:55 +01002370 if (spec->no_analog)
2371 return 0;
2372
Takashi Iwaie08a0072006-09-07 17:52:14 +02002373 /* If the use of more than one ADC is requested for the current
2374 * model, configure a second analog capture-only PCM.
2375 */
Takashi Iwai1fa17572011-11-02 21:30:51 +01002376 have_multi_adcs = (spec->num_adc_nids > 1) &&
2377 !spec->dyn_adc_switch && !spec->auto_mic &&
2378 (!spec->input_mux || spec->input_mux->num_items > 1);
Takashi Iwaie08a0072006-09-07 17:52:14 +02002379 /* Additional Analaog capture for index #2 */
Takashi Iwai1fa17572011-11-02 21:30:51 +01002380 if (spec->alt_dac_nid || have_multi_adcs) {
Takashi Iwaie08a0072006-09-07 17:52:14 +02002381 codec->num_pcms = 3;
Takashi Iwaic06134d2006-10-11 18:49:13 +02002382 info = spec->pcm_rec + 2;
Takashi Iwaie08a0072006-09-07 17:52:14 +02002383 info->name = spec->stream_name_analog;
Takashi Iwai63300792008-01-24 15:31:36 +01002384 if (spec->alt_dac_nid) {
Takashi Iwaic2d986b2011-07-06 18:30:08 +02002385 p = spec->stream_analog_alt_playback;
2386 if (!p)
2387 p = &alc_pcm_analog_alt_playback;
2388 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p;
Takashi Iwai63300792008-01-24 15:31:36 +01002389 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
2390 spec->alt_dac_nid;
2391 } else {
2392 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
2393 alc_pcm_null_stream;
2394 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
2395 }
Takashi Iwai1fa17572011-11-02 21:30:51 +01002396 if (have_multi_adcs) {
Takashi Iwaic2d986b2011-07-06 18:30:08 +02002397 p = spec->stream_analog_alt_capture;
2398 if (!p)
2399 p = &alc_pcm_analog_alt_capture;
2400 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p;
Takashi Iwai63300792008-01-24 15:31:36 +01002401 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
2402 spec->adc_nids[1];
2403 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams =
2404 spec->num_adc_nids - 1;
2405 } else {
2406 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
2407 alc_pcm_null_stream;
2408 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0;
Takashi Iwaie08a0072006-09-07 17:52:14 +02002409 }
2410 }
2411
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412 return 0;
2413}
2414
Takashi Iwaia4e09aa2009-12-27 11:22:24 +01002415static inline void alc_shutup(struct hda_codec *codec)
2416{
Takashi Iwai1c716152011-04-07 10:37:16 +02002417 struct alc_spec *spec = codec->spec;
2418
2419 if (spec && spec->shutup)
2420 spec->shutup(codec);
Takashi Iwaia4e09aa2009-12-27 11:22:24 +01002421 snd_hda_shutup_pins(codec);
2422}
2423
Takashi Iwai603c4012008-07-30 15:01:44 +02002424static void alc_free_kctls(struct hda_codec *codec)
2425{
2426 struct alc_spec *spec = codec->spec;
2427
2428 if (spec->kctls.list) {
2429 struct snd_kcontrol_new *kctl = spec->kctls.list;
2430 int i;
2431 for (i = 0; i < spec->kctls.used; i++)
2432 kfree(kctl[i].name);
2433 }
2434 snd_array_free(&spec->kctls);
2435}
2436
Takashi Iwai23c09b02011-08-19 09:05:35 +02002437static void alc_free_bind_ctls(struct hda_codec *codec)
2438{
2439 struct alc_spec *spec = codec->spec;
2440 if (spec->bind_ctls.list) {
2441 struct hda_bind_ctls **ctl = spec->bind_ctls.list;
2442 int i;
2443 for (i = 0; i < spec->bind_ctls.used; i++)
2444 kfree(ctl[i]);
2445 }
2446 snd_array_free(&spec->bind_ctls);
2447}
2448
Linus Torvalds1da177e2005-04-16 15:20:36 -07002449static void alc_free(struct hda_codec *codec)
2450{
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002451 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002452
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002453 if (!spec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002454 return;
2455
Takashi Iwaia4e09aa2009-12-27 11:22:24 +01002456 alc_shutup(codec);
Takashi Iwai603c4012008-07-30 15:01:44 +02002457 alc_free_kctls(codec);
Takashi Iwai23c09b02011-08-19 09:05:35 +02002458 alc_free_bind_ctls(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002459 kfree(spec);
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09002460 snd_hda_detach_beep_device(codec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461}
2462
Hector Martinf5de24b2009-12-20 22:51:31 +01002463#ifdef CONFIG_SND_HDA_POWER_SAVE
Daniel T Chenc97259d2009-12-27 18:52:08 -05002464static void alc_power_eapd(struct hda_codec *codec)
2465{
Takashi Iwai691f1fc2011-04-07 10:31:43 +02002466 alc_auto_setup_eapd(codec, false);
Daniel T Chenc97259d2009-12-27 18:52:08 -05002467}
2468
Hector Martinf5de24b2009-12-20 22:51:31 +01002469static int alc_suspend(struct hda_codec *codec, pm_message_t state)
2470{
2471 struct alc_spec *spec = codec->spec;
Takashi Iwaia4e09aa2009-12-27 11:22:24 +01002472 alc_shutup(codec);
Hector Martinf5de24b2009-12-20 22:51:31 +01002473 if (spec && spec->power_hook)
Daniel T Chenc97259d2009-12-27 18:52:08 -05002474 spec->power_hook(codec);
Hector Martinf5de24b2009-12-20 22:51:31 +01002475 return 0;
2476}
2477#endif
2478
Takashi Iwai2a439522011-07-26 09:52:50 +02002479#ifdef CONFIG_PM
Takashi Iwaie044c392008-10-27 16:56:24 +01002480static int alc_resume(struct hda_codec *codec)
2481{
Takashi Iwai1c716152011-04-07 10:37:16 +02002482 msleep(150); /* to avoid pop noise */
Takashi Iwaie044c392008-10-27 16:56:24 +01002483 codec->patch_ops.init(codec);
2484 snd_hda_codec_resume_amp(codec);
2485 snd_hda_codec_resume_cache(codec);
Takashi Iwai9e5341b2010-09-21 09:57:06 +02002486 hda_call_check_power_status(codec, 0x01);
Takashi Iwaie044c392008-10-27 16:56:24 +01002487 return 0;
2488}
Takashi Iwaie044c392008-10-27 16:56:24 +01002489#endif
2490
Linus Torvalds1da177e2005-04-16 15:20:36 -07002491/*
2492 */
Takashi Iwaia9111322011-05-02 11:30:18 +02002493static const struct hda_codec_ops alc_patch_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002494 .build_controls = alc_build_controls,
2495 .build_pcms = alc_build_pcms,
2496 .init = alc_init,
2497 .free = alc_free,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01002498 .unsol_event = alc_unsol_event,
Takashi Iwai2a439522011-07-26 09:52:50 +02002499#ifdef CONFIG_PM
Takashi Iwaie044c392008-10-27 16:56:24 +01002500 .resume = alc_resume,
2501#endif
Takashi Iwaicb53c622007-08-10 17:21:45 +02002502#ifdef CONFIG_SND_HDA_POWER_SAVE
Hector Martinf5de24b2009-12-20 22:51:31 +01002503 .suspend = alc_suspend,
Takashi Iwaicb53c622007-08-10 17:21:45 +02002504 .check_power_status = alc_check_power_status,
2505#endif
Daniel T Chenc97259d2009-12-27 18:52:08 -05002506 .reboot_notify = alc_shutup,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002507};
2508
Kailang Yangc027ddc2010-03-19 11:33:06 +01002509/* replace the codec chip_name with the given string */
2510static int alc_codec_rename(struct hda_codec *codec, const char *name)
2511{
2512 kfree(codec->chip_name);
2513 codec->chip_name = kstrdup(name, GFP_KERNEL);
2514 if (!codec->chip_name) {
2515 alc_free(codec);
2516 return -ENOMEM;
2517 }
2518 return 0;
2519}
2520
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002521/*
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02002522 * Rename codecs appropriately from COEF value
2523 */
2524struct alc_codec_rename_table {
2525 unsigned int vendor_id;
2526 unsigned short coef_mask;
2527 unsigned short coef_bits;
2528 const char *name;
2529};
2530
2531static struct alc_codec_rename_table rename_tbl[] = {
2532 { 0x10ec0269, 0xfff0, 0x3010, "ALC277" },
2533 { 0x10ec0269, 0xf0f0, 0x2010, "ALC259" },
2534 { 0x10ec0269, 0xf0f0, 0x3010, "ALC258" },
2535 { 0x10ec0269, 0x00f0, 0x0010, "ALC269VB" },
2536 { 0x10ec0269, 0xffff, 0xa023, "ALC259" },
2537 { 0x10ec0269, 0xffff, 0x6023, "ALC281X" },
2538 { 0x10ec0269, 0x00f0, 0x0020, "ALC269VC" },
2539 { 0x10ec0887, 0x00f0, 0x0030, "ALC887-VD" },
2540 { 0x10ec0888, 0x00f0, 0x0030, "ALC888-VD" },
2541 { 0x10ec0888, 0xf0f0, 0x3020, "ALC886" },
2542 { 0x10ec0899, 0x2000, 0x2000, "ALC899" },
2543 { 0x10ec0892, 0xffff, 0x8020, "ALC661" },
2544 { 0x10ec0892, 0xffff, 0x8011, "ALC661" },
2545 { 0x10ec0892, 0xffff, 0x4011, "ALC656" },
2546 { } /* terminator */
2547};
2548
2549static int alc_codec_rename_from_preset(struct hda_codec *codec)
2550{
2551 const struct alc_codec_rename_table *p;
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02002552
2553 for (p = rename_tbl; p->vendor_id; p++) {
2554 if (p->vendor_id != codec->vendor_id)
2555 continue;
Takashi Iwai1bb7e432011-10-17 16:50:59 +02002556 if ((alc_get_coef0(codec) & p->coef_mask) == p->coef_bits)
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02002557 return alc_codec_rename(codec, p->name);
2558 }
2559 return 0;
2560}
2561
2562/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002563 * Automatic parse of I/O pins from the BIOS configuration
2564 */
2565
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002566enum {
2567 ALC_CTL_WIDGET_VOL,
2568 ALC_CTL_WIDGET_MUTE,
2569 ALC_CTL_BIND_MUTE,
Takashi Iwai23c09b02011-08-19 09:05:35 +02002570 ALC_CTL_BIND_VOL,
2571 ALC_CTL_BIND_SW,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002572};
Takashi Iwai1d045db2011-07-07 18:23:21 +02002573static const struct snd_kcontrol_new alc_control_templates[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002574 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
2575 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Takashi Iwai985be542005-11-02 18:26:49 +01002576 HDA_BIND_MUTE(NULL, 0, 0, 0),
Takashi Iwai23c09b02011-08-19 09:05:35 +02002577 HDA_BIND_VOL(NULL, 0),
2578 HDA_BIND_SW(NULL, 0),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002579};
2580
2581/* add dynamic controls */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002582static int add_control(struct alc_spec *spec, int type, const char *name,
Takashi Iwai66ceeb62010-08-30 13:05:52 +02002583 int cidx, unsigned long val)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002584{
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002585 struct snd_kcontrol_new *knew;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002586
Takashi Iwaice764ab2011-04-27 16:35:23 +02002587 knew = alc_kcontrol_new(spec);
Takashi Iwai603c4012008-07-30 15:01:44 +02002588 if (!knew)
2589 return -ENOMEM;
Takashi Iwai1d045db2011-07-07 18:23:21 +02002590 *knew = alc_control_templates[type];
Paulo Marques543537b2005-06-23 00:09:02 -07002591 knew->name = kstrdup(name, GFP_KERNEL);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002592 if (!knew->name)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002593 return -ENOMEM;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02002594 knew->index = cidx;
Jaroslav Kysela4d02d1b2009-11-12 10:15:48 +01002595 if (get_amp_nid_(val))
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +01002596 knew->subdevice = HDA_SUBDEV_AMP_FLAG;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002597 knew->private_value = val;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002598 return 0;
2599}
2600
Takashi Iwai0afe5f82009-10-02 09:20:00 +02002601static int add_control_with_pfx(struct alc_spec *spec, int type,
2602 const char *pfx, const char *dir,
Takashi Iwai66ceeb62010-08-30 13:05:52 +02002603 const char *sfx, int cidx, unsigned long val)
Takashi Iwai0afe5f82009-10-02 09:20:00 +02002604{
2605 char name[32];
2606 snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx);
Takashi Iwai66ceeb62010-08-30 13:05:52 +02002607 return add_control(spec, type, name, cidx, val);
Takashi Iwai0afe5f82009-10-02 09:20:00 +02002608}
2609
Takashi Iwai66ceeb62010-08-30 13:05:52 +02002610#define add_pb_vol_ctrl(spec, type, pfx, val) \
2611 add_control_with_pfx(spec, type, pfx, "Playback", "Volume", 0, val)
2612#define add_pb_sw_ctrl(spec, type, pfx, val) \
2613 add_control_with_pfx(spec, type, pfx, "Playback", "Switch", 0, val)
2614#define __add_pb_vol_ctrl(spec, type, pfx, cidx, val) \
2615 add_control_with_pfx(spec, type, pfx, "Playback", "Volume", cidx, val)
2616#define __add_pb_sw_ctrl(spec, type, pfx, cidx, val) \
2617 add_control_with_pfx(spec, type, pfx, "Playback", "Switch", cidx, val)
Takashi Iwai0afe5f82009-10-02 09:20:00 +02002618
Takashi Iwai23c09b02011-08-19 09:05:35 +02002619static const char * const channel_name[4] = {
2620 "Front", "Surround", "CLFE", "Side"
2621};
2622
Takashi Iwai6843ca12011-06-24 11:03:58 +02002623static const char *alc_get_line_out_pfx(struct alc_spec *spec, int ch,
2624 bool can_be_master, int *index)
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01002625{
Takashi Iwaice764ab2011-04-27 16:35:23 +02002626 struct auto_pin_cfg *cfg = &spec->autocfg;
2627
Takashi Iwai6843ca12011-06-24 11:03:58 +02002628 *index = 0;
Takashi Iwaice764ab2011-04-27 16:35:23 +02002629 if (cfg->line_outs == 1 && !spec->multi_ios &&
2630 !cfg->hp_outs && !cfg->speaker_outs && can_be_master)
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01002631 return "Master";
2632
2633 switch (cfg->line_out_type) {
2634 case AUTO_PIN_SPEAKER_OUT:
David Henningssonebbeb3d2011-03-04 14:08:30 +01002635 if (cfg->line_outs == 1)
2636 return "Speaker";
Takashi Iwaifbabc242011-12-07 17:14:20 +01002637 if (cfg->line_outs == 2)
2638 return ch ? "Bass Speaker" : "Speaker";
David Henningssonebbeb3d2011-03-04 14:08:30 +01002639 break;
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01002640 case AUTO_PIN_HP_OUT:
Takashi Iwai6843ca12011-06-24 11:03:58 +02002641 /* for multi-io case, only the primary out */
2642 if (ch && spec->multi_ios)
2643 break;
2644 *index = ch;
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01002645 return "Headphone";
2646 default:
Takashi Iwaice764ab2011-04-27 16:35:23 +02002647 if (cfg->line_outs == 1 && !spec->multi_ios)
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01002648 return "PCM";
2649 break;
2650 }
Takashi Iwai23c09b02011-08-19 09:05:35 +02002651 if (snd_BUG_ON(ch >= ARRAY_SIZE(channel_name)))
2652 return "PCM";
2653
2654 return channel_name[ch];
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01002655}
2656
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002657/* create input playback/capture controls for the given pin */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002658static int new_analog_input(struct alc_spec *spec, hda_nid_t pin,
Takashi Iwai66ceeb62010-08-30 13:05:52 +02002659 const char *ctlname, int ctlidx,
Kailang Yangdf694da2005-12-05 19:42:22 +01002660 int idx, hda_nid_t mix_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002661{
Kailang Yangdf694da2005-12-05 19:42:22 +01002662 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002663
Takashi Iwai66ceeb62010-08-30 13:05:52 +02002664 err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname, ctlidx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002665 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
2666 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002667 return err;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02002668 err = __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname, ctlidx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002669 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
2670 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002671 return err;
2672 return 0;
2673}
2674
Takashi Iwai05f5f472009-08-25 13:10:18 +02002675static int alc_is_input_pin(struct hda_codec *codec, hda_nid_t nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002676{
Takashi Iwai05f5f472009-08-25 13:10:18 +02002677 unsigned int pincap = snd_hda_query_pin_caps(codec, nid);
2678 return (pincap & AC_PINCAP_IN) != 0;
2679}
2680
Takashi Iwai1d045db2011-07-07 18:23:21 +02002681/* Parse the codec tree and retrieve ADCs and corresponding capsrc MUXs */
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02002682static int alc_auto_fill_adc_caps(struct hda_codec *codec)
Takashi Iwaib7821702011-07-06 15:12:46 +02002683{
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02002684 struct alc_spec *spec = codec->spec;
Takashi Iwaib7821702011-07-06 15:12:46 +02002685 hda_nid_t nid;
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02002686 hda_nid_t *adc_nids = spec->private_adc_nids;
2687 hda_nid_t *cap_nids = spec->private_capsrc_nids;
2688 int max_nums = ARRAY_SIZE(spec->private_adc_nids);
Takashi Iwaib7821702011-07-06 15:12:46 +02002689 int i, nums = 0;
2690
Takashi Iwai24de1832011-11-07 17:13:39 +01002691 if (spec->shared_mic_hp)
2692 max_nums = 1; /* no multi streams with the shared HP/mic */
2693
Takashi Iwaib7821702011-07-06 15:12:46 +02002694 nid = codec->start_nid;
2695 for (i = 0; i < codec->num_nodes; i++, nid++) {
2696 hda_nid_t src;
2697 const hda_nid_t *list;
2698 unsigned int caps = get_wcaps(codec, nid);
2699 int type = get_wcaps_type(caps);
2700
2701 if (type != AC_WID_AUD_IN || (caps & AC_WCAP_DIGITAL))
2702 continue;
2703 adc_nids[nums] = nid;
2704 cap_nids[nums] = nid;
2705 src = nid;
2706 for (;;) {
2707 int n;
2708 type = get_wcaps_type(get_wcaps(codec, src));
2709 if (type == AC_WID_PIN)
2710 break;
2711 if (type == AC_WID_AUD_SEL) {
2712 cap_nids[nums] = src;
2713 break;
2714 }
2715 n = snd_hda_get_conn_list(codec, src, &list);
2716 if (n > 1) {
2717 cap_nids[nums] = src;
2718 break;
2719 } else if (n != 1)
2720 break;
2721 src = *list;
2722 }
2723 if (++nums >= max_nums)
2724 break;
2725 }
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02002726 spec->adc_nids = spec->private_adc_nids;
Takashi Iwai21268962011-07-07 15:01:13 +02002727 spec->capsrc_nids = spec->private_capsrc_nids;
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02002728 spec->num_adc_nids = nums;
Takashi Iwaib7821702011-07-06 15:12:46 +02002729 return nums;
2730}
2731
Takashi Iwai05f5f472009-08-25 13:10:18 +02002732/* create playback/capture controls for input pins */
Takashi Iwaib7821702011-07-06 15:12:46 +02002733static int alc_auto_create_input_ctls(struct hda_codec *codec)
Takashi Iwai05f5f472009-08-25 13:10:18 +02002734{
2735 struct alc_spec *spec = codec->spec;
Takashi Iwaib7821702011-07-06 15:12:46 +02002736 const struct auto_pin_cfg *cfg = &spec->autocfg;
2737 hda_nid_t mixer = spec->mixer_nid;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02002738 struct hda_input_mux *imux = &spec->private_imux[0];
Takashi Iwaib7821702011-07-06 15:12:46 +02002739 int num_adcs;
Takashi Iwaib7821702011-07-06 15:12:46 +02002740 int i, c, err, idx, type_idx = 0;
David Henningsson5322bf22011-01-05 11:03:56 +01002741 const char *prev_label = NULL;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002742
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02002743 num_adcs = alc_auto_fill_adc_caps(codec);
Takashi Iwaib7821702011-07-06 15:12:46 +02002744 if (num_adcs < 0)
2745 return 0;
2746
Takashi Iwai66ceeb62010-08-30 13:05:52 +02002747 for (i = 0; i < cfg->num_inputs; i++) {
Takashi Iwai05f5f472009-08-25 13:10:18 +02002748 hda_nid_t pin;
Takashi Iwai10a20af2010-09-09 16:28:02 +02002749 const char *label;
Takashi Iwai05f5f472009-08-25 13:10:18 +02002750
Takashi Iwai66ceeb62010-08-30 13:05:52 +02002751 pin = cfg->inputs[i].pin;
Takashi Iwai05f5f472009-08-25 13:10:18 +02002752 if (!alc_is_input_pin(codec, pin))
2753 continue;
2754
David Henningsson5322bf22011-01-05 11:03:56 +01002755 label = hda_get_autocfg_input_label(codec, cfg, i);
Takashi Iwai24de1832011-11-07 17:13:39 +01002756 if (spec->shared_mic_hp && !strcmp(label, "Misc"))
2757 label = "Headphone Mic";
David Henningsson5322bf22011-01-05 11:03:56 +01002758 if (prev_label && !strcmp(label, prev_label))
Takashi Iwai66ceeb62010-08-30 13:05:52 +02002759 type_idx++;
2760 else
2761 type_idx = 0;
David Henningsson5322bf22011-01-05 11:03:56 +01002762 prev_label = label;
2763
Takashi Iwai05f5f472009-08-25 13:10:18 +02002764 if (mixer) {
2765 idx = get_connection_index(codec, mixer, pin);
2766 if (idx >= 0) {
2767 err = new_analog_input(spec, pin,
Takashi Iwai10a20af2010-09-09 16:28:02 +02002768 label, type_idx,
2769 idx, mixer);
Takashi Iwai05f5f472009-08-25 13:10:18 +02002770 if (err < 0)
2771 return err;
2772 }
2773 }
2774
Takashi Iwaib7821702011-07-06 15:12:46 +02002775 for (c = 0; c < num_adcs; c++) {
Takashi Iwai61071592011-11-23 07:52:15 +01002776 hda_nid_t cap = get_capsrc(spec, c);
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02002777 idx = get_connection_index(codec, cap, pin);
Takashi Iwaib7821702011-07-06 15:12:46 +02002778 if (idx >= 0) {
Takashi Iwai21268962011-07-07 15:01:13 +02002779 spec->imux_pins[imux->num_items] = pin;
Takashi Iwaib7821702011-07-06 15:12:46 +02002780 snd_hda_add_imux_item(imux, label, idx, NULL);
2781 break;
2782 }
2783 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002784 }
Takashi Iwai21268962011-07-07 15:01:13 +02002785
2786 spec->num_mux_defs = 1;
2787 spec->input_mux = imux;
2788
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002789 return 0;
2790}
2791
Takashi Iwai24de1832011-11-07 17:13:39 +01002792/* create a shared input with the headphone out */
2793static int alc_auto_create_shared_input(struct hda_codec *codec)
2794{
2795 struct alc_spec *spec = codec->spec;
2796 struct auto_pin_cfg *cfg = &spec->autocfg;
2797 unsigned int defcfg;
2798 hda_nid_t nid;
2799
2800 /* only one internal input pin? */
2801 if (cfg->num_inputs != 1)
2802 return 0;
2803 defcfg = snd_hda_codec_get_pincfg(codec, cfg->inputs[0].pin);
2804 if (snd_hda_get_input_pin_attr(defcfg) != INPUT_PIN_ATTR_INT)
2805 return 0;
2806
2807 if (cfg->hp_outs == 1 && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
2808 nid = cfg->hp_pins[0]; /* OK, we have a single HP-out */
2809 else if (cfg->line_outs == 1 && cfg->line_out_type == AUTO_PIN_HP_OUT)
2810 nid = cfg->line_out_pins[0]; /* OK, we have a single line-out */
2811 else
2812 return 0; /* both not available */
2813
2814 if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_IN))
2815 return 0; /* no input */
2816
2817 cfg->inputs[1].pin = nid;
2818 cfg->inputs[1].type = AUTO_PIN_MIC;
2819 cfg->num_inputs = 2;
2820 spec->shared_mic_hp = 1;
2821 snd_printdd("realtek: Enable shared I/O jack on NID 0x%x\n", nid);
2822 return 0;
2823}
2824
Takashi Iwaif6c7e542008-02-12 18:32:23 +01002825static void alc_set_pin_output(struct hda_codec *codec, hda_nid_t nid,
2826 unsigned int pin_type)
2827{
2828 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
2829 pin_type);
2830 /* unmute pin */
Takashi Iwai44c02402011-07-08 15:14:19 +02002831 if (nid_has_mute(codec, nid, HDA_OUTPUT))
2832 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwaid260cdf2008-02-13 17:19:35 +01002833 AMP_OUT_UNMUTE);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01002834}
2835
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02002836static int get_pin_type(int line_out_type)
2837{
2838 if (line_out_type == AUTO_PIN_HP_OUT)
2839 return PIN_HP;
2840 else
2841 return PIN_OUT;
2842}
2843
Takashi Iwai0a7f5322011-07-06 15:15:12 +02002844static void alc_auto_init_analog_input(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002845{
2846 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02002847 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002848 int i;
2849
Takashi Iwai66ceeb62010-08-30 13:05:52 +02002850 for (i = 0; i < cfg->num_inputs; i++) {
2851 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai05f5f472009-08-25 13:10:18 +02002852 if (alc_is_input_pin(codec, nid)) {
Takashi Iwai30ea0982010-09-16 18:47:56 +02002853 alc_set_input_pin(codec, nid, cfg->inputs[i].type);
Takashi Iwai1f0f4b82011-06-27 10:52:59 +02002854 if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002855 snd_hda_codec_write(codec, nid, 0,
2856 AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002857 AMP_OUT_MUTE);
2858 }
2859 }
Takashi Iwai1f0f4b82011-06-27 10:52:59 +02002860
2861 /* mute all loopback inputs */
2862 if (spec->mixer_nid) {
2863 int nums = snd_hda_get_conn_list(codec, spec->mixer_nid, NULL);
2864 for (i = 0; i < nums; i++)
2865 snd_hda_codec_write(codec, spec->mixer_nid, 0,
2866 AC_VERB_SET_AMP_GAIN_MUTE,
2867 AMP_IN_MUTE(i));
2868 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002869}
2870
Takashi Iwai7085ec12009-10-02 09:03:58 +02002871/* convert from MIX nid to DAC */
Takashi Iwai604401a2011-04-27 15:14:23 +02002872static hda_nid_t alc_auto_mix_to_dac(struct hda_codec *codec, hda_nid_t nid)
Takashi Iwai7085ec12009-10-02 09:03:58 +02002873{
Takashi Iwai604401a2011-04-27 15:14:23 +02002874 hda_nid_t list[5];
Takashi Iwai1304ac82011-04-06 15:16:21 +02002875 int i, num;
2876
Takashi Iwaiafcd5512011-07-08 11:07:59 +02002877 if (get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_AUD_OUT)
2878 return nid;
Takashi Iwai1304ac82011-04-06 15:16:21 +02002879 num = snd_hda_get_connections(codec, nid, list, ARRAY_SIZE(list));
2880 for (i = 0; i < num; i++) {
2881 if (get_wcaps_type(get_wcaps(codec, list[i])) == AC_WID_AUD_OUT)
2882 return list[i];
2883 }
2884 return 0;
Takashi Iwai7085ec12009-10-02 09:03:58 +02002885}
2886
Takashi Iwai604401a2011-04-27 15:14:23 +02002887/* go down to the selector widget before the mixer */
2888static hda_nid_t alc_go_down_to_selector(struct hda_codec *codec, hda_nid_t pin)
2889{
2890 hda_nid_t srcs[5];
2891 int num = snd_hda_get_connections(codec, pin, srcs,
2892 ARRAY_SIZE(srcs));
2893 if (num != 1 ||
2894 get_wcaps_type(get_wcaps(codec, srcs[0])) != AC_WID_AUD_SEL)
2895 return pin;
2896 return srcs[0];
2897}
2898
Takashi Iwai7085ec12009-10-02 09:03:58 +02002899/* get MIX nid connected to the given pin targeted to DAC */
Takashi Iwai604401a2011-04-27 15:14:23 +02002900static hda_nid_t alc_auto_dac_to_mix(struct hda_codec *codec, hda_nid_t pin,
Takashi Iwai7085ec12009-10-02 09:03:58 +02002901 hda_nid_t dac)
2902{
David Henningssoncc1c4522010-11-24 14:17:47 +01002903 hda_nid_t mix[5];
Takashi Iwai7085ec12009-10-02 09:03:58 +02002904 int i, num;
2905
Takashi Iwai604401a2011-04-27 15:14:23 +02002906 pin = alc_go_down_to_selector(codec, pin);
Takashi Iwai7085ec12009-10-02 09:03:58 +02002907 num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix));
2908 for (i = 0; i < num; i++) {
Takashi Iwai604401a2011-04-27 15:14:23 +02002909 if (alc_auto_mix_to_dac(codec, mix[i]) == dac)
Takashi Iwai7085ec12009-10-02 09:03:58 +02002910 return mix[i];
2911 }
2912 return 0;
2913}
2914
Takashi Iwaice764ab2011-04-27 16:35:23 +02002915/* select the connection from pin to DAC if needed */
2916static int alc_auto_select_dac(struct hda_codec *codec, hda_nid_t pin,
2917 hda_nid_t dac)
2918{
2919 hda_nid_t mix[5];
2920 int i, num;
2921
2922 pin = alc_go_down_to_selector(codec, pin);
2923 num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix));
2924 if (num < 2)
2925 return 0;
2926 for (i = 0; i < num; i++) {
2927 if (alc_auto_mix_to_dac(codec, mix[i]) == dac) {
2928 snd_hda_codec_update_cache(codec, pin, 0,
2929 AC_VERB_SET_CONNECT_SEL, i);
2930 return 0;
2931 }
2932 }
2933 return 0;
2934}
2935
Takashi Iwai7085ec12009-10-02 09:03:58 +02002936/* look for an empty DAC slot */
Takashi Iwai604401a2011-04-27 15:14:23 +02002937static hda_nid_t alc_auto_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
Takashi Iwai7085ec12009-10-02 09:03:58 +02002938{
2939 struct alc_spec *spec = codec->spec;
2940 hda_nid_t srcs[5];
Takashi Iwai3af9ee62011-06-27 12:34:01 +02002941 int i, num;
Takashi Iwai7085ec12009-10-02 09:03:58 +02002942
Takashi Iwai604401a2011-04-27 15:14:23 +02002943 pin = alc_go_down_to_selector(codec, pin);
Takashi Iwai7085ec12009-10-02 09:03:58 +02002944 num = snd_hda_get_connections(codec, pin, srcs, ARRAY_SIZE(srcs));
Takashi Iwai7085ec12009-10-02 09:03:58 +02002945 for (i = 0; i < num; i++) {
Takashi Iwai604401a2011-04-27 15:14:23 +02002946 hda_nid_t nid = alc_auto_mix_to_dac(codec, srcs[i]);
Takashi Iwai7085ec12009-10-02 09:03:58 +02002947 if (!nid)
2948 continue;
Takashi Iwai3af9ee62011-06-27 12:34:01 +02002949 if (found_in_nid_list(nid, spec->multiout.dac_nids,
Takashi Iwai0a34b422011-12-07 17:20:30 +01002950 ARRAY_SIZE(spec->private_dac_nids)))
Takashi Iwai3af9ee62011-06-27 12:34:01 +02002951 continue;
Takashi Iwaic2674682011-08-24 17:57:44 +02002952 if (found_in_nid_list(nid, spec->multiout.hp_out_nid,
2953 ARRAY_SIZE(spec->multiout.hp_out_nid)))
2954 continue;
Takashi Iwai3af9ee62011-06-27 12:34:01 +02002955 if (found_in_nid_list(nid, spec->multiout.extra_out_nid,
2956 ARRAY_SIZE(spec->multiout.extra_out_nid)))
2957 continue;
2958 return nid;
Takashi Iwai7085ec12009-10-02 09:03:58 +02002959 }
2960 return 0;
2961}
2962
Takashi Iwai07b18f62011-11-10 15:42:54 +01002963/* check whether the DAC is reachable from the pin */
2964static bool alc_auto_is_dac_reachable(struct hda_codec *codec,
2965 hda_nid_t pin, hda_nid_t dac)
2966{
2967 hda_nid_t srcs[5];
2968 int i, num;
2969
2970 pin = alc_go_down_to_selector(codec, pin);
2971 num = snd_hda_get_connections(codec, pin, srcs, ARRAY_SIZE(srcs));
2972 for (i = 0; i < num; i++) {
2973 hda_nid_t nid = alc_auto_mix_to_dac(codec, srcs[i]);
2974 if (nid == dac)
2975 return true;
2976 }
2977 return false;
2978}
2979
Takashi Iwai3af9ee62011-06-27 12:34:01 +02002980static hda_nid_t get_dac_if_single(struct hda_codec *codec, hda_nid_t pin)
2981{
2982 hda_nid_t sel = alc_go_down_to_selector(codec, pin);
2983 if (snd_hda_get_conn_list(codec, sel, NULL) == 1)
2984 return alc_auto_look_for_dac(codec, pin);
2985 return 0;
2986}
2987
Takashi Iwai0a34b422011-12-07 17:20:30 +01002988/* return 0 if no possible DAC is found, 1 if one or more found */
Takashi Iwaic2674682011-08-24 17:57:44 +02002989static int alc_auto_fill_extra_dacs(struct hda_codec *codec, int num_outs,
2990 const hda_nid_t *pins, hda_nid_t *dacs)
2991{
2992 int i;
2993
2994 if (num_outs && !dacs[0]) {
2995 dacs[0] = alc_auto_look_for_dac(codec, pins[0]);
2996 if (!dacs[0])
2997 return 0;
2998 }
2999
3000 for (i = 1; i < num_outs; i++)
3001 dacs[i] = get_dac_if_single(codec, pins[i]);
3002 for (i = 1; i < num_outs; i++) {
3003 if (!dacs[i])
3004 dacs[i] = alc_auto_look_for_dac(codec, pins[i]);
3005 }
Takashi Iwai0a34b422011-12-07 17:20:30 +01003006 return 1;
Takashi Iwaic2674682011-08-24 17:57:44 +02003007}
3008
3009static int alc_auto_fill_multi_ios(struct hda_codec *codec,
Takashi Iwai07b18f62011-11-10 15:42:54 +01003010 unsigned int location, int offset);
David Henningssonfde48a12011-12-09 18:27:42 +08003011static hda_nid_t alc_look_for_out_vol_nid(struct hda_codec *codec,
3012 hda_nid_t pin, hda_nid_t dac);
Takashi Iwaic2674682011-08-24 17:57:44 +02003013
Takashi Iwai7085ec12009-10-02 09:03:58 +02003014/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwai343a04b2011-07-06 14:28:39 +02003015static int alc_auto_fill_dac_nids(struct hda_codec *codec)
Takashi Iwai7085ec12009-10-02 09:03:58 +02003016{
3017 struct alc_spec *spec = codec->spec;
Takashi Iwai0a34b422011-12-07 17:20:30 +01003018 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwai07b18f62011-11-10 15:42:54 +01003019 unsigned int location, defcfg;
3020 int num_pins;
Takashi Iwai350434e2011-06-30 21:29:12 +02003021 bool redone = false;
Takashi Iwai7085ec12009-10-02 09:03:58 +02003022 int i;
Takashi Iwai7085ec12009-10-02 09:03:58 +02003023
Takashi Iwai3af9ee62011-06-27 12:34:01 +02003024 again:
Takashi Iwai8f398ae2011-07-23 18:57:11 +02003025 /* set num_dacs once to full for alc_auto_look_for_dac() */
3026 spec->multiout.num_dacs = cfg->line_outs;
Takashi Iwaie23832a2011-08-23 18:16:56 +02003027 spec->multiout.hp_out_nid[0] = 0;
Takashi Iwai3af9ee62011-06-27 12:34:01 +02003028 spec->multiout.extra_out_nid[0] = 0;
3029 memset(spec->private_dac_nids, 0, sizeof(spec->private_dac_nids));
3030 spec->multiout.dac_nids = spec->private_dac_nids;
Takashi Iwai0a34b422011-12-07 17:20:30 +01003031 spec->multi_ios = 0;
Takashi Iwai3af9ee62011-06-27 12:34:01 +02003032
3033 /* fill hard-wired DACs first */
3034 if (!redone) {
3035 for (i = 0; i < cfg->line_outs; i++)
3036 spec->private_dac_nids[i] =
3037 get_dac_if_single(codec, cfg->line_out_pins[i]);
3038 if (cfg->hp_outs)
Takashi Iwaie23832a2011-08-23 18:16:56 +02003039 spec->multiout.hp_out_nid[0] =
Takashi Iwai3af9ee62011-06-27 12:34:01 +02003040 get_dac_if_single(codec, cfg->hp_pins[0]);
3041 if (cfg->speaker_outs)
3042 spec->multiout.extra_out_nid[0] =
3043 get_dac_if_single(codec, cfg->speaker_pins[0]);
Takashi Iwai7085ec12009-10-02 09:03:58 +02003044 }
Takashi Iwai3af9ee62011-06-27 12:34:01 +02003045
3046 for (i = 0; i < cfg->line_outs; i++) {
3047 hda_nid_t pin = cfg->line_out_pins[i];
3048 if (spec->private_dac_nids[i])
3049 continue;
3050 spec->private_dac_nids[i] = alc_auto_look_for_dac(codec, pin);
3051 if (!spec->private_dac_nids[i] && !redone) {
3052 /* if we can't find primary DACs, re-probe without
3053 * checking the hard-wired DACs
3054 */
3055 redone = true;
3056 goto again;
3057 }
3058 }
3059
Takashi Iwai8f398ae2011-07-23 18:57:11 +02003060 /* re-count num_dacs and squash invalid entries */
3061 spec->multiout.num_dacs = 0;
Takashi Iwai3af9ee62011-06-27 12:34:01 +02003062 for (i = 0; i < cfg->line_outs; i++) {
3063 if (spec->private_dac_nids[i])
3064 spec->multiout.num_dacs++;
Takashi Iwai0a34b422011-12-07 17:20:30 +01003065 else {
Takashi Iwai3af9ee62011-06-27 12:34:01 +02003066 memmove(spec->private_dac_nids + i,
3067 spec->private_dac_nids + i + 1,
3068 sizeof(hda_nid_t) * (cfg->line_outs - i - 1));
Takashi Iwai0a34b422011-12-07 17:20:30 +01003069 spec->private_dac_nids[cfg->line_outs - 1] = 0;
3070 }
Takashi Iwai3af9ee62011-06-27 12:34:01 +02003071 }
3072
Takashi Iwaic2674682011-08-24 17:57:44 +02003073 if (cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
3074 /* try to fill multi-io first */
Takashi Iwaic2674682011-08-24 17:57:44 +02003075 defcfg = snd_hda_codec_get_pincfg(codec, cfg->line_out_pins[0]);
3076 location = get_defcfg_location(defcfg);
Takashi Iwai7085ec12009-10-02 09:03:58 +02003077
Takashi Iwai07b18f62011-11-10 15:42:54 +01003078 num_pins = alc_auto_fill_multi_ios(codec, location, 0);
Takashi Iwaic2674682011-08-24 17:57:44 +02003079 if (num_pins > 0) {
3080 spec->multi_ios = num_pins;
3081 spec->ext_channel_count = 2;
3082 spec->multiout.num_dacs = num_pins + 1;
3083 }
Takashi Iwai23c09b02011-08-19 09:05:35 +02003084 }
Takashi Iwaic2674682011-08-24 17:57:44 +02003085
Takashi Iwai716eef02011-10-21 15:07:42 +02003086 if (cfg->line_out_type != AUTO_PIN_HP_OUT)
3087 alc_auto_fill_extra_dacs(codec, cfg->hp_outs, cfg->hp_pins,
Takashi Iwaic2674682011-08-24 17:57:44 +02003088 spec->multiout.hp_out_nid);
Takashi Iwai0a34b422011-12-07 17:20:30 +01003089 if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
3090 int err = alc_auto_fill_extra_dacs(codec, cfg->speaker_outs,
3091 cfg->speaker_pins,
3092 spec->multiout.extra_out_nid);
3093 /* if no speaker volume is assigned, try again as the primary
3094 * output
3095 */
3096 if (!err && cfg->speaker_outs > 0 &&
3097 cfg->line_out_type == AUTO_PIN_HP_OUT) {
3098 cfg->hp_outs = cfg->line_outs;
3099 memcpy(cfg->hp_pins, cfg->line_out_pins,
3100 sizeof(cfg->hp_pins));
3101 cfg->line_outs = cfg->speaker_outs;
3102 memcpy(cfg->line_out_pins, cfg->speaker_pins,
3103 sizeof(cfg->speaker_pins));
3104 cfg->speaker_outs = 0;
3105 memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins));
3106 cfg->line_out_type = AUTO_PIN_SPEAKER_OUT;
3107 redone = false;
3108 goto again;
3109 }
3110 }
Takashi Iwaic2674682011-08-24 17:57:44 +02003111
Takashi Iwai07b18f62011-11-10 15:42:54 +01003112 if (!spec->multi_ios &&
3113 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT &&
3114 cfg->hp_outs) {
3115 /* try multi-ios with HP + inputs */
3116 defcfg = snd_hda_codec_get_pincfg(codec, cfg->hp_pins[0]);
3117 location = get_defcfg_location(defcfg);
3118
3119 num_pins = alc_auto_fill_multi_ios(codec, location, 1);
3120 if (num_pins > 0) {
3121 spec->multi_ios = num_pins;
3122 spec->ext_channel_count = 2;
3123 spec->multiout.num_dacs = num_pins + 1;
3124 }
3125 }
3126
David Henningssonfde48a12011-12-09 18:27:42 +08003127 if (cfg->line_out_pins[0])
3128 spec->vmaster_nid =
3129 alc_look_for_out_vol_nid(codec, cfg->line_out_pins[0],
3130 spec->multiout.dac_nids[0]);
Takashi Iwai23c09b02011-08-19 09:05:35 +02003131 return 0;
3132}
3133
Takashi Iwai527e4d72011-10-27 16:33:27 +02003134static inline unsigned int get_ctl_pos(unsigned int data)
3135{
3136 hda_nid_t nid = get_amp_nid_(data);
3137 unsigned int dir = get_amp_direction_(data);
3138 return (nid << 1) | dir;
3139}
3140
3141#define is_ctl_used(bits, data) \
3142 test_bit(get_ctl_pos(data), bits)
3143#define mark_ctl_usage(bits, data) \
3144 set_bit(get_ctl_pos(data), bits)
3145
Takashi Iwai343a04b2011-07-06 14:28:39 +02003146static int alc_auto_add_vol_ctl(struct hda_codec *codec,
Takashi Iwai97aaab72011-07-06 14:02:55 +02003147 const char *pfx, int cidx,
3148 hda_nid_t nid, unsigned int chs)
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003149{
Takashi Iwai527e4d72011-10-27 16:33:27 +02003150 struct alc_spec *spec = codec->spec;
3151 unsigned int val;
Takashi Iwaiafcd5512011-07-08 11:07:59 +02003152 if (!nid)
3153 return 0;
Takashi Iwai527e4d72011-10-27 16:33:27 +02003154 val = HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT);
3155 if (is_ctl_used(spec->vol_ctls, val) && chs != 2) /* exclude LFE */
3156 return 0;
3157 mark_ctl_usage(spec->vol_ctls, val);
Takashi Iwai97aaab72011-07-06 14:02:55 +02003158 return __add_pb_vol_ctrl(codec->spec, ALC_CTL_WIDGET_VOL, pfx, cidx,
Takashi Iwai527e4d72011-10-27 16:33:27 +02003159 val);
Takashi Iwai7085ec12009-10-02 09:03:58 +02003160}
3161
Takashi Iwaie29d3772011-11-14 17:13:23 +01003162static int alc_auto_add_stereo_vol(struct hda_codec *codec,
3163 const char *pfx, int cidx,
3164 hda_nid_t nid)
3165{
3166 int chs = 1;
3167 if (get_wcaps(codec, nid) & AC_WCAP_STEREO)
3168 chs = 3;
3169 return alc_auto_add_vol_ctl(codec, pfx, cidx, nid, chs);
3170}
Takashi Iwai97aaab72011-07-06 14:02:55 +02003171
3172/* create a mute-switch for the given mixer widget;
3173 * if it has multiple sources (e.g. DAC and loopback), create a bind-mute
3174 */
Takashi Iwai343a04b2011-07-06 14:28:39 +02003175static int alc_auto_add_sw_ctl(struct hda_codec *codec,
Takashi Iwai97aaab72011-07-06 14:02:55 +02003176 const char *pfx, int cidx,
3177 hda_nid_t nid, unsigned int chs)
Takashi Iwai7085ec12009-10-02 09:03:58 +02003178{
Takashi Iwai527e4d72011-10-27 16:33:27 +02003179 struct alc_spec *spec = codec->spec;
Takashi Iwaiafcd5512011-07-08 11:07:59 +02003180 int wid_type;
Takashi Iwai97aaab72011-07-06 14:02:55 +02003181 int type;
3182 unsigned long val;
Takashi Iwaiafcd5512011-07-08 11:07:59 +02003183 if (!nid)
3184 return 0;
3185 wid_type = get_wcaps_type(get_wcaps(codec, nid));
3186 if (wid_type == AC_WID_PIN || wid_type == AC_WID_AUD_OUT) {
3187 type = ALC_CTL_WIDGET_MUTE;
3188 val = HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT);
3189 } else if (snd_hda_get_conn_list(codec, nid, NULL) == 1) {
Takashi Iwai97aaab72011-07-06 14:02:55 +02003190 type = ALC_CTL_WIDGET_MUTE;
3191 val = HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_INPUT);
3192 } else {
3193 type = ALC_CTL_BIND_MUTE;
3194 val = HDA_COMPOSE_AMP_VAL(nid, chs, 2, HDA_INPUT);
3195 }
Takashi Iwai527e4d72011-10-27 16:33:27 +02003196 if (is_ctl_used(spec->sw_ctls, val) && chs != 2) /* exclude LFE */
3197 return 0;
3198 mark_ctl_usage(spec->sw_ctls, val);
Takashi Iwai97aaab72011-07-06 14:02:55 +02003199 return __add_pb_sw_ctrl(codec->spec, type, pfx, cidx, val);
Takashi Iwai7085ec12009-10-02 09:03:58 +02003200}
3201
Takashi Iwaie29d3772011-11-14 17:13:23 +01003202static int alc_auto_add_stereo_sw(struct hda_codec *codec, const char *pfx,
3203 int cidx, hda_nid_t nid)
3204{
3205 int chs = 1;
3206 if (get_wcaps(codec, nid) & AC_WCAP_STEREO)
3207 chs = 3;
3208 return alc_auto_add_sw_ctl(codec, pfx, cidx, nid, chs);
3209}
Takashi Iwai7085ec12009-10-02 09:03:58 +02003210
Takashi Iwaiafcd5512011-07-08 11:07:59 +02003211static hda_nid_t alc_look_for_out_mute_nid(struct hda_codec *codec,
3212 hda_nid_t pin, hda_nid_t dac)
3213{
3214 hda_nid_t mix = alc_auto_dac_to_mix(codec, pin, dac);
3215 if (nid_has_mute(codec, pin, HDA_OUTPUT))
3216 return pin;
3217 else if (mix && nid_has_mute(codec, mix, HDA_INPUT))
3218 return mix;
3219 else if (nid_has_mute(codec, dac, HDA_OUTPUT))
3220 return dac;
3221 return 0;
3222}
3223
3224static hda_nid_t alc_look_for_out_vol_nid(struct hda_codec *codec,
3225 hda_nid_t pin, hda_nid_t dac)
3226{
3227 hda_nid_t mix = alc_auto_dac_to_mix(codec, pin, dac);
3228 if (nid_has_volume(codec, dac, HDA_OUTPUT))
3229 return dac;
3230 else if (nid_has_volume(codec, mix, HDA_OUTPUT))
3231 return mix;
3232 else if (nid_has_volume(codec, pin, HDA_OUTPUT))
3233 return pin;
3234 return 0;
3235}
3236
Takashi Iwai7085ec12009-10-02 09:03:58 +02003237/* add playback controls from the parsed DAC table */
Takashi Iwai343a04b2011-07-06 14:28:39 +02003238static int alc_auto_create_multi_out_ctls(struct hda_codec *codec,
Takashi Iwai7085ec12009-10-02 09:03:58 +02003239 const struct auto_pin_cfg *cfg)
3240{
3241 struct alc_spec *spec = codec->spec;
Takashi Iwaice764ab2011-04-27 16:35:23 +02003242 int i, err, noutputs;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003243
Takashi Iwaice764ab2011-04-27 16:35:23 +02003244 noutputs = cfg->line_outs;
Takashi Iwaib90bf1d2012-01-19 11:42:55 +01003245 if (spec->multi_ios > 0 && cfg->line_outs < 3)
Takashi Iwaice764ab2011-04-27 16:35:23 +02003246 noutputs += spec->multi_ios;
3247
3248 for (i = 0; i < noutputs; i++) {
Takashi Iwai6843ca12011-06-24 11:03:58 +02003249 const char *name;
3250 int index;
Takashi Iwaiafcd5512011-07-08 11:07:59 +02003251 hda_nid_t dac, pin;
3252 hda_nid_t sw, vol;
3253
3254 dac = spec->multiout.dac_nids[i];
3255 if (!dac)
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003256 continue;
Takashi Iwaice764ab2011-04-27 16:35:23 +02003257 if (i >= cfg->line_outs)
3258 pin = spec->multi_io[i - 1].pin;
3259 else
3260 pin = cfg->line_out_pins[i];
Takashi Iwaiafcd5512011-07-08 11:07:59 +02003261
3262 sw = alc_look_for_out_mute_nid(codec, pin, dac);
3263 vol = alc_look_for_out_vol_nid(codec, pin, dac);
Takashi Iwai6843ca12011-06-24 11:03:58 +02003264 name = alc_get_line_out_pfx(spec, i, true, &index);
Takashi Iwai9c4e84d2011-08-24 17:27:52 +02003265 if (!name || !strcmp(name, "CLFE")) {
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003266 /* Center/LFE */
Takashi Iwaiafcd5512011-07-08 11:07:59 +02003267 err = alc_auto_add_vol_ctl(codec, "Center", 0, vol, 1);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003268 if (err < 0)
3269 return err;
Takashi Iwaiafcd5512011-07-08 11:07:59 +02003270 err = alc_auto_add_vol_ctl(codec, "LFE", 0, vol, 2);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003271 if (err < 0)
3272 return err;
Takashi Iwaiafcd5512011-07-08 11:07:59 +02003273 err = alc_auto_add_sw_ctl(codec, "Center", 0, sw, 1);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003274 if (err < 0)
3275 return err;
Takashi Iwaiafcd5512011-07-08 11:07:59 +02003276 err = alc_auto_add_sw_ctl(codec, "LFE", 0, sw, 2);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003277 if (err < 0)
3278 return err;
3279 } else {
Takashi Iwaiafcd5512011-07-08 11:07:59 +02003280 err = alc_auto_add_stereo_vol(codec, name, index, vol);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003281 if (err < 0)
3282 return err;
Takashi Iwaiafcd5512011-07-08 11:07:59 +02003283 err = alc_auto_add_stereo_sw(codec, name, index, sw);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003284 if (err < 0)
3285 return err;
3286 }
3287 }
3288 return 0;
3289}
3290
Takashi Iwai343a04b2011-07-06 14:28:39 +02003291static int alc_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
Takashi Iwai766ddee2011-12-07 16:55:19 +01003292 hda_nid_t dac, const char *pfx,
3293 int cidx)
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003294{
Takashi Iwai7085ec12009-10-02 09:03:58 +02003295 struct alc_spec *spec = codec->spec;
Takashi Iwaiafcd5512011-07-08 11:07:59 +02003296 hda_nid_t sw, vol;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003297 int err;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003298
Takashi Iwai3af9ee62011-06-27 12:34:01 +02003299 if (!dac) {
Takashi Iwai527e4d72011-10-27 16:33:27 +02003300 unsigned int val;
Takashi Iwai7085ec12009-10-02 09:03:58 +02003301 /* the corresponding DAC is already occupied */
3302 if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP))
3303 return 0; /* no way */
3304 /* create a switch only */
Takashi Iwai527e4d72011-10-27 16:33:27 +02003305 val = HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT);
3306 if (is_ctl_used(spec->sw_ctls, val))
3307 return 0; /* already created */
3308 mark_ctl_usage(spec->sw_ctls, val);
Takashi Iwai766ddee2011-12-07 16:55:19 +01003309 return __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, cidx, val);
Takashi Iwai7085ec12009-10-02 09:03:58 +02003310 }
3311
Takashi Iwaiafcd5512011-07-08 11:07:59 +02003312 sw = alc_look_for_out_mute_nid(codec, pin, dac);
3313 vol = alc_look_for_out_vol_nid(codec, pin, dac);
Takashi Iwai766ddee2011-12-07 16:55:19 +01003314 err = alc_auto_add_stereo_vol(codec, pfx, cidx, vol);
Takashi Iwai7085ec12009-10-02 09:03:58 +02003315 if (err < 0)
Takashi Iwai24fb9172008-09-02 14:48:20 +02003316 return err;
Takashi Iwai766ddee2011-12-07 16:55:19 +01003317 err = alc_auto_add_stereo_sw(codec, pfx, cidx, sw);
Takashi Iwai7085ec12009-10-02 09:03:58 +02003318 if (err < 0)
3319 return err;
Takashi Iwai3af9ee62011-06-27 12:34:01 +02003320 return 0;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003321}
3322
Takashi Iwai23c09b02011-08-19 09:05:35 +02003323static struct hda_bind_ctls *new_bind_ctl(struct hda_codec *codec,
3324 unsigned int nums,
3325 struct hda_ctl_ops *ops)
3326{
3327 struct alc_spec *spec = codec->spec;
3328 struct hda_bind_ctls **ctlp, *ctl;
3329 snd_array_init(&spec->bind_ctls, sizeof(ctl), 8);
3330 ctlp = snd_array_new(&spec->bind_ctls);
3331 if (!ctlp)
3332 return NULL;
3333 ctl = kzalloc(sizeof(*ctl) + sizeof(long) * (nums + 1), GFP_KERNEL);
3334 *ctlp = ctl;
3335 if (ctl)
3336 ctl->ops = ops;
3337 return ctl;
3338}
3339
3340/* add playback controls for speaker and HP outputs */
3341static int alc_auto_create_extra_outs(struct hda_codec *codec, int num_pins,
3342 const hda_nid_t *pins,
3343 const hda_nid_t *dacs,
3344 const char *pfx)
3345{
3346 struct alc_spec *spec = codec->spec;
3347 struct hda_bind_ctls *ctl;
3348 char name[32];
3349 int i, n, err;
3350
3351 if (!num_pins || !pins[0])
3352 return 0;
3353
Takashi Iwai527e4d72011-10-27 16:33:27 +02003354 if (num_pins == 1) {
3355 hda_nid_t dac = *dacs;
3356 if (!dac)
3357 dac = spec->multiout.dac_nids[0];
Takashi Iwai766ddee2011-12-07 16:55:19 +01003358 return alc_auto_create_extra_out(codec, *pins, dac, pfx, 0);
Takashi Iwai527e4d72011-10-27 16:33:27 +02003359 }
Takashi Iwai23c09b02011-08-19 09:05:35 +02003360
3361 if (dacs[num_pins - 1]) {
3362 /* OK, we have a multi-output system with individual volumes */
3363 for (i = 0; i < num_pins; i++) {
Takashi Iwai766ddee2011-12-07 16:55:19 +01003364 if (num_pins >= 3) {
3365 snprintf(name, sizeof(name), "%s %s",
3366 pfx, channel_name[i]);
3367 err = alc_auto_create_extra_out(codec, pins[i], dacs[i],
3368 name, 0);
3369 } else {
3370 err = alc_auto_create_extra_out(codec, pins[i], dacs[i],
3371 pfx, i);
3372 }
Takashi Iwai23c09b02011-08-19 09:05:35 +02003373 if (err < 0)
3374 return err;
3375 }
3376 return 0;
3377 }
3378
3379 /* Let's create a bind-controls */
3380 ctl = new_bind_ctl(codec, num_pins, &snd_hda_bind_sw);
3381 if (!ctl)
3382 return -ENOMEM;
3383 n = 0;
3384 for (i = 0; i < num_pins; i++) {
3385 if (get_wcaps(codec, pins[i]) & AC_WCAP_OUT_AMP)
3386 ctl->values[n++] =
3387 HDA_COMPOSE_AMP_VAL(pins[i], 3, 0, HDA_OUTPUT);
3388 }
3389 if (n) {
3390 snprintf(name, sizeof(name), "%s Playback Switch", pfx);
3391 err = add_control(spec, ALC_CTL_BIND_SW, name, 0, (long)ctl);
3392 if (err < 0)
3393 return err;
3394 }
3395
3396 ctl = new_bind_ctl(codec, num_pins, &snd_hda_bind_vol);
3397 if (!ctl)
3398 return -ENOMEM;
3399 n = 0;
3400 for (i = 0; i < num_pins; i++) {
3401 hda_nid_t vol;
3402 if (!pins[i] || !dacs[i])
3403 continue;
3404 vol = alc_look_for_out_vol_nid(codec, pins[i], dacs[i]);
3405 if (vol)
3406 ctl->values[n++] =
3407 HDA_COMPOSE_AMP_VAL(vol, 3, 0, HDA_OUTPUT);
3408 }
3409 if (n) {
3410 snprintf(name, sizeof(name), "%s Playback Volume", pfx);
3411 err = add_control(spec, ALC_CTL_BIND_VOL, name, 0, (long)ctl);
3412 if (err < 0)
3413 return err;
3414 }
3415 return 0;
3416}
3417
Takashi Iwai343a04b2011-07-06 14:28:39 +02003418static int alc_auto_create_hp_out(struct hda_codec *codec)
3419{
3420 struct alc_spec *spec = codec->spec;
Takashi Iwaie23832a2011-08-23 18:16:56 +02003421 return alc_auto_create_extra_outs(codec, spec->autocfg.hp_outs,
3422 spec->autocfg.hp_pins,
3423 spec->multiout.hp_out_nid,
3424 "Headphone");
Takashi Iwai343a04b2011-07-06 14:28:39 +02003425}
3426
3427static int alc_auto_create_speaker_out(struct hda_codec *codec)
3428{
3429 struct alc_spec *spec = codec->spec;
Takashi Iwai23c09b02011-08-19 09:05:35 +02003430 return alc_auto_create_extra_outs(codec, spec->autocfg.speaker_outs,
3431 spec->autocfg.speaker_pins,
3432 spec->multiout.extra_out_nid,
3433 "Speaker");
Takashi Iwai343a04b2011-07-06 14:28:39 +02003434}
3435
Takashi Iwai343a04b2011-07-06 14:28:39 +02003436static void alc_auto_set_output_and_unmute(struct hda_codec *codec,
Takashi Iwaiafcd5512011-07-08 11:07:59 +02003437 hda_nid_t pin, int pin_type,
Takashi Iwai7085ec12009-10-02 09:03:58 +02003438 hda_nid_t dac)
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003439{
Takashi Iwai7085ec12009-10-02 09:03:58 +02003440 int i, num;
Takashi Iwaiafcd5512011-07-08 11:07:59 +02003441 hda_nid_t nid, mix = 0;
Takashi Iwaice503f32010-07-30 10:37:29 +02003442 hda_nid_t srcs[HDA_MAX_CONNECTIONS];
Takashi Iwai7085ec12009-10-02 09:03:58 +02003443
Takashi Iwaiafcd5512011-07-08 11:07:59 +02003444 alc_set_pin_output(codec, pin, pin_type);
3445 nid = alc_go_down_to_selector(codec, pin);
Takashi Iwai7085ec12009-10-02 09:03:58 +02003446 num = snd_hda_get_connections(codec, nid, srcs, ARRAY_SIZE(srcs));
Takashi Iwai7085ec12009-10-02 09:03:58 +02003447 for (i = 0; i < num; i++) {
Takashi Iwai604401a2011-04-27 15:14:23 +02003448 if (alc_auto_mix_to_dac(codec, srcs[i]) != dac)
Takashi Iwai7085ec12009-10-02 09:03:58 +02003449 continue;
Takashi Iwaicd511552011-07-06 13:10:42 +02003450 mix = srcs[i];
3451 break;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003452 }
Takashi Iwaicd511552011-07-06 13:10:42 +02003453 if (!mix)
3454 return;
3455
3456 /* need the manual connection? */
3457 if (num > 1)
3458 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, i);
3459 /* unmute mixer widget inputs */
Takashi Iwaiafcd5512011-07-08 11:07:59 +02003460 if (nid_has_mute(codec, mix, HDA_INPUT)) {
3461 snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwaicd511552011-07-06 13:10:42 +02003462 AMP_IN_UNMUTE(0));
Takashi Iwaiafcd5512011-07-08 11:07:59 +02003463 snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwaicd511552011-07-06 13:10:42 +02003464 AMP_IN_UNMUTE(1));
Takashi Iwaiafcd5512011-07-08 11:07:59 +02003465 }
Takashi Iwaicd511552011-07-06 13:10:42 +02003466 /* initialize volume */
Takashi Iwaiafcd5512011-07-08 11:07:59 +02003467 nid = alc_look_for_out_vol_nid(codec, pin, dac);
3468 if (nid)
3469 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
3470 AMP_OUT_ZERO);
Takashi Iwai43dea222011-11-06 11:25:34 +01003471
3472 /* unmute DAC if it's not assigned to a mixer */
3473 nid = alc_look_for_out_mute_nid(codec, pin, dac);
3474 if (nid == mix && nid_has_mute(codec, dac, HDA_OUTPUT))
3475 snd_hda_codec_write(codec, dac, 0, AC_VERB_SET_AMP_GAIN_MUTE,
3476 AMP_OUT_ZERO);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003477}
3478
Takashi Iwai343a04b2011-07-06 14:28:39 +02003479static void alc_auto_init_multi_out(struct hda_codec *codec)
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003480{
3481 struct alc_spec *spec = codec->spec;
Takashi Iwai7085ec12009-10-02 09:03:58 +02003482 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003483 int i;
3484
3485 for (i = 0; i <= HDA_SIDE; i++) {
3486 hda_nid_t nid = spec->autocfg.line_out_pins[i];
3487 if (nid)
Takashi Iwai343a04b2011-07-06 14:28:39 +02003488 alc_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwai7085ec12009-10-02 09:03:58 +02003489 spec->multiout.dac_nids[i]);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003490 }
3491}
3492
Takashi Iwai343a04b2011-07-06 14:28:39 +02003493static void alc_auto_init_extra_out(struct hda_codec *codec)
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003494{
3495 struct alc_spec *spec = codec->spec;
Takashi Iwai8cd07752011-08-23 15:16:22 +02003496 int i;
Takashi Iwai675c1aa2011-08-23 12:36:28 +02003497 hda_nid_t pin, dac;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003498
David Henningsson636030e2011-10-12 19:26:03 +02003499 for (i = 0; i < spec->autocfg.hp_outs; i++) {
Takashi Iwai716eef02011-10-21 15:07:42 +02003500 if (spec->autocfg.line_out_type == AUTO_PIN_HP_OUT)
3501 break;
Takashi Iwaie23832a2011-08-23 18:16:56 +02003502 pin = spec->autocfg.hp_pins[i];
3503 if (!pin)
3504 break;
3505 dac = spec->multiout.hp_out_nid[i];
3506 if (!dac) {
3507 if (i > 0 && spec->multiout.hp_out_nid[0])
3508 dac = spec->multiout.hp_out_nid[0];
3509 else
3510 dac = spec->multiout.dac_nids[0];
3511 }
Takashi Iwai675c1aa2011-08-23 12:36:28 +02003512 alc_auto_set_output_and_unmute(codec, pin, PIN_HP, dac);
3513 }
Takashi Iwai8cd07752011-08-23 15:16:22 +02003514 for (i = 0; i < spec->autocfg.speaker_outs; i++) {
Takashi Iwai716eef02011-10-21 15:07:42 +02003515 if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT)
3516 break;
Takashi Iwai8cd07752011-08-23 15:16:22 +02003517 pin = spec->autocfg.speaker_pins[i];
3518 if (!pin)
3519 break;
3520 dac = spec->multiout.extra_out_nid[i];
3521 if (!dac) {
3522 if (i > 0 && spec->multiout.extra_out_nid[0])
3523 dac = spec->multiout.extra_out_nid[0];
3524 else
3525 dac = spec->multiout.dac_nids[0];
3526 }
Takashi Iwai675c1aa2011-08-23 12:36:28 +02003527 alc_auto_set_output_and_unmute(codec, pin, PIN_OUT, dac);
3528 }
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003529}
3530
Takashi Iwaice764ab2011-04-27 16:35:23 +02003531/*
3532 * multi-io helper
3533 */
3534static int alc_auto_fill_multi_ios(struct hda_codec *codec,
Takashi Iwai07b18f62011-11-10 15:42:54 +01003535 unsigned int location,
3536 int offset)
Takashi Iwaice764ab2011-04-27 16:35:23 +02003537{
3538 struct alc_spec *spec = codec->spec;
3539 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwaic2674682011-08-24 17:57:44 +02003540 hda_nid_t prime_dac = spec->private_dac_nids[0];
Takashi Iwai07b18f62011-11-10 15:42:54 +01003541 int type, i, dacs, num_pins = 0;
Takashi Iwaice764ab2011-04-27 16:35:23 +02003542
Takashi Iwai07b18f62011-11-10 15:42:54 +01003543 dacs = spec->multiout.num_dacs;
Takashi Iwaice764ab2011-04-27 16:35:23 +02003544 for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) {
3545 for (i = 0; i < cfg->num_inputs; i++) {
3546 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai07b18f62011-11-10 15:42:54 +01003547 hda_nid_t dac = 0;
Takashi Iwaice764ab2011-04-27 16:35:23 +02003548 unsigned int defcfg, caps;
3549 if (cfg->inputs[i].type != type)
3550 continue;
3551 defcfg = snd_hda_codec_get_pincfg(codec, nid);
3552 if (get_defcfg_connect(defcfg) != AC_JACK_PORT_COMPLEX)
3553 continue;
3554 if (location && get_defcfg_location(defcfg) != location)
3555 continue;
3556 caps = snd_hda_query_pin_caps(codec, nid);
3557 if (!(caps & AC_PINCAP_OUT))
3558 continue;
Takashi Iwai07b18f62011-11-10 15:42:54 +01003559 if (offset && offset + num_pins < dacs) {
3560 dac = spec->private_dac_nids[offset + num_pins];
3561 if (!alc_auto_is_dac_reachable(codec, nid, dac))
3562 dac = 0;
3563 }
3564 if (!dac)
3565 dac = alc_auto_look_for_dac(codec, nid);
Takashi Iwaice764ab2011-04-27 16:35:23 +02003566 if (!dac)
3567 continue;
3568 spec->multi_io[num_pins].pin = nid;
3569 spec->multi_io[num_pins].dac = dac;
3570 num_pins++;
Takashi Iwaidda14412011-05-02 11:29:30 +02003571 spec->private_dac_nids[spec->multiout.num_dacs++] = dac;
Takashi Iwaice764ab2011-04-27 16:35:23 +02003572 }
3573 }
Takashi Iwai07b18f62011-11-10 15:42:54 +01003574 spec->multiout.num_dacs = dacs;
Takashi Iwaic2674682011-08-24 17:57:44 +02003575 if (num_pins < 2) {
3576 /* clear up again */
Takashi Iwai07b18f62011-11-10 15:42:54 +01003577 memset(spec->private_dac_nids + dacs, 0,
3578 sizeof(hda_nid_t) * (AUTO_CFG_MAX_OUTS - dacs));
Takashi Iwaic2674682011-08-24 17:57:44 +02003579 spec->private_dac_nids[0] = prime_dac;
Takashi Iwaice764ab2011-04-27 16:35:23 +02003580 return 0;
Takashi Iwaic2674682011-08-24 17:57:44 +02003581 }
Takashi Iwaice764ab2011-04-27 16:35:23 +02003582 return num_pins;
3583}
3584
3585static int alc_auto_ch_mode_info(struct snd_kcontrol *kcontrol,
3586 struct snd_ctl_elem_info *uinfo)
3587{
3588 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3589 struct alc_spec *spec = codec->spec;
3590
3591 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
3592 uinfo->count = 1;
3593 uinfo->value.enumerated.items = spec->multi_ios + 1;
3594 if (uinfo->value.enumerated.item > spec->multi_ios)
3595 uinfo->value.enumerated.item = spec->multi_ios;
3596 sprintf(uinfo->value.enumerated.name, "%dch",
3597 (uinfo->value.enumerated.item + 1) * 2);
3598 return 0;
3599}
3600
3601static int alc_auto_ch_mode_get(struct snd_kcontrol *kcontrol,
3602 struct snd_ctl_elem_value *ucontrol)
3603{
3604 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3605 struct alc_spec *spec = codec->spec;
3606 ucontrol->value.enumerated.item[0] = (spec->ext_channel_count - 1) / 2;
3607 return 0;
3608}
3609
3610static int alc_set_multi_io(struct hda_codec *codec, int idx, bool output)
3611{
3612 struct alc_spec *spec = codec->spec;
3613 hda_nid_t nid = spec->multi_io[idx].pin;
3614
3615 if (!spec->multi_io[idx].ctl_in)
3616 spec->multi_io[idx].ctl_in =
3617 snd_hda_codec_read(codec, nid, 0,
3618 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
3619 if (output) {
3620 snd_hda_codec_update_cache(codec, nid, 0,
3621 AC_VERB_SET_PIN_WIDGET_CONTROL,
3622 PIN_OUT);
3623 if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
3624 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
3625 HDA_AMP_MUTE, 0);
3626 alc_auto_select_dac(codec, nid, spec->multi_io[idx].dac);
3627 } else {
3628 if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
3629 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
3630 HDA_AMP_MUTE, HDA_AMP_MUTE);
3631 snd_hda_codec_update_cache(codec, nid, 0,
3632 AC_VERB_SET_PIN_WIDGET_CONTROL,
3633 spec->multi_io[idx].ctl_in);
3634 }
3635 return 0;
3636}
3637
3638static int alc_auto_ch_mode_put(struct snd_kcontrol *kcontrol,
3639 struct snd_ctl_elem_value *ucontrol)
3640{
3641 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3642 struct alc_spec *spec = codec->spec;
3643 int i, ch;
3644
3645 ch = ucontrol->value.enumerated.item[0];
3646 if (ch < 0 || ch > spec->multi_ios)
3647 return -EINVAL;
3648 if (ch == (spec->ext_channel_count - 1) / 2)
3649 return 0;
3650 spec->ext_channel_count = (ch + 1) * 2;
3651 for (i = 0; i < spec->multi_ios; i++)
3652 alc_set_multi_io(codec, i, i < ch);
3653 spec->multiout.max_channels = spec->ext_channel_count;
Takashi Iwai7b1655f2011-07-14 15:31:21 +02003654 if (spec->need_dac_fix && !spec->const_channel_count)
3655 spec->multiout.num_dacs = spec->multiout.max_channels / 2;
Takashi Iwaice764ab2011-04-27 16:35:23 +02003656 return 1;
3657}
3658
Takashi Iwaia9111322011-05-02 11:30:18 +02003659static const struct snd_kcontrol_new alc_auto_channel_mode_enum = {
Takashi Iwaice764ab2011-04-27 16:35:23 +02003660 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3661 .name = "Channel Mode",
3662 .info = alc_auto_ch_mode_info,
3663 .get = alc_auto_ch_mode_get,
3664 .put = alc_auto_ch_mode_put,
3665};
3666
Takashi Iwai23c09b02011-08-19 09:05:35 +02003667static int alc_auto_add_multi_channel_mode(struct hda_codec *codec)
Takashi Iwaice764ab2011-04-27 16:35:23 +02003668{
3669 struct alc_spec *spec = codec->spec;
Takashi Iwaice764ab2011-04-27 16:35:23 +02003670
Takashi Iwaic2674682011-08-24 17:57:44 +02003671 if (spec->multi_ios > 0) {
Takashi Iwaice764ab2011-04-27 16:35:23 +02003672 struct snd_kcontrol_new *knew;
3673
3674 knew = alc_kcontrol_new(spec);
3675 if (!knew)
3676 return -ENOMEM;
3677 *knew = alc_auto_channel_mode_enum;
3678 knew->name = kstrdup("Channel Mode", GFP_KERNEL);
3679 if (!knew->name)
3680 return -ENOMEM;
Takashi Iwaice764ab2011-04-27 16:35:23 +02003681 }
3682 return 0;
3683}
3684
Takashi Iwai1d045db2011-07-07 18:23:21 +02003685/* filter out invalid adc_nids (and capsrc_nids) that don't give all
3686 * active input pins
3687 */
3688static void alc_remove_invalid_adc_nids(struct hda_codec *codec)
3689{
3690 struct alc_spec *spec = codec->spec;
3691 const struct hda_input_mux *imux;
3692 hda_nid_t adc_nids[ARRAY_SIZE(spec->private_adc_nids)];
3693 hda_nid_t capsrc_nids[ARRAY_SIZE(spec->private_adc_nids)];
3694 int i, n, nums;
3695
3696 imux = spec->input_mux;
3697 if (!imux)
3698 return;
3699 if (spec->dyn_adc_switch)
3700 return;
3701
3702 nums = 0;
3703 for (n = 0; n < spec->num_adc_nids; n++) {
3704 hda_nid_t cap = spec->private_capsrc_nids[n];
3705 int num_conns = snd_hda_get_conn_list(codec, cap, NULL);
3706 for (i = 0; i < imux->num_items; i++) {
3707 hda_nid_t pin = spec->imux_pins[i];
3708 if (pin) {
3709 if (get_connection_index(codec, cap, pin) < 0)
3710 break;
3711 } else if (num_conns <= imux->items[i].index)
3712 break;
3713 }
3714 if (i >= imux->num_items) {
3715 adc_nids[nums] = spec->private_adc_nids[n];
3716 capsrc_nids[nums++] = cap;
3717 }
3718 }
3719 if (!nums) {
3720 /* check whether ADC-switch is possible */
3721 if (!alc_check_dyn_adc_switch(codec)) {
3722 printk(KERN_WARNING "hda_codec: %s: no valid ADC found;"
3723 " using fallback 0x%x\n",
3724 codec->chip_name, spec->private_adc_nids[0]);
3725 spec->num_adc_nids = 1;
3726 spec->auto_mic = 0;
3727 return;
3728 }
3729 } else if (nums != spec->num_adc_nids) {
3730 memcpy(spec->private_adc_nids, adc_nids,
3731 nums * sizeof(hda_nid_t));
3732 memcpy(spec->private_capsrc_nids, capsrc_nids,
3733 nums * sizeof(hda_nid_t));
3734 spec->num_adc_nids = nums;
3735 }
3736
3737 if (spec->auto_mic)
3738 alc_auto_mic_check_imux(codec); /* check auto-mic setups */
3739 else if (spec->input_mux->num_items == 1)
3740 spec->num_adc_nids = 1; /* reduce to a single ADC */
3741}
3742
3743/*
3744 * initialize ADC paths
3745 */
3746static void alc_auto_init_adc(struct hda_codec *codec, int adc_idx)
3747{
3748 struct alc_spec *spec = codec->spec;
3749 hda_nid_t nid;
3750
3751 nid = spec->adc_nids[adc_idx];
3752 /* mute ADC */
Takashi Iwai44c02402011-07-08 15:14:19 +02003753 if (nid_has_mute(codec, nid, HDA_INPUT)) {
Takashi Iwai1d045db2011-07-07 18:23:21 +02003754 snd_hda_codec_write(codec, nid, 0,
3755 AC_VERB_SET_AMP_GAIN_MUTE,
3756 AMP_IN_MUTE(0));
3757 return;
3758 }
3759 if (!spec->capsrc_nids)
3760 return;
3761 nid = spec->capsrc_nids[adc_idx];
Takashi Iwai44c02402011-07-08 15:14:19 +02003762 if (nid_has_mute(codec, nid, HDA_OUTPUT))
Takashi Iwai1d045db2011-07-07 18:23:21 +02003763 snd_hda_codec_write(codec, nid, 0,
3764 AC_VERB_SET_AMP_GAIN_MUTE,
3765 AMP_OUT_MUTE);
3766}
3767
3768static void alc_auto_init_input_src(struct hda_codec *codec)
3769{
3770 struct alc_spec *spec = codec->spec;
3771 int c, nums;
3772
3773 for (c = 0; c < spec->num_adc_nids; c++)
3774 alc_auto_init_adc(codec, c);
3775 if (spec->dyn_adc_switch)
3776 nums = 1;
3777 else
3778 nums = spec->num_adc_nids;
3779 for (c = 0; c < nums; c++)
3780 alc_mux_select(codec, 0, spec->cur_mux[c], true);
3781}
3782
3783/* add mic boosts if needed */
3784static int alc_auto_add_mic_boost(struct hda_codec *codec)
3785{
3786 struct alc_spec *spec = codec->spec;
3787 struct auto_pin_cfg *cfg = &spec->autocfg;
3788 int i, err;
3789 int type_idx = 0;
3790 hda_nid_t nid;
3791 const char *prev_label = NULL;
3792
3793 for (i = 0; i < cfg->num_inputs; i++) {
3794 if (cfg->inputs[i].type > AUTO_PIN_MIC)
3795 break;
3796 nid = cfg->inputs[i].pin;
3797 if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) {
3798 const char *label;
3799 char boost_label[32];
3800
3801 label = hda_get_autocfg_input_label(codec, cfg, i);
Takashi Iwai24de1832011-11-07 17:13:39 +01003802 if (spec->shared_mic_hp && !strcmp(label, "Misc"))
3803 label = "Headphone Mic";
Takashi Iwai1d045db2011-07-07 18:23:21 +02003804 if (prev_label && !strcmp(label, prev_label))
3805 type_idx++;
3806 else
3807 type_idx = 0;
3808 prev_label = label;
3809
3810 snprintf(boost_label, sizeof(boost_label),
3811 "%s Boost Volume", label);
3812 err = add_control(spec, ALC_CTL_WIDGET_VOL,
3813 boost_label, type_idx,
3814 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
3815 if (err < 0)
3816 return err;
3817 }
3818 }
3819 return 0;
3820}
3821
3822/* select or unmute the given capsrc route */
3823static void select_or_unmute_capsrc(struct hda_codec *codec, hda_nid_t cap,
3824 int idx)
3825{
3826 if (get_wcaps_type(get_wcaps(codec, cap)) == AC_WID_AUD_MIX) {
3827 snd_hda_codec_amp_stereo(codec, cap, HDA_INPUT, idx,
3828 HDA_AMP_MUTE, 0);
3829 } else if (snd_hda_get_conn_list(codec, cap, NULL) > 1) {
3830 snd_hda_codec_write_cache(codec, cap, 0,
3831 AC_VERB_SET_CONNECT_SEL, idx);
3832 }
3833}
3834
3835/* set the default connection to that pin */
3836static int init_capsrc_for_pin(struct hda_codec *codec, hda_nid_t pin)
3837{
3838 struct alc_spec *spec = codec->spec;
3839 int i;
3840
3841 if (!pin)
3842 return 0;
3843 for (i = 0; i < spec->num_adc_nids; i++) {
Takashi Iwai61071592011-11-23 07:52:15 +01003844 hda_nid_t cap = get_capsrc(spec, i);
Takashi Iwai1d045db2011-07-07 18:23:21 +02003845 int idx;
3846
3847 idx = get_connection_index(codec, cap, pin);
3848 if (idx < 0)
3849 continue;
3850 select_or_unmute_capsrc(codec, cap, idx);
3851 return i; /* return the found index */
3852 }
3853 return -1; /* not found */
3854}
3855
3856/* initialize some special cases for input sources */
3857static void alc_init_special_input_src(struct hda_codec *codec)
3858{
3859 struct alc_spec *spec = codec->spec;
3860 int i;
3861
3862 for (i = 0; i < spec->autocfg.num_inputs; i++)
3863 init_capsrc_for_pin(codec, spec->autocfg.inputs[i].pin);
3864}
3865
3866/* assign appropriate capture mixers */
3867static void set_capture_mixer(struct hda_codec *codec)
3868{
3869 struct alc_spec *spec = codec->spec;
3870 static const struct snd_kcontrol_new *caps[2][3] = {
3871 { alc_capture_mixer_nosrc1,
3872 alc_capture_mixer_nosrc2,
3873 alc_capture_mixer_nosrc3 },
3874 { alc_capture_mixer1,
3875 alc_capture_mixer2,
3876 alc_capture_mixer3 },
3877 };
3878
3879 /* check whether either of ADC or MUX has a volume control */
Takashi Iwai44c02402011-07-08 15:14:19 +02003880 if (!nid_has_volume(codec, spec->adc_nids[0], HDA_INPUT)) {
Takashi Iwai1d045db2011-07-07 18:23:21 +02003881 if (!spec->capsrc_nids)
3882 return; /* no volume */
Takashi Iwai44c02402011-07-08 15:14:19 +02003883 if (!nid_has_volume(codec, spec->capsrc_nids[0], HDA_OUTPUT))
Takashi Iwai1d045db2011-07-07 18:23:21 +02003884 return; /* no volume in capsrc, too */
3885 spec->vol_in_capsrc = 1;
3886 }
3887
3888 if (spec->num_adc_nids > 0) {
3889 int mux = 0;
3890 int num_adcs = 0;
3891
3892 if (spec->input_mux && spec->input_mux->num_items > 1)
3893 mux = 1;
3894 if (spec->auto_mic) {
3895 num_adcs = 1;
3896 mux = 0;
3897 } else if (spec->dyn_adc_switch)
3898 num_adcs = 1;
3899 if (!num_adcs) {
3900 if (spec->num_adc_nids > 3)
3901 spec->num_adc_nids = 3;
3902 else if (!spec->num_adc_nids)
3903 return;
3904 num_adcs = spec->num_adc_nids;
3905 }
3906 spec->cap_mixer = caps[mux][num_adcs - 1];
3907 }
3908}
3909
3910/*
Takashi Iwaie4770622011-07-08 11:11:35 +02003911 * standard auto-parser initializations
3912 */
3913static void alc_auto_init_std(struct hda_codec *codec)
3914{
3915 struct alc_spec *spec = codec->spec;
3916 alc_auto_init_multi_out(codec);
3917 alc_auto_init_extra_out(codec);
3918 alc_auto_init_analog_input(codec);
3919 alc_auto_init_input_src(codec);
3920 alc_auto_init_digital(codec);
3921 if (spec->unsol_event)
3922 alc_inithook(codec);
3923}
3924
3925/*
Takashi Iwai1d045db2011-07-07 18:23:21 +02003926 * Digital-beep handlers
3927 */
3928#ifdef CONFIG_SND_HDA_INPUT_BEEP
3929#define set_beep_amp(spec, nid, idx, dir) \
3930 ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir))
3931
3932static const struct snd_pci_quirk beep_white_list[] = {
3933 SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1),
3934 SND_PCI_QUIRK(0x1043, 0x83ce, "EeePC", 1),
3935 SND_PCI_QUIRK(0x1043, 0x831a, "EeePC", 1),
3936 SND_PCI_QUIRK(0x1043, 0x834a, "EeePC", 1),
3937 SND_PCI_QUIRK(0x8086, 0xd613, "Intel", 1),
3938 {}
3939};
3940
3941static inline int has_cdefine_beep(struct hda_codec *codec)
3942{
3943 struct alc_spec *spec = codec->spec;
3944 const struct snd_pci_quirk *q;
3945 q = snd_pci_quirk_lookup(codec->bus->pci, beep_white_list);
3946 if (q)
3947 return q->value;
3948 return spec->cdefine.enable_pcbeep;
3949}
3950#else
3951#define set_beep_amp(spec, nid, idx, dir) /* NOP */
3952#define has_cdefine_beep(codec) 0
3953#endif
3954
3955/* parse the BIOS configuration and set up the alc_spec */
3956/* return 1 if successful, 0 if the proper config is not found,
3957 * or a negative error code
3958 */
Takashi Iwai3e6179b2011-07-08 16:55:13 +02003959static int alc_parse_auto_config(struct hda_codec *codec,
3960 const hda_nid_t *ignore_nids,
3961 const hda_nid_t *ssid_nids)
Takashi Iwai1d045db2011-07-07 18:23:21 +02003962{
3963 struct alc_spec *spec = codec->spec;
Takashi Iwai23c09b02011-08-19 09:05:35 +02003964 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwai1d045db2011-07-07 18:23:21 +02003965 int err;
Takashi Iwai1d045db2011-07-07 18:23:21 +02003966
Takashi Iwai53c334a2011-08-23 18:27:14 +02003967 err = snd_hda_parse_pin_defcfg(codec, cfg, ignore_nids,
3968 spec->parse_flags);
Takashi Iwai1d045db2011-07-07 18:23:21 +02003969 if (err < 0)
3970 return err;
Takashi Iwai23c09b02011-08-19 09:05:35 +02003971 if (!cfg->line_outs) {
3972 if (cfg->dig_outs || cfg->dig_in_pin) {
Takashi Iwai3e6179b2011-07-08 16:55:13 +02003973 spec->multiout.max_channels = 2;
3974 spec->no_analog = 1;
3975 goto dig_only;
3976 }
Takashi Iwai1d045db2011-07-07 18:23:21 +02003977 return 0; /* can't find valid BIOS pin config */
Takashi Iwai3e6179b2011-07-08 16:55:13 +02003978 }
Takashi Iwai23c09b02011-08-19 09:05:35 +02003979
Takashi Iwai06503672011-10-06 08:27:19 +02003980 if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT &&
3981 cfg->line_outs <= cfg->hp_outs) {
Takashi Iwai23c09b02011-08-19 09:05:35 +02003982 /* use HP as primary out */
3983 cfg->speaker_outs = cfg->line_outs;
3984 memcpy(cfg->speaker_pins, cfg->line_out_pins,
3985 sizeof(cfg->speaker_pins));
3986 cfg->line_outs = cfg->hp_outs;
3987 memcpy(cfg->line_out_pins, cfg->hp_pins, sizeof(cfg->hp_pins));
3988 cfg->hp_outs = 0;
3989 memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins));
3990 cfg->line_out_type = AUTO_PIN_HP_OUT;
3991 }
3992
Takashi Iwai1d045db2011-07-07 18:23:21 +02003993 err = alc_auto_fill_dac_nids(codec);
3994 if (err < 0)
3995 return err;
Takashi Iwai23c09b02011-08-19 09:05:35 +02003996 err = alc_auto_add_multi_channel_mode(codec);
Takashi Iwai3e6179b2011-07-08 16:55:13 +02003997 if (err < 0)
3998 return err;
Takashi Iwai23c09b02011-08-19 09:05:35 +02003999 err = alc_auto_create_multi_out_ctls(codec, cfg);
Takashi Iwai1d045db2011-07-07 18:23:21 +02004000 if (err < 0)
4001 return err;
4002 err = alc_auto_create_hp_out(codec);
4003 if (err < 0)
4004 return err;
4005 err = alc_auto_create_speaker_out(codec);
4006 if (err < 0)
4007 return err;
Takashi Iwai24de1832011-11-07 17:13:39 +01004008 err = alc_auto_create_shared_input(codec);
4009 if (err < 0)
4010 return err;
Takashi Iwai1d045db2011-07-07 18:23:21 +02004011 err = alc_auto_create_input_ctls(codec);
4012 if (err < 0)
4013 return err;
4014
4015 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
4016
Takashi Iwai3e6179b2011-07-08 16:55:13 +02004017 dig_only:
Takashi Iwai1d045db2011-07-07 18:23:21 +02004018 alc_auto_parse_digital(codec);
4019
Takashi Iwai3e6179b2011-07-08 16:55:13 +02004020 if (!spec->no_analog)
4021 alc_remove_invalid_adc_nids(codec);
4022
4023 if (ssid_nids)
4024 alc_ssid_check(codec, ssid_nids);
4025
4026 if (!spec->no_analog) {
4027 alc_auto_check_switches(codec);
4028 err = alc_auto_add_mic_boost(codec);
4029 if (err < 0)
4030 return err;
4031 }
4032
Takashi Iwai1d045db2011-07-07 18:23:21 +02004033 if (spec->kctls.list)
4034 add_mixer(spec, spec->kctls.list);
4035
Takashi Iwai1d045db2011-07-07 18:23:21 +02004036 return 1;
4037}
4038
Takashi Iwai3e6179b2011-07-08 16:55:13 +02004039static int alc880_parse_auto_config(struct hda_codec *codec)
4040{
4041 static const hda_nid_t alc880_ignore[] = { 0x1d, 0 };
4042 static const hda_nid_t alc880_ssids[] = { 0x15, 0x1b, 0x14, 0 };
4043 return alc_parse_auto_config(codec, alc880_ignore, alc880_ssids);
4044}
4045
Takashi Iwai1d045db2011-07-07 18:23:21 +02004046#ifdef CONFIG_SND_HDA_POWER_SAVE
4047static const struct hda_amp_list alc880_loopbacks[] = {
4048 { 0x0b, HDA_INPUT, 0 },
4049 { 0x0b, HDA_INPUT, 1 },
4050 { 0x0b, HDA_INPUT, 2 },
4051 { 0x0b, HDA_INPUT, 3 },
4052 { 0x0b, HDA_INPUT, 4 },
4053 { } /* end */
4054};
4055#endif
4056
4057/*
Takashi Iwaiee3b2962011-11-15 14:26:54 +01004058 * ALC880 fix-ups
4059 */
4060enum {
4061 ALC880_FIXUP_GPIO2,
4062 ALC880_FIXUP_MEDION_RIM,
4063};
4064
4065static const struct alc_fixup alc880_fixups[] = {
4066 [ALC880_FIXUP_GPIO2] = {
4067 .type = ALC_FIXUP_VERBS,
4068 .v.verbs = alc_gpio2_init_verbs,
4069 },
4070 [ALC880_FIXUP_MEDION_RIM] = {
4071 .type = ALC_FIXUP_VERBS,
4072 .v.verbs = (const struct hda_verb[]) {
4073 { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
4074 { 0x20, AC_VERB_SET_PROC_COEF, 0x3060 },
4075 { }
4076 },
4077 .chained = true,
4078 .chain_id = ALC880_FIXUP_GPIO2,
4079 },
4080};
4081
4082static const struct snd_pci_quirk alc880_fixup_tbl[] = {
4083 SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_FIXUP_MEDION_RIM),
4084 {}
4085};
4086
4087
4088/*
Takashi Iwai1d045db2011-07-07 18:23:21 +02004089 * board setups
4090 */
4091#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
4092#define alc_board_config \
4093 snd_hda_check_board_config
4094#define alc_board_codec_sid_config \
4095 snd_hda_check_board_codec_sid_config
4096#include "alc_quirks.c"
4097#else
4098#define alc_board_config(codec, nums, models, tbl) -1
4099#define alc_board_codec_sid_config(codec, nums, models, tbl) -1
4100#define setup_preset(codec, x) /* NOP */
4101#endif
4102
4103/*
4104 * OK, here we have finally the patch for ALC880
4105 */
4106#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
4107#include "alc880_quirks.c"
4108#endif
4109
4110static int patch_alc880(struct hda_codec *codec)
4111{
4112 struct alc_spec *spec;
4113 int board_config;
4114 int err;
4115
4116 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4117 if (spec == NULL)
4118 return -ENOMEM;
4119
4120 codec->spec = spec;
4121
4122 spec->mixer_nid = 0x0b;
Takashi Iwai7b1655f2011-07-14 15:31:21 +02004123 spec->need_dac_fix = 1;
Takashi Iwai1d045db2011-07-07 18:23:21 +02004124
4125 board_config = alc_board_config(codec, ALC880_MODEL_LAST,
4126 alc880_models, alc880_cfg_tbl);
4127 if (board_config < 0) {
4128 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
4129 codec->chip_name);
4130 board_config = ALC_MODEL_AUTO;
4131 }
4132
4133 if (board_config == ALC_MODEL_AUTO) {
Takashi Iwaiee3b2962011-11-15 14:26:54 +01004134 alc_pick_fixup(codec, NULL, alc880_fixup_tbl, alc880_fixups);
4135 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
4136 }
4137
4138 if (board_config == ALC_MODEL_AUTO) {
Takashi Iwai1d045db2011-07-07 18:23:21 +02004139 /* automatic parse from the BIOS config */
4140 err = alc880_parse_auto_config(codec);
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02004141 if (err < 0)
4142 goto error;
Takashi Iwai1d045db2011-07-07 18:23:21 +02004143#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
4144 else if (!err) {
4145 printk(KERN_INFO
4146 "hda_codec: Cannot set up configuration "
4147 "from BIOS. Using 3-stack mode...\n");
4148 board_config = ALC880_3ST;
4149 }
4150#endif
4151 }
4152
David Henningssonfde48a12011-12-09 18:27:42 +08004153 if (board_config != ALC_MODEL_AUTO) {
4154 spec->vmaster_nid = 0x0c;
Takashi Iwai1d045db2011-07-07 18:23:21 +02004155 setup_preset(codec, &alc880_presets[board_config]);
David Henningssonfde48a12011-12-09 18:27:42 +08004156 }
Takashi Iwai1d045db2011-07-07 18:23:21 +02004157
Takashi Iwai60a6a842011-07-27 14:01:24 +02004158 if (!spec->no_analog && !spec->adc_nids) {
Takashi Iwai1d045db2011-07-07 18:23:21 +02004159 alc_auto_fill_adc_caps(codec);
4160 alc_rebuild_imux_for_auto_mic(codec);
4161 alc_remove_invalid_adc_nids(codec);
4162 }
Takashi Iwai3e6179b2011-07-08 16:55:13 +02004163
4164 if (!spec->no_analog && !spec->cap_mixer)
4165 set_capture_mixer(codec);
4166
4167 if (!spec->no_analog) {
4168 err = snd_hda_attach_beep_device(codec, 0x1);
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02004169 if (err < 0)
4170 goto error;
Takashi Iwai3e6179b2011-07-08 16:55:13 +02004171 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
4172 }
Takashi Iwai1d045db2011-07-07 18:23:21 +02004173
Takashi Iwaiee3b2962011-11-15 14:26:54 +01004174 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
4175
Takashi Iwai1d045db2011-07-07 18:23:21 +02004176 codec->patch_ops = alc_patch_ops;
4177 if (board_config == ALC_MODEL_AUTO)
Takashi Iwaie4770622011-07-08 11:11:35 +02004178 spec->init_hook = alc_auto_init_std;
Takashi Iwaif21d78e2012-01-19 12:10:29 +01004179 else
4180 codec->patch_ops.build_controls = __alc_build_controls;
Takashi Iwai1d045db2011-07-07 18:23:21 +02004181#ifdef CONFIG_SND_HDA_POWER_SAVE
4182 if (!spec->loopback.amplist)
4183 spec->loopback.amplist = alc880_loopbacks;
4184#endif
4185
4186 return 0;
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02004187
4188 error:
4189 alc_free(codec);
4190 return err;
Takashi Iwai1d045db2011-07-07 18:23:21 +02004191}
4192
4193
4194/*
4195 * ALC260 support
4196 */
Takashi Iwai1d045db2011-07-07 18:23:21 +02004197static int alc260_parse_auto_config(struct hda_codec *codec)
4198{
Takashi Iwai1d045db2011-07-07 18:23:21 +02004199 static const hda_nid_t alc260_ignore[] = { 0x17, 0 };
Takashi Iwai3e6179b2011-07-08 16:55:13 +02004200 static const hda_nid_t alc260_ssids[] = { 0x10, 0x15, 0x0f, 0 };
4201 return alc_parse_auto_config(codec, alc260_ignore, alc260_ssids);
Takashi Iwai1d045db2011-07-07 18:23:21 +02004202}
4203
Takashi Iwai1d045db2011-07-07 18:23:21 +02004204#ifdef CONFIG_SND_HDA_POWER_SAVE
4205static const struct hda_amp_list alc260_loopbacks[] = {
4206 { 0x07, HDA_INPUT, 0 },
4207 { 0x07, HDA_INPUT, 1 },
4208 { 0x07, HDA_INPUT, 2 },
4209 { 0x07, HDA_INPUT, 3 },
4210 { 0x07, HDA_INPUT, 4 },
4211 { } /* end */
4212};
4213#endif
4214
4215/*
4216 * Pin config fixes
4217 */
4218enum {
4219 PINFIX_HP_DC5750,
4220};
4221
4222static const struct alc_fixup alc260_fixups[] = {
4223 [PINFIX_HP_DC5750] = {
4224 .type = ALC_FIXUP_PINS,
4225 .v.pins = (const struct alc_pincfg[]) {
4226 { 0x11, 0x90130110 }, /* speaker */
4227 { }
4228 }
4229 },
4230};
4231
4232static const struct snd_pci_quirk alc260_fixup_tbl[] = {
4233 SND_PCI_QUIRK(0x103c, 0x280a, "HP dc5750", PINFIX_HP_DC5750),
4234 {}
4235};
4236
4237/*
4238 */
4239#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
4240#include "alc260_quirks.c"
4241#endif
4242
4243static int patch_alc260(struct hda_codec *codec)
4244{
4245 struct alc_spec *spec;
4246 int err, board_config;
4247
4248 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4249 if (spec == NULL)
4250 return -ENOMEM;
4251
4252 codec->spec = spec;
4253
4254 spec->mixer_nid = 0x07;
4255
4256 board_config = alc_board_config(codec, ALC260_MODEL_LAST,
4257 alc260_models, alc260_cfg_tbl);
4258 if (board_config < 0) {
4259 snd_printd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
4260 codec->chip_name);
4261 board_config = ALC_MODEL_AUTO;
4262 }
4263
4264 if (board_config == ALC_MODEL_AUTO) {
4265 alc_pick_fixup(codec, NULL, alc260_fixup_tbl, alc260_fixups);
4266 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
4267 }
4268
4269 if (board_config == ALC_MODEL_AUTO) {
4270 /* automatic parse from the BIOS config */
4271 err = alc260_parse_auto_config(codec);
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02004272 if (err < 0)
4273 goto error;
Takashi Iwai1d045db2011-07-07 18:23:21 +02004274#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
4275 else if (!err) {
4276 printk(KERN_INFO
4277 "hda_codec: Cannot set up configuration "
4278 "from BIOS. Using base mode...\n");
4279 board_config = ALC260_BASIC;
4280 }
4281#endif
4282 }
4283
David Henningssonfde48a12011-12-09 18:27:42 +08004284 if (board_config != ALC_MODEL_AUTO) {
Takashi Iwai1d045db2011-07-07 18:23:21 +02004285 setup_preset(codec, &alc260_presets[board_config]);
David Henningssonfde48a12011-12-09 18:27:42 +08004286 spec->vmaster_nid = 0x08;
4287 }
Takashi Iwai1d045db2011-07-07 18:23:21 +02004288
Takashi Iwai60a6a842011-07-27 14:01:24 +02004289 if (!spec->no_analog && !spec->adc_nids) {
Takashi Iwai1d045db2011-07-07 18:23:21 +02004290 alc_auto_fill_adc_caps(codec);
4291 alc_rebuild_imux_for_auto_mic(codec);
4292 alc_remove_invalid_adc_nids(codec);
4293 }
Takashi Iwai3e6179b2011-07-08 16:55:13 +02004294
4295 if (!spec->no_analog && !spec->cap_mixer)
4296 set_capture_mixer(codec);
4297
4298 if (!spec->no_analog) {
4299 err = snd_hda_attach_beep_device(codec, 0x1);
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02004300 if (err < 0)
4301 goto error;
Takashi Iwai3e6179b2011-07-08 16:55:13 +02004302 set_beep_amp(spec, 0x07, 0x05, HDA_INPUT);
4303 }
Takashi Iwai1d045db2011-07-07 18:23:21 +02004304
4305 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
4306
Takashi Iwai1d045db2011-07-07 18:23:21 +02004307 codec->patch_ops = alc_patch_ops;
4308 if (board_config == ALC_MODEL_AUTO)
Takashi Iwai8452a982011-07-08 16:19:48 +02004309 spec->init_hook = alc_auto_init_std;
Takashi Iwaif21d78e2012-01-19 12:10:29 +01004310 else
4311 codec->patch_ops.build_controls = __alc_build_controls;
Takashi Iwai1d045db2011-07-07 18:23:21 +02004312 spec->shutup = alc_eapd_shutup;
4313#ifdef CONFIG_SND_HDA_POWER_SAVE
4314 if (!spec->loopback.amplist)
4315 spec->loopback.amplist = alc260_loopbacks;
4316#endif
4317
4318 return 0;
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02004319
4320 error:
4321 alc_free(codec);
4322 return err;
Takashi Iwai1d045db2011-07-07 18:23:21 +02004323}
4324
4325
4326/*
4327 * ALC882/883/885/888/889 support
4328 *
4329 * ALC882 is almost identical with ALC880 but has cleaner and more flexible
4330 * configuration. Each pin widget can choose any input DACs and a mixer.
4331 * Each ADC is connected from a mixer of all inputs. This makes possible
4332 * 6-channel independent captures.
4333 *
4334 * In addition, an independent DAC for the multi-playback (not used in this
4335 * driver yet).
4336 */
4337#ifdef CONFIG_SND_HDA_POWER_SAVE
4338#define alc882_loopbacks alc880_loopbacks
4339#endif
4340
4341/*
4342 * Pin config fixes
4343 */
4344enum {
Takashi Iwai5c0ebfb2011-11-07 17:59:13 +01004345 ALC882_FIXUP_ABIT_AW9D_MAX,
4346 ALC882_FIXUP_LENOVO_Y530,
4347 ALC882_FIXUP_PB_M5210,
4348 ALC882_FIXUP_ACER_ASPIRE_7736,
4349 ALC882_FIXUP_ASUS_W90V,
4350 ALC889_FIXUP_VAIO_TT,
Takashi Iwai0e7cc2e2011-11-09 12:42:48 +01004351 ALC888_FIXUP_EEE1601,
Takashi Iwai177943a2011-11-09 12:55:18 +01004352 ALC882_FIXUP_EAPD,
Takashi Iwai7a6069b2011-11-09 15:22:01 +01004353 ALC883_FIXUP_EAPD,
Takashi Iwai8812c4f2011-11-09 17:39:15 +01004354 ALC883_FIXUP_ACER_EAPD,
Takashi Iwaieb844d52011-11-09 18:03:07 +01004355 ALC882_FIXUP_GPIO3,
Takashi Iwai68ef0562011-11-09 18:24:44 +01004356 ALC889_FIXUP_COEF,
4357 ALC882_FIXUP_ASUS_W2JC,
Takashi Iwaic3e837b2011-11-10 16:01:47 +01004358 ALC882_FIXUP_ACER_ASPIRE_4930G,
4359 ALC882_FIXUP_ACER_ASPIRE_8930G,
4360 ALC882_FIXUP_ASPIRE_8930G_VERBS,
Takashi Iwai56710872011-11-14 17:42:11 +01004361 ALC885_FIXUP_MACPRO_GPIO,
Takashi Iwai1d045db2011-07-07 18:23:21 +02004362};
4363
Takashi Iwai68ef0562011-11-09 18:24:44 +01004364static void alc889_fixup_coef(struct hda_codec *codec,
4365 const struct alc_fixup *fix, int action)
4366{
4367 if (action != ALC_FIXUP_ACT_INIT)
4368 return;
4369 alc889_coef_init(codec);
4370}
4371
Takashi Iwai56710872011-11-14 17:42:11 +01004372/* toggle speaker-output according to the hp-jack state */
4373static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted)
4374{
4375 unsigned int gpiostate, gpiomask, gpiodir;
4376
4377 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
4378 AC_VERB_GET_GPIO_DATA, 0);
4379
4380 if (!muted)
4381 gpiostate |= (1 << pin);
4382 else
4383 gpiostate &= ~(1 << pin);
4384
4385 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
4386 AC_VERB_GET_GPIO_MASK, 0);
4387 gpiomask |= (1 << pin);
4388
4389 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
4390 AC_VERB_GET_GPIO_DIRECTION, 0);
4391 gpiodir |= (1 << pin);
4392
4393
4394 snd_hda_codec_write(codec, codec->afg, 0,
4395 AC_VERB_SET_GPIO_MASK, gpiomask);
4396 snd_hda_codec_write(codec, codec->afg, 0,
4397 AC_VERB_SET_GPIO_DIRECTION, gpiodir);
4398
4399 msleep(1);
4400
4401 snd_hda_codec_write(codec, codec->afg, 0,
4402 AC_VERB_SET_GPIO_DATA, gpiostate);
4403}
4404
4405/* set up GPIO at initialization */
4406static void alc885_fixup_macpro_gpio(struct hda_codec *codec,
4407 const struct alc_fixup *fix, int action)
4408{
4409 if (action != ALC_FIXUP_ACT_INIT)
4410 return;
4411 alc882_gpio_mute(codec, 0, 0);
4412 alc882_gpio_mute(codec, 1, 0);
4413}
4414
Takashi Iwai1d045db2011-07-07 18:23:21 +02004415static const struct alc_fixup alc882_fixups[] = {
Takashi Iwai5c0ebfb2011-11-07 17:59:13 +01004416 [ALC882_FIXUP_ABIT_AW9D_MAX] = {
Takashi Iwai1d045db2011-07-07 18:23:21 +02004417 .type = ALC_FIXUP_PINS,
4418 .v.pins = (const struct alc_pincfg[]) {
4419 { 0x15, 0x01080104 }, /* side */
4420 { 0x16, 0x01011012 }, /* rear */
4421 { 0x17, 0x01016011 }, /* clfe */
4422 { }
4423 }
4424 },
Takashi Iwai5c0ebfb2011-11-07 17:59:13 +01004425 [ALC882_FIXUP_LENOVO_Y530] = {
Takashi Iwai1d045db2011-07-07 18:23:21 +02004426 .type = ALC_FIXUP_PINS,
4427 .v.pins = (const struct alc_pincfg[]) {
4428 { 0x15, 0x99130112 }, /* rear int speakers */
4429 { 0x16, 0x99130111 }, /* subwoofer */
4430 { }
4431 }
4432 },
Takashi Iwai5c0ebfb2011-11-07 17:59:13 +01004433 [ALC882_FIXUP_PB_M5210] = {
Takashi Iwai1d045db2011-07-07 18:23:21 +02004434 .type = ALC_FIXUP_VERBS,
4435 .v.verbs = (const struct hda_verb[]) {
4436 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 },
4437 {}
4438 }
4439 },
Takashi Iwai5c0ebfb2011-11-07 17:59:13 +01004440 [ALC882_FIXUP_ACER_ASPIRE_7736] = {
Takashi Iwai1d045db2011-07-07 18:23:21 +02004441 .type = ALC_FIXUP_SKU,
4442 .v.sku = ALC_FIXUP_SKU_IGNORE,
4443 },
Takashi Iwai5c0ebfb2011-11-07 17:59:13 +01004444 [ALC882_FIXUP_ASUS_W90V] = {
Takashi Iwai5cdf7452011-10-26 23:04:08 +02004445 .type = ALC_FIXUP_PINS,
4446 .v.pins = (const struct alc_pincfg[]) {
4447 { 0x16, 0x99130110 }, /* fix sequence for CLFE */
4448 { }
4449 }
4450 },
Takashi Iwai5c0ebfb2011-11-07 17:59:13 +01004451 [ALC889_FIXUP_VAIO_TT] = {
4452 .type = ALC_FIXUP_PINS,
4453 .v.pins = (const struct alc_pincfg[]) {
4454 { 0x17, 0x90170111 }, /* hidden surround speaker */
4455 { }
4456 }
4457 },
Takashi Iwai0e7cc2e2011-11-09 12:42:48 +01004458 [ALC888_FIXUP_EEE1601] = {
4459 .type = ALC_FIXUP_VERBS,
4460 .v.verbs = (const struct hda_verb[]) {
4461 { 0x20, AC_VERB_SET_COEF_INDEX, 0x0b },
4462 { 0x20, AC_VERB_SET_PROC_COEF, 0x0838 },
4463 { }
4464 }
Takashi Iwai177943a2011-11-09 12:55:18 +01004465 },
4466 [ALC882_FIXUP_EAPD] = {
4467 .type = ALC_FIXUP_VERBS,
4468 .v.verbs = (const struct hda_verb[]) {
4469 /* change to EAPD mode */
4470 { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
4471 { 0x20, AC_VERB_SET_PROC_COEF, 0x3060 },
4472 { }
4473 }
4474 },
Takashi Iwai7a6069b2011-11-09 15:22:01 +01004475 [ALC883_FIXUP_EAPD] = {
4476 .type = ALC_FIXUP_VERBS,
4477 .v.verbs = (const struct hda_verb[]) {
4478 /* change to EAPD mode */
4479 { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
4480 { 0x20, AC_VERB_SET_PROC_COEF, 0x3070 },
4481 { }
4482 }
4483 },
Takashi Iwai8812c4f2011-11-09 17:39:15 +01004484 [ALC883_FIXUP_ACER_EAPD] = {
4485 .type = ALC_FIXUP_VERBS,
4486 .v.verbs = (const struct hda_verb[]) {
4487 /* eanable EAPD on Acer laptops */
4488 { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
4489 { 0x20, AC_VERB_SET_PROC_COEF, 0x3050 },
4490 { }
4491 }
4492 },
Takashi Iwaieb844d52011-11-09 18:03:07 +01004493 [ALC882_FIXUP_GPIO3] = {
4494 .type = ALC_FIXUP_VERBS,
4495 .v.verbs = alc_gpio3_init_verbs,
4496 },
Takashi Iwai68ef0562011-11-09 18:24:44 +01004497 [ALC882_FIXUP_ASUS_W2JC] = {
4498 .type = ALC_FIXUP_VERBS,
4499 .v.verbs = alc_gpio1_init_verbs,
4500 .chained = true,
4501 .chain_id = ALC882_FIXUP_EAPD,
4502 },
4503 [ALC889_FIXUP_COEF] = {
4504 .type = ALC_FIXUP_FUNC,
4505 .v.func = alc889_fixup_coef,
4506 },
Takashi Iwaic3e837b2011-11-10 16:01:47 +01004507 [ALC882_FIXUP_ACER_ASPIRE_4930G] = {
4508 .type = ALC_FIXUP_PINS,
4509 .v.pins = (const struct alc_pincfg[]) {
4510 { 0x16, 0x99130111 }, /* CLFE speaker */
4511 { 0x17, 0x99130112 }, /* surround speaker */
4512 { }
4513 }
4514 },
4515 [ALC882_FIXUP_ACER_ASPIRE_8930G] = {
4516 .type = ALC_FIXUP_PINS,
4517 .v.pins = (const struct alc_pincfg[]) {
4518 { 0x16, 0x99130111 }, /* CLFE speaker */
4519 { 0x1b, 0x99130112 }, /* surround speaker */
4520 { }
4521 },
4522 .chained = true,
4523 .chain_id = ALC882_FIXUP_ASPIRE_8930G_VERBS,
4524 },
4525 [ALC882_FIXUP_ASPIRE_8930G_VERBS] = {
4526 /* additional init verbs for Acer Aspire 8930G */
4527 .type = ALC_FIXUP_VERBS,
4528 .v.verbs = (const struct hda_verb[]) {
4529 /* Enable all DACs */
4530 /* DAC DISABLE/MUTE 1? */
4531 /* setting bits 1-5 disables DAC nids 0x02-0x06
4532 * apparently. Init=0x38 */
4533 { 0x20, AC_VERB_SET_COEF_INDEX, 0x03 },
4534 { 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
4535 /* DAC DISABLE/MUTE 2? */
4536 /* some bit here disables the other DACs.
4537 * Init=0x4900 */
4538 { 0x20, AC_VERB_SET_COEF_INDEX, 0x08 },
4539 { 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
4540 /* DMIC fix
4541 * This laptop has a stereo digital microphone.
4542 * The mics are only 1cm apart which makes the stereo
4543 * useless. However, either the mic or the ALC889
4544 * makes the signal become a difference/sum signal
4545 * instead of standard stereo, which is annoying.
4546 * So instead we flip this bit which makes the
4547 * codec replicate the sum signal to both channels,
4548 * turning it into a normal mono mic.
4549 */
4550 /* DMIC_CONTROL? Init value = 0x0001 */
4551 { 0x20, AC_VERB_SET_COEF_INDEX, 0x0b },
4552 { 0x20, AC_VERB_SET_PROC_COEF, 0x0003 },
4553 { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
4554 { 0x20, AC_VERB_SET_PROC_COEF, 0x3050 },
4555 { }
4556 }
4557 },
Takashi Iwai56710872011-11-14 17:42:11 +01004558 [ALC885_FIXUP_MACPRO_GPIO] = {
4559 .type = ALC_FIXUP_FUNC,
4560 .v.func = alc885_fixup_macpro_gpio,
4561 },
Takashi Iwai1d045db2011-07-07 18:23:21 +02004562};
4563
4564static const struct snd_pci_quirk alc882_fixup_tbl[] = {
Takashi Iwai8812c4f2011-11-09 17:39:15 +01004565 SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_FIXUP_ACER_EAPD),
4566 SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_FIXUP_ACER_EAPD),
4567 SND_PCI_QUIRK(0x1025, 0x010a, "Acer Ferrari 5000", ALC883_FIXUP_ACER_EAPD),
4568 SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_FIXUP_ACER_EAPD),
4569 SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_FIXUP_ACER_EAPD),
4570 SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_FIXUP_ACER_EAPD),
Takashi Iwaic3e837b2011-11-10 16:01:47 +01004571 SND_PCI_QUIRK(0x1025, 0x013e, "Acer Aspire 4930G",
4572 ALC882_FIXUP_ACER_ASPIRE_4930G),
4573 SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G",
4574 ALC882_FIXUP_ACER_ASPIRE_4930G),
4575 SND_PCI_QUIRK(0x1025, 0x0145, "Acer Aspire 8930G",
4576 ALC882_FIXUP_ACER_ASPIRE_8930G),
4577 SND_PCI_QUIRK(0x1025, 0x0146, "Acer Aspire 6935G",
4578 ALC882_FIXUP_ACER_ASPIRE_8930G),
4579 SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G",
4580 ALC882_FIXUP_ACER_ASPIRE_4930G),
4581 SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G",
4582 ALC882_FIXUP_ACER_ASPIRE_4930G),
4583 SND_PCI_QUIRK(0x1025, 0x0142, "Acer Aspire 7730G",
4584 ALC882_FIXUP_ACER_ASPIRE_4930G),
Takashi Iwai5c0ebfb2011-11-07 17:59:13 +01004585 SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", ALC882_FIXUP_PB_M5210),
Takashi Iwaiac9b1cd2011-11-09 17:45:55 +01004586 SND_PCI_QUIRK(0x1025, 0x0296, "Acer Aspire 7736z", ALC882_FIXUP_ACER_ASPIRE_7736),
Takashi Iwai177943a2011-11-09 12:55:18 +01004587 SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_FIXUP_EAPD),
Takashi Iwai5c0ebfb2011-11-07 17:59:13 +01004588 SND_PCI_QUIRK(0x1043, 0x1873, "ASUS W90V", ALC882_FIXUP_ASUS_W90V),
Takashi Iwai68ef0562011-11-09 18:24:44 +01004589 SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_FIXUP_ASUS_W2JC),
Takashi Iwai0e7cc2e2011-11-09 12:42:48 +01004590 SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_FIXUP_EEE1601),
Takashi Iwaiac9b1cd2011-11-09 17:45:55 +01004591 SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC889_FIXUP_VAIO_TT),
Takashi Iwai56710872011-11-14 17:42:11 +01004592
4593 /* All Apple entries are in codec SSIDs */
4594 SND_PCI_QUIRK(0x106b, 0x0c00, "Mac Pro", ALC885_FIXUP_MACPRO_GPIO),
4595 SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_FIXUP_MACPRO_GPIO),
4596 SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_FIXUP_MACPRO_GPIO),
4597 SND_PCI_QUIRK(0x106b, 0x3200, "iMac 7,1 Aluminum", ALC882_FIXUP_EAPD),
4598 SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_FIXUP_MACPRO_GPIO),
4599
Takashi Iwai7a6069b2011-11-09 15:22:01 +01004600 SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC882_FIXUP_EAPD),
Takashi Iwaieb844d52011-11-09 18:03:07 +01004601 SND_PCI_QUIRK_VENDOR(0x1462, "MSI", ALC882_FIXUP_GPIO3),
Takashi Iwai5c0ebfb2011-11-07 17:59:13 +01004602 SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", ALC882_FIXUP_ABIT_AW9D_MAX),
Takashi Iwai7a6069b2011-11-09 15:22:01 +01004603 SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC882_FIXUP_EAPD),
4604 SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_FIXUP_EAPD),
Takashi Iwaiac9b1cd2011-11-09 17:45:55 +01004605 SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Y530", ALC882_FIXUP_LENOVO_Y530),
Takashi Iwai68ef0562011-11-09 18:24:44 +01004606 SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC889_FIXUP_COEF),
Takashi Iwai1d045db2011-07-07 18:23:21 +02004607 {}
4608};
4609
4610/*
4611 * BIOS auto configuration
4612 */
4613/* almost identical with ALC880 parser... */
4614static int alc882_parse_auto_config(struct hda_codec *codec)
4615{
Takashi Iwai1d045db2011-07-07 18:23:21 +02004616 static const hda_nid_t alc882_ignore[] = { 0x1d, 0 };
Takashi Iwai3e6179b2011-07-08 16:55:13 +02004617 static const hda_nid_t alc882_ssids[] = { 0x15, 0x1b, 0x14, 0 };
4618 return alc_parse_auto_config(codec, alc882_ignore, alc882_ssids);
Takashi Iwai1d045db2011-07-07 18:23:21 +02004619}
4620
Takashi Iwai1d045db2011-07-07 18:23:21 +02004621/*
4622 */
4623#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
4624#include "alc882_quirks.c"
4625#endif
4626
4627static int patch_alc882(struct hda_codec *codec)
4628{
4629 struct alc_spec *spec;
4630 int err, board_config;
4631
4632 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4633 if (spec == NULL)
4634 return -ENOMEM;
4635
4636 codec->spec = spec;
4637
4638 spec->mixer_nid = 0x0b;
4639
4640 switch (codec->vendor_id) {
4641 case 0x10ec0882:
4642 case 0x10ec0885:
4643 break;
4644 default:
4645 /* ALC883 and variants */
4646 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
4647 break;
4648 }
4649
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02004650 err = alc_codec_rename_from_preset(codec);
4651 if (err < 0)
4652 goto error;
4653
Takashi Iwaib2539692011-11-14 17:32:17 +01004654 board_config = alc_board_config(codec, ALC882_MODEL_LAST,
4655 alc882_models, NULL);
4656 if (board_config < 0)
4657 board_config = alc_board_codec_sid_config(codec,
Takashi Iwai1d045db2011-07-07 18:23:21 +02004658 ALC882_MODEL_LAST, alc882_models, alc882_ssid_cfg_tbl);
4659
4660 if (board_config < 0) {
4661 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
4662 codec->chip_name);
4663 board_config = ALC_MODEL_AUTO;
4664 }
4665
4666 if (board_config == ALC_MODEL_AUTO) {
4667 alc_pick_fixup(codec, NULL, alc882_fixup_tbl, alc882_fixups);
4668 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
4669 }
4670
4671 alc_auto_parse_customize_define(codec);
4672
4673 if (board_config == ALC_MODEL_AUTO) {
4674 /* automatic parse from the BIOS config */
4675 err = alc882_parse_auto_config(codec);
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02004676 if (err < 0)
4677 goto error;
Takashi Iwai1d045db2011-07-07 18:23:21 +02004678 }
4679
David Henningssonfde48a12011-12-09 18:27:42 +08004680 if (board_config != ALC_MODEL_AUTO) {
Takashi Iwai1d045db2011-07-07 18:23:21 +02004681 setup_preset(codec, &alc882_presets[board_config]);
David Henningssonfde48a12011-12-09 18:27:42 +08004682 spec->vmaster_nid = 0x0c;
4683 }
Takashi Iwai1d045db2011-07-07 18:23:21 +02004684
Takashi Iwai60a6a842011-07-27 14:01:24 +02004685 if (!spec->no_analog && !spec->adc_nids) {
Takashi Iwai1d045db2011-07-07 18:23:21 +02004686 alc_auto_fill_adc_caps(codec);
4687 alc_rebuild_imux_for_auto_mic(codec);
4688 alc_remove_invalid_adc_nids(codec);
4689 }
4690
Takashi Iwai3e6179b2011-07-08 16:55:13 +02004691 if (!spec->no_analog && !spec->cap_mixer)
4692 set_capture_mixer(codec);
Takashi Iwai1d045db2011-07-07 18:23:21 +02004693
Takashi Iwai3e6179b2011-07-08 16:55:13 +02004694 if (!spec->no_analog && has_cdefine_beep(codec)) {
4695 err = snd_hda_attach_beep_device(codec, 0x1);
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02004696 if (err < 0)
4697 goto error;
Takashi Iwai1d045db2011-07-07 18:23:21 +02004698 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Takashi Iwai3e6179b2011-07-08 16:55:13 +02004699 }
Takashi Iwai1d045db2011-07-07 18:23:21 +02004700
4701 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
4702
Takashi Iwai1d045db2011-07-07 18:23:21 +02004703 codec->patch_ops = alc_patch_ops;
4704 if (board_config == ALC_MODEL_AUTO)
Takashi Iwaie4770622011-07-08 11:11:35 +02004705 spec->init_hook = alc_auto_init_std;
Takashi Iwaif21d78e2012-01-19 12:10:29 +01004706 else
4707 codec->patch_ops.build_controls = __alc_build_controls;
Takashi Iwai1d045db2011-07-07 18:23:21 +02004708
Takashi Iwai1d045db2011-07-07 18:23:21 +02004709#ifdef CONFIG_SND_HDA_POWER_SAVE
4710 if (!spec->loopback.amplist)
4711 spec->loopback.amplist = alc882_loopbacks;
4712#endif
4713
4714 return 0;
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02004715
4716 error:
4717 alc_free(codec);
4718 return err;
Takashi Iwai1d045db2011-07-07 18:23:21 +02004719}
4720
4721
4722/*
4723 * ALC262 support
4724 */
Takashi Iwai1d045db2011-07-07 18:23:21 +02004725static int alc262_parse_auto_config(struct hda_codec *codec)
4726{
Takashi Iwai1d045db2011-07-07 18:23:21 +02004727 static const hda_nid_t alc262_ignore[] = { 0x1d, 0 };
Takashi Iwai3e6179b2011-07-08 16:55:13 +02004728 static const hda_nid_t alc262_ssids[] = { 0x15, 0x1b, 0x14, 0 };
4729 return alc_parse_auto_config(codec, alc262_ignore, alc262_ssids);
Takashi Iwai1d045db2011-07-07 18:23:21 +02004730}
4731
4732/*
4733 * Pin config fixes
4734 */
4735enum {
Takashi Iwaiea4e7af2011-11-07 12:23:55 +01004736 ALC262_FIXUP_FSC_H270,
4737 ALC262_FIXUP_HP_Z200,
4738 ALC262_FIXUP_TYAN,
Takashi Iwai12837c982011-11-07 12:45:24 +01004739 ALC262_FIXUP_TOSHIBA_RX1,
Takashi Iwaic4701502011-11-07 14:20:07 +01004740 ALC262_FIXUP_LENOVO_3000,
Takashi Iwaib42590b2011-11-07 14:41:01 +01004741 ALC262_FIXUP_BENQ,
4742 ALC262_FIXUP_BENQ_T31,
Takashi Iwai1d045db2011-07-07 18:23:21 +02004743};
4744
4745static const struct alc_fixup alc262_fixups[] = {
Takashi Iwaiea4e7af2011-11-07 12:23:55 +01004746 [ALC262_FIXUP_FSC_H270] = {
Takashi Iwai1d045db2011-07-07 18:23:21 +02004747 .type = ALC_FIXUP_PINS,
4748 .v.pins = (const struct alc_pincfg[]) {
4749 { 0x14, 0x99130110 }, /* speaker */
4750 { 0x15, 0x0221142f }, /* front HP */
4751 { 0x1b, 0x0121141f }, /* rear HP */
4752 { }
4753 }
4754 },
Takashi Iwaiea4e7af2011-11-07 12:23:55 +01004755 [ALC262_FIXUP_HP_Z200] = {
Takashi Iwai1d045db2011-07-07 18:23:21 +02004756 .type = ALC_FIXUP_PINS,
4757 .v.pins = (const struct alc_pincfg[]) {
4758 { 0x16, 0x99130120 }, /* internal speaker */
4759 { }
4760 }
4761 },
Takashi Iwaiea4e7af2011-11-07 12:23:55 +01004762 [ALC262_FIXUP_TYAN] = {
4763 .type = ALC_FIXUP_PINS,
4764 .v.pins = (const struct alc_pincfg[]) {
4765 { 0x14, 0x1993e1f0 }, /* int AUX */
4766 { }
4767 }
4768 },
Takashi Iwai12837c982011-11-07 12:45:24 +01004769 [ALC262_FIXUP_TOSHIBA_RX1] = {
4770 .type = ALC_FIXUP_PINS,
4771 .v.pins = (const struct alc_pincfg[]) {
4772 { 0x14, 0x90170110 }, /* speaker */
4773 { 0x15, 0x0421101f }, /* HP */
4774 { 0x1a, 0x40f000f0 }, /* N/A */
4775 { 0x1b, 0x40f000f0 }, /* N/A */
4776 { 0x1e, 0x40f000f0 }, /* N/A */
4777 }
4778 },
Takashi Iwaic4701502011-11-07 14:20:07 +01004779 [ALC262_FIXUP_LENOVO_3000] = {
4780 .type = ALC_FIXUP_VERBS,
4781 .v.verbs = (const struct hda_verb[]) {
4782 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 },
Takashi Iwaib42590b2011-11-07 14:41:01 +01004783 {}
4784 },
4785 .chained = true,
4786 .chain_id = ALC262_FIXUP_BENQ,
4787 },
4788 [ALC262_FIXUP_BENQ] = {
4789 .type = ALC_FIXUP_VERBS,
4790 .v.verbs = (const struct hda_verb[]) {
Takashi Iwaic4701502011-11-07 14:20:07 +01004791 { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
4792 { 0x20, AC_VERB_SET_PROC_COEF, 0x3070 },
4793 {}
4794 }
4795 },
Takashi Iwaib42590b2011-11-07 14:41:01 +01004796 [ALC262_FIXUP_BENQ_T31] = {
4797 .type = ALC_FIXUP_VERBS,
4798 .v.verbs = (const struct hda_verb[]) {
4799 { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
4800 { 0x20, AC_VERB_SET_PROC_COEF, 0x3050 },
4801 {}
4802 }
4803 },
Takashi Iwai1d045db2011-07-07 18:23:21 +02004804};
4805
4806static const struct snd_pci_quirk alc262_fixup_tbl[] = {
Takashi Iwaiea4e7af2011-11-07 12:23:55 +01004807 SND_PCI_QUIRK(0x103c, 0x170b, "HP Z200", ALC262_FIXUP_HP_Z200),
Takashi Iwai3dcd3be2011-11-07 14:59:40 +01004808 SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FIXUP_BENQ),
4809 SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FIXUP_BENQ),
Takashi Iwaiea4e7af2011-11-07 12:23:55 +01004810 SND_PCI_QUIRK(0x10f1, 0x2915, "Tyan Thunder n6650W", ALC262_FIXUP_TYAN),
Takashi Iwai12837c982011-11-07 12:45:24 +01004811 SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1",
4812 ALC262_FIXUP_TOSHIBA_RX1),
Takashi Iwaiea4e7af2011-11-07 12:23:55 +01004813 SND_PCI_QUIRK(0x1734, 0x1147, "FSC Celsius H270", ALC262_FIXUP_FSC_H270),
Takashi Iwaic4701502011-11-07 14:20:07 +01004814 SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000", ALC262_FIXUP_LENOVO_3000),
Takashi Iwaib42590b2011-11-07 14:41:01 +01004815 SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_FIXUP_BENQ),
4816 SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_FIXUP_BENQ_T31),
Takashi Iwai1d045db2011-07-07 18:23:21 +02004817 {}
4818};
4819
4820
4821#ifdef CONFIG_SND_HDA_POWER_SAVE
4822#define alc262_loopbacks alc880_loopbacks
4823#endif
4824
Takashi Iwai1d045db2011-07-07 18:23:21 +02004825/*
4826 */
Takashi Iwai1d045db2011-07-07 18:23:21 +02004827static int patch_alc262(struct hda_codec *codec)
4828{
4829 struct alc_spec *spec;
Takashi Iwai1d045db2011-07-07 18:23:21 +02004830 int err;
4831
4832 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4833 if (spec == NULL)
4834 return -ENOMEM;
4835
4836 codec->spec = spec;
4837
4838 spec->mixer_nid = 0x0b;
4839
4840#if 0
4841 /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is
4842 * under-run
4843 */
4844 {
4845 int tmp;
4846 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
4847 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
4848 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
4849 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80);
4850 }
4851#endif
4852 alc_auto_parse_customize_define(codec);
4853
4854 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
4855
Takashi Iwai42399f72011-11-07 17:18:44 +01004856 alc_pick_fixup(codec, NULL, alc262_fixup_tbl, alc262_fixups);
4857 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
Takashi Iwai1d045db2011-07-07 18:23:21 +02004858
Takashi Iwai42399f72011-11-07 17:18:44 +01004859 /* automatic parse from the BIOS config */
4860 err = alc262_parse_auto_config(codec);
4861 if (err < 0)
4862 goto error;
Takashi Iwai3e6179b2011-07-08 16:55:13 +02004863
Takashi Iwai60a6a842011-07-27 14:01:24 +02004864 if (!spec->no_analog && !spec->adc_nids) {
Takashi Iwai3e6179b2011-07-08 16:55:13 +02004865 alc_auto_fill_adc_caps(codec);
4866 alc_rebuild_imux_for_auto_mic(codec);
4867 alc_remove_invalid_adc_nids(codec);
4868 }
4869
4870 if (!spec->no_analog && !spec->cap_mixer)
4871 set_capture_mixer(codec);
4872
Takashi Iwai1d045db2011-07-07 18:23:21 +02004873 if (!spec->no_analog && has_cdefine_beep(codec)) {
4874 err = snd_hda_attach_beep_device(codec, 0x1);
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02004875 if (err < 0)
4876 goto error;
Takashi Iwai1d045db2011-07-07 18:23:21 +02004877 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Takashi Iwai3e6179b2011-07-08 16:55:13 +02004878 }
Takashi Iwai1d045db2011-07-07 18:23:21 +02004879
4880 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
4881
Takashi Iwai1d045db2011-07-07 18:23:21 +02004882 codec->patch_ops = alc_patch_ops;
Takashi Iwai42399f72011-11-07 17:18:44 +01004883 spec->init_hook = alc_auto_init_std;
Takashi Iwai1d045db2011-07-07 18:23:21 +02004884 spec->shutup = alc_eapd_shutup;
4885
Takashi Iwai1d045db2011-07-07 18:23:21 +02004886#ifdef CONFIG_SND_HDA_POWER_SAVE
4887 if (!spec->loopback.amplist)
4888 spec->loopback.amplist = alc262_loopbacks;
4889#endif
4890
4891 return 0;
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02004892
4893 error:
4894 alc_free(codec);
4895 return err;
Takashi Iwai1d045db2011-07-07 18:23:21 +02004896}
4897
4898/*
4899 * ALC268
4900 */
Takashi Iwai1d045db2011-07-07 18:23:21 +02004901/* bind Beep switches of both NID 0x0f and 0x10 */
4902static const struct hda_bind_ctls alc268_bind_beep_sw = {
4903 .ops = &snd_hda_bind_sw,
4904 .values = {
4905 HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT),
4906 HDA_COMPOSE_AMP_VAL(0x10, 3, 1, HDA_INPUT),
4907 0
4908 },
4909};
4910
4911static const struct snd_kcontrol_new alc268_beep_mixer[] = {
4912 HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT),
4913 HDA_BIND_SW("Beep Playback Switch", &alc268_bind_beep_sw),
4914 { }
4915};
4916
4917/* set PCBEEP vol = 0, mute connections */
4918static const struct hda_verb alc268_beep_init_verbs[] = {
4919 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4920 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4921 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4922 { }
4923};
4924
4925/*
4926 * BIOS auto configuration
4927 */
4928static int alc268_parse_auto_config(struct hda_codec *codec)
4929{
Takashi Iwai3e6179b2011-07-08 16:55:13 +02004930 static const hda_nid_t alc268_ssids[] = { 0x15, 0x1b, 0x14, 0 };
Takashi Iwai1d045db2011-07-07 18:23:21 +02004931 struct alc_spec *spec = codec->spec;
Takashi Iwai3e6179b2011-07-08 16:55:13 +02004932 int err = alc_parse_auto_config(codec, NULL, alc268_ssids);
4933 if (err > 0) {
4934 if (!spec->no_analog && spec->autocfg.speaker_pins[0] != 0x1d) {
4935 add_mixer(spec, alc268_beep_mixer);
4936 add_verb(spec, alc268_beep_init_verbs);
Takashi Iwai1d045db2011-07-07 18:23:21 +02004937 }
Takashi Iwai1d045db2011-07-07 18:23:21 +02004938 }
Takashi Iwai3e6179b2011-07-08 16:55:13 +02004939 return err;
Takashi Iwai1d045db2011-07-07 18:23:21 +02004940}
4941
Takashi Iwai1d045db2011-07-07 18:23:21 +02004942/*
4943 */
Takashi Iwai1d045db2011-07-07 18:23:21 +02004944static int patch_alc268(struct hda_codec *codec)
4945{
4946 struct alc_spec *spec;
Takashi Iwai1d045db2011-07-07 18:23:21 +02004947 int i, has_beep, err;
4948
4949 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4950 if (spec == NULL)
4951 return -ENOMEM;
4952
4953 codec->spec = spec;
4954
4955 /* ALC268 has no aa-loopback mixer */
4956
Takashi Iwai6ebb8052011-08-16 15:15:40 +02004957 /* automatic parse from the BIOS config */
4958 err = alc268_parse_auto_config(codec);
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02004959 if (err < 0)
4960 goto error;
Takashi Iwai1d045db2011-07-07 18:23:21 +02004961
Takashi Iwai1d045db2011-07-07 18:23:21 +02004962 has_beep = 0;
4963 for (i = 0; i < spec->num_mixers; i++) {
4964 if (spec->mixers[i] == alc268_beep_mixer) {
4965 has_beep = 1;
4966 break;
4967 }
4968 }
4969
4970 if (has_beep) {
4971 err = snd_hda_attach_beep_device(codec, 0x1);
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02004972 if (err < 0)
4973 goto error;
Takashi Iwai1d045db2011-07-07 18:23:21 +02004974 if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
4975 /* override the amp caps for beep generator */
4976 snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT,
4977 (0x0c << AC_AMPCAP_OFFSET_SHIFT) |
4978 (0x0c << AC_AMPCAP_NUM_STEPS_SHIFT) |
4979 (0x07 << AC_AMPCAP_STEP_SIZE_SHIFT) |
4980 (0 << AC_AMPCAP_MUTE_SHIFT));
4981 }
4982
Takashi Iwai60a6a842011-07-27 14:01:24 +02004983 if (!spec->no_analog && !spec->adc_nids) {
Takashi Iwai1d045db2011-07-07 18:23:21 +02004984 alc_auto_fill_adc_caps(codec);
4985 alc_rebuild_imux_for_auto_mic(codec);
4986 alc_remove_invalid_adc_nids(codec);
4987 }
4988
Takashi Iwai3e6179b2011-07-08 16:55:13 +02004989 if (!spec->no_analog && !spec->cap_mixer)
Takashi Iwai1d045db2011-07-07 18:23:21 +02004990 set_capture_mixer(codec);
4991
Takashi Iwai1d045db2011-07-07 18:23:21 +02004992 codec->patch_ops = alc_patch_ops;
Takashi Iwai6ebb8052011-08-16 15:15:40 +02004993 spec->init_hook = alc_auto_init_std;
Takashi Iwai1d045db2011-07-07 18:23:21 +02004994 spec->shutup = alc_eapd_shutup;
4995
Takashi Iwai1d045db2011-07-07 18:23:21 +02004996 return 0;
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02004997
4998 error:
4999 alc_free(codec);
5000 return err;
Takashi Iwai1d045db2011-07-07 18:23:21 +02005001}
5002
5003/*
5004 * ALC269
5005 */
Takashi Iwai1d045db2011-07-07 18:23:21 +02005006#ifdef CONFIG_SND_HDA_POWER_SAVE
5007#define alc269_loopbacks alc880_loopbacks
5008#endif
5009
5010static const struct hda_pcm_stream alc269_44k_pcm_analog_playback = {
5011 .substreams = 1,
5012 .channels_min = 2,
5013 .channels_max = 8,
5014 .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
5015 /* NID is set in alc_build_pcms */
5016 .ops = {
5017 .open = alc_playback_pcm_open,
5018 .prepare = alc_playback_pcm_prepare,
5019 .cleanup = alc_playback_pcm_cleanup
5020 },
5021};
5022
5023static const struct hda_pcm_stream alc269_44k_pcm_analog_capture = {
5024 .substreams = 1,
5025 .channels_min = 2,
5026 .channels_max = 2,
5027 .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
5028 /* NID is set in alc_build_pcms */
5029};
5030
5031#ifdef CONFIG_SND_HDA_POWER_SAVE
5032static int alc269_mic2_for_mute_led(struct hda_codec *codec)
5033{
5034 switch (codec->subsystem_id) {
5035 case 0x103c1586:
5036 return 1;
5037 }
5038 return 0;
5039}
5040
5041static int alc269_mic2_mute_check_ps(struct hda_codec *codec, hda_nid_t nid)
5042{
5043 /* update mute-LED according to the speaker mute state */
5044 if (nid == 0x01 || nid == 0x14) {
5045 int pinval;
5046 if (snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0) &
5047 HDA_AMP_MUTE)
5048 pinval = 0x24;
5049 else
5050 pinval = 0x20;
5051 /* mic2 vref pin is used for mute LED control */
5052 snd_hda_codec_update_cache(codec, 0x19, 0,
5053 AC_VERB_SET_PIN_WIDGET_CONTROL,
5054 pinval);
5055 }
5056 return alc_check_power_status(codec, nid);
5057}
5058#endif /* CONFIG_SND_HDA_POWER_SAVE */
5059
5060/* different alc269-variants */
5061enum {
5062 ALC269_TYPE_ALC269VA,
5063 ALC269_TYPE_ALC269VB,
5064 ALC269_TYPE_ALC269VC,
5065};
5066
5067/*
5068 * BIOS auto configuration
5069 */
5070static int alc269_parse_auto_config(struct hda_codec *codec)
5071{
Takashi Iwai1d045db2011-07-07 18:23:21 +02005072 static const hda_nid_t alc269_ignore[] = { 0x1d, 0 };
Takashi Iwai3e6179b2011-07-08 16:55:13 +02005073 static const hda_nid_t alc269_ssids[] = { 0, 0x1b, 0x14, 0x21 };
5074 static const hda_nid_t alc269va_ssids[] = { 0x15, 0x1b, 0x14, 0 };
5075 struct alc_spec *spec = codec->spec;
5076 const hda_nid_t *ssids = spec->codec_variant == ALC269_TYPE_ALC269VA ?
5077 alc269va_ssids : alc269_ssids;
Takashi Iwai1d045db2011-07-07 18:23:21 +02005078
Takashi Iwai3e6179b2011-07-08 16:55:13 +02005079 return alc_parse_auto_config(codec, alc269_ignore, ssids);
Takashi Iwai1d045db2011-07-07 18:23:21 +02005080}
5081
Takashi Iwai1d045db2011-07-07 18:23:21 +02005082static void alc269_toggle_power_output(struct hda_codec *codec, int power_up)
5083{
5084 int val = alc_read_coef_idx(codec, 0x04);
5085 if (power_up)
5086 val |= 1 << 11;
5087 else
5088 val &= ~(1 << 11);
5089 alc_write_coef_idx(codec, 0x04, val);
5090}
5091
5092static void alc269_shutup(struct hda_codec *codec)
5093{
Takashi Iwai1bb7e432011-10-17 16:50:59 +02005094 if ((alc_get_coef0(codec) & 0x00ff) == 0x017)
Takashi Iwai1d045db2011-07-07 18:23:21 +02005095 alc269_toggle_power_output(codec, 0);
Takashi Iwai1bb7e432011-10-17 16:50:59 +02005096 if ((alc_get_coef0(codec) & 0x00ff) == 0x018) {
Takashi Iwai1d045db2011-07-07 18:23:21 +02005097 alc269_toggle_power_output(codec, 0);
5098 msleep(150);
5099 }
5100}
5101
Takashi Iwai2a439522011-07-26 09:52:50 +02005102#ifdef CONFIG_PM
Takashi Iwai1d045db2011-07-07 18:23:21 +02005103static int alc269_resume(struct hda_codec *codec)
5104{
Takashi Iwai1bb7e432011-10-17 16:50:59 +02005105 if ((alc_get_coef0(codec) & 0x00ff) == 0x018) {
Takashi Iwai1d045db2011-07-07 18:23:21 +02005106 alc269_toggle_power_output(codec, 0);
5107 msleep(150);
5108 }
5109
5110 codec->patch_ops.init(codec);
5111
Takashi Iwai1bb7e432011-10-17 16:50:59 +02005112 if ((alc_get_coef0(codec) & 0x00ff) == 0x017) {
Takashi Iwai1d045db2011-07-07 18:23:21 +02005113 alc269_toggle_power_output(codec, 1);
5114 msleep(200);
5115 }
5116
Takashi Iwai1bb7e432011-10-17 16:50:59 +02005117 if ((alc_get_coef0(codec) & 0x00ff) == 0x018)
Takashi Iwai1d045db2011-07-07 18:23:21 +02005118 alc269_toggle_power_output(codec, 1);
5119
5120 snd_hda_codec_resume_amp(codec);
5121 snd_hda_codec_resume_cache(codec);
5122 hda_call_check_power_status(codec, 0x01);
5123 return 0;
5124}
Takashi Iwai2a439522011-07-26 09:52:50 +02005125#endif /* CONFIG_PM */
Takashi Iwai1d045db2011-07-07 18:23:21 +02005126
5127static void alc269_fixup_hweq(struct hda_codec *codec,
5128 const struct alc_fixup *fix, int action)
5129{
5130 int coef;
5131
5132 if (action != ALC_FIXUP_ACT_INIT)
5133 return;
5134 coef = alc_read_coef_idx(codec, 0x1e);
5135 alc_write_coef_idx(codec, 0x1e, coef | 0x80);
5136}
5137
5138static void alc271_fixup_dmic(struct hda_codec *codec,
5139 const struct alc_fixup *fix, int action)
5140{
5141 static const struct hda_verb verbs[] = {
5142 {0x20, AC_VERB_SET_COEF_INDEX, 0x0d},
5143 {0x20, AC_VERB_SET_PROC_COEF, 0x4000},
5144 {}
5145 };
5146 unsigned int cfg;
5147
5148 if (strcmp(codec->chip_name, "ALC271X"))
5149 return;
5150 cfg = snd_hda_codec_get_pincfg(codec, 0x12);
5151 if (get_defcfg_connect(cfg) == AC_JACK_PORT_FIXED)
5152 snd_hda_sequence_write(codec, verbs);
5153}
5154
Takashi Iwai017f2a12011-07-09 14:42:25 +02005155static void alc269_fixup_pcm_44k(struct hda_codec *codec,
5156 const struct alc_fixup *fix, int action)
5157{
5158 struct alc_spec *spec = codec->spec;
5159
5160 if (action != ALC_FIXUP_ACT_PROBE)
5161 return;
5162
5163 /* Due to a hardware problem on Lenovo Ideadpad, we need to
5164 * fix the sample rate of analog I/O to 44.1kHz
5165 */
5166 spec->stream_analog_playback = &alc269_44k_pcm_analog_playback;
5167 spec->stream_analog_capture = &alc269_44k_pcm_analog_capture;
5168}
5169
Takashi Iwaiadabb3e2011-08-03 07:48:37 +02005170static void alc269_fixup_stereo_dmic(struct hda_codec *codec,
5171 const struct alc_fixup *fix, int action)
5172{
5173 int coef;
5174
5175 if (action != ALC_FIXUP_ACT_INIT)
5176 return;
5177 /* The digital-mic unit sends PDM (differential signal) instead of
5178 * the standard PCM, thus you can't record a valid mono stream as is.
5179 * Below is a workaround specific to ALC269 to control the dmic
5180 * signal source as mono.
5181 */
5182 coef = alc_read_coef_idx(codec, 0x07);
5183 alc_write_coef_idx(codec, 0x07, coef | 0x80);
5184}
5185
Takashi Iwai24519912011-08-16 15:08:49 +02005186static void alc269_quanta_automute(struct hda_codec *codec)
5187{
David Henningsson42cf0d02011-09-20 12:04:56 +02005188 update_outputs(codec);
Takashi Iwai24519912011-08-16 15:08:49 +02005189
5190 snd_hda_codec_write(codec, 0x20, 0,
5191 AC_VERB_SET_COEF_INDEX, 0x0c);
5192 snd_hda_codec_write(codec, 0x20, 0,
5193 AC_VERB_SET_PROC_COEF, 0x680);
5194
5195 snd_hda_codec_write(codec, 0x20, 0,
5196 AC_VERB_SET_COEF_INDEX, 0x0c);
5197 snd_hda_codec_write(codec, 0x20, 0,
5198 AC_VERB_SET_PROC_COEF, 0x480);
5199}
5200
5201static void alc269_fixup_quanta_mute(struct hda_codec *codec,
5202 const struct alc_fixup *fix, int action)
5203{
5204 struct alc_spec *spec = codec->spec;
5205 if (action != ALC_FIXUP_ACT_PROBE)
5206 return;
5207 spec->automute_hook = alc269_quanta_automute;
5208}
5209
Takashi Iwai1d045db2011-07-07 18:23:21 +02005210enum {
5211 ALC269_FIXUP_SONY_VAIO,
5212 ALC275_FIXUP_SONY_VAIO_GPIO2,
5213 ALC269_FIXUP_DELL_M101Z,
5214 ALC269_FIXUP_SKU_IGNORE,
5215 ALC269_FIXUP_ASUS_G73JW,
5216 ALC269_FIXUP_LENOVO_EAPD,
5217 ALC275_FIXUP_SONY_HWEQ,
5218 ALC271_FIXUP_DMIC,
Takashi Iwai017f2a12011-07-09 14:42:25 +02005219 ALC269_FIXUP_PCM_44K,
Takashi Iwaiadabb3e2011-08-03 07:48:37 +02005220 ALC269_FIXUP_STEREO_DMIC,
Takashi Iwai24519912011-08-16 15:08:49 +02005221 ALC269_FIXUP_QUANTA_MUTE,
5222 ALC269_FIXUP_LIFEBOOK,
Takashi Iwaia4297b52011-08-23 18:40:12 +02005223 ALC269_FIXUP_AMIC,
5224 ALC269_FIXUP_DMIC,
5225 ALC269VB_FIXUP_AMIC,
5226 ALC269VB_FIXUP_DMIC,
Takashi Iwai1d045db2011-07-07 18:23:21 +02005227};
5228
5229static const struct alc_fixup alc269_fixups[] = {
5230 [ALC269_FIXUP_SONY_VAIO] = {
5231 .type = ALC_FIXUP_VERBS,
5232 .v.verbs = (const struct hda_verb[]) {
5233 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREFGRD},
5234 {}
5235 }
5236 },
5237 [ALC275_FIXUP_SONY_VAIO_GPIO2] = {
5238 .type = ALC_FIXUP_VERBS,
5239 .v.verbs = (const struct hda_verb[]) {
5240 {0x01, AC_VERB_SET_GPIO_MASK, 0x04},
5241 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x04},
5242 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
5243 { }
5244 },
5245 .chained = true,
5246 .chain_id = ALC269_FIXUP_SONY_VAIO
5247 },
5248 [ALC269_FIXUP_DELL_M101Z] = {
5249 .type = ALC_FIXUP_VERBS,
5250 .v.verbs = (const struct hda_verb[]) {
5251 /* Enables internal speaker */
5252 {0x20, AC_VERB_SET_COEF_INDEX, 13},
5253 {0x20, AC_VERB_SET_PROC_COEF, 0x4040},
5254 {}
5255 }
5256 },
5257 [ALC269_FIXUP_SKU_IGNORE] = {
5258 .type = ALC_FIXUP_SKU,
5259 .v.sku = ALC_FIXUP_SKU_IGNORE,
5260 },
5261 [ALC269_FIXUP_ASUS_G73JW] = {
5262 .type = ALC_FIXUP_PINS,
5263 .v.pins = (const struct alc_pincfg[]) {
5264 { 0x17, 0x99130111 }, /* subwoofer */
5265 { }
5266 }
5267 },
5268 [ALC269_FIXUP_LENOVO_EAPD] = {
5269 .type = ALC_FIXUP_VERBS,
5270 .v.verbs = (const struct hda_verb[]) {
5271 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 0},
5272 {}
5273 }
5274 },
5275 [ALC275_FIXUP_SONY_HWEQ] = {
5276 .type = ALC_FIXUP_FUNC,
5277 .v.func = alc269_fixup_hweq,
5278 .chained = true,
5279 .chain_id = ALC275_FIXUP_SONY_VAIO_GPIO2
5280 },
5281 [ALC271_FIXUP_DMIC] = {
5282 .type = ALC_FIXUP_FUNC,
5283 .v.func = alc271_fixup_dmic,
5284 },
Takashi Iwai017f2a12011-07-09 14:42:25 +02005285 [ALC269_FIXUP_PCM_44K] = {
5286 .type = ALC_FIXUP_FUNC,
5287 .v.func = alc269_fixup_pcm_44k,
5288 },
Takashi Iwaiadabb3e2011-08-03 07:48:37 +02005289 [ALC269_FIXUP_STEREO_DMIC] = {
5290 .type = ALC_FIXUP_FUNC,
5291 .v.func = alc269_fixup_stereo_dmic,
5292 },
Takashi Iwai24519912011-08-16 15:08:49 +02005293 [ALC269_FIXUP_QUANTA_MUTE] = {
5294 .type = ALC_FIXUP_FUNC,
5295 .v.func = alc269_fixup_quanta_mute,
5296 },
5297 [ALC269_FIXUP_LIFEBOOK] = {
5298 .type = ALC_FIXUP_PINS,
5299 .v.pins = (const struct alc_pincfg[]) {
5300 { 0x1a, 0x2101103f }, /* dock line-out */
5301 { 0x1b, 0x23a11040 }, /* dock mic-in */
5302 { }
5303 },
5304 .chained = true,
5305 .chain_id = ALC269_FIXUP_QUANTA_MUTE
5306 },
Takashi Iwaia4297b52011-08-23 18:40:12 +02005307 [ALC269_FIXUP_AMIC] = {
5308 .type = ALC_FIXUP_PINS,
5309 .v.pins = (const struct alc_pincfg[]) {
5310 { 0x14, 0x99130110 }, /* speaker */
5311 { 0x15, 0x0121401f }, /* HP out */
5312 { 0x18, 0x01a19c20 }, /* mic */
5313 { 0x19, 0x99a3092f }, /* int-mic */
5314 { }
5315 },
5316 },
5317 [ALC269_FIXUP_DMIC] = {
5318 .type = ALC_FIXUP_PINS,
5319 .v.pins = (const struct alc_pincfg[]) {
5320 { 0x12, 0x99a3092f }, /* int-mic */
5321 { 0x14, 0x99130110 }, /* speaker */
5322 { 0x15, 0x0121401f }, /* HP out */
5323 { 0x18, 0x01a19c20 }, /* mic */
5324 { }
5325 },
5326 },
5327 [ALC269VB_FIXUP_AMIC] = {
5328 .type = ALC_FIXUP_PINS,
5329 .v.pins = (const struct alc_pincfg[]) {
5330 { 0x14, 0x99130110 }, /* speaker */
5331 { 0x18, 0x01a19c20 }, /* mic */
5332 { 0x19, 0x99a3092f }, /* int-mic */
5333 { 0x21, 0x0121401f }, /* HP out */
5334 { }
5335 },
5336 },
David Henningsson2267ea92012-01-03 08:45:56 +01005337 [ALC269VB_FIXUP_DMIC] = {
Takashi Iwaia4297b52011-08-23 18:40:12 +02005338 .type = ALC_FIXUP_PINS,
5339 .v.pins = (const struct alc_pincfg[]) {
5340 { 0x12, 0x99a3092f }, /* int-mic */
5341 { 0x14, 0x99130110 }, /* speaker */
5342 { 0x18, 0x01a19c20 }, /* mic */
5343 { 0x21, 0x0121401f }, /* HP out */
5344 { }
5345 },
5346 },
Takashi Iwai1d045db2011-07-07 18:23:21 +02005347};
5348
5349static const struct snd_pci_quirk alc269_fixup_tbl[] = {
Takashi Iwai017f2a12011-07-09 14:42:25 +02005350 SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW),
Takashi Iwaiadabb3e2011-08-03 07:48:37 +02005351 SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_FIXUP_STEREO_DMIC),
5352 SND_PCI_QUIRK(0x1043, 0x831a, "ASUS P901", ALC269_FIXUP_STEREO_DMIC),
5353 SND_PCI_QUIRK(0x1043, 0x834a, "ASUS S101", ALC269_FIXUP_STEREO_DMIC),
5354 SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005", ALC269_FIXUP_STEREO_DMIC),
5355 SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005", ALC269_FIXUP_STEREO_DMIC),
Takashi Iwai1d045db2011-07-07 18:23:21 +02005356 SND_PCI_QUIRK(0x104d, 0x9073, "Sony VAIO", ALC275_FIXUP_SONY_VAIO_GPIO2),
5357 SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
5358 SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
5359 SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO),
5360 SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z),
5361 SND_PCI_QUIRK_VENDOR(0x1025, "Acer Aspire", ALC271_FIXUP_DMIC),
Takashi Iwai24519912011-08-16 15:08:49 +02005362 SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook", ALC269_FIXUP_LIFEBOOK),
Takashi Iwai1d045db2011-07-07 18:23:21 +02005363 SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE),
5364 SND_PCI_QUIRK(0x17aa, 0x215e, "Thinkpad L512", ALC269_FIXUP_SKU_IGNORE),
5365 SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE),
5366 SND_PCI_QUIRK(0x17aa, 0x21ca, "Thinkpad L412", ALC269_FIXUP_SKU_IGNORE),
5367 SND_PCI_QUIRK(0x17aa, 0x21e9, "Thinkpad Edge 15", ALC269_FIXUP_SKU_IGNORE),
Takashi Iwai24519912011-08-16 15:08:49 +02005368 SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_QUANTA_MUTE),
Takashi Iwai017f2a12011-07-09 14:42:25 +02005369 SND_PCI_QUIRK(0x17aa, 0x3bf8, "Lenovo Ideapd", ALC269_FIXUP_PCM_44K),
Takashi Iwai1d045db2011-07-07 18:23:21 +02005370 SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
Takashi Iwaia4297b52011-08-23 18:40:12 +02005371
5372#if 1
5373 /* Below is a quirk table taken from the old code.
5374 * Basically the device should work as is without the fixup table.
5375 * If BIOS doesn't give a proper info, enable the corresponding
5376 * fixup entry.
5377 */
5378 SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A",
5379 ALC269_FIXUP_AMIC),
5380 SND_PCI_QUIRK(0x1043, 0x1013, "ASUS N61Da", ALC269_FIXUP_AMIC),
5381 SND_PCI_QUIRK(0x1043, 0x1113, "ASUS N63Jn", ALC269_FIXUP_AMIC),
5382 SND_PCI_QUIRK(0x1043, 0x1143, "ASUS B53f", ALC269_FIXUP_AMIC),
5383 SND_PCI_QUIRK(0x1043, 0x1133, "ASUS UJ20ft", ALC269_FIXUP_AMIC),
5384 SND_PCI_QUIRK(0x1043, 0x1183, "ASUS K72DR", ALC269_FIXUP_AMIC),
5385 SND_PCI_QUIRK(0x1043, 0x11b3, "ASUS K52DR", ALC269_FIXUP_AMIC),
5386 SND_PCI_QUIRK(0x1043, 0x11e3, "ASUS U33Jc", ALC269_FIXUP_AMIC),
5387 SND_PCI_QUIRK(0x1043, 0x1273, "ASUS UL80Jt", ALC269_FIXUP_AMIC),
5388 SND_PCI_QUIRK(0x1043, 0x1283, "ASUS U53Jc", ALC269_FIXUP_AMIC),
5389 SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS N82JV", ALC269_FIXUP_AMIC),
5390 SND_PCI_QUIRK(0x1043, 0x12d3, "ASUS N61Jv", ALC269_FIXUP_AMIC),
5391 SND_PCI_QUIRK(0x1043, 0x13a3, "ASUS UL30Vt", ALC269_FIXUP_AMIC),
5392 SND_PCI_QUIRK(0x1043, 0x1373, "ASUS G73JX", ALC269_FIXUP_AMIC),
5393 SND_PCI_QUIRK(0x1043, 0x1383, "ASUS UJ30Jc", ALC269_FIXUP_AMIC),
5394 SND_PCI_QUIRK(0x1043, 0x13d3, "ASUS N61JA", ALC269_FIXUP_AMIC),
5395 SND_PCI_QUIRK(0x1043, 0x1413, "ASUS UL50", ALC269_FIXUP_AMIC),
5396 SND_PCI_QUIRK(0x1043, 0x1443, "ASUS UL30", ALC269_FIXUP_AMIC),
5397 SND_PCI_QUIRK(0x1043, 0x1453, "ASUS M60Jv", ALC269_FIXUP_AMIC),
5398 SND_PCI_QUIRK(0x1043, 0x1483, "ASUS UL80", ALC269_FIXUP_AMIC),
5399 SND_PCI_QUIRK(0x1043, 0x14f3, "ASUS F83Vf", ALC269_FIXUP_AMIC),
5400 SND_PCI_QUIRK(0x1043, 0x14e3, "ASUS UL20", ALC269_FIXUP_AMIC),
5401 SND_PCI_QUIRK(0x1043, 0x1513, "ASUS UX30", ALC269_FIXUP_AMIC),
5402 SND_PCI_QUIRK(0x1043, 0x1593, "ASUS N51Vn", ALC269_FIXUP_AMIC),
5403 SND_PCI_QUIRK(0x1043, 0x15a3, "ASUS N60Jv", ALC269_FIXUP_AMIC),
5404 SND_PCI_QUIRK(0x1043, 0x15b3, "ASUS N60Dp", ALC269_FIXUP_AMIC),
5405 SND_PCI_QUIRK(0x1043, 0x15c3, "ASUS N70De", ALC269_FIXUP_AMIC),
5406 SND_PCI_QUIRK(0x1043, 0x15e3, "ASUS F83T", ALC269_FIXUP_AMIC),
5407 SND_PCI_QUIRK(0x1043, 0x1643, "ASUS M60J", ALC269_FIXUP_AMIC),
5408 SND_PCI_QUIRK(0x1043, 0x1653, "ASUS U50", ALC269_FIXUP_AMIC),
5409 SND_PCI_QUIRK(0x1043, 0x1693, "ASUS F50N", ALC269_FIXUP_AMIC),
5410 SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS F5Q", ALC269_FIXUP_AMIC),
5411 SND_PCI_QUIRK(0x1043, 0x1723, "ASUS P80", ALC269_FIXUP_AMIC),
5412 SND_PCI_QUIRK(0x1043, 0x1743, "ASUS U80", ALC269_FIXUP_AMIC),
5413 SND_PCI_QUIRK(0x1043, 0x1773, "ASUS U20A", ALC269_FIXUP_AMIC),
5414 SND_PCI_QUIRK(0x1043, 0x1883, "ASUS F81Se", ALC269_FIXUP_AMIC),
5415 SND_PCI_QUIRK(0x152d, 0x1778, "Quanta ON1", ALC269_FIXUP_DMIC),
5416 SND_PCI_QUIRK(0x17aa, 0x3be9, "Quanta Wistron", ALC269_FIXUP_AMIC),
5417 SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_AMIC),
5418 SND_PCI_QUIRK(0x17ff, 0x059a, "Quanta EL3", ALC269_FIXUP_DMIC),
5419 SND_PCI_QUIRK(0x17ff, 0x059b, "Quanta JR1", ALC269_FIXUP_DMIC),
5420#endif
5421 {}
5422};
5423
5424static const struct alc_model_fixup alc269_fixup_models[] = {
5425 {.id = ALC269_FIXUP_AMIC, .name = "laptop-amic"},
5426 {.id = ALC269_FIXUP_DMIC, .name = "laptop-dmic"},
Takashi Iwai1d045db2011-07-07 18:23:21 +02005427 {}
5428};
5429
5430
5431static int alc269_fill_coef(struct hda_codec *codec)
5432{
5433 int val;
5434
Takashi Iwai1bb7e432011-10-17 16:50:59 +02005435 if ((alc_get_coef0(codec) & 0x00ff) < 0x015) {
Takashi Iwai1d045db2011-07-07 18:23:21 +02005436 alc_write_coef_idx(codec, 0xf, 0x960b);
5437 alc_write_coef_idx(codec, 0xe, 0x8817);
5438 }
5439
Takashi Iwai1bb7e432011-10-17 16:50:59 +02005440 if ((alc_get_coef0(codec) & 0x00ff) == 0x016) {
Takashi Iwai1d045db2011-07-07 18:23:21 +02005441 alc_write_coef_idx(codec, 0xf, 0x960b);
5442 alc_write_coef_idx(codec, 0xe, 0x8814);
5443 }
5444
Takashi Iwai1bb7e432011-10-17 16:50:59 +02005445 if ((alc_get_coef0(codec) & 0x00ff) == 0x017) {
Takashi Iwai1d045db2011-07-07 18:23:21 +02005446 val = alc_read_coef_idx(codec, 0x04);
5447 /* Power up output pin */
5448 alc_write_coef_idx(codec, 0x04, val | (1<<11));
5449 }
5450
Takashi Iwai1bb7e432011-10-17 16:50:59 +02005451 if ((alc_get_coef0(codec) & 0x00ff) == 0x018) {
Takashi Iwai1d045db2011-07-07 18:23:21 +02005452 val = alc_read_coef_idx(codec, 0xd);
5453 if ((val & 0x0c00) >> 10 != 0x1) {
5454 /* Capless ramp up clock control */
5455 alc_write_coef_idx(codec, 0xd, val | (1<<10));
5456 }
5457 val = alc_read_coef_idx(codec, 0x17);
5458 if ((val & 0x01c0) >> 6 != 0x4) {
5459 /* Class D power on reset */
5460 alc_write_coef_idx(codec, 0x17, val | (1<<7));
5461 }
5462 }
5463
5464 val = alc_read_coef_idx(codec, 0xd); /* Class D */
5465 alc_write_coef_idx(codec, 0xd, val | (1<<14));
5466
5467 val = alc_read_coef_idx(codec, 0x4); /* HP */
5468 alc_write_coef_idx(codec, 0x4, val | (1<<11));
5469
5470 return 0;
5471}
5472
5473/*
5474 */
Takashi Iwai1d045db2011-07-07 18:23:21 +02005475static int patch_alc269(struct hda_codec *codec)
5476{
5477 struct alc_spec *spec;
Takashi Iwai20ca0c32011-10-17 16:00:35 +02005478 int err = 0;
Takashi Iwai1d045db2011-07-07 18:23:21 +02005479
5480 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
5481 if (spec == NULL)
5482 return -ENOMEM;
5483
5484 codec->spec = spec;
5485
5486 spec->mixer_nid = 0x0b;
5487
5488 alc_auto_parse_customize_define(codec);
5489
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02005490 err = alc_codec_rename_from_preset(codec);
5491 if (err < 0)
5492 goto error;
5493
Takashi Iwai1d045db2011-07-07 18:23:21 +02005494 if (codec->vendor_id == 0x10ec0269) {
5495 spec->codec_variant = ALC269_TYPE_ALC269VA;
Takashi Iwai1bb7e432011-10-17 16:50:59 +02005496 switch (alc_get_coef0(codec) & 0x00f0) {
5497 case 0x0010:
Takashi Iwai1d045db2011-07-07 18:23:21 +02005498 if (codec->bus->pci->subsystem_vendor == 0x1025 &&
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02005499 spec->cdefine.platform_type == 1)
Takashi Iwai20ca0c32011-10-17 16:00:35 +02005500 err = alc_codec_rename(codec, "ALC271X");
Takashi Iwai1d045db2011-07-07 18:23:21 +02005501 spec->codec_variant = ALC269_TYPE_ALC269VB;
Takashi Iwai1bb7e432011-10-17 16:50:59 +02005502 break;
5503 case 0x0020:
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02005504 if (codec->bus->pci->subsystem_vendor == 0x17aa &&
5505 codec->bus->pci->subsystem_device == 0x21f3)
Takashi Iwai20ca0c32011-10-17 16:00:35 +02005506 err = alc_codec_rename(codec, "ALC3202");
Takashi Iwai1d045db2011-07-07 18:23:21 +02005507 spec->codec_variant = ALC269_TYPE_ALC269VC;
Takashi Iwai1bb7e432011-10-17 16:50:59 +02005508 break;
5509 default:
Takashi Iwai1d045db2011-07-07 18:23:21 +02005510 alc_fix_pll_init(codec, 0x20, 0x04, 15);
Takashi Iwai1bb7e432011-10-17 16:50:59 +02005511 }
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02005512 if (err < 0)
5513 goto error;
Takashi Iwai1d045db2011-07-07 18:23:21 +02005514 alc269_fill_coef(codec);
5515 }
5516
Takashi Iwaia4297b52011-08-23 18:40:12 +02005517 alc_pick_fixup(codec, alc269_fixup_models,
5518 alc269_fixup_tbl, alc269_fixups);
5519 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
Takashi Iwai1d045db2011-07-07 18:23:21 +02005520
Takashi Iwaia4297b52011-08-23 18:40:12 +02005521 /* automatic parse from the BIOS config */
5522 err = alc269_parse_auto_config(codec);
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02005523 if (err < 0)
5524 goto error;
Takashi Iwai1d045db2011-07-07 18:23:21 +02005525
Takashi Iwai60a6a842011-07-27 14:01:24 +02005526 if (!spec->no_analog && !spec->adc_nids) {
Takashi Iwai1d045db2011-07-07 18:23:21 +02005527 alc_auto_fill_adc_caps(codec);
5528 alc_rebuild_imux_for_auto_mic(codec);
5529 alc_remove_invalid_adc_nids(codec);
5530 }
5531
Takashi Iwai3e6179b2011-07-08 16:55:13 +02005532 if (!spec->no_analog && !spec->cap_mixer)
Takashi Iwai1d045db2011-07-07 18:23:21 +02005533 set_capture_mixer(codec);
Takashi Iwai3e6179b2011-07-08 16:55:13 +02005534
5535 if (!spec->no_analog && has_cdefine_beep(codec)) {
5536 err = snd_hda_attach_beep_device(codec, 0x1);
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02005537 if (err < 0)
5538 goto error;
Takashi Iwai1d045db2011-07-07 18:23:21 +02005539 set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
Takashi Iwai3e6179b2011-07-08 16:55:13 +02005540 }
Takashi Iwai1d045db2011-07-07 18:23:21 +02005541
5542 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
5543
Takashi Iwai1d045db2011-07-07 18:23:21 +02005544 codec->patch_ops = alc_patch_ops;
Takashi Iwai2a439522011-07-26 09:52:50 +02005545#ifdef CONFIG_PM
Takashi Iwai1d045db2011-07-07 18:23:21 +02005546 codec->patch_ops.resume = alc269_resume;
5547#endif
Takashi Iwaia4297b52011-08-23 18:40:12 +02005548 spec->init_hook = alc_auto_init_std;
Takashi Iwai1d045db2011-07-07 18:23:21 +02005549 spec->shutup = alc269_shutup;
5550
Takashi Iwai1d045db2011-07-07 18:23:21 +02005551#ifdef CONFIG_SND_HDA_POWER_SAVE
5552 if (!spec->loopback.amplist)
5553 spec->loopback.amplist = alc269_loopbacks;
5554 if (alc269_mic2_for_mute_led(codec))
5555 codec->patch_ops.check_power_status = alc269_mic2_mute_check_ps;
5556#endif
5557
5558 return 0;
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02005559
5560 error:
5561 alc_free(codec);
5562 return err;
Takashi Iwai1d045db2011-07-07 18:23:21 +02005563}
5564
5565/*
5566 * ALC861
5567 */
5568
Takashi Iwai1d045db2011-07-07 18:23:21 +02005569static int alc861_parse_auto_config(struct hda_codec *codec)
5570{
Takashi Iwai1d045db2011-07-07 18:23:21 +02005571 static const hda_nid_t alc861_ignore[] = { 0x1d, 0 };
Takashi Iwai3e6179b2011-07-08 16:55:13 +02005572 static const hda_nid_t alc861_ssids[] = { 0x0e, 0x0f, 0x0b, 0 };
5573 return alc_parse_auto_config(codec, alc861_ignore, alc861_ssids);
Takashi Iwai1d045db2011-07-07 18:23:21 +02005574}
5575
Takashi Iwai1d045db2011-07-07 18:23:21 +02005576#ifdef CONFIG_SND_HDA_POWER_SAVE
5577static const struct hda_amp_list alc861_loopbacks[] = {
5578 { 0x15, HDA_INPUT, 0 },
5579 { 0x15, HDA_INPUT, 1 },
5580 { 0x15, HDA_INPUT, 2 },
5581 { 0x15, HDA_INPUT, 3 },
5582 { } /* end */
5583};
5584#endif
5585
5586
5587/* Pin config fixes */
5588enum {
5589 PINFIX_FSC_AMILO_PI1505,
5590};
5591
5592static const struct alc_fixup alc861_fixups[] = {
5593 [PINFIX_FSC_AMILO_PI1505] = {
5594 .type = ALC_FIXUP_PINS,
5595 .v.pins = (const struct alc_pincfg[]) {
5596 { 0x0b, 0x0221101f }, /* HP */
5597 { 0x0f, 0x90170310 }, /* speaker */
5598 { }
5599 }
5600 },
5601};
5602
5603static const struct snd_pci_quirk alc861_fixup_tbl[] = {
5604 SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", PINFIX_FSC_AMILO_PI1505),
5605 {}
5606};
5607
5608/*
5609 */
Takashi Iwai1d045db2011-07-07 18:23:21 +02005610static int patch_alc861(struct hda_codec *codec)
5611{
5612 struct alc_spec *spec;
Takashi Iwai1d045db2011-07-07 18:23:21 +02005613 int err;
5614
5615 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
5616 if (spec == NULL)
5617 return -ENOMEM;
5618
5619 codec->spec = spec;
5620
5621 spec->mixer_nid = 0x15;
5622
Takashi Iwaicb4e4822011-08-23 17:34:25 +02005623 alc_pick_fixup(codec, NULL, alc861_fixup_tbl, alc861_fixups);
5624 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
Takashi Iwai1d045db2011-07-07 18:23:21 +02005625
Takashi Iwaicb4e4822011-08-23 17:34:25 +02005626 /* automatic parse from the BIOS config */
5627 err = alc861_parse_auto_config(codec);
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02005628 if (err < 0)
5629 goto error;
Takashi Iwai1d045db2011-07-07 18:23:21 +02005630
Takashi Iwai60a6a842011-07-27 14:01:24 +02005631 if (!spec->no_analog && !spec->adc_nids) {
Takashi Iwai1d045db2011-07-07 18:23:21 +02005632 alc_auto_fill_adc_caps(codec);
5633 alc_rebuild_imux_for_auto_mic(codec);
5634 alc_remove_invalid_adc_nids(codec);
5635 }
5636
Takashi Iwai3e6179b2011-07-08 16:55:13 +02005637 if (!spec->no_analog && !spec->cap_mixer)
Takashi Iwai1d045db2011-07-07 18:23:21 +02005638 set_capture_mixer(codec);
Takashi Iwai3e6179b2011-07-08 16:55:13 +02005639
5640 if (!spec->no_analog) {
5641 err = snd_hda_attach_beep_device(codec, 0x23);
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02005642 if (err < 0)
5643 goto error;
Takashi Iwai3e6179b2011-07-08 16:55:13 +02005644 set_beep_amp(spec, 0x23, 0, HDA_OUTPUT);
5645 }
Takashi Iwai1d045db2011-07-07 18:23:21 +02005646
Takashi Iwai1d045db2011-07-07 18:23:21 +02005647 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
5648
5649 codec->patch_ops = alc_patch_ops;
Takashi Iwaicb4e4822011-08-23 17:34:25 +02005650 spec->init_hook = alc_auto_init_std;
Takashi Iwai1d045db2011-07-07 18:23:21 +02005651#ifdef CONFIG_SND_HDA_POWER_SAVE
Takashi Iwaicb4e4822011-08-23 17:34:25 +02005652 spec->power_hook = alc_power_eapd;
Takashi Iwai1d045db2011-07-07 18:23:21 +02005653 if (!spec->loopback.amplist)
5654 spec->loopback.amplist = alc861_loopbacks;
5655#endif
5656
5657 return 0;
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02005658
5659 error:
5660 alc_free(codec);
5661 return err;
Takashi Iwai1d045db2011-07-07 18:23:21 +02005662}
5663
5664/*
5665 * ALC861-VD support
5666 *
5667 * Based on ALC882
5668 *
5669 * In addition, an independent DAC
5670 */
5671#ifdef CONFIG_SND_HDA_POWER_SAVE
5672#define alc861vd_loopbacks alc880_loopbacks
5673#endif
5674
Takashi Iwai1d045db2011-07-07 18:23:21 +02005675static int alc861vd_parse_auto_config(struct hda_codec *codec)
5676{
Takashi Iwai1d045db2011-07-07 18:23:21 +02005677 static const hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
Takashi Iwai3e6179b2011-07-08 16:55:13 +02005678 static const hda_nid_t alc861vd_ssids[] = { 0x15, 0x1b, 0x14, 0 };
5679 return alc_parse_auto_config(codec, alc861vd_ignore, alc861vd_ssids);
Takashi Iwai1d045db2011-07-07 18:23:21 +02005680}
5681
Takashi Iwai1d045db2011-07-07 18:23:21 +02005682enum {
Takashi Iwai8fdcb6f2011-08-23 17:28:55 +02005683 ALC660VD_FIX_ASUS_GPIO1,
5684 ALC861VD_FIX_DALLAS,
Takashi Iwai1d045db2011-07-07 18:23:21 +02005685};
5686
Takashi Iwai8fdcb6f2011-08-23 17:28:55 +02005687/* exclude VREF80 */
5688static void alc861vd_fixup_dallas(struct hda_codec *codec,
5689 const struct alc_fixup *fix, int action)
5690{
5691 if (action == ALC_FIXUP_ACT_PRE_PROBE) {
5692 snd_hda_override_pin_caps(codec, 0x18, 0x00001714);
5693 snd_hda_override_pin_caps(codec, 0x19, 0x0000171c);
5694 }
5695}
5696
Takashi Iwai1d045db2011-07-07 18:23:21 +02005697static const struct alc_fixup alc861vd_fixups[] = {
5698 [ALC660VD_FIX_ASUS_GPIO1] = {
5699 .type = ALC_FIXUP_VERBS,
5700 .v.verbs = (const struct hda_verb[]) {
Takashi Iwai8fdcb6f2011-08-23 17:28:55 +02005701 /* reset GPIO1 */
Takashi Iwai1d045db2011-07-07 18:23:21 +02005702 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
5703 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
5704 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
5705 { }
5706 }
5707 },
Takashi Iwai8fdcb6f2011-08-23 17:28:55 +02005708 [ALC861VD_FIX_DALLAS] = {
5709 .type = ALC_FIXUP_FUNC,
5710 .v.func = alc861vd_fixup_dallas,
5711 },
Takashi Iwai1d045db2011-07-07 18:23:21 +02005712};
5713
5714static const struct snd_pci_quirk alc861vd_fixup_tbl[] = {
Takashi Iwai8fdcb6f2011-08-23 17:28:55 +02005715 SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_FIX_DALLAS),
Takashi Iwai1d045db2011-07-07 18:23:21 +02005716 SND_PCI_QUIRK(0x1043, 0x1339, "ASUS A7-K", ALC660VD_FIX_ASUS_GPIO1),
Takashi Iwai8fdcb6f2011-08-23 17:28:55 +02005717 SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_FIX_DALLAS),
Takashi Iwai1d045db2011-07-07 18:23:21 +02005718 {}
5719};
5720
5721static const struct hda_verb alc660vd_eapd_verbs[] = {
5722 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
5723 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
5724 { }
5725};
5726
5727/*
5728 */
Takashi Iwai1d045db2011-07-07 18:23:21 +02005729static int patch_alc861vd(struct hda_codec *codec)
5730{
5731 struct alc_spec *spec;
Takashi Iwaicb4e4822011-08-23 17:34:25 +02005732 int err;
Takashi Iwai1d045db2011-07-07 18:23:21 +02005733
5734 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
5735 if (spec == NULL)
5736 return -ENOMEM;
5737
5738 codec->spec = spec;
5739
5740 spec->mixer_nid = 0x0b;
5741
Takashi Iwaicb4e4822011-08-23 17:34:25 +02005742 alc_pick_fixup(codec, NULL, alc861vd_fixup_tbl, alc861vd_fixups);
5743 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
Takashi Iwai1d045db2011-07-07 18:23:21 +02005744
Takashi Iwaicb4e4822011-08-23 17:34:25 +02005745 /* automatic parse from the BIOS config */
5746 err = alc861vd_parse_auto_config(codec);
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02005747 if (err < 0)
5748 goto error;
Takashi Iwai1d045db2011-07-07 18:23:21 +02005749
Takashi Iwai1d045db2011-07-07 18:23:21 +02005750 if (codec->vendor_id == 0x10ec0660) {
5751 /* always turn on EAPD */
5752 add_verb(spec, alc660vd_eapd_verbs);
5753 }
5754
Takashi Iwai60a6a842011-07-27 14:01:24 +02005755 if (!spec->no_analog && !spec->adc_nids) {
Takashi Iwai1d045db2011-07-07 18:23:21 +02005756 alc_auto_fill_adc_caps(codec);
5757 alc_rebuild_imux_for_auto_mic(codec);
5758 alc_remove_invalid_adc_nids(codec);
5759 }
5760
Takashi Iwai3e6179b2011-07-08 16:55:13 +02005761 if (!spec->no_analog && !spec->cap_mixer)
5762 set_capture_mixer(codec);
5763
5764 if (!spec->no_analog) {
5765 err = snd_hda_attach_beep_device(codec, 0x23);
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02005766 if (err < 0)
5767 goto error;
Takashi Iwai3e6179b2011-07-08 16:55:13 +02005768 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
5769 }
Takashi Iwai1d045db2011-07-07 18:23:21 +02005770
Takashi Iwai1d045db2011-07-07 18:23:21 +02005771 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
5772
5773 codec->patch_ops = alc_patch_ops;
5774
Takashi Iwaicb4e4822011-08-23 17:34:25 +02005775 spec->init_hook = alc_auto_init_std;
Takashi Iwai1d045db2011-07-07 18:23:21 +02005776 spec->shutup = alc_eapd_shutup;
5777#ifdef CONFIG_SND_HDA_POWER_SAVE
5778 if (!spec->loopback.amplist)
5779 spec->loopback.amplist = alc861vd_loopbacks;
5780#endif
5781
5782 return 0;
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02005783
5784 error:
5785 alc_free(codec);
5786 return err;
Takashi Iwai1d045db2011-07-07 18:23:21 +02005787}
5788
5789/*
5790 * ALC662 support
5791 *
5792 * ALC662 is almost identical with ALC880 but has cleaner and more flexible
5793 * configuration. Each pin widget can choose any input DACs and a mixer.
5794 * Each ADC is connected from a mixer of all inputs. This makes possible
5795 * 6-channel independent captures.
5796 *
5797 * In addition, an independent DAC for the multi-playback (not used in this
5798 * driver yet).
5799 */
5800#ifdef CONFIG_SND_HDA_POWER_SAVE
5801#define alc662_loopbacks alc880_loopbacks
5802#endif
5803
5804/*
5805 * BIOS auto configuration
5806 */
5807
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005808static int alc662_parse_auto_config(struct hda_codec *codec)
5809{
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02005810 static const hda_nid_t alc662_ignore[] = { 0x1d, 0 };
Takashi Iwai3e6179b2011-07-08 16:55:13 +02005811 static const hda_nid_t alc663_ssids[] = { 0x15, 0x1b, 0x14, 0x21 };
5812 static const hda_nid_t alc662_ssids[] = { 0x15, 0x1b, 0x14, 0 };
5813 const hda_nid_t *ssids;
Takashi Iwaiee979a142008-09-02 15:42:20 +02005814
Kailang Yang6227cdc2010-02-25 08:36:52 +01005815 if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 ||
5816 codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670)
Takashi Iwai3e6179b2011-07-08 16:55:13 +02005817 ssids = alc663_ssids;
Kailang Yang6227cdc2010-02-25 08:36:52 +01005818 else
Takashi Iwai3e6179b2011-07-08 16:55:13 +02005819 ssids = alc662_ssids;
5820 return alc_parse_auto_config(codec, alc662_ignore, ssids);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02005821}
5822
Todd Broch6be79482010-12-07 16:51:05 -08005823static void alc272_fixup_mario(struct hda_codec *codec,
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01005824 const struct alc_fixup *fix, int action)
Takashi Iwai6fc398c2011-01-13 14:36:37 +01005825{
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01005826 if (action != ALC_FIXUP_ACT_PROBE)
Takashi Iwai6fc398c2011-01-13 14:36:37 +01005827 return;
Todd Broch6be79482010-12-07 16:51:05 -08005828 if (snd_hda_override_amp_caps(codec, 0x2, HDA_OUTPUT,
5829 (0x3b << AC_AMPCAP_OFFSET_SHIFT) |
5830 (0x3b << AC_AMPCAP_NUM_STEPS_SHIFT) |
5831 (0x03 << AC_AMPCAP_STEP_SIZE_SHIFT) |
5832 (0 << AC_AMPCAP_MUTE_SHIFT)))
5833 printk(KERN_WARNING
5834 "hda_codec: failed to override amp caps for NID 0x2\n");
5835}
5836
David Henningsson6cb3b702010-09-09 08:51:44 +02005837enum {
Daniel T Chen2df03512010-10-10 22:39:28 -04005838 ALC662_FIXUP_ASPIRE,
David Henningsson6cb3b702010-09-09 08:51:44 +02005839 ALC662_FIXUP_IDEAPAD,
Todd Broch6be79482010-12-07 16:51:05 -08005840 ALC272_FIXUP_MARIO,
Anisse Astierd2ebd472011-01-20 12:36:21 +01005841 ALC662_FIXUP_CZC_P10T,
David Henningsson94024cd2011-04-29 14:10:55 +02005842 ALC662_FIXUP_SKU_IGNORE,
Takashi Iwaie59ea3e2011-06-29 17:21:00 +02005843 ALC662_FIXUP_HP_RP5800,
Takashi Iwai53c334a2011-08-23 18:27:14 +02005844 ALC662_FIXUP_ASUS_MODE1,
5845 ALC662_FIXUP_ASUS_MODE2,
5846 ALC662_FIXUP_ASUS_MODE3,
5847 ALC662_FIXUP_ASUS_MODE4,
5848 ALC662_FIXUP_ASUS_MODE5,
5849 ALC662_FIXUP_ASUS_MODE6,
5850 ALC662_FIXUP_ASUS_MODE7,
5851 ALC662_FIXUP_ASUS_MODE8,
David Henningsson6cb3b702010-09-09 08:51:44 +02005852};
5853
5854static const struct alc_fixup alc662_fixups[] = {
Daniel T Chen2df03512010-10-10 22:39:28 -04005855 [ALC662_FIXUP_ASPIRE] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01005856 .type = ALC_FIXUP_PINS,
5857 .v.pins = (const struct alc_pincfg[]) {
Daniel T Chen2df03512010-10-10 22:39:28 -04005858 { 0x15, 0x99130112 }, /* subwoofer */
5859 { }
5860 }
5861 },
David Henningsson6cb3b702010-09-09 08:51:44 +02005862 [ALC662_FIXUP_IDEAPAD] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01005863 .type = ALC_FIXUP_PINS,
5864 .v.pins = (const struct alc_pincfg[]) {
David Henningsson6cb3b702010-09-09 08:51:44 +02005865 { 0x17, 0x99130112 }, /* subwoofer */
5866 { }
5867 }
5868 },
Todd Broch6be79482010-12-07 16:51:05 -08005869 [ALC272_FIXUP_MARIO] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01005870 .type = ALC_FIXUP_FUNC,
5871 .v.func = alc272_fixup_mario,
Anisse Astierd2ebd472011-01-20 12:36:21 +01005872 },
5873 [ALC662_FIXUP_CZC_P10T] = {
5874 .type = ALC_FIXUP_VERBS,
5875 .v.verbs = (const struct hda_verb[]) {
5876 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 0},
5877 {}
5878 }
5879 },
David Henningsson94024cd2011-04-29 14:10:55 +02005880 [ALC662_FIXUP_SKU_IGNORE] = {
5881 .type = ALC_FIXUP_SKU,
5882 .v.sku = ALC_FIXUP_SKU_IGNORE,
Takashi Iwaic6b35872011-03-28 12:05:31 +02005883 },
Takashi Iwaie59ea3e2011-06-29 17:21:00 +02005884 [ALC662_FIXUP_HP_RP5800] = {
5885 .type = ALC_FIXUP_PINS,
5886 .v.pins = (const struct alc_pincfg[]) {
5887 { 0x14, 0x0221201f }, /* HP out */
5888 { }
5889 },
5890 .chained = true,
5891 .chain_id = ALC662_FIXUP_SKU_IGNORE
5892 },
Takashi Iwai53c334a2011-08-23 18:27:14 +02005893 [ALC662_FIXUP_ASUS_MODE1] = {
5894 .type = ALC_FIXUP_PINS,
5895 .v.pins = (const struct alc_pincfg[]) {
5896 { 0x14, 0x99130110 }, /* speaker */
5897 { 0x18, 0x01a19c20 }, /* mic */
5898 { 0x19, 0x99a3092f }, /* int-mic */
5899 { 0x21, 0x0121401f }, /* HP out */
5900 { }
5901 },
5902 .chained = true,
5903 .chain_id = ALC662_FIXUP_SKU_IGNORE
5904 },
5905 [ALC662_FIXUP_ASUS_MODE2] = {
Takashi Iwai2996bdb2011-08-18 16:02:24 +02005906 .type = ALC_FIXUP_PINS,
5907 .v.pins = (const struct alc_pincfg[]) {
5908 { 0x14, 0x99130110 }, /* speaker */
5909 { 0x18, 0x01a19820 }, /* mic */
5910 { 0x19, 0x99a3092f }, /* int-mic */
5911 { 0x1b, 0x0121401f }, /* HP out */
5912 { }
5913 },
Takashi Iwai53c334a2011-08-23 18:27:14 +02005914 .chained = true,
5915 .chain_id = ALC662_FIXUP_SKU_IGNORE
5916 },
5917 [ALC662_FIXUP_ASUS_MODE3] = {
5918 .type = ALC_FIXUP_PINS,
5919 .v.pins = (const struct alc_pincfg[]) {
5920 { 0x14, 0x99130110 }, /* speaker */
5921 { 0x15, 0x0121441f }, /* HP */
5922 { 0x18, 0x01a19840 }, /* mic */
5923 { 0x19, 0x99a3094f }, /* int-mic */
5924 { 0x21, 0x01211420 }, /* HP2 */
5925 { }
5926 },
5927 .chained = true,
5928 .chain_id = ALC662_FIXUP_SKU_IGNORE
5929 },
5930 [ALC662_FIXUP_ASUS_MODE4] = {
5931 .type = ALC_FIXUP_PINS,
5932 .v.pins = (const struct alc_pincfg[]) {
5933 { 0x14, 0x99130110 }, /* speaker */
5934 { 0x16, 0x99130111 }, /* speaker */
5935 { 0x18, 0x01a19840 }, /* mic */
5936 { 0x19, 0x99a3094f }, /* int-mic */
5937 { 0x21, 0x0121441f }, /* HP */
5938 { }
5939 },
5940 .chained = true,
5941 .chain_id = ALC662_FIXUP_SKU_IGNORE
5942 },
5943 [ALC662_FIXUP_ASUS_MODE5] = {
5944 .type = ALC_FIXUP_PINS,
5945 .v.pins = (const struct alc_pincfg[]) {
5946 { 0x14, 0x99130110 }, /* speaker */
5947 { 0x15, 0x0121441f }, /* HP */
5948 { 0x16, 0x99130111 }, /* speaker */
5949 { 0x18, 0x01a19840 }, /* mic */
5950 { 0x19, 0x99a3094f }, /* int-mic */
5951 { }
5952 },
5953 .chained = true,
5954 .chain_id = ALC662_FIXUP_SKU_IGNORE
5955 },
5956 [ALC662_FIXUP_ASUS_MODE6] = {
5957 .type = ALC_FIXUP_PINS,
5958 .v.pins = (const struct alc_pincfg[]) {
5959 { 0x14, 0x99130110 }, /* speaker */
5960 { 0x15, 0x01211420 }, /* HP2 */
5961 { 0x18, 0x01a19840 }, /* mic */
5962 { 0x19, 0x99a3094f }, /* int-mic */
5963 { 0x1b, 0x0121441f }, /* HP */
5964 { }
5965 },
5966 .chained = true,
5967 .chain_id = ALC662_FIXUP_SKU_IGNORE
5968 },
5969 [ALC662_FIXUP_ASUS_MODE7] = {
5970 .type = ALC_FIXUP_PINS,
5971 .v.pins = (const struct alc_pincfg[]) {
5972 { 0x14, 0x99130110 }, /* speaker */
5973 { 0x17, 0x99130111 }, /* speaker */
5974 { 0x18, 0x01a19840 }, /* mic */
5975 { 0x19, 0x99a3094f }, /* int-mic */
5976 { 0x1b, 0x01214020 }, /* HP */
5977 { 0x21, 0x0121401f }, /* HP */
5978 { }
5979 },
5980 .chained = true,
5981 .chain_id = ALC662_FIXUP_SKU_IGNORE
5982 },
5983 [ALC662_FIXUP_ASUS_MODE8] = {
5984 .type = ALC_FIXUP_PINS,
5985 .v.pins = (const struct alc_pincfg[]) {
5986 { 0x14, 0x99130110 }, /* speaker */
5987 { 0x12, 0x99a30970 }, /* int-mic */
5988 { 0x15, 0x01214020 }, /* HP */
5989 { 0x17, 0x99130111 }, /* speaker */
5990 { 0x18, 0x01a19840 }, /* mic */
5991 { 0x21, 0x0121401f }, /* HP */
5992 { }
5993 },
5994 .chained = true,
5995 .chain_id = ALC662_FIXUP_SKU_IGNORE
Takashi Iwai2996bdb2011-08-18 16:02:24 +02005996 },
David Henningsson6cb3b702010-09-09 08:51:44 +02005997};
5998
Takashi Iwaia9111322011-05-02 11:30:18 +02005999static const struct snd_pci_quirk alc662_fixup_tbl[] = {
Takashi Iwai53c334a2011-08-23 18:27:14 +02006000 SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_FIXUP_ASUS_MODE2),
David Henningssona6c47a82011-02-10 15:39:19 +01006001 SND_PCI_QUIRK(0x1025, 0x0308, "Acer Aspire 8942G", ALC662_FIXUP_ASPIRE),
David Henningsson94024cd2011-04-29 14:10:55 +02006002 SND_PCI_QUIRK(0x1025, 0x031c, "Gateway NV79", ALC662_FIXUP_SKU_IGNORE),
Daniel T Chen2df03512010-10-10 22:39:28 -04006003 SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE),
Takashi Iwaie59ea3e2011-06-29 17:21:00 +02006004 SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800),
Takashi Iwai53c334a2011-08-23 18:27:14 +02006005 SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_FIXUP_ASUS_MODE2),
Daniel T Chena0e90ac2010-11-20 10:20:35 -05006006 SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD),
Valentine Sinitsynd4118582010-10-01 22:24:08 +06006007 SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD),
David Henningsson6cb3b702010-09-09 08:51:44 +02006008 SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD),
Anisse Astierd2ebd472011-01-20 12:36:21 +01006009 SND_PCI_QUIRK(0x1b35, 0x2206, "CZC P10T", ALC662_FIXUP_CZC_P10T),
Takashi Iwai53c334a2011-08-23 18:27:14 +02006010
6011#if 0
6012 /* Below is a quirk table taken from the old code.
6013 * Basically the device should work as is without the fixup table.
6014 * If BIOS doesn't give a proper info, enable the corresponding
6015 * fixup entry.
6016 */
6017 SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC662_FIXUP_ASUS_MODE1),
6018 SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC662_FIXUP_ASUS_MODE3),
6019 SND_PCI_QUIRK(0x1043, 0x1173, "ASUS K73Jn", ALC662_FIXUP_ASUS_MODE1),
6020 SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC662_FIXUP_ASUS_MODE3),
6021 SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC662_FIXUP_ASUS_MODE1),
6022 SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
6023 SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC662_FIXUP_ASUS_MODE1),
6024 SND_PCI_QUIRK(0x1043, 0x1303, "ASUS G60J", ALC662_FIXUP_ASUS_MODE1),
6025 SND_PCI_QUIRK(0x1043, 0x1333, "ASUS G60Jx", ALC662_FIXUP_ASUS_MODE1),
6026 SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
6027 SND_PCI_QUIRK(0x1043, 0x13e3, "ASUS N71JA", ALC662_FIXUP_ASUS_MODE7),
6028 SND_PCI_QUIRK(0x1043, 0x1463, "ASUS N71", ALC662_FIXUP_ASUS_MODE7),
6029 SND_PCI_QUIRK(0x1043, 0x14d3, "ASUS G72", ALC662_FIXUP_ASUS_MODE8),
6030 SND_PCI_QUIRK(0x1043, 0x1563, "ASUS N90", ALC662_FIXUP_ASUS_MODE3),
6031 SND_PCI_QUIRK(0x1043, 0x15d3, "ASUS N50SF F50SF", ALC662_FIXUP_ASUS_MODE1),
6032 SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
6033 SND_PCI_QUIRK(0x1043, 0x16f3, "ASUS K40C K50C", ALC662_FIXUP_ASUS_MODE2),
6034 SND_PCI_QUIRK(0x1043, 0x1733, "ASUS N81De", ALC662_FIXUP_ASUS_MODE1),
6035 SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
6036 SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC662_FIXUP_ASUS_MODE6),
6037 SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC662_FIXUP_ASUS_MODE6),
6038 SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
6039 SND_PCI_QUIRK(0x1043, 0x1793, "ASUS F50GX", ALC662_FIXUP_ASUS_MODE1),
6040 SND_PCI_QUIRK(0x1043, 0x17b3, "ASUS F70SL", ALC662_FIXUP_ASUS_MODE3),
6041 SND_PCI_QUIRK(0x1043, 0x17f3, "ASUS X58LE", ALC662_FIXUP_ASUS_MODE2),
6042 SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
6043 SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC662_FIXUP_ASUS_MODE5),
6044 SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC662_FIXUP_ASUS_MODE6),
6045 SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
6046 SND_PCI_QUIRK(0x1043, 0x1853, "ASUS F50Z", ALC662_FIXUP_ASUS_MODE1),
6047 SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
6048 SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
6049 SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC662_FIXUP_ASUS_MODE3),
6050 SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC662_FIXUP_ASUS_MODE3),
6051 SND_PCI_QUIRK(0x1043, 0x18b3, "ASUS N80Vc", ALC662_FIXUP_ASUS_MODE1),
6052 SND_PCI_QUIRK(0x1043, 0x18c3, "ASUS VX5", ALC662_FIXUP_ASUS_MODE1),
6053 SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS N81Te", ALC662_FIXUP_ASUS_MODE1),
6054 SND_PCI_QUIRK(0x1043, 0x18f3, "ASUS N505Tp", ALC662_FIXUP_ASUS_MODE1),
6055 SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC662_FIXUP_ASUS_MODE1),
6056 SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
6057 SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_FIXUP_ASUS_MODE2),
6058 SND_PCI_QUIRK(0x1043, 0x1943, "ASUS Vx3V", ALC662_FIXUP_ASUS_MODE1),
6059 SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC662_FIXUP_ASUS_MODE1),
6060 SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC662_FIXUP_ASUS_MODE3),
6061 SND_PCI_QUIRK(0x1043, 0x1983, "ASUS N5051A", ALC662_FIXUP_ASUS_MODE1),
6062 SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC662_FIXUP_ASUS_MODE1),
6063 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC662_FIXUP_ASUS_MODE1),
6064 SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_FIXUP_ASUS_MODE2),
6065 SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC662_FIXUP_ASUS_MODE1),
6066 SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC662_FIXUP_ASUS_MODE4),
6067#endif
David Henningsson6cb3b702010-09-09 08:51:44 +02006068 {}
6069};
6070
Todd Broch6be79482010-12-07 16:51:05 -08006071static const struct alc_model_fixup alc662_fixup_models[] = {
6072 {.id = ALC272_FIXUP_MARIO, .name = "mario"},
Takashi Iwai53c334a2011-08-23 18:27:14 +02006073 {.id = ALC662_FIXUP_ASUS_MODE1, .name = "asus-mode1"},
6074 {.id = ALC662_FIXUP_ASUS_MODE2, .name = "asus-mode2"},
6075 {.id = ALC662_FIXUP_ASUS_MODE3, .name = "asus-mode3"},
6076 {.id = ALC662_FIXUP_ASUS_MODE4, .name = "asus-mode4"},
6077 {.id = ALC662_FIXUP_ASUS_MODE5, .name = "asus-mode5"},
6078 {.id = ALC662_FIXUP_ASUS_MODE6, .name = "asus-mode6"},
6079 {.id = ALC662_FIXUP_ASUS_MODE7, .name = "asus-mode7"},
6080 {.id = ALC662_FIXUP_ASUS_MODE8, .name = "asus-mode8"},
Todd Broch6be79482010-12-07 16:51:05 -08006081 {}
6082};
David Henningsson6cb3b702010-09-09 08:51:44 +02006083
6084
Takashi Iwai1d045db2011-07-07 18:23:21 +02006085/*
6086 */
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006087static int patch_alc662(struct hda_codec *codec)
6088{
6089 struct alc_spec *spec;
Takashi Iwai20ca0c32011-10-17 16:00:35 +02006090 int err = 0;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006091
6092 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
6093 if (!spec)
6094 return -ENOMEM;
6095
6096 codec->spec = spec;
6097
Takashi Iwai1f0f4b82011-06-27 10:52:59 +02006098 spec->mixer_nid = 0x0b;
6099
Takashi Iwai53c334a2011-08-23 18:27:14 +02006100 /* handle multiple HPs as is */
6101 spec->parse_flags = HDA_PINCFG_NO_HP_FIXUP;
6102
Kailang Yangda00c242010-03-19 11:23:45 +01006103 alc_auto_parse_customize_define(codec);
6104
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02006105 alc_fix_pll_init(codec, 0x20, 0x04, 15);
6106
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02006107 err = alc_codec_rename_from_preset(codec);
6108 if (err < 0)
6109 goto error;
6110
Takashi Iwai1bb7e432011-10-17 16:50:59 +02006111 if ((alc_get_coef0(codec) & (1 << 14)) &&
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02006112 codec->bus->pci->subsystem_vendor == 0x1025 &&
6113 spec->cdefine.platform_type == 1) {
6114 if (alc_codec_rename(codec, "ALC272X") < 0)
6115 goto error;
Takashi Iwai20ca0c32011-10-17 16:00:35 +02006116 }
Kailang Yang274693f2009-12-03 10:07:50 +01006117
Takashi Iwaib9c51062011-08-24 18:08:07 +02006118 alc_pick_fixup(codec, alc662_fixup_models,
6119 alc662_fixup_tbl, alc662_fixups);
6120 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
6121 /* automatic parse from the BIOS config */
6122 err = alc662_parse_auto_config(codec);
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02006123 if (err < 0)
6124 goto error;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006125
Takashi Iwai60a6a842011-07-27 14:01:24 +02006126 if (!spec->no_analog && !spec->adc_nids) {
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02006127 alc_auto_fill_adc_caps(codec);
Takashi Iwai21268962011-07-07 15:01:13 +02006128 alc_rebuild_imux_for_auto_mic(codec);
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02006129 alc_remove_invalid_adc_nids(codec);
Takashi Iwaidd704692009-08-11 08:45:11 +02006130 }
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006131
Takashi Iwai3e6179b2011-07-08 16:55:13 +02006132 if (!spec->no_analog && !spec->cap_mixer)
Takashi Iwaib59bdf32009-08-11 09:47:30 +02006133 set_capture_mixer(codec);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01006134
Takashi Iwai3e6179b2011-07-08 16:55:13 +02006135 if (!spec->no_analog && has_cdefine_beep(codec)) {
6136 err = snd_hda_attach_beep_device(codec, 0x1);
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02006137 if (err < 0)
6138 goto error;
Kailang Yangda00c242010-03-19 11:23:45 +01006139 switch (codec->vendor_id) {
6140 case 0x10ec0662:
6141 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
6142 break;
6143 case 0x10ec0272:
6144 case 0x10ec0663:
6145 case 0x10ec0665:
6146 set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
6147 break;
6148 case 0x10ec0273:
6149 set_beep_amp(spec, 0x0b, 0x03, HDA_INPUT);
6150 break;
6151 }
Kailang Yangcec27c82010-02-04 14:18:18 +01006152 }
Takashi Iwai2134ea42008-01-10 16:53:55 +01006153
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01006154 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
6155
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006156 codec->patch_ops = alc_patch_ops;
Takashi Iwaib9c51062011-08-24 18:08:07 +02006157 spec->init_hook = alc_auto_init_std;
Takashi Iwai1c716152011-04-07 10:37:16 +02006158 spec->shutup = alc_eapd_shutup;
David Henningsson6cb3b702010-09-09 08:51:44 +02006159
Takashi Iwaicb53c622007-08-10 17:21:45 +02006160#ifdef CONFIG_SND_HDA_POWER_SAVE
6161 if (!spec->loopback.amplist)
6162 spec->loopback.amplist = alc662_loopbacks;
6163#endif
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006164
6165 return 0;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006166
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02006167 error:
6168 alc_free(codec);
6169 return err;
Kailang Yangb478b992011-05-18 11:51:15 +02006170}
6171
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006172/*
Kailang Yangd1eb57f2010-06-23 16:25:26 +02006173 * ALC680 support
6174 */
Kailang Yangd1eb57f2010-06-23 16:25:26 +02006175
Kailang Yangd1eb57f2010-06-23 16:25:26 +02006176static int alc680_parse_auto_config(struct hda_codec *codec)
6177{
Takashi Iwai3e6179b2011-07-08 16:55:13 +02006178 return alc_parse_auto_config(codec, NULL, NULL);
Kailang Yangd1eb57f2010-06-23 16:25:26 +02006179}
6180
Kailang Yangd1eb57f2010-06-23 16:25:26 +02006181/*
Kailang Yangd1eb57f2010-06-23 16:25:26 +02006182 */
Kailang Yangd1eb57f2010-06-23 16:25:26 +02006183static int patch_alc680(struct hda_codec *codec)
6184{
6185 struct alc_spec *spec;
Kailang Yangd1eb57f2010-06-23 16:25:26 +02006186 int err;
6187
6188 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
6189 if (spec == NULL)
6190 return -ENOMEM;
6191
6192 codec->spec = spec;
6193
Takashi Iwai1f0f4b82011-06-27 10:52:59 +02006194 /* ALC680 has no aa-loopback mixer */
6195
Takashi Iwai1ebec5f2011-08-15 13:21:48 +02006196 /* automatic parse from the BIOS config */
6197 err = alc680_parse_auto_config(codec);
6198 if (err < 0) {
6199 alc_free(codec);
6200 return err;
Kailang Yangd1eb57f2010-06-23 16:25:26 +02006201 }
6202
Takashi Iwai3e6179b2011-07-08 16:55:13 +02006203 if (!spec->no_analog && !spec->cap_mixer)
Kailang Yangd1eb57f2010-06-23 16:25:26 +02006204 set_capture_mixer(codec);
6205
Kailang Yangd1eb57f2010-06-23 16:25:26 +02006206 codec->patch_ops = alc_patch_ops;
Takashi Iwai1ebec5f2011-08-15 13:21:48 +02006207 spec->init_hook = alc_auto_init_std;
Kailang Yangd1eb57f2010-06-23 16:25:26 +02006208
6209 return 0;
6210}
6211
6212/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07006213 * patch entries
6214 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006215static const struct hda_codec_preset snd_hda_preset_realtek[] = {
Kailang Yang296f0332011-05-18 11:52:36 +02006216 { .id = 0x10ec0221, .name = "ALC221", .patch = patch_alc269 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07006217 { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
Kailang Yangdf694da2005-12-05 19:42:22 +01006218 { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
Kailang Yangf6a92242007-12-13 16:52:54 +01006219 { .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 },
Kailang Yanga361d842007-06-05 12:30:55 +02006220 { .id = 0x10ec0268, .name = "ALC268", .patch = patch_alc268 },
Kailang Yangf6a92242007-12-13 16:52:54 +01006221 { .id = 0x10ec0269, .name = "ALC269", .patch = patch_alc269 },
Kailang Yangebb83ee2009-12-17 12:23:00 +01006222 { .id = 0x10ec0270, .name = "ALC270", .patch = patch_alc269 },
Kailang Yang01afd412008-10-15 11:22:09 +02006223 { .id = 0x10ec0272, .name = "ALC272", .patch = patch_alc662 },
Kailang Yangebb83ee2009-12-17 12:23:00 +01006224 { .id = 0x10ec0275, .name = "ALC275", .patch = patch_alc269 },
Kailang Yang296f0332011-05-18 11:52:36 +02006225 { .id = 0x10ec0276, .name = "ALC276", .patch = patch_alc269 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +01006226 { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006227 .patch = patch_alc861 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +01006228 { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
6229 { .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 },
6230 { .id = 0x10ec0862, .name = "ALC861-VD", .patch = patch_alc861vd },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006231 { .id = 0x10ec0662, .rev = 0x100002, .name = "ALC662 rev2",
Takashi Iwai4953550a2009-06-30 15:28:30 +02006232 .patch = patch_alc882 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006233 { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1",
6234 .patch = patch_alc662 },
David Henningssoncc667a72011-10-18 14:07:51 +02006235 { .id = 0x10ec0662, .rev = 0x100300, .name = "ALC662 rev3",
6236 .patch = patch_alc662 },
Kailang Yang6dda9f42008-05-27 12:05:31 +02006237 { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 },
Kailang Yangcec27c82010-02-04 14:18:18 +01006238 { .id = 0x10ec0665, .name = "ALC665", .patch = patch_alc662 },
Kailang Yang6227cdc2010-02-25 08:36:52 +01006239 { .id = 0x10ec0670, .name = "ALC670", .patch = patch_alc662 },
Kailang Yangd1eb57f2010-06-23 16:25:26 +02006240 { .id = 0x10ec0680, .name = "ALC680", .patch = patch_alc680 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +01006241 { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07006242 { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
Takashi Iwai4953550a2009-06-30 15:28:30 +02006243 { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc882 },
Clive Messer669faba2008-09-30 15:49:13 +02006244 { .id = 0x10ec0885, .rev = 0x100101, .name = "ALC889A",
Takashi Iwai4953550a2009-06-30 15:28:30 +02006245 .patch = patch_alc882 },
Takashi Iwaicb308f92008-04-16 14:13:29 +02006246 { .id = 0x10ec0885, .rev = 0x100103, .name = "ALC889A",
Takashi Iwai4953550a2009-06-30 15:28:30 +02006247 .patch = patch_alc882 },
Kailang Yangdf694da2005-12-05 19:42:22 +01006248 { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02006249 { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc882 },
Kailang Yang44426082008-10-15 11:18:05 +02006250 { .id = 0x10ec0888, .rev = 0x100101, .name = "ALC1200",
Takashi Iwai4953550a2009-06-30 15:28:30 +02006251 .patch = patch_alc882 },
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02006252 { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc882 },
Takashi Iwai4953550a2009-06-30 15:28:30 +02006253 { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc882 },
Kailang Yang274693f2009-12-03 10:07:50 +01006254 { .id = 0x10ec0892, .name = "ALC892", .patch = patch_alc662 },
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02006255 { .id = 0x10ec0899, .name = "ALC898", .patch = patch_alc882 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07006256 {} /* terminator */
6257};
Takashi Iwai1289e9e2008-11-27 15:47:11 +01006258
6259MODULE_ALIAS("snd-hda-codec-id:10ec*");
6260
6261MODULE_LICENSE("GPL");
6262MODULE_DESCRIPTION("Realtek HD-audio codec");
6263
6264static struct hda_codec_preset_list realtek_list = {
6265 .preset = snd_hda_preset_realtek,
6266 .owner = THIS_MODULE,
6267};
6268
6269static int __init patch_realtek_init(void)
6270{
6271 return snd_hda_add_codec_preset(&realtek_list);
6272}
6273
6274static void __exit patch_realtek_exit(void)
6275{
6276 snd_hda_delete_codec_preset(&realtek_list);
6277}
6278
6279module_init(patch_realtek_init)
6280module_exit(patch_realtek_exit)