blob: a3046144f1499ac71a4c71e7e13956c369d98370 [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 Woithe409a3e92012-03-27 13:01:01 +10309 * Jonathan Woithe <jwoithe@just42.net>
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"
Takashi Iwai23d30f22012-05-07 17:17:32 +020035#include "hda_auto_parser.h"
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090036#include "hda_beep.h"
Takashi Iwai1835a0f2011-10-27 22:12:46 +020037#include "hda_jack.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070038
Takashi Iwai1d045db2011-07-07 18:23:21 +020039/* unsol event tags */
40#define ALC_FRONT_EVENT 0x01
41#define ALC_DCVOL_EVENT 0x02
42#define ALC_HP_EVENT 0x04
43#define ALC_MIC_EVENT 0x08
Takashi Iwaid4a86d82010-06-23 17:51:26 +020044
Kailang Yangdf694da2005-12-05 19:42:22 +010045/* for GPIO Poll */
46#define GPIO_MASK 0x03
47
Takashi Iwai4a79ba32009-04-22 16:31:35 +020048/* extra amp-initialization sequence types */
49enum {
50 ALC_INIT_NONE,
51 ALC_INIT_DEFAULT,
52 ALC_INIT_GPIO1,
53 ALC_INIT_GPIO2,
54 ALC_INIT_GPIO3,
55};
56
Kailang Yangda00c242010-03-19 11:23:45 +010057struct alc_customize_define {
58 unsigned int sku_cfg;
59 unsigned char port_connectivity;
60 unsigned char check_sum;
61 unsigned char customization;
62 unsigned char external_amp;
63 unsigned int enable_pcbeep:1;
64 unsigned int platform_type:1;
65 unsigned int swap:1;
66 unsigned int override:1;
David Henningsson90622912010-10-14 14:50:18 +020067 unsigned int fixup:1; /* Means that this sku is set by driver, not read from hw */
Kailang Yangda00c242010-03-19 11:23:45 +010068};
69
Takashi Iwaice764ab2011-04-27 16:35:23 +020070struct alc_multi_io {
71 hda_nid_t pin; /* multi-io widget pin NID */
72 hda_nid_t dac; /* DAC to be connected */
73 unsigned int ctl_in; /* cached input-pin control value */
74};
75
Takashi Iwai23d30f22012-05-07 17:17:32 +020076/* make compatible with old code */
77#define alc_apply_pincfgs snd_hda_apply_pincfgs
78#define alc_apply_fixup snd_hda_apply_fixup
79#define alc_pick_fixup snd_hda_pick_fixup
80#define alc_fixup hda_fixup
81#define alc_pincfg hda_pintbl
82#define alc_model_fixup hda_model_fixup
83
84#define ALC_FIXUP_PINS HDA_FIXUP_PINS
85#define ALC_FIXUP_VERBS HDA_FIXUP_VERBS
86#define ALC_FIXUP_FUNC HDA_FIXUP_FUNC
87
88#define ALC_FIXUP_ACT_PRE_PROBE HDA_FIXUP_ACT_PRE_PROBE
89#define ALC_FIXUP_ACT_PROBE HDA_FIXUP_ACT_PROBE
90#define ALC_FIXUP_ACT_INIT HDA_FIXUP_ACT_INIT
91#define ALC_FIXUP_ACT_BUILD HDA_FIXUP_ACT_BUILD
92
93
Takashi Iwai30dcd3b2012-12-06 15:45:38 +010094#define MAX_NID_PATH_DEPTH 5
95
Takashi Iwai8dd48672012-12-14 18:19:04 +010096enum {
97 NID_PATH_VOL_CTL,
98 NID_PATH_MUTE_CTL,
99 NID_PATH_BOOST_CTL,
100 NID_PATH_NUM_CTLS
101};
102
Takashi Iwai36f0fd52012-12-12 17:25:00 +0100103/* Widget connection path
104 *
105 * For output, stored in the order of DAC -> ... -> pin,
106 * for input, pin -> ... -> ADC.
107 *
Takashi Iwai95e960c2012-12-10 17:27:57 +0100108 * idx[i] contains the source index number to select on of the widget path[i];
109 * e.g. idx[1] is the index of the DAC (path[0]) selected by path[1] widget
Takashi Iwai30dcd3b2012-12-06 15:45:38 +0100110 * multi[] indicates whether it's a selector widget with multi-connectors
111 * (i.e. the connection selection is mandatory)
112 * vol_ctl and mute_ctl contains the NIDs for the assigned mixers
113 */
114struct nid_path {
115 int depth;
116 hda_nid_t path[MAX_NID_PATH_DEPTH];
117 unsigned char idx[MAX_NID_PATH_DEPTH];
118 unsigned char multi[MAX_NID_PATH_DEPTH];
Takashi Iwai8dd48672012-12-14 18:19:04 +0100119 unsigned int ctls[NID_PATH_NUM_CTLS]; /* NID_PATH_XXX_CTL */
Takashi Iwai130e5f02012-12-14 16:09:29 +0100120 bool active;
Takashi Iwai30dcd3b2012-12-06 15:45:38 +0100121};
122
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123struct alc_spec {
Takashi Iwai23d30f22012-05-07 17:17:32 +0200124 struct hda_gen_spec gen;
125
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126 /* codec parameterization */
Takashi Iwaia9111322011-05-02 11:30:18 +0200127 const struct snd_kcontrol_new *mixers[5]; /* mixer arrays */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128 unsigned int num_mixers;
Takashi Iwai45bdd1c2009-02-06 16:11:25 +0100129 unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130
Takashi Iwaiaa563af2009-07-31 10:05:11 +0200131 char stream_name_analog[32]; /* analog PCM stream */
Takashi Iwaia9111322011-05-02 11:30:18 +0200132 const struct hda_pcm_stream *stream_analog_playback;
133 const struct hda_pcm_stream *stream_analog_capture;
134 const struct hda_pcm_stream *stream_analog_alt_playback;
135 const struct hda_pcm_stream *stream_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136
Takashi Iwaiaa563af2009-07-31 10:05:11 +0200137 char stream_name_digital[32]; /* digital PCM stream */
Takashi Iwaia9111322011-05-02 11:30:18 +0200138 const struct hda_pcm_stream *stream_digital_playback;
139 const struct hda_pcm_stream *stream_digital_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140
141 /* playback */
Takashi Iwai16ded522005-06-10 19:58:24 +0200142 struct hda_multi_out multiout; /* playback set-up
143 * max_channels, dacs must be set
144 * dig_out_nid and hp_nid are optional
145 */
Takashi Iwai63300792008-01-24 15:31:36 +0100146 hda_nid_t alt_dac_nid;
Takashi Iwai6a05ac42009-02-13 11:19:09 +0100147 hda_nid_t slave_dig_outs[3]; /* optional - for auto-parsing */
Takashi Iwai8c441982009-01-20 18:30:20 +0100148 int dig_out_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149
150 /* capture */
151 unsigned int num_adc_nids;
Takashi Iwai27d31532012-12-18 08:57:05 +0100152 hda_nid_t adc_nids[AUTO_CFG_MAX_OUTS];
Takashi Iwai16ded522005-06-10 19:58:24 +0200153 hda_nid_t dig_in_nid; /* digital-in NID; optional */
Takashi Iwai1f0f4b82011-06-27 10:52:59 +0200154 hda_nid_t mixer_nid; /* analog-mixer NID */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155
Takashi Iwai840b64c2010-07-13 22:49:01 +0200156 /* capture setup for dynamic dual-adc switch */
Takashi Iwai840b64c2010-07-13 22:49:01 +0200157 hda_nid_t cur_adc;
158 unsigned int cur_adc_stream_tag;
159 unsigned int cur_adc_format;
160
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 /* capture source */
Takashi Iwai27d31532012-12-18 08:57:05 +0100162 struct hda_input_mux input_mux;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163 unsigned int cur_mux[3];
Takashi Iwai21268962011-07-07 15:01:13 +0200164 hda_nid_t ext_mic_pin;
165 hda_nid_t dock_mic_pin;
166 hda_nid_t int_mic_pin;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167
168 /* channel model */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100169 const struct hda_channel_mode *channel_mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170 int num_channel_mode;
Takashi Iwaib6adb572012-12-03 10:30:58 +0100171 int const_channel_count; /* min. channel count (for speakers) */
172 int ext_channel_count; /* current channel count for multi-io */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173
174 /* PCM information */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100175 struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */
Takashi Iwai41e41f12005-06-08 14:48:49 +0200176
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200177 /* dynamic controls, init_verbs and input_mux */
178 struct auto_pin_cfg autocfg;
Kailang Yangda00c242010-03-19 11:23:45 +0100179 struct alc_customize_define cdefine;
Takashi Iwai603c4012008-07-30 15:01:44 +0200180 struct snd_array kctls;
Takashi Iwai41923e42007-10-22 17:20:10 +0200181 hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
Takashi Iwai21268962011-07-07 15:01:13 +0200182 hda_nid_t imux_pins[HDA_MAX_NUM_INPUTS];
183 unsigned int dyn_adc_idx[HDA_MAX_NUM_INPUTS];
184 int int_mic_idx, ext_mic_idx, dock_mic_idx; /* for auto-mic */
Takashi Iwai125821a2012-06-22 14:30:29 +0200185 hda_nid_t inv_dmic_pin;
Takashi Iwai37c04202012-12-18 14:22:45 +0100186 hda_nid_t shared_mic_vref_pin;
Takashi Iwai834be882006-03-01 14:16:17 +0100187
Takashi Iwai463419d2012-12-05 14:17:37 +0100188 /* DAC list */
189 int num_all_dacs;
190 hda_nid_t all_dacs[16];
191
Takashi Iwaic9967f12012-12-14 16:39:22 +0100192 /* path list */
193 struct snd_array paths;
Takashi Iwaic2fd19c2012-12-12 18:02:41 +0100194
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100195 /* hooks */
196 void (*init_hook)(struct hda_codec *codec);
Takashi Iwai83012a72012-08-24 18:38:08 +0200197#ifdef CONFIG_PM
Daniel T Chenc97259d2009-12-27 18:52:08 -0500198 void (*power_hook)(struct hda_codec *codec);
Hector Martinf5de24b2009-12-20 22:51:31 +0100199#endif
Takashi Iwai1c716152011-04-07 10:37:16 +0200200 void (*shutup)(struct hda_codec *codec);
Takashi Iwai24519912011-08-16 15:08:49 +0200201 void (*automute_hook)(struct hda_codec *codec);
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100202
Takashi Iwai834be882006-03-01 14:16:17 +0100203 /* for pin sensing */
David Henningsson42cf0d02011-09-20 12:04:56 +0200204 unsigned int hp_jack_present:1;
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200205 unsigned int line_jack_present:1;
Takashi Iwaie9427962011-04-28 15:46:07 +0200206 unsigned int master_mute:1;
Takashi Iwai6c819492009-08-10 18:47:44 +0200207 unsigned int auto_mic:1;
David Henningsson42cf0d02011-09-20 12:04:56 +0200208 unsigned int automute_speaker:1; /* automute speaker outputs */
209 unsigned int automute_lo:1; /* automute LO outputs */
210 unsigned int detect_hp:1; /* Headphone detection enabled */
211 unsigned int detect_lo:1; /* Line-out detection enabled */
212 unsigned int automute_speaker_possible:1; /* there are speakers and either LO or HP */
213 unsigned int automute_lo_possible:1; /* there are line outs and HP */
Takashi Iwai31150f22012-01-30 10:54:08 +0100214 unsigned int keep_vref_in_automute:1; /* Don't clear VREF in automute */
Takashi Iwaicb53c622007-08-10 17:21:45 +0200215
Takashi Iwaie64f14f2009-01-20 18:32:55 +0100216 /* other flags */
Takashi Iwai20c18f52012-12-18 14:33:21 +0100217 unsigned int need_dac_fix:1; /* need to limit DACs for multi channels */
Takashi Iwaie64f14f2009-01-20 18:32:55 +0100218 unsigned int no_analog :1; /* digital I/O only */
Takashi Iwai21268962011-07-07 15:01:13 +0200219 unsigned int dyn_adc_switch:1; /* switch ADCs (for ALC275) */
Takashi Iwai24de1832011-11-07 17:13:39 +0100220 unsigned int shared_mic_hp:1; /* HP/Mic-in sharing */
Takashi Iwai125821a2012-06-22 14:30:29 +0200221 unsigned int inv_dmic_fixup:1; /* has inverted digital-mic workaround */
222 unsigned int inv_dmic_muted:1; /* R-ch of inv d-mic is muted? */
Takashi Iwaie427c232012-07-29 10:04:08 +0200223 unsigned int no_primary_hp:1; /* Don't prefer HP pins to speaker pins */
Takashi Iwaid922b512011-04-28 12:18:53 +0200224
Takashi Iwai20c18f52012-12-18 14:33:21 +0100225 unsigned int parse_flags; /* passed to snd_hda_parse_pin_defcfg() */
Takashi Iwaid922b512011-04-28 12:18:53 +0200226
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200227 int init_amp;
Takashi Iwaid433a672010-09-20 15:11:54 +0200228 int codec_variant; /* flag for other variants */
Takashi Iwaie64f14f2009-01-20 18:32:55 +0100229
Takashi Iwai2134ea42008-01-10 16:53:55 +0100230 /* for virtual master */
231 hda_nid_t vmaster_nid;
Takashi Iwaid2f344b2012-03-12 16:59:58 +0100232 struct hda_vmaster_mute_hook vmaster_mute;
Takashi Iwai83012a72012-08-24 18:38:08 +0200233#ifdef CONFIG_PM
Takashi Iwaicb53c622007-08-10 17:21:45 +0200234 struct hda_loopback_check loopback;
Takashi Iwai164f73e2012-02-21 11:27:09 +0100235 int num_loopbacks;
236 struct hda_amp_list loopback_list[8];
Takashi Iwaicb53c622007-08-10 17:21:45 +0200237#endif
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +0200238
239 /* for PLL fix */
240 hda_nid_t pll_nid;
241 unsigned int pll_coef_idx, pll_coef_bit;
Takashi Iwai1bb7e432011-10-17 16:50:59 +0200242 unsigned int coef0;
Takashi Iwaib5bfbc62011-01-13 14:22:32 +0100243
Takashi Iwaice764ab2011-04-27 16:35:23 +0200244 /* multi-io */
245 int multi_ios;
246 struct alc_multi_io multi_io[4];
Takashi Iwai23c09b02011-08-19 09:05:35 +0200247
248 /* bind volumes */
249 struct snd_array bind_ctls;
Kailang Yangdf694da2005-12-05 19:42:22 +0100250};
251
Takashi Iwai44c02402011-07-08 15:14:19 +0200252static bool check_amp_caps(struct hda_codec *codec, hda_nid_t nid,
253 int dir, unsigned int bits)
254{
255 if (!nid)
256 return false;
257 if (get_wcaps(codec, nid) & (1 << (dir + 1)))
258 if (query_amp_caps(codec, nid, dir) & bits)
259 return true;
260 return false;
261}
262
263#define nid_has_mute(codec, nid, dir) \
264 check_amp_caps(codec, nid, dir, AC_AMPCAP_MUTE)
265#define nid_has_volume(codec, nid, dir) \
266 check_amp_caps(codec, nid, dir, AC_AMPCAP_NUM_STEPS)
267
Takashi Iwai666a70d2012-12-17 20:29:29 +0100268static struct nid_path *
269get_nid_path(struct hda_codec *codec, hda_nid_t from_nid, hda_nid_t to_nid);
270static void activate_path(struct hda_codec *codec, struct nid_path *path,
271 bool enable, bool add_aamix);
272
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273/*
274 * input MUX handling
275 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200276static int alc_mux_enum_info(struct snd_kcontrol *kcontrol,
277 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278{
279 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
280 struct alc_spec *spec = codec->spec;
Takashi Iwai27d31532012-12-18 08:57:05 +0100281 return snd_hda_input_mux_info(&spec->input_mux, uinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282}
283
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200284static int alc_mux_enum_get(struct snd_kcontrol *kcontrol,
285 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286{
287 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
288 struct alc_spec *spec = codec->spec;
289 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
290
291 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
292 return 0;
293}
294
Takashi Iwai666a70d2012-12-17 20:29:29 +0100295static hda_nid_t get_adc_nid(struct hda_codec *codec, int adc_idx, int imux_idx)
296{
297 struct alc_spec *spec = codec->spec;
298 if (spec->dyn_adc_switch)
299 adc_idx = spec->dyn_adc_idx[imux_idx];
300 return spec->adc_nids[adc_idx];
301}
302
Takashi Iwai21268962011-07-07 15:01:13 +0200303static bool alc_dyn_adc_pcm_resetup(struct hda_codec *codec, int cur)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304{
Takashi Iwai21268962011-07-07 15:01:13 +0200305 struct alc_spec *spec = codec->spec;
306 hda_nid_t new_adc = spec->adc_nids[spec->dyn_adc_idx[cur]];
307
308 if (spec->cur_adc && spec->cur_adc != new_adc) {
309 /* stream is running, let's swap the current ADC */
310 __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1);
311 spec->cur_adc = new_adc;
312 snd_hda_codec_setup_stream(codec, new_adc,
313 spec->cur_adc_stream_tag, 0,
314 spec->cur_adc_format);
315 return true;
316 }
317 return false;
318}
319
Takashi Iwai24de1832011-11-07 17:13:39 +0100320static void call_update_outputs(struct hda_codec *codec);
Takashi Iwai125821a2012-06-22 14:30:29 +0200321static void alc_inv_dmic_sync(struct hda_codec *codec, bool force);
Takashi Iwai666a70d2012-12-17 20:29:29 +0100322static void alc_inv_dmic_sync_adc(struct hda_codec *codec, int adc_idx);
Takashi Iwai24de1832011-11-07 17:13:39 +0100323
David Henningsson00227f12012-06-27 18:45:44 +0200324/* for shared I/O, change the pin-control accordingly */
325static void update_shared_mic_hp(struct hda_codec *codec, bool set_as_mic)
326{
327 struct alc_spec *spec = codec->spec;
328 unsigned int val;
329 hda_nid_t pin = spec->autocfg.inputs[1].pin;
330 /* NOTE: this assumes that there are only two inputs, the
331 * first is the real internal mic and the second is HP/mic jack.
332 */
333
334 val = snd_hda_get_default_vref(codec, pin);
335
336 /* This pin does not have vref caps - let's enable vref on pin 0x18
337 instead, as suggested by Realtek */
Takashi Iwai37c04202012-12-18 14:22:45 +0100338 if (val == AC_PINCTL_VREF_HIZ && spec->shared_mic_vref_pin) {
339 const hda_nid_t vref_pin = spec->shared_mic_vref_pin;
340 unsigned int vref_val = snd_hda_get_default_vref(codec, vref_pin);
341 if (vref_val != AC_PINCTL_VREF_HIZ)
342 snd_hda_set_pin_ctl(codec, vref_pin, PIN_IN | (set_as_mic ? vref_val : 0));
David Henningsson00227f12012-06-27 18:45:44 +0200343 }
344
345 val = set_as_mic ? val | PIN_IN : PIN_HP;
346 snd_hda_set_pin_ctl(codec, pin, val);
347
348 spec->automute_speaker = !set_as_mic;
349 call_update_outputs(codec);
350}
Takashi Iwai21268962011-07-07 15:01:13 +0200351
352/* select the given imux item; either unmute exclusively or select the route */
353static int alc_mux_select(struct hda_codec *codec, unsigned int adc_idx,
354 unsigned int idx, bool force)
355{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 struct alc_spec *spec = codec->spec;
Takashi Iwaicd896c32008-11-18 12:36:33 +0100357 const struct hda_input_mux *imux;
Takashi Iwai666a70d2012-12-17 20:29:29 +0100358 struct nid_path *path;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359
Takashi Iwai27d31532012-12-18 08:57:05 +0100360 imux = &spec->input_mux;
361 if (!imux->num_items)
Takashi Iwaicce4aa32011-12-02 15:29:12 +0100362 return 0;
Takashi Iwaicd896c32008-11-18 12:36:33 +0100363
Takashi Iwai21268962011-07-07 15:01:13 +0200364 if (idx >= imux->num_items)
365 idx = imux->num_items - 1;
366 if (spec->cur_mux[adc_idx] == idx && !force)
367 return 0;
Takashi Iwai666a70d2012-12-17 20:29:29 +0100368
369 path = get_nid_path(codec, spec->imux_pins[spec->cur_mux[adc_idx]],
370 spec->adc_nids[adc_idx]);
371 if (!path)
372 return 0;
373 if (path->active)
374 activate_path(codec, path, false, false);
375
Takashi Iwai21268962011-07-07 15:01:13 +0200376 spec->cur_mux[adc_idx] = idx;
377
David Henningsson00227f12012-06-27 18:45:44 +0200378 if (spec->shared_mic_hp)
379 update_shared_mic_hp(codec, spec->cur_mux[adc_idx]);
Takashi Iwai24de1832011-11-07 17:13:39 +0100380
Takashi Iwai666a70d2012-12-17 20:29:29 +0100381 if (spec->dyn_adc_switch)
Takashi Iwai21268962011-07-07 15:01:13 +0200382 alc_dyn_adc_pcm_resetup(codec, idx);
Takashi Iwai21268962011-07-07 15:01:13 +0200383
Takashi Iwai666a70d2012-12-17 20:29:29 +0100384 path = get_nid_path(codec, spec->imux_pins[idx],
385 get_adc_nid(codec, adc_idx, idx));
386 if (!path)
387 return 0;
388 if (path->active)
389 return 0;
390 activate_path(codec, path, true, false);
Takashi Iwai125821a2012-06-22 14:30:29 +0200391 alc_inv_dmic_sync(codec, true);
Takashi Iwai21268962011-07-07 15:01:13 +0200392 return 1;
393}
394
395static int alc_mux_enum_put(struct snd_kcontrol *kcontrol,
396 struct snd_ctl_elem_value *ucontrol)
397{
398 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
399 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
400 return alc_mux_select(codec, adc_idx,
401 ucontrol->value.enumerated.item[0], false);
Takashi Iwai54cbc9a2008-10-31 15:24:04 +0100402}
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200403
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404/*
Takashi Iwai23f0c042009-02-26 13:03:58 +0100405 * set up the input pin config (depending on the given auto-pin type)
406 */
407static void alc_set_input_pin(struct hda_codec *codec, hda_nid_t nid,
408 int auto_pin_type)
409{
410 unsigned int val = PIN_IN;
Takashi Iwai47408602012-04-20 13:06:53 +0200411 if (auto_pin_type == AUTO_PIN_MIC)
412 val |= snd_hda_get_default_vref(codec, nid);
Takashi Iwaicdd03ce2012-04-20 12:34:50 +0200413 snd_hda_set_pin_ctl(codec, nid, val);
Takashi Iwai23f0c042009-02-26 13:03:58 +0100414}
415
416/*
Takashi Iwai1d045db2011-07-07 18:23:21 +0200417 * Append the given mixer and verb elements for the later use
418 * The mixer array is referred in build_controls(), and init_verbs are
419 * called in init().
Takashi Iwaid88897e2008-10-31 15:01:37 +0100420 */
Takashi Iwaia9111322011-05-02 11:30:18 +0200421static void add_mixer(struct alc_spec *spec, const struct snd_kcontrol_new *mix)
Takashi Iwaid88897e2008-10-31 15:01:37 +0100422{
423 if (snd_BUG_ON(spec->num_mixers >= ARRAY_SIZE(spec->mixers)))
424 return;
425 spec->mixers[spec->num_mixers++] = mix;
426}
427
Takashi Iwaid88897e2008-10-31 15:01:37 +0100428/*
Takashi Iwai1d045db2011-07-07 18:23:21 +0200429 * GPIO setup tables, used in initialization
Kailang Yangdf694da2005-12-05 19:42:22 +0100430 */
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200431/* Enable GPIO mask and set output */
Takashi Iwaia9111322011-05-02 11:30:18 +0200432static const struct hda_verb alc_gpio1_init_verbs[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200433 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
434 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
435 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
436 { }
437};
438
Takashi Iwaia9111322011-05-02 11:30:18 +0200439static const struct hda_verb alc_gpio2_init_verbs[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200440 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
441 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
442 {0x01, AC_VERB_SET_GPIO_DATA, 0x02},
443 { }
444};
445
Takashi Iwaia9111322011-05-02 11:30:18 +0200446static const struct hda_verb alc_gpio3_init_verbs[] = {
Kailang Yangbdd148a2007-05-08 15:19:08 +0200447 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
448 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
449 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
450 { }
451};
452
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +0200453/*
454 * Fix hardware PLL issue
455 * On some codecs, the analog PLL gating control must be off while
456 * the default value is 1.
457 */
458static void alc_fix_pll(struct hda_codec *codec)
459{
460 struct alc_spec *spec = codec->spec;
461 unsigned int val;
462
463 if (!spec->pll_nid)
464 return;
465 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
466 spec->pll_coef_idx);
467 val = snd_hda_codec_read(codec, spec->pll_nid, 0,
468 AC_VERB_GET_PROC_COEF, 0);
469 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
470 spec->pll_coef_idx);
471 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_PROC_COEF,
472 val & ~(1 << spec->pll_coef_bit));
473}
474
475static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
476 unsigned int coef_idx, unsigned int coef_bit)
477{
478 struct alc_spec *spec = codec->spec;
479 spec->pll_nid = nid;
480 spec->pll_coef_idx = coef_idx;
481 spec->pll_coef_bit = coef_bit;
482 alc_fix_pll(codec);
483}
484
Takashi Iwai1d045db2011-07-07 18:23:21 +0200485/*
Takashi Iwai1d045db2011-07-07 18:23:21 +0200486 * Jack detections for HP auto-mute and mic-switch
487 */
488
489/* check each pin in the given array; returns true if any of them is plugged */
490static bool detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins)
Kailang Yangc9b58002007-10-16 14:30:01 +0200491{
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200492 int i, present = 0;
Kailang Yangc9b58002007-10-16 14:30:01 +0200493
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200494 for (i = 0; i < num_pins; i++) {
495 hda_nid_t nid = pins[i];
Takashi Iwaibb35feb2010-09-08 15:30:49 +0200496 if (!nid)
497 break;
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200498 present |= snd_hda_jack_detect(codec, nid);
Takashi Iwaibb35feb2010-09-08 15:30:49 +0200499 }
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200500 return present;
501}
Takashi Iwaibb35feb2010-09-08 15:30:49 +0200502
Takashi Iwai1d045db2011-07-07 18:23:21 +0200503/* standard HP/line-out auto-mute helper */
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200504static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins,
Takashi Iwaie9427962011-04-28 15:46:07 +0200505 bool mute, bool hp_out)
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200506{
507 struct alc_spec *spec = codec->spec;
Takashi Iwaie9427962011-04-28 15:46:07 +0200508 unsigned int pin_bits = mute ? 0 : (hp_out ? PIN_HP : PIN_OUT);
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200509 int i;
510
511 for (i = 0; i < num_pins; i++) {
512 hda_nid_t nid = pins[i];
Takashi Iwai31150f22012-01-30 10:54:08 +0100513 unsigned int val;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +0200514 if (!nid)
515 break;
Takashi Iwaib8a47c72012-12-14 14:20:34 +0100516 /* don't reset VREF value in case it's controlling
517 * the amp (see alc861_fixup_asus_amp_vref_0f())
518 */
519 if (spec->keep_vref_in_automute) {
520 val = snd_hda_codec_read(codec, nid, 0,
Takashi Iwai31150f22012-01-30 10:54:08 +0100521 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
Takashi Iwaib8a47c72012-12-14 14:20:34 +0100522 val &= ~PIN_HP;
523 } else
524 val = 0;
525 val |= pin_bits;
526 snd_hda_set_pin_ctl(codec, nid, val);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +0200527 }
Kailang Yangc9b58002007-10-16 14:30:01 +0200528}
529
David Henningsson42cf0d02011-09-20 12:04:56 +0200530/* Toggle outputs muting */
531static void update_outputs(struct hda_codec *codec)
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200532{
533 struct alc_spec *spec = codec->spec;
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200534 int on;
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200535
Takashi Iwaic0a20262011-06-10 15:28:15 +0200536 /* Control HP pins/amps depending on master_mute state;
537 * in general, HP pins/amps control should be enabled in all cases,
538 * but currently set only for master_mute, just to be safe
539 */
Takashi Iwai24de1832011-11-07 17:13:39 +0100540 if (!spec->shared_mic_hp) /* don't change HP-pin when shared with mic */
541 do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins),
Takashi Iwaic0a20262011-06-10 15:28:15 +0200542 spec->autocfg.hp_pins, spec->master_mute, true);
543
David Henningsson42cf0d02011-09-20 12:04:56 +0200544 if (!spec->automute_speaker)
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200545 on = 0;
546 else
David Henningsson42cf0d02011-09-20 12:04:56 +0200547 on = spec->hp_jack_present | spec->line_jack_present;
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200548 on |= spec->master_mute;
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200549 do_automute(codec, ARRAY_SIZE(spec->autocfg.speaker_pins),
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200550 spec->autocfg.speaker_pins, on, false);
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200551
552 /* toggle line-out mutes if needed, too */
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200553 /* if LO is a copy of either HP or Speaker, don't need to handle it */
554 if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0] ||
555 spec->autocfg.line_out_pins[0] == spec->autocfg.speaker_pins[0])
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200556 return;
David Henningsson42cf0d02011-09-20 12:04:56 +0200557 if (!spec->automute_lo)
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200558 on = 0;
559 else
David Henningsson42cf0d02011-09-20 12:04:56 +0200560 on = spec->hp_jack_present;
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200561 on |= spec->master_mute;
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200562 do_automute(codec, ARRAY_SIZE(spec->autocfg.line_out_pins),
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200563 spec->autocfg.line_out_pins, on, false);
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200564}
565
David Henningsson42cf0d02011-09-20 12:04:56 +0200566static void call_update_outputs(struct hda_codec *codec)
Takashi Iwai24519912011-08-16 15:08:49 +0200567{
568 struct alc_spec *spec = codec->spec;
569 if (spec->automute_hook)
570 spec->automute_hook(codec);
571 else
David Henningsson42cf0d02011-09-20 12:04:56 +0200572 update_outputs(codec);
Takashi Iwai24519912011-08-16 15:08:49 +0200573}
574
Takashi Iwai1d045db2011-07-07 18:23:21 +0200575/* standard HP-automute helper */
David Henningsson29adc4b2012-09-25 11:31:00 +0200576static void alc_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *jack)
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200577{
578 struct alc_spec *spec = codec->spec;
579
David Henningsson42cf0d02011-09-20 12:04:56 +0200580 spec->hp_jack_present =
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200581 detect_jacks(codec, ARRAY_SIZE(spec->autocfg.hp_pins),
582 spec->autocfg.hp_pins);
David Henningsson42cf0d02011-09-20 12:04:56 +0200583 if (!spec->detect_hp || (!spec->automute_speaker && !spec->automute_lo))
Takashi Iwai3c715a92011-08-23 12:41:09 +0200584 return;
David Henningsson42cf0d02011-09-20 12:04:56 +0200585 call_update_outputs(codec);
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200586}
587
Takashi Iwai1d045db2011-07-07 18:23:21 +0200588/* standard line-out-automute helper */
David Henningsson29adc4b2012-09-25 11:31:00 +0200589static void alc_line_automute(struct hda_codec *codec, struct hda_jack_tbl *jack)
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200590{
591 struct alc_spec *spec = codec->spec;
592
David Henningssonf7f4b2322012-10-10 16:32:09 +0200593 if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT)
594 return;
Takashi Iwaie0d32e32011-09-26 15:19:55 +0200595 /* check LO jack only when it's different from HP */
596 if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0])
597 return;
598
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200599 spec->line_jack_present =
600 detect_jacks(codec, ARRAY_SIZE(spec->autocfg.line_out_pins),
601 spec->autocfg.line_out_pins);
David Henningsson42cf0d02011-09-20 12:04:56 +0200602 if (!spec->automute_speaker || !spec->detect_lo)
Takashi Iwai3c715a92011-08-23 12:41:09 +0200603 return;
David Henningsson42cf0d02011-09-20 12:04:56 +0200604 call_update_outputs(codec);
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200605}
606
Takashi Iwai1d045db2011-07-07 18:23:21 +0200607/* standard mic auto-switch helper */
David Henningsson29adc4b2012-09-25 11:31:00 +0200608static void alc_mic_automute(struct hda_codec *codec, struct hda_jack_tbl *jack)
Kailang Yang7fb0d782008-10-15 11:12:35 +0200609{
610 struct alc_spec *spec = codec->spec;
Takashi Iwai21268962011-07-07 15:01:13 +0200611 hda_nid_t *pins = spec->imux_pins;
Kailang Yang7fb0d782008-10-15 11:12:35 +0200612
Takashi Iwai480967d2012-12-18 14:29:52 +0100613 if (!spec->auto_mic)
Takashi Iwai6c819492009-08-10 18:47:44 +0200614 return;
Takashi Iwai21268962011-07-07 15:01:13 +0200615 if (snd_BUG_ON(spec->int_mic_idx < 0 || spec->ext_mic_idx < 0))
Takashi Iwai840b64c2010-07-13 22:49:01 +0200616 return;
Takashi Iwai840b64c2010-07-13 22:49:01 +0200617
Takashi Iwai21268962011-07-07 15:01:13 +0200618 if (snd_hda_jack_detect(codec, pins[spec->ext_mic_idx]))
619 alc_mux_select(codec, 0, spec->ext_mic_idx, false);
620 else if (spec->dock_mic_idx >= 0 &&
621 snd_hda_jack_detect(codec, pins[spec->dock_mic_idx]))
622 alc_mux_select(codec, 0, spec->dock_mic_idx, false);
623 else
624 alc_mux_select(codec, 0, spec->int_mic_idx, false);
Kailang Yang7fb0d782008-10-15 11:12:35 +0200625}
626
Takashi Iwaicf5a2272012-02-20 16:31:07 +0100627/* update the master volume per volume-knob's unsol event */
David Henningsson29adc4b2012-09-25 11:31:00 +0200628static void alc_update_knob_master(struct hda_codec *codec, struct hda_jack_tbl *jack)
Takashi Iwaicf5a2272012-02-20 16:31:07 +0100629{
630 unsigned int val;
631 struct snd_kcontrol *kctl;
632 struct snd_ctl_elem_value *uctl;
633
634 kctl = snd_hda_find_mixer_ctl(codec, "Master Playback Volume");
635 if (!kctl)
636 return;
637 uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
638 if (!uctl)
639 return;
David Henningsson29adc4b2012-09-25 11:31:00 +0200640 val = snd_hda_codec_read(codec, jack->nid, 0,
Takashi Iwaicf5a2272012-02-20 16:31:07 +0100641 AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
642 val &= HDA_AMP_VOLMASK;
643 uctl->value.integer.value[0] = val;
644 uctl->value.integer.value[1] = val;
645 kctl->put(kctl, uctl);
646 kfree(uctl);
647}
648
David Henningsson29adc4b2012-09-25 11:31:00 +0200649static void alc880_unsol_event(struct hda_codec *codec, unsigned int res)
Takashi Iwaif21d78e2012-01-19 12:10:29 +0100650{
David Henningsson29adc4b2012-09-25 11:31:00 +0200651 /* For some reason, the res given from ALC880 is broken.
652 Here we adjust it properly. */
653 snd_hda_jack_unsol_event(codec, res >> 2);
Takashi Iwaif21d78e2012-01-19 12:10:29 +0100654}
655
Takashi Iwai1d045db2011-07-07 18:23:21 +0200656/* call init functions of standard auto-mute helpers */
Kailang Yang7fb0d782008-10-15 11:12:35 +0200657static void alc_inithook(struct hda_codec *codec)
658{
David Henningsson29adc4b2012-09-25 11:31:00 +0200659 alc_hp_automute(codec, NULL);
660 alc_line_automute(codec, NULL);
661 alc_mic_automute(codec, NULL);
Kailang Yangc9b58002007-10-16 14:30:01 +0200662}
663
Kailang Yangf9423e72008-05-27 12:32:25 +0200664/* additional initialization for ALC888 variants */
665static void alc888_coef_init(struct hda_codec *codec)
666{
667 unsigned int tmp;
668
669 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0);
670 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
671 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
Takashi Iwai37db6232009-03-05 09:40:16 +0100672 if ((tmp & 0xf0) == 0x20)
Kailang Yangf9423e72008-05-27 12:32:25 +0200673 /* alc888S-VC */
674 snd_hda_codec_read(codec, 0x20, 0,
675 AC_VERB_SET_PROC_COEF, 0x830);
676 else
677 /* alc888-VB */
678 snd_hda_codec_read(codec, 0x20, 0,
679 AC_VERB_SET_PROC_COEF, 0x3030);
680}
681
Takashi Iwai1d045db2011-07-07 18:23:21 +0200682/* additional initialization for ALC889 variants */
Jaroslav Kysela87a8c372009-07-23 10:58:29 +0200683static void alc889_coef_init(struct hda_codec *codec)
684{
685 unsigned int tmp;
686
687 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
688 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
689 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
690 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF, tmp|0x2010);
691}
692
Takashi Iwai3fb4a502010-01-19 15:46:37 +0100693/* turn on/off EAPD control (only if available) */
694static void set_eapd(struct hda_codec *codec, hda_nid_t nid, int on)
695{
696 if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
697 return;
698 if (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)
699 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
700 on ? 2 : 0);
701}
702
Takashi Iwai691f1fc2011-04-07 10:31:43 +0200703/* turn on/off EAPD controls of the codec */
704static void alc_auto_setup_eapd(struct hda_codec *codec, bool on)
705{
706 /* We currently only handle front, HP */
Takashi Iwai39fa84e2011-06-27 15:28:57 +0200707 static hda_nid_t pins[] = {
708 0x0f, 0x10, 0x14, 0x15, 0
709 };
710 hda_nid_t *p;
711 for (p = pins; *p; p++)
712 set_eapd(codec, *p, on);
Takashi Iwai691f1fc2011-04-07 10:31:43 +0200713}
714
Takashi Iwai1c716152011-04-07 10:37:16 +0200715/* generic shutup callback;
716 * just turning off EPAD and a little pause for avoiding pop-noise
717 */
718static void alc_eapd_shutup(struct hda_codec *codec)
719{
720 alc_auto_setup_eapd(codec, false);
721 msleep(200);
722}
723
Takashi Iwai1d045db2011-07-07 18:23:21 +0200724/* generic EAPD initialization */
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200725static void alc_auto_init_amp(struct hda_codec *codec, int type)
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200726{
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200727 unsigned int tmp;
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200728
Takashi Iwai39fa84e2011-06-27 15:28:57 +0200729 alc_auto_setup_eapd(codec, true);
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200730 switch (type) {
731 case ALC_INIT_GPIO1:
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200732 snd_hda_sequence_write(codec, alc_gpio1_init_verbs);
733 break;
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200734 case ALC_INIT_GPIO2:
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200735 snd_hda_sequence_write(codec, alc_gpio2_init_verbs);
736 break;
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200737 case ALC_INIT_GPIO3:
Kailang Yangbdd148a2007-05-08 15:19:08 +0200738 snd_hda_sequence_write(codec, alc_gpio3_init_verbs);
739 break;
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200740 case ALC_INIT_DEFAULT:
Kailang Yangc9b58002007-10-16 14:30:01 +0200741 switch (codec->vendor_id) {
742 case 0x10ec0260:
743 snd_hda_codec_write(codec, 0x1a, 0,
744 AC_VERB_SET_COEF_INDEX, 7);
745 tmp = snd_hda_codec_read(codec, 0x1a, 0,
746 AC_VERB_GET_PROC_COEF, 0);
747 snd_hda_codec_write(codec, 0x1a, 0,
748 AC_VERB_SET_COEF_INDEX, 7);
749 snd_hda_codec_write(codec, 0x1a, 0,
750 AC_VERB_SET_PROC_COEF,
751 tmp | 0x2010);
752 break;
753 case 0x10ec0262:
754 case 0x10ec0880:
755 case 0x10ec0882:
756 case 0x10ec0883:
757 case 0x10ec0885:
Takashi Iwai4a5a4c52009-02-06 12:46:59 +0100758 case 0x10ec0887:
Takashi Iwai20b67dd2011-03-23 22:54:32 +0100759 /*case 0x10ec0889:*/ /* this causes an SPDIF problem */
Jaroslav Kysela87a8c372009-07-23 10:58:29 +0200760 alc889_coef_init(codec);
Kailang Yangc9b58002007-10-16 14:30:01 +0200761 break;
Kailang Yangf9423e72008-05-27 12:32:25 +0200762 case 0x10ec0888:
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200763 alc888_coef_init(codec);
Kailang Yangf9423e72008-05-27 12:32:25 +0200764 break;
Takashi Iwai0aea7782010-01-25 15:44:11 +0100765#if 0 /* XXX: This may cause the silent output on speaker on some machines */
Kailang Yangc9b58002007-10-16 14:30:01 +0200766 case 0x10ec0267:
767 case 0x10ec0268:
768 snd_hda_codec_write(codec, 0x20, 0,
769 AC_VERB_SET_COEF_INDEX, 7);
770 tmp = snd_hda_codec_read(codec, 0x20, 0,
771 AC_VERB_GET_PROC_COEF, 0);
772 snd_hda_codec_write(codec, 0x20, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +0200773 AC_VERB_SET_COEF_INDEX, 7);
Kailang Yangc9b58002007-10-16 14:30:01 +0200774 snd_hda_codec_write(codec, 0x20, 0,
775 AC_VERB_SET_PROC_COEF,
776 tmp | 0x3000);
777 break;
Takashi Iwai0aea7782010-01-25 15:44:11 +0100778#endif /* XXX */
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200779 }
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200780 break;
781 }
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200782}
Kailang Yangea1fb292008-08-26 12:58:38 +0200783
Takashi Iwai1d045db2011-07-07 18:23:21 +0200784/*
785 * Auto-Mute mode mixer enum support
786 */
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200787static int alc_automute_mode_info(struct snd_kcontrol *kcontrol,
788 struct snd_ctl_elem_info *uinfo)
789{
Takashi Iwaiae8a60a2011-04-28 18:09:52 +0200790 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
791 struct alc_spec *spec = codec->spec;
Takashi Iwaiae8a60a2011-04-28 18:09:52 +0200792 static const char * const texts3[] = {
Takashi Iwaie49a3432012-03-01 18:14:41 +0100793 "Disabled", "Speaker Only", "Line Out+Speaker"
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200794 };
795
Takashi Iwaidda415d2012-11-30 18:34:38 +0100796 if (spec->automute_speaker_possible && spec->automute_lo_possible)
797 return snd_hda_enum_helper_info(kcontrol, uinfo, 3, texts3);
798 return snd_hda_enum_bool_helper_info(kcontrol, uinfo);
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200799}
800
801static int alc_automute_mode_get(struct snd_kcontrol *kcontrol,
802 struct snd_ctl_elem_value *ucontrol)
803{
804 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
805 struct alc_spec *spec = codec->spec;
David Henningsson42cf0d02011-09-20 12:04:56 +0200806 unsigned int val = 0;
807 if (spec->automute_speaker)
808 val++;
809 if (spec->automute_lo)
810 val++;
811
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200812 ucontrol->value.enumerated.item[0] = val;
813 return 0;
814}
815
816static int alc_automute_mode_put(struct snd_kcontrol *kcontrol,
817 struct snd_ctl_elem_value *ucontrol)
818{
819 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
820 struct alc_spec *spec = codec->spec;
821
822 switch (ucontrol->value.enumerated.item[0]) {
823 case 0:
David Henningsson42cf0d02011-09-20 12:04:56 +0200824 if (!spec->automute_speaker && !spec->automute_lo)
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200825 return 0;
David Henningsson42cf0d02011-09-20 12:04:56 +0200826 spec->automute_speaker = 0;
827 spec->automute_lo = 0;
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200828 break;
829 case 1:
David Henningsson42cf0d02011-09-20 12:04:56 +0200830 if (spec->automute_speaker_possible) {
831 if (!spec->automute_lo && spec->automute_speaker)
832 return 0;
833 spec->automute_speaker = 1;
834 spec->automute_lo = 0;
835 } else if (spec->automute_lo_possible) {
836 if (spec->automute_lo)
837 return 0;
838 spec->automute_lo = 1;
839 } else
840 return -EINVAL;
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200841 break;
842 case 2:
David Henningsson42cf0d02011-09-20 12:04:56 +0200843 if (!spec->automute_lo_possible || !spec->automute_speaker_possible)
Takashi Iwaiae8a60a2011-04-28 18:09:52 +0200844 return -EINVAL;
David Henningsson42cf0d02011-09-20 12:04:56 +0200845 if (spec->automute_speaker && spec->automute_lo)
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200846 return 0;
David Henningsson42cf0d02011-09-20 12:04:56 +0200847 spec->automute_speaker = 1;
848 spec->automute_lo = 1;
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200849 break;
850 default:
851 return -EINVAL;
852 }
David Henningsson42cf0d02011-09-20 12:04:56 +0200853 call_update_outputs(codec);
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200854 return 1;
855}
856
Takashi Iwaia9111322011-05-02 11:30:18 +0200857static const struct snd_kcontrol_new alc_automute_mode_enum = {
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200858 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
859 .name = "Auto-Mute Mode",
860 .info = alc_automute_mode_info,
861 .get = alc_automute_mode_get,
862 .put = alc_automute_mode_put,
863};
864
Takashi Iwai668d1e92012-11-29 14:10:17 +0100865static struct snd_kcontrol_new *
866alc_kcontrol_new(struct alc_spec *spec, const char *name,
867 const struct snd_kcontrol_new *temp)
Takashi Iwai1d045db2011-07-07 18:23:21 +0200868{
Takashi Iwai668d1e92012-11-29 14:10:17 +0100869 struct snd_kcontrol_new *knew = snd_array_new(&spec->kctls);
870 if (!knew)
871 return NULL;
872 *knew = *temp;
873 knew->name = kstrdup(name, GFP_KERNEL);
874 if (!knew->name)
875 return NULL;
876 return knew;
Takashi Iwai1d045db2011-07-07 18:23:21 +0200877}
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200878
879static int alc_add_automute_mode_enum(struct hda_codec *codec)
880{
881 struct alc_spec *spec = codec->spec;
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200882
Takashi Iwai668d1e92012-11-29 14:10:17 +0100883 if (!alc_kcontrol_new(spec, "Auto-Mute Mode", &alc_automute_mode_enum))
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200884 return -ENOMEM;
885 return 0;
886}
887
Takashi Iwai1d045db2011-07-07 18:23:21 +0200888/*
889 * Check the availability of HP/line-out auto-mute;
890 * Set up appropriately if really supported
891 */
Takashi Iwai475c3d22012-11-30 08:31:30 +0100892static int alc_init_automute(struct hda_codec *codec)
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200893{
894 struct alc_spec *spec = codec->spec;
Takashi Iwaibb35feb2010-09-08 15:30:49 +0200895 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwai1daf5f42011-04-28 17:57:46 +0200896 int present = 0;
Takashi Iwai475c3d22012-11-30 08:31:30 +0100897 int i, err;
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200898
Takashi Iwai1daf5f42011-04-28 17:57:46 +0200899 if (cfg->hp_pins[0])
900 present++;
901 if (cfg->line_out_pins[0])
902 present++;
903 if (cfg->speaker_pins[0])
904 present++;
905 if (present < 2) /* need two different output types */
Takashi Iwai475c3d22012-11-30 08:31:30 +0100906 return 0;
Kailang Yangc9b58002007-10-16 14:30:01 +0200907
Takashi Iwaic48a8fb2011-07-27 16:41:57 +0200908 if (!cfg->speaker_pins[0] &&
909 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
Takashi Iwaibb35feb2010-09-08 15:30:49 +0200910 memcpy(cfg->speaker_pins, cfg->line_out_pins,
911 sizeof(cfg->speaker_pins));
912 cfg->speaker_outs = cfg->line_outs;
913 }
914
Takashi Iwaic48a8fb2011-07-27 16:41:57 +0200915 if (!cfg->hp_pins[0] &&
916 cfg->line_out_type == AUTO_PIN_HP_OUT) {
Takashi Iwaibb35feb2010-09-08 15:30:49 +0200917 memcpy(cfg->hp_pins, cfg->line_out_pins,
918 sizeof(cfg->hp_pins));
919 cfg->hp_outs = cfg->line_outs;
920 }
921
922 for (i = 0; i < cfg->hp_outs; i++) {
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200923 hda_nid_t nid = cfg->hp_pins[i];
Takashi Iwai06dec222011-05-17 10:00:16 +0200924 if (!is_jack_detectable(codec, nid))
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200925 continue;
Takashi Iwaibb35feb2010-09-08 15:30:49 +0200926 snd_printdd("realtek: Enable HP auto-muting on NID 0x%x\n",
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200927 nid);
David Henningsson29adc4b2012-09-25 11:31:00 +0200928 snd_hda_jack_detect_enable_callback(codec, nid, ALC_HP_EVENT,
929 alc_hp_automute);
David Henningsson42cf0d02011-09-20 12:04:56 +0200930 spec->detect_hp = 1;
Takashi Iwai1a1455d2011-04-28 17:36:18 +0200931 }
Takashi Iwaiae8a60a2011-04-28 18:09:52 +0200932
David Henningsson42cf0d02011-09-20 12:04:56 +0200933 if (cfg->line_out_type == AUTO_PIN_LINE_OUT && cfg->line_outs) {
934 if (cfg->speaker_outs)
935 for (i = 0; i < cfg->line_outs; i++) {
936 hda_nid_t nid = cfg->line_out_pins[i];
937 if (!is_jack_detectable(codec, nid))
938 continue;
939 snd_printdd("realtek: Enable Line-Out "
940 "auto-muting on NID 0x%x\n", nid);
David Henningsson29adc4b2012-09-25 11:31:00 +0200941 snd_hda_jack_detect_enable_callback(codec, nid, ALC_FRONT_EVENT,
942 alc_line_automute);
David Henningsson42cf0d02011-09-20 12:04:56 +0200943 spec->detect_lo = 1;
David Henningsson29adc4b2012-09-25 11:31:00 +0200944 }
David Henningsson42cf0d02011-09-20 12:04:56 +0200945 spec->automute_lo_possible = spec->detect_hp;
946 }
947
948 spec->automute_speaker_possible = cfg->speaker_outs &&
949 (spec->detect_hp || spec->detect_lo);
950
951 spec->automute_lo = spec->automute_lo_possible;
952 spec->automute_speaker = spec->automute_speaker_possible;
953
Takashi Iwai475c3d22012-11-30 08:31:30 +0100954 if (spec->automute_speaker_possible || spec->automute_lo_possible) {
Takashi Iwaiae8a60a2011-04-28 18:09:52 +0200955 /* create a control for automute mode */
Takashi Iwai475c3d22012-11-30 08:31:30 +0100956 err = alc_add_automute_mode_enum(codec);
957 if (err < 0)
958 return err;
959 }
960 return 0;
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200961}
962
Takashi Iwai1d045db2011-07-07 18:23:21 +0200963/* return the position of NID in the list, or -1 if not found */
Takashi Iwai21268962011-07-07 15:01:13 +0200964static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
965{
966 int i;
967 for (i = 0; i < nums; i++)
968 if (list[i] == nid)
969 return i;
970 return -1;
971}
972
Takashi Iwai21268962011-07-07 15:01:13 +0200973/* check whether all auto-mic pins are valid; setup indices if OK */
974static bool alc_auto_mic_check_imux(struct hda_codec *codec)
975{
976 struct alc_spec *spec = codec->spec;
977 const struct hda_input_mux *imux;
978
Takashi Iwai27d31532012-12-18 08:57:05 +0100979 imux = &spec->input_mux;
Takashi Iwai21268962011-07-07 15:01:13 +0200980 spec->ext_mic_idx = find_idx_in_nid_list(spec->ext_mic_pin,
981 spec->imux_pins, imux->num_items);
982 spec->int_mic_idx = find_idx_in_nid_list(spec->int_mic_pin,
983 spec->imux_pins, imux->num_items);
984 spec->dock_mic_idx = find_idx_in_nid_list(spec->dock_mic_pin,
985 spec->imux_pins, imux->num_items);
Takashi Iwai666a70d2012-12-17 20:29:29 +0100986 if (spec->ext_mic_idx < 0 || spec->int_mic_idx < 0)
Takashi Iwai21268962011-07-07 15:01:13 +0200987 return false; /* no corresponding imux */
Takashi Iwai21268962011-07-07 15:01:13 +0200988
David Henningsson29adc4b2012-09-25 11:31:00 +0200989 snd_hda_jack_detect_enable_callback(codec, spec->ext_mic_pin,
990 ALC_MIC_EVENT, alc_mic_automute);
Takashi Iwai21268962011-07-07 15:01:13 +0200991 if (spec->dock_mic_pin)
David Henningsson29adc4b2012-09-25 11:31:00 +0200992 snd_hda_jack_detect_enable_callback(codec, spec->dock_mic_pin,
993 ALC_MIC_EVENT,
994 alc_mic_automute);
Takashi Iwai21268962011-07-07 15:01:13 +0200995 return true;
996}
997
Takashi Iwai1d045db2011-07-07 18:23:21 +0200998/*
999 * Check the availability of auto-mic switch;
1000 * Set up if really supported
1001 */
Takashi Iwai475c3d22012-11-30 08:31:30 +01001002static int alc_init_auto_mic(struct hda_codec *codec)
Takashi Iwai6c819492009-08-10 18:47:44 +02001003{
1004 struct alc_spec *spec = codec->spec;
1005 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001006 hda_nid_t fixed, ext, dock;
Takashi Iwai6c819492009-08-10 18:47:44 +02001007 int i;
1008
Takashi Iwai21268962011-07-07 15:01:13 +02001009 spec->ext_mic_idx = spec->int_mic_idx = spec->dock_mic_idx = -1;
1010
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001011 fixed = ext = dock = 0;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02001012 for (i = 0; i < cfg->num_inputs; i++) {
1013 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai6c819492009-08-10 18:47:44 +02001014 unsigned int defcfg;
Takashi Iwai6c819492009-08-10 18:47:44 +02001015 defcfg = snd_hda_codec_get_pincfg(codec, nid);
Takashi Iwai99ae28b2010-09-17 14:42:34 +02001016 switch (snd_hda_get_input_pin_attr(defcfg)) {
1017 case INPUT_PIN_ATTR_INT:
Takashi Iwai6c819492009-08-10 18:47:44 +02001018 if (fixed)
Takashi Iwai475c3d22012-11-30 08:31:30 +01001019 return 0; /* already occupied */
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001020 if (cfg->inputs[i].type != AUTO_PIN_MIC)
Takashi Iwai475c3d22012-11-30 08:31:30 +01001021 return 0; /* invalid type */
Takashi Iwai6c819492009-08-10 18:47:44 +02001022 fixed = nid;
1023 break;
Takashi Iwai99ae28b2010-09-17 14:42:34 +02001024 case INPUT_PIN_ATTR_UNUSED:
Takashi Iwai475c3d22012-11-30 08:31:30 +01001025 return 0; /* invalid entry */
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001026 case INPUT_PIN_ATTR_DOCK:
1027 if (dock)
Takashi Iwai475c3d22012-11-30 08:31:30 +01001028 return 0; /* already occupied */
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001029 if (cfg->inputs[i].type > AUTO_PIN_LINE_IN)
Takashi Iwai475c3d22012-11-30 08:31:30 +01001030 return 0; /* invalid type */
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001031 dock = nid;
1032 break;
Takashi Iwai99ae28b2010-09-17 14:42:34 +02001033 default:
Takashi Iwai6c819492009-08-10 18:47:44 +02001034 if (ext)
Takashi Iwai475c3d22012-11-30 08:31:30 +01001035 return 0; /* already occupied */
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001036 if (cfg->inputs[i].type != AUTO_PIN_MIC)
Takashi Iwai475c3d22012-11-30 08:31:30 +01001037 return 0; /* invalid type */
Takashi Iwai6c819492009-08-10 18:47:44 +02001038 ext = nid;
1039 break;
Takashi Iwai6c819492009-08-10 18:47:44 +02001040 }
1041 }
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001042 if (!ext && dock) {
1043 ext = dock;
1044 dock = 0;
1045 }
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01001046 if (!ext || !fixed)
Takashi Iwai475c3d22012-11-30 08:31:30 +01001047 return 0;
Takashi Iwaie35d9d62011-05-17 11:28:16 +02001048 if (!is_jack_detectable(codec, ext))
Takashi Iwai475c3d22012-11-30 08:31:30 +01001049 return 0; /* no unsol support */
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001050 if (dock && !is_jack_detectable(codec, dock))
Takashi Iwai475c3d22012-11-30 08:31:30 +01001051 return 0; /* no unsol support */
Takashi Iwai21268962011-07-07 15:01:13 +02001052
1053 /* check imux indices */
1054 spec->ext_mic_pin = ext;
1055 spec->int_mic_pin = fixed;
1056 spec->dock_mic_pin = dock;
1057
Takashi Iwai21268962011-07-07 15:01:13 +02001058 if (!alc_auto_mic_check_imux(codec))
Takashi Iwai475c3d22012-11-30 08:31:30 +01001059 return 0;
Takashi Iwai21268962011-07-07 15:01:13 +02001060
Takashi Iwai666a70d2012-12-17 20:29:29 +01001061 spec->auto_mic = 1;
1062 spec->num_adc_nids = 1;
1063 spec->cur_mux[0] = spec->int_mic_idx;
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001064 snd_printdd("realtek: Enable auto-mic switch on NID 0x%x/0x%x/0x%x\n",
1065 ext, fixed, dock);
Takashi Iwai475c3d22012-11-30 08:31:30 +01001066
1067 return 0;
Takashi Iwai6c819492009-08-10 18:47:44 +02001068}
1069
Takashi Iwai1d045db2011-07-07 18:23:21 +02001070/*
1071 * Realtek SSID verification
1072 */
1073
David Henningsson90622912010-10-14 14:50:18 +02001074/* Could be any non-zero and even value. When used as fixup, tells
1075 * the driver to ignore any present sku defines.
1076 */
1077#define ALC_FIXUP_SKU_IGNORE (2)
1078
Takashi Iwai23d30f22012-05-07 17:17:32 +02001079static void alc_fixup_sku_ignore(struct hda_codec *codec,
1080 const struct hda_fixup *fix, int action)
1081{
1082 struct alc_spec *spec = codec->spec;
1083 if (action == HDA_FIXUP_ACT_PRE_PROBE) {
1084 spec->cdefine.fixup = 1;
1085 spec->cdefine.sku_cfg = ALC_FIXUP_SKU_IGNORE;
1086 }
1087}
1088
Kailang Yangda00c242010-03-19 11:23:45 +01001089static int alc_auto_parse_customize_define(struct hda_codec *codec)
1090{
1091 unsigned int ass, tmp, i;
Takashi Iwai7fb56222010-03-22 17:09:47 +01001092 unsigned nid = 0;
Kailang Yangda00c242010-03-19 11:23:45 +01001093 struct alc_spec *spec = codec->spec;
1094
Takashi Iwaib6cbe512010-07-28 17:43:36 +02001095 spec->cdefine.enable_pcbeep = 1; /* assume always enabled */
1096
David Henningsson90622912010-10-14 14:50:18 +02001097 if (spec->cdefine.fixup) {
1098 ass = spec->cdefine.sku_cfg;
1099 if (ass == ALC_FIXUP_SKU_IGNORE)
1100 return -1;
1101 goto do_sku;
1102 }
1103
Kailang Yangda00c242010-03-19 11:23:45 +01001104 ass = codec->subsystem_id & 0xffff;
Takashi Iwaib6cbe512010-07-28 17:43:36 +02001105 if (ass != codec->bus->pci->subsystem_device && (ass & 1))
Kailang Yangda00c242010-03-19 11:23:45 +01001106 goto do_sku;
1107
1108 nid = 0x1d;
1109 if (codec->vendor_id == 0x10ec0260)
1110 nid = 0x17;
1111 ass = snd_hda_codec_get_pincfg(codec, nid);
1112
1113 if (!(ass & 1)) {
1114 printk(KERN_INFO "hda_codec: %s: SKU not ready 0x%08x\n",
1115 codec->chip_name, ass);
1116 return -1;
1117 }
1118
1119 /* check sum */
1120 tmp = 0;
1121 for (i = 1; i < 16; i++) {
1122 if ((ass >> i) & 1)
1123 tmp++;
1124 }
1125 if (((ass >> 16) & 0xf) != tmp)
1126 return -1;
1127
1128 spec->cdefine.port_connectivity = ass >> 30;
1129 spec->cdefine.enable_pcbeep = (ass & 0x100000) >> 20;
1130 spec->cdefine.check_sum = (ass >> 16) & 0xf;
1131 spec->cdefine.customization = ass >> 8;
1132do_sku:
1133 spec->cdefine.sku_cfg = ass;
1134 spec->cdefine.external_amp = (ass & 0x38) >> 3;
1135 spec->cdefine.platform_type = (ass & 0x4) >> 2;
1136 spec->cdefine.swap = (ass & 0x2) >> 1;
1137 spec->cdefine.override = ass & 0x1;
1138
1139 snd_printd("SKU: Nid=0x%x sku_cfg=0x%08x\n",
1140 nid, spec->cdefine.sku_cfg);
1141 snd_printd("SKU: port_connectivity=0x%x\n",
1142 spec->cdefine.port_connectivity);
1143 snd_printd("SKU: enable_pcbeep=0x%x\n", spec->cdefine.enable_pcbeep);
1144 snd_printd("SKU: check_sum=0x%08x\n", spec->cdefine.check_sum);
1145 snd_printd("SKU: customization=0x%08x\n", spec->cdefine.customization);
1146 snd_printd("SKU: external_amp=0x%x\n", spec->cdefine.external_amp);
1147 snd_printd("SKU: platform_type=0x%x\n", spec->cdefine.platform_type);
1148 snd_printd("SKU: swap=0x%x\n", spec->cdefine.swap);
1149 snd_printd("SKU: override=0x%x\n", spec->cdefine.override);
1150
1151 return 0;
1152}
1153
Takashi Iwai1d045db2011-07-07 18:23:21 +02001154/* return true if the given NID is found in the list */
Takashi Iwai3af9ee62011-06-27 12:34:01 +02001155static bool found_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
1156{
Takashi Iwai21268962011-07-07 15:01:13 +02001157 return find_idx_in_nid_list(nid, list, nums) >= 0;
Takashi Iwai3af9ee62011-06-27 12:34:01 +02001158}
1159
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001160/* check subsystem ID and set up device-specific initialization;
1161 * return 1 if initialized, 0 if invalid SSID
1162 */
1163/* 32-bit subsystem ID for BIOS loading in HD Audio codec.
1164 * 31 ~ 16 : Manufacture ID
1165 * 15 ~ 8 : SKU ID
1166 * 7 ~ 0 : Assembly ID
1167 * port-A --> pin 39/41, port-E --> pin 14/15, port-D --> pin 35/36
1168 */
1169static int alc_subsystem_id(struct hda_codec *codec,
1170 hda_nid_t porta, hda_nid_t porte,
Kailang Yang6227cdc2010-02-25 08:36:52 +01001171 hda_nid_t portd, hda_nid_t porti)
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001172{
1173 unsigned int ass, tmp, i;
1174 unsigned nid;
1175 struct alc_spec *spec = codec->spec;
1176
David Henningsson90622912010-10-14 14:50:18 +02001177 if (spec->cdefine.fixup) {
1178 ass = spec->cdefine.sku_cfg;
1179 if (ass == ALC_FIXUP_SKU_IGNORE)
1180 return 0;
1181 goto do_sku;
1182 }
1183
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001184 ass = codec->subsystem_id & 0xffff;
1185 if ((ass != codec->bus->pci->subsystem_device) && (ass & 1))
1186 goto do_sku;
1187
1188 /* invalid SSID, check the special NID pin defcfg instead */
1189 /*
Sasha Alexandrdef319f2009-06-16 16:00:15 -04001190 * 31~30 : port connectivity
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001191 * 29~21 : reserve
1192 * 20 : PCBEEP input
1193 * 19~16 : Check sum (15:1)
1194 * 15~1 : Custom
1195 * 0 : override
1196 */
1197 nid = 0x1d;
1198 if (codec->vendor_id == 0x10ec0260)
1199 nid = 0x17;
1200 ass = snd_hda_codec_get_pincfg(codec, nid);
1201 snd_printd("realtek: No valid SSID, "
1202 "checking pincfg 0x%08x for NID 0x%x\n",
Takashi Iwaicb6605c2009-04-28 13:03:19 +02001203 ass, nid);
Kailang Yang6227cdc2010-02-25 08:36:52 +01001204 if (!(ass & 1))
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001205 return 0;
1206 if ((ass >> 30) != 1) /* no physical connection */
1207 return 0;
1208
1209 /* check sum */
1210 tmp = 0;
1211 for (i = 1; i < 16; i++) {
1212 if ((ass >> i) & 1)
1213 tmp++;
1214 }
1215 if (((ass >> 16) & 0xf) != tmp)
1216 return 0;
1217do_sku:
1218 snd_printd("realtek: Enabling init ASM_ID=0x%04x CODEC_ID=%08x\n",
1219 ass & 0xffff, codec->vendor_id);
1220 /*
1221 * 0 : override
1222 * 1 : Swap Jack
1223 * 2 : 0 --> Desktop, 1 --> Laptop
1224 * 3~5 : External Amplifier control
1225 * 7~6 : Reserved
1226 */
1227 tmp = (ass & 0x38) >> 3; /* external Amp control */
1228 switch (tmp) {
1229 case 1:
1230 spec->init_amp = ALC_INIT_GPIO1;
1231 break;
1232 case 3:
1233 spec->init_amp = ALC_INIT_GPIO2;
1234 break;
1235 case 7:
1236 spec->init_amp = ALC_INIT_GPIO3;
1237 break;
1238 case 5:
Takashi Iwai5a8cfb42010-11-26 17:11:18 +01001239 default:
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001240 spec->init_amp = ALC_INIT_DEFAULT;
1241 break;
1242 }
1243
1244 /* is laptop or Desktop and enable the function "Mute internal speaker
1245 * when the external headphone out jack is plugged"
1246 */
1247 if (!(ass & 0x8000))
1248 return 1;
1249 /*
1250 * 10~8 : Jack location
1251 * 12~11: Headphone out -> 00: PortA, 01: PortE, 02: PortD, 03: Resvered
1252 * 14~13: Resvered
1253 * 15 : 1 --> enable the function "Mute internal speaker
1254 * when the external headphone out jack is plugged"
1255 */
Takashi Iwai5fe6e012011-09-26 10:41:21 +02001256 if (!spec->autocfg.hp_pins[0] &&
1257 !(spec->autocfg.line_out_pins[0] &&
1258 spec->autocfg.line_out_type == AUTO_PIN_HP_OUT)) {
Takashi Iwai01d48252009-10-06 13:21:54 +02001259 hda_nid_t nid;
Kailang Yangc9b58002007-10-16 14:30:01 +02001260 tmp = (ass >> 11) & 0x3; /* HP to chassis */
1261 if (tmp == 0)
Takashi Iwai01d48252009-10-06 13:21:54 +02001262 nid = porta;
Kailang Yangc9b58002007-10-16 14:30:01 +02001263 else if (tmp == 1)
Takashi Iwai01d48252009-10-06 13:21:54 +02001264 nid = porte;
Kailang Yangc9b58002007-10-16 14:30:01 +02001265 else if (tmp == 2)
Takashi Iwai01d48252009-10-06 13:21:54 +02001266 nid = portd;
Kailang Yang6227cdc2010-02-25 08:36:52 +01001267 else if (tmp == 3)
1268 nid = porti;
Kailang Yangc9b58002007-10-16 14:30:01 +02001269 else
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001270 return 1;
Takashi Iwai3af9ee62011-06-27 12:34:01 +02001271 if (found_in_nid_list(nid, spec->autocfg.line_out_pins,
1272 spec->autocfg.line_outs))
1273 return 1;
Takashi Iwai01d48252009-10-06 13:21:54 +02001274 spec->autocfg.hp_pins[0] = nid;
Kailang Yangc9b58002007-10-16 14:30:01 +02001275 }
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001276 return 1;
1277}
Kailang Yangea1fb292008-08-26 12:58:38 +02001278
Takashi Iwai3e6179b2011-07-08 16:55:13 +02001279/* Check the validity of ALC subsystem-id
1280 * ports contains an array of 4 pin NIDs for port-A, E, D and I */
1281static void alc_ssid_check(struct hda_codec *codec, const hda_nid_t *ports)
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001282{
Takashi Iwai3e6179b2011-07-08 16:55:13 +02001283 if (!alc_subsystem_id(codec, ports[0], ports[1], ports[2], ports[3])) {
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001284 struct alc_spec *spec = codec->spec;
1285 snd_printd("realtek: "
1286 "Enable default setup for auto mode as fallback\n");
1287 spec->init_amp = ALC_INIT_DEFAULT;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001288 }
Takashi Iwai21268962011-07-07 15:01:13 +02001289}
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001290
Takashi Iwai41e41f12005-06-08 14:48:49 +02001291/*
Takashi Iwai1d045db2011-07-07 18:23:21 +02001292 * COEF access helper functions
1293 */
Kailang Yang274693f2009-12-03 10:07:50 +01001294static int alc_read_coef_idx(struct hda_codec *codec,
1295 unsigned int coef_idx)
1296{
1297 unsigned int val;
1298 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX,
1299 coef_idx);
1300 val = snd_hda_codec_read(codec, 0x20, 0,
1301 AC_VERB_GET_PROC_COEF, 0);
1302 return val;
1303}
1304
Kailang Yang977ddd62010-09-15 10:02:29 +02001305static void alc_write_coef_idx(struct hda_codec *codec, unsigned int coef_idx,
1306 unsigned int coef_val)
1307{
1308 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX,
1309 coef_idx);
1310 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF,
1311 coef_val);
1312}
1313
Takashi Iwai1bb7e432011-10-17 16:50:59 +02001314/* a special bypass for COEF 0; read the cached value at the second time */
1315static unsigned int alc_get_coef0(struct hda_codec *codec)
1316{
1317 struct alc_spec *spec = codec->spec;
1318 if (!spec->coef0)
1319 spec->coef0 = alc_read_coef_idx(codec, 0);
1320 return spec->coef0;
1321}
1322
Takashi Iwaifef7fbb2012-12-14 16:54:44 +01001323static void alc_auto_set_output_and_unmute(struct hda_codec *codec,
1324 hda_nid_t pin, int pin_type,
1325 hda_nid_t dac);
1326static hda_nid_t alc_auto_look_for_dac(struct hda_codec *codec, hda_nid_t pin,
1327 bool is_digital);
Takashi Iwai965cceb2012-12-18 11:46:37 +01001328static bool parse_nid_path(struct hda_codec *codec, hda_nid_t from_nid,
1329 hda_nid_t to_nid, int with_aa_mix,
1330 struct nid_path *path);
1331static struct nid_path *add_new_nid_path(struct hda_codec *codec,
1332 hda_nid_t from_nid, hda_nid_t to_nid,
1333 int with_aa_mix);
Takashi Iwaifef7fbb2012-12-14 16:54:44 +01001334
Takashi Iwai1d045db2011-07-07 18:23:21 +02001335/*
1336 * Digital I/O handling
1337 */
1338
Takashi Iwai757899a2010-07-30 10:48:14 +02001339/* set right pin controls for digital I/O */
1340static void alc_auto_init_digital(struct hda_codec *codec)
1341{
1342 struct alc_spec *spec = codec->spec;
1343 int i;
Takashi Iwaifef7fbb2012-12-14 16:54:44 +01001344 hda_nid_t pin;
Takashi Iwai757899a2010-07-30 10:48:14 +02001345
1346 for (i = 0; i < spec->autocfg.dig_outs; i++) {
1347 pin = spec->autocfg.dig_out_pins[i];
Takashi Iwai1f0f4b82011-06-27 10:52:59 +02001348 if (!pin)
1349 continue;
Takashi Iwaifef7fbb2012-12-14 16:54:44 +01001350 alc_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Takashi Iwai757899a2010-07-30 10:48:14 +02001351 }
1352 pin = spec->autocfg.dig_in_pin;
1353 if (pin)
Takashi Iwaicdd03ce2012-04-20 12:34:50 +02001354 snd_hda_set_pin_ctl(codec, pin, PIN_IN);
Takashi Iwai757899a2010-07-30 10:48:14 +02001355}
1356
1357/* parse digital I/Os and set up NIDs in BIOS auto-parse mode */
1358static void alc_auto_parse_digital(struct hda_codec *codec)
1359{
1360 struct alc_spec *spec = codec->spec;
Takashi Iwai965cceb2012-12-18 11:46:37 +01001361 int i, nums;
Takashi Iwai757899a2010-07-30 10:48:14 +02001362 hda_nid_t dig_nid;
1363
1364 /* support multiple SPDIFs; the secondary is set up as a slave */
Takashi Iwai51e41522011-11-03 16:54:06 +01001365 nums = 0;
Takashi Iwai757899a2010-07-30 10:48:14 +02001366 for (i = 0; i < spec->autocfg.dig_outs; i++) {
Takashi Iwaifef7fbb2012-12-14 16:54:44 +01001367 hda_nid_t pin = spec->autocfg.dig_out_pins[i];
1368 dig_nid = alc_auto_look_for_dac(codec, pin, true);
1369 if (!dig_nid)
Takashi Iwai757899a2010-07-30 10:48:14 +02001370 continue;
Takashi Iwai965cceb2012-12-18 11:46:37 +01001371 if (!add_new_nid_path(codec, dig_nid, pin, 2))
1372 continue;
Takashi Iwai51e41522011-11-03 16:54:06 +01001373 if (!nums) {
Takashi Iwai757899a2010-07-30 10:48:14 +02001374 spec->multiout.dig_out_nid = dig_nid;
1375 spec->dig_out_type = spec->autocfg.dig_out_type[0];
1376 } else {
1377 spec->multiout.slave_dig_outs = spec->slave_dig_outs;
Takashi Iwai51e41522011-11-03 16:54:06 +01001378 if (nums >= ARRAY_SIZE(spec->slave_dig_outs) - 1)
Takashi Iwai757899a2010-07-30 10:48:14 +02001379 break;
Takashi Iwai51e41522011-11-03 16:54:06 +01001380 spec->slave_dig_outs[nums - 1] = dig_nid;
Takashi Iwai757899a2010-07-30 10:48:14 +02001381 }
Takashi Iwai51e41522011-11-03 16:54:06 +01001382 nums++;
Takashi Iwai757899a2010-07-30 10:48:14 +02001383 }
1384
1385 if (spec->autocfg.dig_in_pin) {
Takashi Iwai01fdf182010-09-24 09:09:42 +02001386 dig_nid = codec->start_nid;
1387 for (i = 0; i < codec->num_nodes; i++, dig_nid++) {
Takashi Iwaidf1d1fb2012-12-18 11:55:53 +01001388 struct nid_path *path;
Takashi Iwai01fdf182010-09-24 09:09:42 +02001389 unsigned int wcaps = get_wcaps(codec, dig_nid);
1390 if (get_wcaps_type(wcaps) != AC_WID_AUD_IN)
1391 continue;
1392 if (!(wcaps & AC_WCAP_DIGITAL))
1393 continue;
Takashi Iwaidf1d1fb2012-12-18 11:55:53 +01001394 path = add_new_nid_path(codec, spec->autocfg.dig_in_pin,
1395 dig_nid, 2);
1396 if (path) {
1397 path->active = true;
Takashi Iwai01fdf182010-09-24 09:09:42 +02001398 spec->dig_in_nid = dig_nid;
1399 break;
1400 }
1401 }
Takashi Iwai757899a2010-07-30 10:48:14 +02001402 }
1403}
1404
Takashi Iwaif95474e2007-07-10 00:47:43 +02001405/*
Takashi Iwai1d045db2011-07-07 18:23:21 +02001406 * capture mixer elements
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001407 */
Takashi Iwai666a70d2012-12-17 20:29:29 +01001408#define alc_cap_vol_info snd_hda_mixer_amp_volume_info
1409#define alc_cap_vol_get snd_hda_mixer_amp_volume_get
1410#define alc_cap_vol_tlv snd_hda_mixer_amp_tlv
1411
1412typedef int (*put_call_t)(struct snd_kcontrol *kcontrol,
1413 struct snd_ctl_elem_value *ucontrol);
1414
1415static int alc_cap_put_caller(struct snd_kcontrol *kcontrol,
1416 struct snd_ctl_elem_value *ucontrol,
1417 put_call_t func, int type)
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001418{
1419 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1420 struct alc_spec *spec = codec->spec;
Takashi Iwai666a70d2012-12-17 20:29:29 +01001421 const struct hda_input_mux *imux;
1422 struct nid_path *path;
1423 int i, adc_idx, err = 0;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001424
Takashi Iwai27d31532012-12-18 08:57:05 +01001425 imux = &spec->input_mux;
Takashi Iwai666a70d2012-12-17 20:29:29 +01001426 adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001427 mutex_lock(&codec->control_mutex);
Takashi Iwai666a70d2012-12-17 20:29:29 +01001428 codec->cached_write = 1;
1429 for (i = 0; i < imux->num_items; i++) {
1430 path = get_nid_path(codec, spec->imux_pins[i],
1431 get_adc_nid(codec, adc_idx, i));
1432 if (!path->ctls[type])
1433 continue;
1434 kcontrol->private_value = path->ctls[type];
Takashi Iwai9c7a0832011-07-07 09:25:54 +02001435 err = func(kcontrol, ucontrol);
Takashi Iwai666a70d2012-12-17 20:29:29 +01001436 if (err < 0)
1437 goto error;
Takashi Iwai9c7a0832011-07-07 09:25:54 +02001438 }
1439 error:
Takashi Iwai666a70d2012-12-17 20:29:29 +01001440 codec->cached_write = 0;
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08001441 mutex_unlock(&codec->control_mutex);
Takashi Iwai666a70d2012-12-17 20:29:29 +01001442 snd_hda_codec_resume_amp(codec);
1443 if (err >= 0 && type == NID_PATH_MUTE_CTL &&
1444 spec->inv_dmic_fixup && spec->inv_dmic_muted)
1445 alc_inv_dmic_sync_adc(codec, adc_idx);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001446 return err;
1447}
1448
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001449static int alc_cap_vol_put(struct snd_kcontrol *kcontrol,
1450 struct snd_ctl_elem_value *ucontrol)
1451{
Takashi Iwai666a70d2012-12-17 20:29:29 +01001452 return alc_cap_put_caller(kcontrol, ucontrol,
1453 snd_hda_mixer_amp_volume_put,
1454 NID_PATH_VOL_CTL);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001455}
1456
1457/* capture mixer elements */
1458#define alc_cap_sw_info snd_ctl_boolean_stereo_info
Takashi Iwai666a70d2012-12-17 20:29:29 +01001459#define alc_cap_sw_get snd_hda_mixer_amp_switch_get
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001460
1461static int alc_cap_sw_put(struct snd_kcontrol *kcontrol,
1462 struct snd_ctl_elem_value *ucontrol)
1463{
Takashi Iwai666a70d2012-12-17 20:29:29 +01001464 return alc_cap_put_caller(kcontrol, ucontrol,
1465 snd_hda_mixer_amp_switch_put,
1466 NID_PATH_MUTE_CTL);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01001467}
1468
Takashi Iwai666a70d2012-12-17 20:29:29 +01001469static void alc_inv_dmic_sync_adc(struct hda_codec *codec, int adc_idx)
1470{
1471 struct alc_spec *spec = codec->spec;
Takashi Iwai27d31532012-12-18 08:57:05 +01001472 struct hda_input_mux *imux = &spec->input_mux;
Takashi Iwai666a70d2012-12-17 20:29:29 +01001473 struct nid_path *path;
1474 hda_nid_t nid;
1475 int i, dir, parm;
1476 unsigned int val;
1477
1478 for (i = 0; i < imux->num_items; i++) {
1479 if (spec->imux_pins[i] == spec->inv_dmic_pin)
1480 break;
Takashi Iwaia23b6882009-03-23 15:21:36 +01001481 }
Takashi Iwai666a70d2012-12-17 20:29:29 +01001482 if (i >= imux->num_items)
1483 return;
Takashi Iwaia23b6882009-03-23 15:21:36 +01001484
Takashi Iwai666a70d2012-12-17 20:29:29 +01001485 path = get_nid_path(codec, spec->inv_dmic_pin,
1486 get_adc_nid(codec, adc_idx, i));
1487 val = path->ctls[NID_PATH_MUTE_CTL];
1488 if (!val)
1489 return;
1490 nid = get_amp_nid_(val);
1491 dir = get_amp_direction_(val);
1492 parm = AC_AMP_SET_RIGHT |
1493 (dir == HDA_OUTPUT ? AC_AMP_SET_OUTPUT : AC_AMP_SET_INPUT);
Takashi Iwaia23b6882009-03-23 15:21:36 +01001494
Takashi Iwai666a70d2012-12-17 20:29:29 +01001495 /* we care only right channel */
1496 val = snd_hda_codec_amp_read(codec, nid, 1, dir, 0);
1497 if (val & 0x80) /* if already muted, we don't need to touch */
1498 return;
1499 val |= 0x80;
1500 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
1501 parm | val);
Takashi Iwaia23b6882009-03-23 15:21:36 +01001502}
1503
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001504/*
Takashi Iwai125821a2012-06-22 14:30:29 +02001505 * Inverted digital-mic handling
1506 *
1507 * First off, it's a bit tricky. The "Inverted Internal Mic Capture Switch"
1508 * gives the additional mute only to the right channel of the digital mic
1509 * capture stream. This is a workaround for avoiding the almost silence
1510 * by summing the stereo stream from some (known to be ForteMedia)
1511 * digital mic unit.
1512 *
1513 * The logic is to call alc_inv_dmic_sync() after each action (possibly)
1514 * modifying ADC amp. When the mute flag is set, it mutes the R-channel
1515 * without caching so that the cache can still keep the original value.
1516 * The cached value is then restored when the flag is set off or any other
1517 * than d-mic is used as the current input source.
1518 */
1519static void alc_inv_dmic_sync(struct hda_codec *codec, bool force)
1520{
1521 struct alc_spec *spec = codec->spec;
Takashi Iwai666a70d2012-12-17 20:29:29 +01001522 int src, nums;
Takashi Iwai125821a2012-06-22 14:30:29 +02001523
1524 if (!spec->inv_dmic_fixup)
1525 return;
1526 if (!spec->inv_dmic_muted && !force)
1527 return;
Takashi Iwai666a70d2012-12-17 20:29:29 +01001528 nums = spec->dyn_adc_switch ? 1 : spec->num_adc_nids;
1529 for (src = 0; src < nums; src++) {
Takashi Iwai125821a2012-06-22 14:30:29 +02001530 bool dmic_fixup = false;
Takashi Iwai125821a2012-06-22 14:30:29 +02001531
1532 if (spec->inv_dmic_muted &&
1533 spec->imux_pins[spec->cur_mux[src]] == spec->inv_dmic_pin)
1534 dmic_fixup = true;
1535 if (!dmic_fixup && !force)
1536 continue;
Takashi Iwai666a70d2012-12-17 20:29:29 +01001537 alc_inv_dmic_sync_adc(codec, src);
Takashi Iwai125821a2012-06-22 14:30:29 +02001538 }
1539}
1540
1541static int alc_inv_dmic_sw_get(struct snd_kcontrol *kcontrol,
1542 struct snd_ctl_elem_value *ucontrol)
1543{
1544 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1545 struct alc_spec *spec = codec->spec;
1546
1547 ucontrol->value.integer.value[0] = !spec->inv_dmic_muted;
1548 return 0;
1549}
1550
1551static int alc_inv_dmic_sw_put(struct snd_kcontrol *kcontrol,
1552 struct snd_ctl_elem_value *ucontrol)
1553{
1554 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1555 struct alc_spec *spec = codec->spec;
1556 unsigned int val = !ucontrol->value.integer.value[0];
1557
1558 if (val == spec->inv_dmic_muted)
1559 return 0;
1560 spec->inv_dmic_muted = val;
1561 alc_inv_dmic_sync(codec, true);
1562 return 0;
1563}
1564
1565static const struct snd_kcontrol_new alc_inv_dmic_sw = {
1566 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1567 .info = snd_ctl_boolean_mono_info,
1568 .get = alc_inv_dmic_sw_get,
1569 .put = alc_inv_dmic_sw_put,
1570};
1571
1572static int alc_add_inv_dmic_mixer(struct hda_codec *codec, hda_nid_t nid)
1573{
1574 struct alc_spec *spec = codec->spec;
Takashi Iwai668d1e92012-11-29 14:10:17 +01001575
1576 if (!alc_kcontrol_new(spec, "Inverted Internal Mic Capture Switch",
1577 &alc_inv_dmic_sw))
Takashi Iwai125821a2012-06-22 14:30:29 +02001578 return -ENOMEM;
1579 spec->inv_dmic_fixup = 1;
1580 spec->inv_dmic_muted = 0;
1581 spec->inv_dmic_pin = nid;
1582 return 0;
1583}
1584
Takashi Iwai6e72aa52012-06-25 10:52:25 +02001585/* typically the digital mic is put at node 0x12 */
1586static void alc_fixup_inv_dmic_0x12(struct hda_codec *codec,
1587 const struct alc_fixup *fix, int action)
1588{
1589 if (action == ALC_FIXUP_ACT_PROBE)
1590 alc_add_inv_dmic_mixer(codec, 0x12);
1591}
1592
Takashi Iwai125821a2012-06-22 14:30:29 +02001593/*
Takashi Iwai2134ea42008-01-10 16:53:55 +01001594 * virtual master controls
1595 */
1596
1597/*
1598 * slave controls for virtual master
1599 */
Takashi Iwai9322ca52012-02-03 14:28:01 +01001600static const char * const alc_slave_pfxs[] = {
1601 "Front", "Surround", "Center", "LFE", "Side",
Takashi Iwai7c589752012-03-02 09:00:33 +01001602 "Headphone", "Speaker", "Mono", "Line Out",
Takashi Iwai9322ca52012-02-03 14:28:01 +01001603 "CLFE", "Bass Speaker", "PCM",
Takashi Iwai2134ea42008-01-10 16:53:55 +01001604 NULL,
1605};
1606
1607/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001608 * build control elements
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609 */
Takashi Iwai603c4012008-07-30 15:01:44 +02001610
1611static void alc_free_kctls(struct hda_codec *codec);
1612
Takashi Iwai67d634c2009-11-16 15:35:59 +01001613#ifdef CONFIG_SND_HDA_INPUT_BEEP
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01001614/* additional beep mixers; the actual parameters are overwritten at build */
Takashi Iwaia9111322011-05-02 11:30:18 +02001615static const struct snd_kcontrol_new alc_beep_mixer[] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01001616 HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_INPUT),
Jaroslav Kysela123c07a2009-10-21 14:48:23 +02001617 HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01001618 { } /* end */
1619};
Takashi Iwai67d634c2009-11-16 15:35:59 +01001620#endif
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01001621
Takashi Iwaif21d78e2012-01-19 12:10:29 +01001622static int __alc_build_controls(struct hda_codec *codec)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623{
1624 struct alc_spec *spec = codec->spec;
Takashi Iwai666a70d2012-12-17 20:29:29 +01001625 int i, err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626
1627 for (i = 0; i < spec->num_mixers; i++) {
1628 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
1629 if (err < 0)
1630 return err;
1631 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632 if (spec->multiout.dig_out_nid) {
Takashi Iwaidcda5802012-10-12 17:24:51 +02001633 err = snd_hda_create_dig_out_ctls(codec,
1634 spec->multiout.dig_out_nid,
1635 spec->multiout.dig_out_nid,
1636 spec->pcm_rec[1].pcm_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001637 if (err < 0)
1638 return err;
Takashi Iwaie64f14f2009-01-20 18:32:55 +01001639 if (!spec->no_analog) {
1640 err = snd_hda_create_spdif_share_sw(codec,
1641 &spec->multiout);
1642 if (err < 0)
1643 return err;
1644 spec->multiout.share_spdif = 1;
1645 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646 }
1647 if (spec->dig_in_nid) {
1648 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
1649 if (err < 0)
1650 return err;
1651 }
Takashi Iwai2134ea42008-01-10 16:53:55 +01001652
Takashi Iwai67d634c2009-11-16 15:35:59 +01001653#ifdef CONFIG_SND_HDA_INPUT_BEEP
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01001654 /* create beep controls if needed */
1655 if (spec->beep_amp) {
Takashi Iwaia9111322011-05-02 11:30:18 +02001656 const struct snd_kcontrol_new *knew;
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01001657 for (knew = alc_beep_mixer; knew->name; knew++) {
1658 struct snd_kcontrol *kctl;
1659 kctl = snd_ctl_new1(knew, codec);
1660 if (!kctl)
1661 return -ENOMEM;
1662 kctl->private_value = spec->beep_amp;
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +01001663 err = snd_hda_ctl_add(codec, 0, kctl);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01001664 if (err < 0)
1665 return err;
1666 }
1667 }
Takashi Iwai67d634c2009-11-16 15:35:59 +01001668#endif
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01001669
Takashi Iwai2134ea42008-01-10 16:53:55 +01001670 /* if we have no master control, let's create it */
Takashi Iwaie64f14f2009-01-20 18:32:55 +01001671 if (!spec->no_analog &&
1672 !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001673 unsigned int vmaster_tlv[4];
Takashi Iwai2134ea42008-01-10 16:53:55 +01001674 snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
Takashi Iwai1c82ed12008-02-18 13:05:50 +01001675 HDA_OUTPUT, vmaster_tlv);
Takashi Iwai2134ea42008-01-10 16:53:55 +01001676 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
Takashi Iwai9322ca52012-02-03 14:28:01 +01001677 vmaster_tlv, alc_slave_pfxs,
1678 "Playback Volume");
Takashi Iwai2134ea42008-01-10 16:53:55 +01001679 if (err < 0)
1680 return err;
1681 }
Takashi Iwaie64f14f2009-01-20 18:32:55 +01001682 if (!spec->no_analog &&
1683 !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
Takashi Iwai420b0fe2012-03-12 12:35:27 +01001684 err = __snd_hda_add_vmaster(codec, "Master Playback Switch",
1685 NULL, alc_slave_pfxs,
1686 "Playback Switch",
Takashi Iwaid2f344b2012-03-12 16:59:58 +01001687 true, &spec->vmaster_mute.sw_kctl);
Takashi Iwai2134ea42008-01-10 16:53:55 +01001688 if (err < 0)
1689 return err;
Takashi Iwai3bd7b642012-12-18 14:57:09 +01001690 if (spec->vmaster_mute.hook)
1691 snd_hda_add_vmaster_hook(codec, &spec->vmaster_mute, true);
Takashi Iwai2134ea42008-01-10 16:53:55 +01001692 }
1693
Takashi Iwaibae84e72010-03-22 08:30:20 +01001694 alc_free_kctls(codec); /* no longer needed */
1695
Takashi Iwaif21d78e2012-01-19 12:10:29 +01001696 return 0;
1697}
1698
David Henningsson5780b622012-06-27 18:45:45 +02001699static int alc_build_jacks(struct hda_codec *codec)
Takashi Iwaif21d78e2012-01-19 12:10:29 +01001700{
1701 struct alc_spec *spec = codec->spec;
David Henningsson5780b622012-06-27 18:45:45 +02001702
1703 if (spec->shared_mic_hp) {
1704 int err;
1705 int nid = spec->autocfg.inputs[1].pin;
1706 err = snd_hda_jack_add_kctl(codec, nid, "Headphone Mic", 0);
1707 if (err < 0)
1708 return err;
1709 err = snd_hda_jack_detect_enable(codec, nid, 0);
1710 if (err < 0)
1711 return err;
1712 }
1713
1714 return snd_hda_jack_add_kctls(codec, &spec->autocfg);
1715}
1716
1717static int alc_build_controls(struct hda_codec *codec)
1718{
Takashi Iwaif21d78e2012-01-19 12:10:29 +01001719 int err = __alc_build_controls(codec);
Takashi Iwai01a61e12011-10-28 00:03:22 +02001720 if (err < 0)
1721 return err;
David Henningsson5780b622012-06-27 18:45:45 +02001722
1723 err = alc_build_jacks(codec);
Takashi Iwai420b0fe2012-03-12 12:35:27 +01001724 if (err < 0)
1725 return err;
1726 alc_apply_fixup(codec, ALC_FIXUP_ACT_BUILD);
1727 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728}
1729
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001730
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01001732 * Common callbacks
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001733 */
Takashi Iwai16ded522005-06-10 19:58:24 +02001734
Takashi Iwai070cff42012-02-21 12:54:17 +01001735static void alc_auto_init_std(struct hda_codec *codec);
Takashi Iwai584c0c42011-03-10 12:51:11 +01001736
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737static int alc_init(struct hda_codec *codec)
1738{
1739 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001740
Takashi Iwai546bb672012-03-07 08:37:19 +01001741 if (spec->init_hook)
1742 spec->init_hook(codec);
Kailang Yang526af6e2012-03-07 08:25:20 +01001743
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02001744 alc_fix_pll(codec);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001745 alc_auto_init_amp(codec, spec->init_amp);
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02001746
Takashi Iwai2e8b2b22012-06-13 16:47:32 +02001747 snd_hda_gen_apply_verbs(codec);
Takashi Iwai070cff42012-02-21 12:54:17 +01001748 alc_auto_init_std(codec);
Takashi Iwaiae6b8132006-03-03 16:47:17 +01001749
Takashi Iwai3bd7b642012-12-18 14:57:09 +01001750 if (spec->vmaster_mute.sw_kctl && spec->vmaster_mute.hook)
1751 snd_hda_sync_vmaster_hook(&spec->vmaster_mute);
1752
Takashi Iwai58701122011-01-13 15:41:45 +01001753 alc_apply_fixup(codec, ALC_FIXUP_ACT_INIT);
1754
Takashi Iwai9e5341b2010-09-21 09:57:06 +02001755 hda_call_check_power_status(codec, 0x01);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756 return 0;
1757}
1758
Takashi Iwai83012a72012-08-24 18:38:08 +02001759#ifdef CONFIG_PM
Takashi Iwaicb53c622007-08-10 17:21:45 +02001760static int alc_check_power_status(struct hda_codec *codec, hda_nid_t nid)
1761{
1762 struct alc_spec *spec = codec->spec;
1763 return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
1764}
1765#endif
1766
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767/*
1768 * Analog playback callbacks
1769 */
Takashi Iwaic2d986b2011-07-06 18:30:08 +02001770static int alc_playback_pcm_open(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001772 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773{
1774 struct alc_spec *spec = codec->spec;
Takashi Iwai9a081602008-02-12 18:37:26 +01001775 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
1776 hinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777}
1778
Takashi Iwaic2d986b2011-07-06 18:30:08 +02001779static int alc_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780 struct hda_codec *codec,
1781 unsigned int stream_tag,
1782 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001783 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784{
1785 struct alc_spec *spec = codec->spec;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02001786 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
1787 stream_tag, format, substream);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788}
1789
Takashi Iwaic2d986b2011-07-06 18:30:08 +02001790static int alc_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001792 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793{
1794 struct alc_spec *spec = codec->spec;
1795 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
1796}
1797
1798/*
1799 * Digital out
1800 */
Takashi Iwaic2d986b2011-07-06 18:30:08 +02001801static int alc_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001803 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804{
1805 struct alc_spec *spec = codec->spec;
1806 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
1807}
1808
Takashi Iwaic2d986b2011-07-06 18:30:08 +02001809static int alc_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02001810 struct hda_codec *codec,
1811 unsigned int stream_tag,
1812 unsigned int format,
1813 struct snd_pcm_substream *substream)
1814{
1815 struct alc_spec *spec = codec->spec;
1816 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
1817 stream_tag, format, substream);
1818}
1819
Takashi Iwaic2d986b2011-07-06 18:30:08 +02001820static int alc_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
Takashi Iwai9b5f12e2009-02-13 11:47:37 +01001821 struct hda_codec *codec,
1822 struct snd_pcm_substream *substream)
1823{
1824 struct alc_spec *spec = codec->spec;
1825 return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
1826}
1827
Takashi Iwaic2d986b2011-07-06 18:30:08 +02001828static int alc_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001830 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001831{
1832 struct alc_spec *spec = codec->spec;
1833 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
1834}
1835
1836/*
1837 * Analog capture
1838 */
Takashi Iwaic2d986b2011-07-06 18:30:08 +02001839static int alc_alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840 struct hda_codec *codec,
1841 unsigned int stream_tag,
1842 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001843 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844{
1845 struct alc_spec *spec = codec->spec;
1846
Takashi Iwai63300792008-01-24 15:31:36 +01001847 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1],
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848 stream_tag, 0, format);
1849 return 0;
1850}
1851
Takashi Iwaic2d986b2011-07-06 18:30:08 +02001852static int alc_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001854 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855{
1856 struct alc_spec *spec = codec->spec;
1857
Takashi Iwai888afa12008-03-18 09:57:50 +01001858 snd_hda_codec_cleanup_stream(codec,
1859 spec->adc_nids[substream->number + 1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860 return 0;
1861}
1862
Takashi Iwai840b64c2010-07-13 22:49:01 +02001863/* analog capture with dynamic dual-adc changes */
Takashi Iwai21268962011-07-07 15:01:13 +02001864static int dyn_adc_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
Takashi Iwai840b64c2010-07-13 22:49:01 +02001865 struct hda_codec *codec,
1866 unsigned int stream_tag,
1867 unsigned int format,
1868 struct snd_pcm_substream *substream)
1869{
1870 struct alc_spec *spec = codec->spec;
Takashi Iwai21268962011-07-07 15:01:13 +02001871 spec->cur_adc = spec->adc_nids[spec->dyn_adc_idx[spec->cur_mux[0]]];
Takashi Iwai840b64c2010-07-13 22:49:01 +02001872 spec->cur_adc_stream_tag = stream_tag;
1873 spec->cur_adc_format = format;
1874 snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format);
1875 return 0;
1876}
1877
Takashi Iwai21268962011-07-07 15:01:13 +02001878static int dyn_adc_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
Takashi Iwai840b64c2010-07-13 22:49:01 +02001879 struct hda_codec *codec,
1880 struct snd_pcm_substream *substream)
1881{
1882 struct alc_spec *spec = codec->spec;
1883 snd_hda_codec_cleanup_stream(codec, spec->cur_adc);
1884 spec->cur_adc = 0;
1885 return 0;
1886}
1887
Takashi Iwai21268962011-07-07 15:01:13 +02001888static const struct hda_pcm_stream dyn_adc_pcm_analog_capture = {
Takashi Iwai840b64c2010-07-13 22:49:01 +02001889 .substreams = 1,
1890 .channels_min = 2,
1891 .channels_max = 2,
1892 .nid = 0, /* fill later */
1893 .ops = {
Takashi Iwai21268962011-07-07 15:01:13 +02001894 .prepare = dyn_adc_capture_pcm_prepare,
1895 .cleanup = dyn_adc_capture_pcm_cleanup
Takashi Iwai840b64c2010-07-13 22:49:01 +02001896 },
1897};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898
1899/*
1900 */
Takashi Iwaic2d986b2011-07-06 18:30:08 +02001901static const struct hda_pcm_stream alc_pcm_analog_playback = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902 .substreams = 1,
1903 .channels_min = 2,
1904 .channels_max = 8,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001905 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906 .ops = {
Takashi Iwaic2d986b2011-07-06 18:30:08 +02001907 .open = alc_playback_pcm_open,
1908 .prepare = alc_playback_pcm_prepare,
1909 .cleanup = alc_playback_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910 },
1911};
1912
Takashi Iwaic2d986b2011-07-06 18:30:08 +02001913static const struct hda_pcm_stream alc_pcm_analog_capture = {
Takashi Iwai63300792008-01-24 15:31:36 +01001914 .substreams = 1,
1915 .channels_min = 2,
1916 .channels_max = 2,
1917 /* NID is set in alc_build_pcms */
1918};
1919
Takashi Iwaic2d986b2011-07-06 18:30:08 +02001920static const struct hda_pcm_stream alc_pcm_analog_alt_playback = {
Takashi Iwai63300792008-01-24 15:31:36 +01001921 .substreams = 1,
1922 .channels_min = 2,
1923 .channels_max = 2,
1924 /* NID is set in alc_build_pcms */
1925};
1926
Takashi Iwaic2d986b2011-07-06 18:30:08 +02001927static const struct hda_pcm_stream alc_pcm_analog_alt_capture = {
Takashi Iwai63300792008-01-24 15:31:36 +01001928 .substreams = 2, /* can be overridden */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929 .channels_min = 2,
1930 .channels_max = 2,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02001931 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932 .ops = {
Takashi Iwaic2d986b2011-07-06 18:30:08 +02001933 .prepare = alc_alt_capture_pcm_prepare,
1934 .cleanup = alc_alt_capture_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935 },
1936};
1937
Takashi Iwaic2d986b2011-07-06 18:30:08 +02001938static const struct hda_pcm_stream alc_pcm_digital_playback = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939 .substreams = 1,
1940 .channels_min = 2,
1941 .channels_max = 2,
1942 /* NID is set in alc_build_pcms */
1943 .ops = {
Takashi Iwaic2d986b2011-07-06 18:30:08 +02001944 .open = alc_dig_playback_pcm_open,
1945 .close = alc_dig_playback_pcm_close,
1946 .prepare = alc_dig_playback_pcm_prepare,
1947 .cleanup = alc_dig_playback_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948 },
1949};
1950
Takashi Iwaic2d986b2011-07-06 18:30:08 +02001951static const struct hda_pcm_stream alc_pcm_digital_capture = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952 .substreams = 1,
1953 .channels_min = 2,
1954 .channels_max = 2,
1955 /* NID is set in alc_build_pcms */
1956};
1957
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01001958/* Used by alc_build_pcms to flag that a PCM has no playback stream */
Takashi Iwaia9111322011-05-02 11:30:18 +02001959static const struct hda_pcm_stream alc_pcm_null_stream = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01001960 .substreams = 0,
1961 .channels_min = 0,
1962 .channels_max = 0,
1963};
1964
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965static int alc_build_pcms(struct hda_codec *codec)
1966{
1967 struct alc_spec *spec = codec->spec;
1968 struct hda_pcm *info = spec->pcm_rec;
Takashi Iwaic2d986b2011-07-06 18:30:08 +02001969 const struct hda_pcm_stream *p;
Takashi Iwai1fa17572011-11-02 21:30:51 +01001970 bool have_multi_adcs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001971 int i;
1972
1973 codec->num_pcms = 1;
1974 codec->pcm_info = info;
1975
Takashi Iwaie64f14f2009-01-20 18:32:55 +01001976 if (spec->no_analog)
1977 goto skip_analog;
1978
Takashi Iwai812a2cc2009-05-16 10:00:49 +02001979 snprintf(spec->stream_name_analog, sizeof(spec->stream_name_analog),
1980 "%s Analog", codec->chip_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981 info->name = spec->stream_name_analog;
Kailang Yang274693f2009-12-03 10:07:50 +01001982
Takashi Iwaieedec3d2012-02-06 10:24:04 +01001983 if (spec->multiout.num_dacs > 0) {
Takashi Iwaic2d986b2011-07-06 18:30:08 +02001984 p = spec->stream_analog_playback;
1985 if (!p)
1986 p = &alc_pcm_analog_playback;
1987 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p;
Takashi Iwai4a471b72005-12-07 13:56:29 +01001988 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
Takashi Iwai9c9a5172012-07-31 11:35:35 +02001989 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max =
1990 spec->multiout.max_channels;
Takashi Iwaiee81abb2012-11-08 17:12:10 +01001991 if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT &&
1992 spec->autocfg.line_outs == 2)
1993 info->stream[SNDRV_PCM_STREAM_PLAYBACK].chmap =
1994 snd_pcm_2_1_chmaps;
Takashi Iwai4a471b72005-12-07 13:56:29 +01001995 }
Takashi Iwai27d31532012-12-18 08:57:05 +01001996 if (spec->num_adc_nids) {
Takashi Iwaic2d986b2011-07-06 18:30:08 +02001997 p = spec->stream_analog_capture;
Takashi Iwai21268962011-07-07 15:01:13 +02001998 if (!p) {
1999 if (spec->dyn_adc_switch)
2000 p = &dyn_adc_pcm_analog_capture;
2001 else
2002 p = &alc_pcm_analog_capture;
2003 }
Takashi Iwaic2d986b2011-07-06 18:30:08 +02002004 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p;
Takashi Iwai4a471b72005-12-07 13:56:29 +01002005 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
2006 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007
Takashi Iwai4a471b72005-12-07 13:56:29 +01002008 if (spec->channel_mode) {
2009 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0;
2010 for (i = 0; i < spec->num_channel_mode; i++) {
2011 if (spec->channel_mode[i].channels > info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max) {
2012 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->channel_mode[i].channels;
2013 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014 }
2015 }
2016
Takashi Iwaie64f14f2009-01-20 18:32:55 +01002017 skip_analog:
Takashi Iwaie08a0072006-09-07 17:52:14 +02002018 /* SPDIF for stream index #1 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002019 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
Takashi Iwai812a2cc2009-05-16 10:00:49 +02002020 snprintf(spec->stream_name_digital,
2021 sizeof(spec->stream_name_digital),
2022 "%s Digital", codec->chip_name);
Takashi Iwaie08a0072006-09-07 17:52:14 +02002023 codec->num_pcms = 2;
Wu Fengguangb25c9da2009-02-06 15:02:27 +08002024 codec->slave_dig_outs = spec->multiout.slave_dig_outs;
Takashi Iwaic06134d2006-10-11 18:49:13 +02002025 info = spec->pcm_rec + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026 info->name = spec->stream_name_digital;
Takashi Iwai8c441982009-01-20 18:30:20 +01002027 if (spec->dig_out_type)
2028 info->pcm_type = spec->dig_out_type;
2029 else
2030 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Takashi Iwaic2d986b2011-07-06 18:30:08 +02002031 if (spec->multiout.dig_out_nid) {
2032 p = spec->stream_digital_playback;
2033 if (!p)
2034 p = &alc_pcm_digital_playback;
2035 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002036 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
2037 }
Takashi Iwaic2d986b2011-07-06 18:30:08 +02002038 if (spec->dig_in_nid) {
2039 p = spec->stream_digital_capture;
2040 if (!p)
2041 p = &alc_pcm_digital_capture;
2042 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002043 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
2044 }
Takashi Iwai963f8032008-08-11 10:04:40 +02002045 /* FIXME: do we need this for all Realtek codec models? */
2046 codec->spdif_status_reset = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002047 }
2048
Takashi Iwaie64f14f2009-01-20 18:32:55 +01002049 if (spec->no_analog)
2050 return 0;
2051
Takashi Iwaie08a0072006-09-07 17:52:14 +02002052 /* If the use of more than one ADC is requested for the current
2053 * model, configure a second analog capture-only PCM.
2054 */
Takashi Iwai1fa17572011-11-02 21:30:51 +01002055 have_multi_adcs = (spec->num_adc_nids > 1) &&
Takashi Iwai27d31532012-12-18 08:57:05 +01002056 !spec->dyn_adc_switch && !spec->auto_mic;
Takashi Iwaie08a0072006-09-07 17:52:14 +02002057 /* Additional Analaog capture for index #2 */
Takashi Iwai1fa17572011-11-02 21:30:51 +01002058 if (spec->alt_dac_nid || have_multi_adcs) {
Takashi Iwaie08a0072006-09-07 17:52:14 +02002059 codec->num_pcms = 3;
Takashi Iwaic06134d2006-10-11 18:49:13 +02002060 info = spec->pcm_rec + 2;
Takashi Iwaie08a0072006-09-07 17:52:14 +02002061 info->name = spec->stream_name_analog;
Takashi Iwai63300792008-01-24 15:31:36 +01002062 if (spec->alt_dac_nid) {
Takashi Iwaic2d986b2011-07-06 18:30:08 +02002063 p = spec->stream_analog_alt_playback;
2064 if (!p)
2065 p = &alc_pcm_analog_alt_playback;
2066 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p;
Takashi Iwai63300792008-01-24 15:31:36 +01002067 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
2068 spec->alt_dac_nid;
2069 } else {
2070 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
2071 alc_pcm_null_stream;
2072 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
2073 }
Takashi Iwai1fa17572011-11-02 21:30:51 +01002074 if (have_multi_adcs) {
Takashi Iwaic2d986b2011-07-06 18:30:08 +02002075 p = spec->stream_analog_alt_capture;
2076 if (!p)
2077 p = &alc_pcm_analog_alt_capture;
2078 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p;
Takashi Iwai63300792008-01-24 15:31:36 +01002079 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
2080 spec->adc_nids[1];
2081 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams =
2082 spec->num_adc_nids - 1;
2083 } else {
2084 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
2085 alc_pcm_null_stream;
2086 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0;
Takashi Iwaie08a0072006-09-07 17:52:14 +02002087 }
2088 }
2089
Linus Torvalds1da177e2005-04-16 15:20:36 -07002090 return 0;
2091}
2092
Takashi Iwaia4e09aa2009-12-27 11:22:24 +01002093static inline void alc_shutup(struct hda_codec *codec)
2094{
Takashi Iwai1c716152011-04-07 10:37:16 +02002095 struct alc_spec *spec = codec->spec;
2096
2097 if (spec && spec->shutup)
2098 spec->shutup(codec);
Takashi Iwaia4e09aa2009-12-27 11:22:24 +01002099 snd_hda_shutup_pins(codec);
2100}
2101
Takashi Iwai603c4012008-07-30 15:01:44 +02002102static void alc_free_kctls(struct hda_codec *codec)
2103{
2104 struct alc_spec *spec = codec->spec;
2105
2106 if (spec->kctls.list) {
2107 struct snd_kcontrol_new *kctl = spec->kctls.list;
2108 int i;
2109 for (i = 0; i < spec->kctls.used; i++)
2110 kfree(kctl[i].name);
2111 }
2112 snd_array_free(&spec->kctls);
2113}
2114
Takashi Iwai23c09b02011-08-19 09:05:35 +02002115static void alc_free_bind_ctls(struct hda_codec *codec)
2116{
2117 struct alc_spec *spec = codec->spec;
2118 if (spec->bind_ctls.list) {
2119 struct hda_bind_ctls **ctl = spec->bind_ctls.list;
2120 int i;
2121 for (i = 0; i < spec->bind_ctls.used; i++)
2122 kfree(ctl[i]);
2123 }
2124 snd_array_free(&spec->bind_ctls);
2125}
2126
Linus Torvalds1da177e2005-04-16 15:20:36 -07002127static void alc_free(struct hda_codec *codec)
2128{
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002129 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002130
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002131 if (!spec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002132 return;
2133
Takashi Iwai603c4012008-07-30 15:01:44 +02002134 alc_free_kctls(codec);
Takashi Iwai23c09b02011-08-19 09:05:35 +02002135 alc_free_bind_ctls(codec);
Takashi Iwaic9967f12012-12-14 16:39:22 +01002136 snd_array_free(&spec->paths);
Takashi Iwaiee48df52012-06-26 14:54:32 +02002137 snd_hda_gen_free(&spec->gen);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002138 kfree(spec);
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09002139 snd_hda_detach_beep_device(codec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002140}
2141
Takashi Iwai83012a72012-08-24 18:38:08 +02002142#ifdef CONFIG_PM
Daniel T Chenc97259d2009-12-27 18:52:08 -05002143static void alc_power_eapd(struct hda_codec *codec)
2144{
Takashi Iwai691f1fc2011-04-07 10:31:43 +02002145 alc_auto_setup_eapd(codec, false);
Daniel T Chenc97259d2009-12-27 18:52:08 -05002146}
2147
Takashi Iwai68cb2b52012-07-02 15:20:37 +02002148static int alc_suspend(struct hda_codec *codec)
Hector Martinf5de24b2009-12-20 22:51:31 +01002149{
2150 struct alc_spec *spec = codec->spec;
Takashi Iwaia4e09aa2009-12-27 11:22:24 +01002151 alc_shutup(codec);
Hector Martinf5de24b2009-12-20 22:51:31 +01002152 if (spec && spec->power_hook)
Daniel T Chenc97259d2009-12-27 18:52:08 -05002153 spec->power_hook(codec);
Hector Martinf5de24b2009-12-20 22:51:31 +01002154 return 0;
2155}
2156#endif
2157
Takashi Iwai2a439522011-07-26 09:52:50 +02002158#ifdef CONFIG_PM
Takashi Iwaie044c392008-10-27 16:56:24 +01002159static int alc_resume(struct hda_codec *codec)
2160{
Takashi Iwai1c716152011-04-07 10:37:16 +02002161 msleep(150); /* to avoid pop noise */
Takashi Iwaie044c392008-10-27 16:56:24 +01002162 codec->patch_ops.init(codec);
2163 snd_hda_codec_resume_amp(codec);
2164 snd_hda_codec_resume_cache(codec);
Takashi Iwai125821a2012-06-22 14:30:29 +02002165 alc_inv_dmic_sync(codec, true);
Takashi Iwai9e5341b2010-09-21 09:57:06 +02002166 hda_call_check_power_status(codec, 0x01);
Takashi Iwaie044c392008-10-27 16:56:24 +01002167 return 0;
2168}
Takashi Iwaie044c392008-10-27 16:56:24 +01002169#endif
2170
Linus Torvalds1da177e2005-04-16 15:20:36 -07002171/*
2172 */
Takashi Iwaia9111322011-05-02 11:30:18 +02002173static const struct hda_codec_ops alc_patch_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002174 .build_controls = alc_build_controls,
2175 .build_pcms = alc_build_pcms,
2176 .init = alc_init,
2177 .free = alc_free,
David Henningsson29adc4b2012-09-25 11:31:00 +02002178 .unsol_event = snd_hda_jack_unsol_event,
Takashi Iwai2a439522011-07-26 09:52:50 +02002179#ifdef CONFIG_PM
Takashi Iwaie044c392008-10-27 16:56:24 +01002180 .resume = alc_resume,
2181#endif
Takashi Iwai83012a72012-08-24 18:38:08 +02002182#ifdef CONFIG_PM
Hector Martinf5de24b2009-12-20 22:51:31 +01002183 .suspend = alc_suspend,
Takashi Iwaicb53c622007-08-10 17:21:45 +02002184 .check_power_status = alc_check_power_status,
2185#endif
Daniel T Chenc97259d2009-12-27 18:52:08 -05002186 .reboot_notify = alc_shutup,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002187};
2188
David Henningsson29adc4b2012-09-25 11:31:00 +02002189
Kailang Yangc027ddc2010-03-19 11:33:06 +01002190/* replace the codec chip_name with the given string */
2191static int alc_codec_rename(struct hda_codec *codec, const char *name)
2192{
2193 kfree(codec->chip_name);
2194 codec->chip_name = kstrdup(name, GFP_KERNEL);
2195 if (!codec->chip_name) {
2196 alc_free(codec);
2197 return -ENOMEM;
2198 }
2199 return 0;
2200}
2201
Takashi Iwai2fa522b2005-05-12 14:51:12 +02002202/*
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02002203 * Rename codecs appropriately from COEF value
2204 */
2205struct alc_codec_rename_table {
2206 unsigned int vendor_id;
2207 unsigned short coef_mask;
2208 unsigned short coef_bits;
2209 const char *name;
2210};
2211
2212static struct alc_codec_rename_table rename_tbl[] = {
2213 { 0x10ec0269, 0xfff0, 0x3010, "ALC277" },
2214 { 0x10ec0269, 0xf0f0, 0x2010, "ALC259" },
2215 { 0x10ec0269, 0xf0f0, 0x3010, "ALC258" },
2216 { 0x10ec0269, 0x00f0, 0x0010, "ALC269VB" },
2217 { 0x10ec0269, 0xffff, 0xa023, "ALC259" },
2218 { 0x10ec0269, 0xffff, 0x6023, "ALC281X" },
2219 { 0x10ec0269, 0x00f0, 0x0020, "ALC269VC" },
Kailang Yangadcc70b2012-05-25 08:08:38 +02002220 { 0x10ec0269, 0x00f0, 0x0030, "ALC269VD" },
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02002221 { 0x10ec0887, 0x00f0, 0x0030, "ALC887-VD" },
2222 { 0x10ec0888, 0x00f0, 0x0030, "ALC888-VD" },
2223 { 0x10ec0888, 0xf0f0, 0x3020, "ALC886" },
2224 { 0x10ec0899, 0x2000, 0x2000, "ALC899" },
2225 { 0x10ec0892, 0xffff, 0x8020, "ALC661" },
2226 { 0x10ec0892, 0xffff, 0x8011, "ALC661" },
2227 { 0x10ec0892, 0xffff, 0x4011, "ALC656" },
2228 { } /* terminator */
2229};
2230
2231static int alc_codec_rename_from_preset(struct hda_codec *codec)
2232{
2233 const struct alc_codec_rename_table *p;
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02002234
2235 for (p = rename_tbl; p->vendor_id; p++) {
2236 if (p->vendor_id != codec->vendor_id)
2237 continue;
Takashi Iwai1bb7e432011-10-17 16:50:59 +02002238 if ((alc_get_coef0(codec) & p->coef_mask) == p->coef_bits)
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02002239 return alc_codec_rename(codec, p->name);
2240 }
2241 return 0;
2242}
2243
2244/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002245 * Automatic parse of I/O pins from the BIOS configuration
2246 */
2247
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002248enum {
2249 ALC_CTL_WIDGET_VOL,
2250 ALC_CTL_WIDGET_MUTE,
2251 ALC_CTL_BIND_MUTE,
Takashi Iwai23c09b02011-08-19 09:05:35 +02002252 ALC_CTL_BIND_VOL,
2253 ALC_CTL_BIND_SW,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002254};
Takashi Iwai1d045db2011-07-07 18:23:21 +02002255static const struct snd_kcontrol_new alc_control_templates[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002256 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
2257 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Takashi Iwai985be542005-11-02 18:26:49 +01002258 HDA_BIND_MUTE(NULL, 0, 0, 0),
Takashi Iwai23c09b02011-08-19 09:05:35 +02002259 HDA_BIND_VOL(NULL, 0),
2260 HDA_BIND_SW(NULL, 0),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002261};
2262
2263/* add dynamic controls */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002264static int add_control(struct alc_spec *spec, int type, const char *name,
Takashi Iwai66ceeb62010-08-30 13:05:52 +02002265 int cidx, unsigned long val)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002266{
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01002267 struct snd_kcontrol_new *knew;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002268
Takashi Iwai668d1e92012-11-29 14:10:17 +01002269 knew = alc_kcontrol_new(spec, name, &alc_control_templates[type]);
Takashi Iwai603c4012008-07-30 15:01:44 +02002270 if (!knew)
2271 return -ENOMEM;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02002272 knew->index = cidx;
Jaroslav Kysela4d02d1b2009-11-12 10:15:48 +01002273 if (get_amp_nid_(val))
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +01002274 knew->subdevice = HDA_SUBDEV_AMP_FLAG;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002275 knew->private_value = val;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002276 return 0;
2277}
2278
Takashi Iwai0afe5f82009-10-02 09:20:00 +02002279static int add_control_with_pfx(struct alc_spec *spec, int type,
2280 const char *pfx, const char *dir,
Takashi Iwai66ceeb62010-08-30 13:05:52 +02002281 const char *sfx, int cidx, unsigned long val)
Takashi Iwai0afe5f82009-10-02 09:20:00 +02002282{
2283 char name[32];
2284 snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx);
Takashi Iwai66ceeb62010-08-30 13:05:52 +02002285 return add_control(spec, type, name, cidx, val);
Takashi Iwai0afe5f82009-10-02 09:20:00 +02002286}
2287
Takashi Iwai66ceeb62010-08-30 13:05:52 +02002288#define add_pb_vol_ctrl(spec, type, pfx, val) \
2289 add_control_with_pfx(spec, type, pfx, "Playback", "Volume", 0, val)
2290#define add_pb_sw_ctrl(spec, type, pfx, val) \
2291 add_control_with_pfx(spec, type, pfx, "Playback", "Switch", 0, val)
2292#define __add_pb_vol_ctrl(spec, type, pfx, cidx, val) \
2293 add_control_with_pfx(spec, type, pfx, "Playback", "Volume", cidx, val)
2294#define __add_pb_sw_ctrl(spec, type, pfx, cidx, val) \
2295 add_control_with_pfx(spec, type, pfx, "Playback", "Switch", cidx, val)
Takashi Iwai0afe5f82009-10-02 09:20:00 +02002296
Takashi Iwai23c09b02011-08-19 09:05:35 +02002297static const char * const channel_name[4] = {
2298 "Front", "Surround", "CLFE", "Side"
2299};
2300
Takashi Iwai6843ca12011-06-24 11:03:58 +02002301static const char *alc_get_line_out_pfx(struct alc_spec *spec, int ch,
2302 bool can_be_master, int *index)
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01002303{
Takashi Iwaice764ab2011-04-27 16:35:23 +02002304 struct auto_pin_cfg *cfg = &spec->autocfg;
2305
Takashi Iwai6843ca12011-06-24 11:03:58 +02002306 *index = 0;
Takashi Iwaice764ab2011-04-27 16:35:23 +02002307 if (cfg->line_outs == 1 && !spec->multi_ios &&
2308 !cfg->hp_outs && !cfg->speaker_outs && can_be_master)
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01002309 return "Master";
2310
2311 switch (cfg->line_out_type) {
2312 case AUTO_PIN_SPEAKER_OUT:
David Henningssonebbeb3d2011-03-04 14:08:30 +01002313 if (cfg->line_outs == 1)
2314 return "Speaker";
Takashi Iwaifbabc242011-12-07 17:14:20 +01002315 if (cfg->line_outs == 2)
2316 return ch ? "Bass Speaker" : "Speaker";
David Henningssonebbeb3d2011-03-04 14:08:30 +01002317 break;
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01002318 case AUTO_PIN_HP_OUT:
Takashi Iwai6843ca12011-06-24 11:03:58 +02002319 /* for multi-io case, only the primary out */
2320 if (ch && spec->multi_ios)
2321 break;
2322 *index = ch;
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01002323 return "Headphone";
2324 default:
Takashi Iwaice764ab2011-04-27 16:35:23 +02002325 if (cfg->line_outs == 1 && !spec->multi_ios)
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01002326 return "PCM";
2327 break;
2328 }
David Henningsson71aa5eb2012-10-17 12:43:44 +02002329 if (ch >= ARRAY_SIZE(channel_name)) {
2330 snd_BUG();
Takashi Iwai23c09b02011-08-19 09:05:35 +02002331 return "PCM";
David Henningsson71aa5eb2012-10-17 12:43:44 +02002332 }
Takashi Iwai23c09b02011-08-19 09:05:35 +02002333
2334 return channel_name[ch];
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01002335}
2336
Takashi Iwai83012a72012-08-24 18:38:08 +02002337#ifdef CONFIG_PM
Takashi Iwai164f73e2012-02-21 11:27:09 +01002338/* add the powersave loopback-list entry */
2339static void add_loopback_list(struct alc_spec *spec, hda_nid_t mix, int idx)
2340{
2341 struct hda_amp_list *list;
2342
2343 if (spec->num_loopbacks >= ARRAY_SIZE(spec->loopback_list) - 1)
2344 return;
2345 list = spec->loopback_list + spec->num_loopbacks;
2346 list->nid = mix;
2347 list->dir = HDA_INPUT;
2348 list->idx = idx;
2349 spec->num_loopbacks++;
2350 spec->loopback.amplist = spec->loopback_list;
2351}
2352#else
2353#define add_loopback_list(spec, mix, idx) /* NOP */
2354#endif
2355
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002356/* create input playback/capture controls for the given pin */
Takashi Iwaic2fd19c2012-12-12 18:02:41 +01002357static int new_analog_input(struct hda_codec *codec, hda_nid_t pin,
Takashi Iwai66ceeb62010-08-30 13:05:52 +02002358 const char *ctlname, int ctlidx,
Takashi Iwaic2fd19c2012-12-12 18:02:41 +01002359 hda_nid_t mix_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002360{
Takashi Iwaic2fd19c2012-12-12 18:02:41 +01002361 struct alc_spec *spec = codec->spec;
2362 struct nid_path *path;
Takashi Iwai829f69e2012-12-14 18:26:02 +01002363 unsigned int val;
Takashi Iwaic2fd19c2012-12-12 18:02:41 +01002364 int err, idx;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002365
Takashi Iwaibd32f782012-12-12 18:08:52 +01002366 if (!nid_has_volume(codec, mix_nid, HDA_INPUT) &&
2367 !nid_has_mute(codec, mix_nid, HDA_INPUT))
2368 return 0; /* no need for analog loopback */
2369
Takashi Iwai965cceb2012-12-18 11:46:37 +01002370 path = add_new_nid_path(codec, pin, mix_nid, 2);
Takashi Iwaic2fd19c2012-12-12 18:02:41 +01002371 if (!path)
Takashi Iwaic2fd19c2012-12-12 18:02:41 +01002372 return -EINVAL;
2373
2374 idx = path->idx[path->depth - 1];
Takashi Iwaibd32f782012-12-12 18:08:52 +01002375 if (nid_has_volume(codec, mix_nid, HDA_INPUT)) {
Takashi Iwai829f69e2012-12-14 18:26:02 +01002376 val = HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT);
2377 err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname, ctlidx, val);
Takashi Iwaibd32f782012-12-12 18:08:52 +01002378 if (err < 0)
2379 return err;
Takashi Iwai829f69e2012-12-14 18:26:02 +01002380 path->ctls[NID_PATH_VOL_CTL] = val;
Takashi Iwaibd32f782012-12-12 18:08:52 +01002381 }
2382
2383 if (nid_has_mute(codec, mix_nid, HDA_INPUT)) {
Takashi Iwai829f69e2012-12-14 18:26:02 +01002384 val = HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT);
2385 err = __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname, ctlidx, val);
Takashi Iwaibd32f782012-12-12 18:08:52 +01002386 if (err < 0)
2387 return err;
Takashi Iwai829f69e2012-12-14 18:26:02 +01002388 path->ctls[NID_PATH_MUTE_CTL] = val;
Takashi Iwaibd32f782012-12-12 18:08:52 +01002389 }
2390
Takashi Iwai829f69e2012-12-14 18:26:02 +01002391 path->active = true;
Takashi Iwai164f73e2012-02-21 11:27:09 +01002392 add_loopback_list(spec, mix_nid, idx);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002393 return 0;
2394}
2395
Takashi Iwai05f5f472009-08-25 13:10:18 +02002396static int alc_is_input_pin(struct hda_codec *codec, hda_nid_t nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002397{
Takashi Iwai05f5f472009-08-25 13:10:18 +02002398 unsigned int pincap = snd_hda_query_pin_caps(codec, nid);
2399 return (pincap & AC_PINCAP_IN) != 0;
2400}
2401
Takashi Iwaic2fd19c2012-12-12 18:02:41 +01002402/* check whether the given two widgets can be connected */
2403static bool is_reachable_path(struct hda_codec *codec,
2404 hda_nid_t from_nid, hda_nid_t to_nid)
2405{
2406 if (!from_nid || !to_nid)
2407 return false;
2408 return snd_hda_get_conn_index(codec, to_nid, from_nid, true) >= 0;
2409}
2410
Takashi Iwai666a70d2012-12-17 20:29:29 +01002411/* Parse the codec tree and retrieve ADCs */
2412static int alc_auto_fill_adc_nids(struct hda_codec *codec)
Takashi Iwaib7821702011-07-06 15:12:46 +02002413{
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02002414 struct alc_spec *spec = codec->spec;
Takashi Iwaib7821702011-07-06 15:12:46 +02002415 hda_nid_t nid;
Takashi Iwai27d31532012-12-18 08:57:05 +01002416 hda_nid_t *adc_nids = spec->adc_nids;
2417 int max_nums = ARRAY_SIZE(spec->adc_nids);
Takashi Iwaib7821702011-07-06 15:12:46 +02002418 int i, nums = 0;
2419
2420 nid = codec->start_nid;
2421 for (i = 0; i < codec->num_nodes; i++, nid++) {
Takashi Iwaib7821702011-07-06 15:12:46 +02002422 unsigned int caps = get_wcaps(codec, nid);
2423 int type = get_wcaps_type(caps);
2424
2425 if (type != AC_WID_AUD_IN || (caps & AC_WCAP_DIGITAL))
2426 continue;
2427 adc_nids[nums] = nid;
Takashi Iwaib7821702011-07-06 15:12:46 +02002428 if (++nums >= max_nums)
2429 break;
2430 }
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02002431 spec->num_adc_nids = nums;
Takashi Iwaib7821702011-07-06 15:12:46 +02002432 return nums;
2433}
2434
Takashi Iwai666a70d2012-12-17 20:29:29 +01002435/* filter out invalid adc_nids that don't give all active input pins;
2436 * if needed, check whether dynamic ADC-switching is available
2437 */
2438static int check_dyn_adc_switch(struct hda_codec *codec)
2439{
2440 struct alc_spec *spec = codec->spec;
Takashi Iwai27d31532012-12-18 08:57:05 +01002441 struct hda_input_mux *imux = &spec->input_mux;
2442 hda_nid_t adc_nids[ARRAY_SIZE(spec->adc_nids)];
Takashi Iwai666a70d2012-12-17 20:29:29 +01002443 int i, n, nums;
2444 hda_nid_t pin, adc;
2445
2446 again:
2447 nums = 0;
2448 for (n = 0; n < spec->num_adc_nids; n++) {
2449 adc = spec->adc_nids[n];
2450 for (i = 0; i < imux->num_items; i++) {
2451 pin = spec->imux_pins[i];
2452 if (!is_reachable_path(codec, pin, adc))
2453 break;
2454 }
2455 if (i >= imux->num_items)
2456 adc_nids[nums++] = adc;
2457 }
2458
2459 if (!nums) {
2460 if (spec->shared_mic_hp) {
2461 spec->shared_mic_hp = 0;
Takashi Iwai27d31532012-12-18 08:57:05 +01002462 imux->num_items = 1;
Takashi Iwai666a70d2012-12-17 20:29:29 +01002463 goto again;
2464 }
2465
2466 /* check whether ADC-switch is possible */
2467 for (i = 0; i < imux->num_items; i++) {
2468 pin = spec->imux_pins[i];
2469 for (n = 0; n < spec->num_adc_nids; n++) {
2470 adc = spec->adc_nids[n];
2471 if (is_reachable_path(codec, pin, adc)) {
2472 spec->dyn_adc_idx[i] = n;
2473 break;
2474 }
2475 }
2476 }
2477
2478 snd_printdd("realtek: enabling ADC switching\n");
2479 spec->dyn_adc_switch = 1;
2480 } else if (nums != spec->num_adc_nids) {
Takashi Iwai27d31532012-12-18 08:57:05 +01002481 memcpy(spec->adc_nids, adc_nids, nums * sizeof(hda_nid_t));
Takashi Iwai666a70d2012-12-17 20:29:29 +01002482 spec->num_adc_nids = nums;
2483 }
2484
Takashi Iwai27d31532012-12-18 08:57:05 +01002485 if (imux->num_items == 1 || spec->shared_mic_hp) {
Takashi Iwai666a70d2012-12-17 20:29:29 +01002486 snd_printdd("realtek: reducing to a single ADC\n");
2487 spec->num_adc_nids = 1; /* reduce to a single ADC */
2488 }
2489
2490 return 0;
2491}
2492
2493/* templates for capture controls */
2494static const struct snd_kcontrol_new cap_src_temp = {
2495 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2496 .name = "Input Source",
2497 .info = alc_mux_enum_info,
2498 .get = alc_mux_enum_get,
2499 .put = alc_mux_enum_put,
2500};
2501
2502static const struct snd_kcontrol_new cap_vol_temp = {
2503 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2504 .name = "Capture Volume",
2505 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
2506 SNDRV_CTL_ELEM_ACCESS_TLV_READ |
2507 SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK),
2508 .info = alc_cap_vol_info,
2509 .get = alc_cap_vol_get,
2510 .put = alc_cap_vol_put,
2511 .tlv = { .c = alc_cap_vol_tlv },
2512};
2513
2514static const struct snd_kcontrol_new cap_sw_temp = {
2515 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2516 .name = "Capture Switch",
2517 .info = alc_cap_sw_info,
2518 .get = alc_cap_sw_get,
2519 .put = alc_cap_sw_put,
2520};
2521
2522static int parse_capvol_in_path(struct hda_codec *codec, struct nid_path *path)
2523{
2524 hda_nid_t nid;
2525 int i, depth;
2526
2527 path->ctls[NID_PATH_VOL_CTL] = path->ctls[NID_PATH_MUTE_CTL] = 0;
2528 for (depth = 0; depth < 3; depth++) {
2529 if (depth >= path->depth)
2530 return -EINVAL;
2531 i = path->depth - depth - 1;
2532 nid = path->path[i];
2533 if (!path->ctls[NID_PATH_VOL_CTL]) {
2534 if (nid_has_volume(codec, nid, HDA_OUTPUT))
2535 path->ctls[NID_PATH_VOL_CTL] =
2536 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
2537 else if (nid_has_volume(codec, nid, HDA_INPUT)) {
2538 int idx = path->idx[i];
2539 if (!depth && codec->single_adc_amp)
2540 idx = 0;
2541 path->ctls[NID_PATH_VOL_CTL] =
2542 HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_INPUT);
2543 }
2544 }
2545 if (!path->ctls[NID_PATH_MUTE_CTL]) {
2546 if (nid_has_mute(codec, nid, HDA_OUTPUT))
2547 path->ctls[NID_PATH_MUTE_CTL] =
2548 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
2549 else if (nid_has_mute(codec, nid, HDA_INPUT)) {
2550 int idx = path->idx[i];
2551 if (!depth && codec->single_adc_amp)
2552 idx = 0;
2553 path->ctls[NID_PATH_MUTE_CTL] =
2554 HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_INPUT);
2555 }
2556 }
2557 }
2558 return 0;
2559}
2560
2561static int create_capture_mixers(struct hda_codec *codec)
2562{
2563 struct alc_spec *spec = codec->spec;
Takashi Iwai27d31532012-12-18 08:57:05 +01002564 struct hda_input_mux *imux = &spec->input_mux;
Takashi Iwai666a70d2012-12-17 20:29:29 +01002565 struct snd_kcontrol_new *knew;
2566 int i, n, nums;
2567
2568 if (spec->dyn_adc_switch)
2569 nums = 1;
2570 else
2571 nums = spec->num_adc_nids;
2572
2573 if (!spec->auto_mic && imux->num_items > 1) {
2574 knew = alc_kcontrol_new(spec, "Input Source", &cap_src_temp);
2575 if (!knew)
2576 return -ENOMEM;
2577 knew->count = nums;
2578 }
2579
2580 for (n = 0; n < nums; n++) {
2581 int vol, sw;
2582
2583 vol = sw = 0;
2584 for (i = 0; i < imux->num_items; i++) {
2585 struct nid_path *path;
2586 path = get_nid_path(codec, spec->imux_pins[i],
2587 get_adc_nid(codec, n, i));
2588 if (!path)
2589 continue;
2590 parse_capvol_in_path(codec, path);
2591 if (!vol)
2592 vol = path->ctls[NID_PATH_VOL_CTL];
2593 if (!sw)
2594 sw = path->ctls[NID_PATH_MUTE_CTL];
2595 }
2596
2597 if (vol) {
2598 knew = alc_kcontrol_new(spec, "Capture Volume",
2599 &cap_vol_temp);
2600 if (!knew)
2601 return -ENOMEM;
2602 knew->index = n;
2603 knew->private_value = vol;
2604 knew->subdevice = HDA_SUBDEV_AMP_FLAG;
2605 }
2606 if (sw) {
2607 knew = alc_kcontrol_new(spec, "Capture Switch",
2608 &cap_sw_temp);
2609 if (!knew)
2610 return -ENOMEM;
2611 knew->index = n;
2612 knew->private_value = sw;
2613 knew->subdevice = HDA_SUBDEV_AMP_FLAG;
2614 }
2615 }
2616
2617 return 0;
2618}
2619
Takashi Iwai05f5f472009-08-25 13:10:18 +02002620/* create playback/capture controls for input pins */
Takashi Iwaib7821702011-07-06 15:12:46 +02002621static int alc_auto_create_input_ctls(struct hda_codec *codec)
Takashi Iwai05f5f472009-08-25 13:10:18 +02002622{
2623 struct alc_spec *spec = codec->spec;
Takashi Iwaib7821702011-07-06 15:12:46 +02002624 const struct auto_pin_cfg *cfg = &spec->autocfg;
2625 hda_nid_t mixer = spec->mixer_nid;
Takashi Iwai27d31532012-12-18 08:57:05 +01002626 struct hda_input_mux *imux = &spec->input_mux;
Takashi Iwaib7821702011-07-06 15:12:46 +02002627 int num_adcs;
Takashi Iwai666a70d2012-12-17 20:29:29 +01002628 int i, c, err, type_idx = 0;
David Henningsson5322bf22011-01-05 11:03:56 +01002629 const char *prev_label = NULL;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002630
Takashi Iwai666a70d2012-12-17 20:29:29 +01002631 num_adcs = alc_auto_fill_adc_nids(codec);
Takashi Iwaib7821702011-07-06 15:12:46 +02002632 if (num_adcs < 0)
2633 return 0;
2634
Takashi Iwai66ceeb62010-08-30 13:05:52 +02002635 for (i = 0; i < cfg->num_inputs; i++) {
Takashi Iwai05f5f472009-08-25 13:10:18 +02002636 hda_nid_t pin;
Takashi Iwai10a20af2010-09-09 16:28:02 +02002637 const char *label;
Takashi Iwai666a70d2012-12-17 20:29:29 +01002638 bool imux_added;
Takashi Iwai05f5f472009-08-25 13:10:18 +02002639
Takashi Iwai66ceeb62010-08-30 13:05:52 +02002640 pin = cfg->inputs[i].pin;
Takashi Iwai05f5f472009-08-25 13:10:18 +02002641 if (!alc_is_input_pin(codec, pin))
2642 continue;
2643
David Henningsson5322bf22011-01-05 11:03:56 +01002644 label = hda_get_autocfg_input_label(codec, cfg, i);
Takashi Iwai24de1832011-11-07 17:13:39 +01002645 if (spec->shared_mic_hp && !strcmp(label, "Misc"))
2646 label = "Headphone Mic";
David Henningsson5322bf22011-01-05 11:03:56 +01002647 if (prev_label && !strcmp(label, prev_label))
Takashi Iwai66ceeb62010-08-30 13:05:52 +02002648 type_idx++;
2649 else
2650 type_idx = 0;
David Henningsson5322bf22011-01-05 11:03:56 +01002651 prev_label = label;
2652
Takashi Iwai05f5f472009-08-25 13:10:18 +02002653 if (mixer) {
Takashi Iwaic2fd19c2012-12-12 18:02:41 +01002654 if (is_reachable_path(codec, pin, mixer)) {
2655 err = new_analog_input(codec, pin,
2656 label, type_idx, mixer);
Takashi Iwai05f5f472009-08-25 13:10:18 +02002657 if (err < 0)
2658 return err;
2659 }
2660 }
2661
Takashi Iwai666a70d2012-12-17 20:29:29 +01002662 imux_added = false;
Takashi Iwaib7821702011-07-06 15:12:46 +02002663 for (c = 0; c < num_adcs; c++) {
Takashi Iwai666a70d2012-12-17 20:29:29 +01002664 struct nid_path *path;
2665 hda_nid_t adc = spec->adc_nids[c];
2666
2667 if (!is_reachable_path(codec, pin, adc))
2668 continue;
2669 path = snd_array_new(&spec->paths);
2670 if (!path)
2671 return -ENOMEM;
2672 memset(path, 0, sizeof(*path));
2673 if (!parse_nid_path(codec, pin, adc, 2, path)) {
2674 snd_printd(KERN_ERR
2675 "invalid input path 0x%x -> 0x%x\n",
2676 pin, adc);
2677 spec->paths.used--;
2678 continue;
2679 }
2680
2681 if (!imux_added) {
2682 spec->imux_pins[imux->num_items] = pin;
2683 snd_hda_add_imux_item(imux, label,
2684 imux->num_items, NULL);
2685 imux_added = true;
Takashi Iwaib7821702011-07-06 15:12:46 +02002686 }
2687 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002688 }
Takashi Iwai21268962011-07-07 15:01:13 +02002689
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002690 return 0;
2691}
2692
Takashi Iwai24de1832011-11-07 17:13:39 +01002693/* create a shared input with the headphone out */
2694static int alc_auto_create_shared_input(struct hda_codec *codec)
2695{
2696 struct alc_spec *spec = codec->spec;
2697 struct auto_pin_cfg *cfg = &spec->autocfg;
2698 unsigned int defcfg;
2699 hda_nid_t nid;
2700
2701 /* only one internal input pin? */
2702 if (cfg->num_inputs != 1)
2703 return 0;
2704 defcfg = snd_hda_codec_get_pincfg(codec, cfg->inputs[0].pin);
2705 if (snd_hda_get_input_pin_attr(defcfg) != INPUT_PIN_ATTR_INT)
2706 return 0;
2707
2708 if (cfg->hp_outs == 1 && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
2709 nid = cfg->hp_pins[0]; /* OK, we have a single HP-out */
2710 else if (cfg->line_outs == 1 && cfg->line_out_type == AUTO_PIN_HP_OUT)
2711 nid = cfg->line_out_pins[0]; /* OK, we have a single line-out */
2712 else
2713 return 0; /* both not available */
2714
2715 if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_IN))
2716 return 0; /* no input */
2717
2718 cfg->inputs[1].pin = nid;
2719 cfg->inputs[1].type = AUTO_PIN_MIC;
2720 cfg->num_inputs = 2;
2721 spec->shared_mic_hp = 1;
2722 snd_printdd("realtek: Enable shared I/O jack on NID 0x%x\n", nid);
2723 return 0;
2724}
2725
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02002726static int get_pin_type(int line_out_type)
2727{
2728 if (line_out_type == AUTO_PIN_HP_OUT)
2729 return PIN_HP;
2730 else
2731 return PIN_OUT;
2732}
2733
Takashi Iwai0a7f5322011-07-06 15:15:12 +02002734static void alc_auto_init_analog_input(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002735{
2736 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02002737 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002738 int i;
2739
Takashi Iwai66ceeb62010-08-30 13:05:52 +02002740 for (i = 0; i < cfg->num_inputs; i++) {
2741 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai62343992012-12-18 09:06:01 +01002742 if (alc_is_input_pin(codec, nid))
Takashi Iwai30ea0982010-09-16 18:47:56 +02002743 alc_set_input_pin(codec, nid, cfg->inputs[i].type);
Takashi Iwai1f0f4b82011-06-27 10:52:59 +02002744
Takashi Iwai829f69e2012-12-14 18:26:02 +01002745 /* mute loopback inputs */
2746 if (spec->mixer_nid) {
2747 struct nid_path *path;
2748 path = get_nid_path(codec, nid, spec->mixer_nid);
2749 if (path)
Takashi Iwai666a70d2012-12-17 20:29:29 +01002750 activate_path(codec, path, path->active, false);
Takashi Iwai829f69e2012-12-14 18:26:02 +01002751 }
Takashi Iwai1f0f4b82011-06-27 10:52:59 +02002752 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002753}
2754
Takashi Iwai185d99f2012-02-16 18:39:45 +01002755static bool alc_is_dac_already_used(struct hda_codec *codec, hda_nid_t nid)
2756{
2757 struct alc_spec *spec = codec->spec;
Takashi Iwai276dd702012-02-17 16:17:03 +01002758 int i;
Takashi Iwai30dcd3b2012-12-06 15:45:38 +01002759
Takashi Iwaic9967f12012-12-14 16:39:22 +01002760 for (i = 0; i < spec->paths.used; i++) {
2761 struct nid_path *path = snd_array_elem(&spec->paths, i);
Takashi Iwai30dcd3b2012-12-06 15:45:38 +01002762 if (path->path[0] == nid)
Takashi Iwai276dd702012-02-17 16:17:03 +01002763 return true;
2764 }
Takashi Iwai185d99f2012-02-16 18:39:45 +01002765 return false;
2766}
2767
Takashi Iwai463419d2012-12-05 14:17:37 +01002768/* look for an empty DAC slot */
Takashi Iwaifef7fbb2012-12-14 16:54:44 +01002769static hda_nid_t alc_auto_look_for_dac(struct hda_codec *codec, hda_nid_t pin,
2770 bool is_digital)
Takashi Iwai463419d2012-12-05 14:17:37 +01002771{
2772 struct alc_spec *spec = codec->spec;
Takashi Iwaifef7fbb2012-12-14 16:54:44 +01002773 bool cap_digital;
Takashi Iwai463419d2012-12-05 14:17:37 +01002774 int i;
2775
2776 for (i = 0; i < spec->num_all_dacs; i++) {
2777 hda_nid_t nid = spec->all_dacs[i];
2778 if (!nid || alc_is_dac_already_used(codec, nid))
2779 continue;
Takashi Iwaifef7fbb2012-12-14 16:54:44 +01002780 cap_digital = !!(get_wcaps(codec, nid) & AC_WCAP_DIGITAL);
2781 if (is_digital != cap_digital)
2782 continue;
Takashi Iwai9c640762012-12-14 16:15:56 +01002783 if (is_reachable_path(codec, nid, pin))
Takashi Iwai463419d2012-12-05 14:17:37 +01002784 return nid;
2785 }
2786 return 0;
2787}
2788
Takashi Iwai30dcd3b2012-12-06 15:45:38 +01002789/* called recursively */
Takashi Iwai36f0fd52012-12-12 17:25:00 +01002790static bool __parse_nid_path(struct hda_codec *codec,
2791 hda_nid_t from_nid, hda_nid_t to_nid,
2792 int with_aa_mix, struct nid_path *path, int depth)
Takashi Iwai30dcd3b2012-12-06 15:45:38 +01002793{
2794 struct alc_spec *spec = codec->spec;
Takashi Iwai36f0fd52012-12-12 17:25:00 +01002795 hda_nid_t conn[16];
Takashi Iwai30dcd3b2012-12-06 15:45:38 +01002796 int i, nums;
2797
Takashi Iwai36f0fd52012-12-12 17:25:00 +01002798 if (to_nid == spec->mixer_nid) {
Takashi Iwai30dcd3b2012-12-06 15:45:38 +01002799 if (!with_aa_mix)
2800 return false;
2801 with_aa_mix = 2; /* mark aa-mix is included */
2802 }
2803
Takashi Iwai36f0fd52012-12-12 17:25:00 +01002804 nums = snd_hda_get_connections(codec, to_nid, conn, ARRAY_SIZE(conn));
Takashi Iwai30dcd3b2012-12-06 15:45:38 +01002805 for (i = 0; i < nums; i++) {
Takashi Iwai36f0fd52012-12-12 17:25:00 +01002806 if (conn[i] != from_nid) {
2807 /* special case: when from_nid is 0,
2808 * try to find an empty DAC
2809 */
2810 if (from_nid ||
2811 get_wcaps_type(get_wcaps(codec, conn[i])) != AC_WID_AUD_OUT ||
2812 alc_is_dac_already_used(codec, conn[i]))
2813 continue;
Takashi Iwai30dcd3b2012-12-06 15:45:38 +01002814 }
Takashi Iwai36f0fd52012-12-12 17:25:00 +01002815 /* aa-mix is requested but not included? */
2816 if (!(spec->mixer_nid && with_aa_mix == 1))
2817 goto found;
Takashi Iwai30dcd3b2012-12-06 15:45:38 +01002818 }
2819 if (depth >= MAX_NID_PATH_DEPTH)
2820 return false;
2821 for (i = 0; i < nums; i++) {
2822 unsigned int type;
2823 type = get_wcaps_type(get_wcaps(codec, conn[i]));
Takashi Iwai36f0fd52012-12-12 17:25:00 +01002824 if (type == AC_WID_AUD_OUT || type == AC_WID_AUD_IN ||
2825 type == AC_WID_PIN)
Takashi Iwai30dcd3b2012-12-06 15:45:38 +01002826 continue;
Takashi Iwai36f0fd52012-12-12 17:25:00 +01002827 if (__parse_nid_path(codec, from_nid, conn[i],
2828 with_aa_mix, path, depth + 1))
Takashi Iwai30dcd3b2012-12-06 15:45:38 +01002829 goto found;
2830 }
2831 return false;
2832
2833 found:
2834 path->path[path->depth] = conn[i];
Takashi Iwai95e960c2012-12-10 17:27:57 +01002835 path->idx[path->depth + 1] = i;
Takashi Iwai36f0fd52012-12-12 17:25:00 +01002836 if (nums > 1 && get_wcaps_type(get_wcaps(codec, to_nid)) != AC_WID_AUD_MIX)
Takashi Iwai95e960c2012-12-10 17:27:57 +01002837 path->multi[path->depth + 1] = 1;
Takashi Iwai30dcd3b2012-12-06 15:45:38 +01002838 path->depth++;
2839 return true;
2840}
2841
Takashi Iwai36f0fd52012-12-12 17:25:00 +01002842/* parse the widget path from the given nid to the target nid;
2843 * when @from_nid is 0, try to find an empty DAC;
2844 * when @with_aa_mix is 0, paths with spec->mixer_nid are excluded.
2845 * when @with_aa_mix is 1, paths without spec->mixer_nid are excluded.
2846 * when @with_aa_mix is 2, no special handling about spec->mixer_nid.
Takashi Iwai30dcd3b2012-12-06 15:45:38 +01002847 */
Takashi Iwai36f0fd52012-12-12 17:25:00 +01002848static bool parse_nid_path(struct hda_codec *codec, hda_nid_t from_nid,
2849 hda_nid_t to_nid, int with_aa_mix,
2850 struct nid_path *path)
Takashi Iwai30dcd3b2012-12-06 15:45:38 +01002851{
Takashi Iwai36f0fd52012-12-12 17:25:00 +01002852 if (__parse_nid_path(codec, from_nid, to_nid, with_aa_mix, path, 1)) {
2853 path->path[path->depth] = to_nid;
Takashi Iwai30dcd3b2012-12-06 15:45:38 +01002854 path->depth++;
2855#if 0
Takashi Iwai36f0fd52012-12-12 17:25:00 +01002856 snd_printdd("path: depth=%d, %02x/%02x/%02x/%02x/%02x\n",
Takashi Iwai30dcd3b2012-12-06 15:45:38 +01002857 path->depth, path->path[0], path->path[1],
2858 path->path[2], path->path[3], path->path[4]);
2859#endif
2860 return true;
2861 }
2862 return false;
2863}
2864
Takashi Iwai3af9ee62011-06-27 12:34:01 +02002865static hda_nid_t get_dac_if_single(struct hda_codec *codec, hda_nid_t pin)
2866{
Takashi Iwai140547e2012-02-16 17:23:46 +01002867 struct alc_spec *spec = codec->spec;
Takashi Iwai463419d2012-12-05 14:17:37 +01002868 int i;
2869 hda_nid_t nid_found = 0;
2870
2871 for (i = 0; i < spec->num_all_dacs; i++) {
2872 hda_nid_t nid = spec->all_dacs[i];
2873 if (!nid || alc_is_dac_already_used(codec, nid))
Takashi Iwai185d99f2012-02-16 18:39:45 +01002874 continue;
Takashi Iwai9c640762012-12-14 16:15:56 +01002875 if (is_reachable_path(codec, nid, pin)) {
Takashi Iwai185d99f2012-02-16 18:39:45 +01002876 if (nid_found)
2877 return 0;
2878 nid_found = nid;
2879 }
2880 }
2881 return nid_found;
Takashi Iwai3af9ee62011-06-27 12:34:01 +02002882}
2883
Takashi Iwaiba8111272012-12-06 18:06:23 +01002884static bool is_ctl_used(struct hda_codec *codec, unsigned int val, int type)
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01002885{
Takashi Iwaiba8111272012-12-06 18:06:23 +01002886 struct alc_spec *spec = codec->spec;
2887 int i;
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01002888
Takashi Iwaic9967f12012-12-14 16:39:22 +01002889 for (i = 0; i < spec->paths.used; i++) {
2890 struct nid_path *path = snd_array_elem(&spec->paths, i);
Takashi Iwaiba8111272012-12-06 18:06:23 +01002891 if (path->ctls[type] == val)
2892 return true;
2893 }
2894 return false;
2895}
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01002896
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01002897/* badness definition */
2898enum {
2899 /* No primary DAC is found for the main output */
2900 BAD_NO_PRIMARY_DAC = 0x10000,
2901 /* No DAC is found for the extra output */
2902 BAD_NO_DAC = 0x4000,
Takashi Iwai276dd702012-02-17 16:17:03 +01002903 /* No possible multi-ios */
2904 BAD_MULTI_IO = 0x103,
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01002905 /* No individual DAC for extra output */
Takashi Iwai276dd702012-02-17 16:17:03 +01002906 BAD_NO_EXTRA_DAC = 0x102,
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01002907 /* No individual DAC for extra surrounds */
Takashi Iwai276dd702012-02-17 16:17:03 +01002908 BAD_NO_EXTRA_SURR_DAC = 0x101,
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01002909 /* Primary DAC shared with main surrounds */
2910 BAD_SHARED_SURROUND = 0x100,
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01002911 /* Primary DAC shared with main CLFE */
2912 BAD_SHARED_CLFE = 0x10,
2913 /* Primary DAC shared with extra surrounds */
2914 BAD_SHARED_EXTRA_SURROUND = 0x10,
Takashi Iwai276dd702012-02-17 16:17:03 +01002915 /* Volume widget is shared */
2916 BAD_SHARED_VOL = 0x10,
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01002917};
2918
2919static hda_nid_t alc_look_for_out_mute_nid(struct hda_codec *codec,
Takashi Iwaiba8111272012-12-06 18:06:23 +01002920 struct nid_path *path);
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01002921static hda_nid_t alc_look_for_out_vol_nid(struct hda_codec *codec,
Takashi Iwaiba8111272012-12-06 18:06:23 +01002922 struct nid_path *path);
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01002923
Takashi Iwai965cceb2012-12-18 11:46:37 +01002924static struct nid_path *add_new_nid_path(struct hda_codec *codec,
2925 hda_nid_t from_nid, hda_nid_t to_nid,
2926 int with_aa_mix)
Takashi Iwai30dcd3b2012-12-06 15:45:38 +01002927{
2928 struct alc_spec *spec = codec->spec;
2929 struct nid_path *path;
2930
Takashi Iwai965cceb2012-12-18 11:46:37 +01002931 if (from_nid && to_nid && !is_reachable_path(codec, from_nid, to_nid))
2932 return NULL;
2933
Takashi Iwaic9967f12012-12-14 16:39:22 +01002934 path = snd_array_new(&spec->paths);
Takashi Iwai30dcd3b2012-12-06 15:45:38 +01002935 if (!path)
Takashi Iwai965cceb2012-12-18 11:46:37 +01002936 return NULL;
Takashi Iwai30dcd3b2012-12-06 15:45:38 +01002937 memset(path, 0, sizeof(*path));
Takashi Iwai965cceb2012-12-18 11:46:37 +01002938 if (parse_nid_path(codec, from_nid, to_nid, with_aa_mix, path))
2939 return path;
Takashi Iwai30dcd3b2012-12-06 15:45:38 +01002940 /* push back */
Takashi Iwaic9967f12012-12-14 16:39:22 +01002941 spec->paths.used--;
Takashi Iwai965cceb2012-12-18 11:46:37 +01002942 return NULL;
Takashi Iwai30dcd3b2012-12-06 15:45:38 +01002943}
2944
Takashi Iwai6518f7a2012-12-14 17:34:51 +01002945/* get the path between the given NIDs;
Takashi Iwaiba8111272012-12-06 18:06:23 +01002946 * passing 0 to either @pin or @dac behaves as a wildcard
2947 */
Takashi Iwai6518f7a2012-12-14 17:34:51 +01002948static struct nid_path *
2949get_nid_path(struct hda_codec *codec, hda_nid_t from_nid, hda_nid_t to_nid)
Takashi Iwaiba8111272012-12-06 18:06:23 +01002950{
2951 struct alc_spec *spec = codec->spec;
2952 int i;
2953
Takashi Iwaic9967f12012-12-14 16:39:22 +01002954 for (i = 0; i < spec->paths.used; i++) {
2955 struct nid_path *path = snd_array_elem(&spec->paths, i);
Takashi Iwaiba8111272012-12-06 18:06:23 +01002956 if (path->depth <= 0)
2957 continue;
Takashi Iwai6518f7a2012-12-14 17:34:51 +01002958 if ((!from_nid || path->path[0] == from_nid) &&
2959 (!to_nid || path->path[path->depth - 1] == to_nid))
Takashi Iwaiba8111272012-12-06 18:06:23 +01002960 return path;
2961 }
2962 return NULL;
2963}
2964
Takashi Iwai792cf2f2012-12-10 16:04:30 +01002965/* look for widgets in the path between the given NIDs appropriate for
2966 * volume and mute controls, and assign the values to ctls[].
2967 *
2968 * When no appropriate widget is found in the path, the badness value
2969 * is incremented depending on the situation. The function returns the
2970 * total badness for both volume and mute controls.
2971 */
2972static int assign_out_path_ctls(struct hda_codec *codec, hda_nid_t pin,
2973 hda_nid_t dac)
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01002974{
Takashi Iwai6518f7a2012-12-14 17:34:51 +01002975 struct nid_path *path = get_nid_path(codec, dac, pin);
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01002976 hda_nid_t nid;
2977 unsigned int val;
2978 int badness = 0;
2979
Takashi Iwaiba8111272012-12-06 18:06:23 +01002980 if (!path)
2981 return BAD_SHARED_VOL * 2;
2982 nid = alc_look_for_out_vol_nid(codec, path);
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01002983 if (nid) {
2984 val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
Takashi Iwaiba8111272012-12-06 18:06:23 +01002985 if (is_ctl_used(codec, val, NID_PATH_VOL_CTL))
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01002986 badness += BAD_SHARED_VOL;
2987 else
Takashi Iwaiba8111272012-12-06 18:06:23 +01002988 path->ctls[NID_PATH_VOL_CTL] = val;
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01002989 } else
2990 badness += BAD_SHARED_VOL;
Takashi Iwaiba8111272012-12-06 18:06:23 +01002991 nid = alc_look_for_out_mute_nid(codec, path);
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01002992 if (nid) {
2993 unsigned int wid_type = get_wcaps_type(get_wcaps(codec, nid));
Takashi Iwai792cf2f2012-12-10 16:04:30 +01002994 if (wid_type == AC_WID_PIN || wid_type == AC_WID_AUD_OUT ||
2995 nid_has_mute(codec, nid, HDA_OUTPUT))
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01002996 val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
2997 else
2998 val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT);
Takashi Iwaiba8111272012-12-06 18:06:23 +01002999 if (is_ctl_used(codec, val, NID_PATH_MUTE_CTL))
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01003000 badness += BAD_SHARED_VOL;
3001 else
Takashi Iwaiba8111272012-12-06 18:06:23 +01003002 path->ctls[NID_PATH_MUTE_CTL] = val;
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01003003 } else
3004 badness += BAD_SHARED_VOL;
3005 return badness;
3006}
3007
Takashi Iwaidc31b582012-02-17 17:27:53 +01003008struct badness_table {
3009 int no_primary_dac; /* no primary DAC */
3010 int no_dac; /* no secondary DACs */
3011 int shared_primary; /* primary DAC is shared with main output */
3012 int shared_surr; /* secondary DAC shared with main or primary */
3013 int shared_clfe; /* third DAC shared with main or primary */
3014 int shared_surr_main; /* secondary DAC sahred with main/DAC0 */
3015};
3016
3017static struct badness_table main_out_badness = {
3018 .no_primary_dac = BAD_NO_PRIMARY_DAC,
3019 .no_dac = BAD_NO_DAC,
3020 .shared_primary = BAD_NO_PRIMARY_DAC,
3021 .shared_surr = BAD_SHARED_SURROUND,
3022 .shared_clfe = BAD_SHARED_CLFE,
3023 .shared_surr_main = BAD_SHARED_SURROUND,
3024};
3025
3026static struct badness_table extra_out_badness = {
3027 .no_primary_dac = BAD_NO_DAC,
3028 .no_dac = BAD_NO_DAC,
3029 .shared_primary = BAD_NO_EXTRA_DAC,
3030 .shared_surr = BAD_SHARED_EXTRA_SURROUND,
3031 .shared_clfe = BAD_SHARED_EXTRA_SURROUND,
3032 .shared_surr_main = BAD_NO_EXTRA_SURR_DAC,
3033};
3034
3035/* try to assign DACs to pins and return the resultant badness */
3036static int alc_auto_fill_dacs(struct hda_codec *codec, int num_outs,
3037 const hda_nid_t *pins, hda_nid_t *dacs,
3038 const struct badness_table *bad)
Takashi Iwaic2674682011-08-24 17:57:44 +02003039{
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01003040 struct alc_spec *spec = codec->spec;
Takashi Iwaidc31b582012-02-17 17:27:53 +01003041 struct auto_pin_cfg *cfg = &spec->autocfg;
3042 int i, j;
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01003043 int badness = 0;
3044 hda_nid_t dac;
Takashi Iwaic2674682011-08-24 17:57:44 +02003045
Takashi Iwai185d99f2012-02-16 18:39:45 +01003046 if (!num_outs)
3047 return 0;
3048
Takashi Iwaidc31b582012-02-17 17:27:53 +01003049 for (i = 0; i < num_outs; i++) {
3050 hda_nid_t pin = pins[i];
3051 if (!dacs[i])
Takashi Iwaifef7fbb2012-12-14 16:54:44 +01003052 dacs[i] = alc_auto_look_for_dac(codec, pin, false);
Takashi Iwaidc31b582012-02-17 17:27:53 +01003053 if (!dacs[i] && !i) {
3054 for (j = 1; j < num_outs; j++) {
Takashi Iwai9c640762012-12-14 16:15:56 +01003055 if (is_reachable_path(codec, dacs[j], pin)) {
Takashi Iwaidc31b582012-02-17 17:27:53 +01003056 dacs[0] = dacs[j];
3057 dacs[j] = 0;
3058 break;
3059 }
Takashi Iwai185d99f2012-02-16 18:39:45 +01003060 }
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01003061 }
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01003062 dac = dacs[i];
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01003063 if (!dac) {
Takashi Iwai9c640762012-12-14 16:15:56 +01003064 if (is_reachable_path(codec, dacs[0], pin))
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01003065 dac = dacs[0];
Takashi Iwaidc31b582012-02-17 17:27:53 +01003066 else if (cfg->line_outs > i &&
Takashi Iwai9c640762012-12-14 16:15:56 +01003067 is_reachable_path(codec, spec->private_dac_nids[i], pin))
Takashi Iwaidc31b582012-02-17 17:27:53 +01003068 dac = spec->private_dac_nids[i];
3069 if (dac) {
3070 if (!i)
3071 badness += bad->shared_primary;
3072 else if (i == 1)
3073 badness += bad->shared_surr;
3074 else
3075 badness += bad->shared_clfe;
Takashi Iwai9c640762012-12-14 16:15:56 +01003076 } else if (is_reachable_path(codec, spec->private_dac_nids[0], pin)) {
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01003077 dac = spec->private_dac_nids[0];
Takashi Iwaidc31b582012-02-17 17:27:53 +01003078 badness += bad->shared_surr_main;
3079 } else if (!i)
3080 badness += bad->no_primary_dac;
3081 else
3082 badness += bad->no_dac;
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01003083 }
Takashi Iwai965cceb2012-12-18 11:46:37 +01003084 if (!add_new_nid_path(codec, dac, pin, 0))
Takashi Iwai30dcd3b2012-12-06 15:45:38 +01003085 dac = dacs[i] = 0;
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01003086 if (dac)
Takashi Iwai792cf2f2012-12-10 16:04:30 +01003087 badness += assign_out_path_ctls(codec, pin, dac);
Takashi Iwaic2674682011-08-24 17:57:44 +02003088 }
Takashi Iwaidc31b582012-02-17 17:27:53 +01003089
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01003090 return badness;
Takashi Iwaic2674682011-08-24 17:57:44 +02003091}
3092
3093static int alc_auto_fill_multi_ios(struct hda_codec *codec,
Takashi Iwai276dd702012-02-17 16:17:03 +01003094 hda_nid_t reference_pin,
3095 bool hardwired, int offset);
Takashi Iwaic2674682011-08-24 17:57:44 +02003096
Takashi Iwai185d99f2012-02-16 18:39:45 +01003097static bool alc_map_singles(struct hda_codec *codec, int outs,
3098 const hda_nid_t *pins, hda_nid_t *dacs)
3099{
3100 int i;
3101 bool found = false;
3102 for (i = 0; i < outs; i++) {
Takashi Iwai30dcd3b2012-12-06 15:45:38 +01003103 hda_nid_t dac;
Takashi Iwai185d99f2012-02-16 18:39:45 +01003104 if (dacs[i])
3105 continue;
Takashi Iwai30dcd3b2012-12-06 15:45:38 +01003106 dac = get_dac_if_single(codec, pins[i]);
3107 if (!dac)
3108 continue;
Takashi Iwai965cceb2012-12-18 11:46:37 +01003109 if (add_new_nid_path(codec, dac, pins[i], 0)) {
Takashi Iwai30dcd3b2012-12-06 15:45:38 +01003110 dacs[i] = dac;
Takashi Iwai185d99f2012-02-16 18:39:45 +01003111 found = true;
Takashi Iwai30dcd3b2012-12-06 15:45:38 +01003112 }
Takashi Iwai185d99f2012-02-16 18:39:45 +01003113 }
3114 return found;
3115}
3116
Takashi Iwai7085ec12009-10-02 09:03:58 +02003117/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01003118static int fill_and_eval_dacs(struct hda_codec *codec,
Takashi Iwai276dd702012-02-17 16:17:03 +01003119 bool fill_hardwired,
3120 bool fill_mio_first)
Takashi Iwai7085ec12009-10-02 09:03:58 +02003121{
3122 struct alc_spec *spec = codec->spec;
Takashi Iwai0a34b422011-12-07 17:20:30 +01003123 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwaidc31b582012-02-17 17:27:53 +01003124 int i, err, badness;
Takashi Iwai7085ec12009-10-02 09:03:58 +02003125
Takashi Iwai8f398ae2011-07-23 18:57:11 +02003126 /* set num_dacs once to full for alc_auto_look_for_dac() */
3127 spec->multiout.num_dacs = cfg->line_outs;
Takashi Iwai3af9ee62011-06-27 12:34:01 +02003128 spec->multiout.dac_nids = spec->private_dac_nids;
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01003129 memset(spec->private_dac_nids, 0, sizeof(spec->private_dac_nids));
3130 memset(spec->multiout.hp_out_nid, 0, sizeof(spec->multiout.hp_out_nid));
3131 memset(spec->multiout.extra_out_nid, 0, sizeof(spec->multiout.extra_out_nid));
Takashi Iwai0a34b422011-12-07 17:20:30 +01003132 spec->multi_ios = 0;
Takashi Iwaic9967f12012-12-14 16:39:22 +01003133 snd_array_free(&spec->paths);
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01003134 badness = 0;
Takashi Iwai3af9ee62011-06-27 12:34:01 +02003135
3136 /* fill hard-wired DACs first */
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01003137 if (fill_hardwired) {
Takashi Iwai185d99f2012-02-16 18:39:45 +01003138 bool mapped;
3139 do {
3140 mapped = alc_map_singles(codec, cfg->line_outs,
Takashi Iwai276dd702012-02-17 16:17:03 +01003141 cfg->line_out_pins,
3142 spec->private_dac_nids);
Takashi Iwai185d99f2012-02-16 18:39:45 +01003143 mapped |= alc_map_singles(codec, cfg->hp_outs,
3144 cfg->hp_pins,
3145 spec->multiout.hp_out_nid);
3146 mapped |= alc_map_singles(codec, cfg->speaker_outs,
3147 cfg->speaker_pins,
3148 spec->multiout.extra_out_nid);
Takashi Iwai276dd702012-02-17 16:17:03 +01003149 if (fill_mio_first && cfg->line_outs == 1 &&
3150 cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
3151 err = alc_auto_fill_multi_ios(codec, cfg->line_out_pins[0], true, 0);
3152 if (!err)
3153 mapped = true;
3154 }
Takashi Iwai185d99f2012-02-16 18:39:45 +01003155 } while (mapped);
Takashi Iwai7085ec12009-10-02 09:03:58 +02003156 }
Takashi Iwai3af9ee62011-06-27 12:34:01 +02003157
Takashi Iwaidc31b582012-02-17 17:27:53 +01003158 badness += alc_auto_fill_dacs(codec, cfg->line_outs, cfg->line_out_pins,
3159 spec->private_dac_nids,
3160 &main_out_badness);
Takashi Iwai3af9ee62011-06-27 12:34:01 +02003161
Takashi Iwai8f398ae2011-07-23 18:57:11 +02003162 /* re-count num_dacs and squash invalid entries */
3163 spec->multiout.num_dacs = 0;
Takashi Iwai3af9ee62011-06-27 12:34:01 +02003164 for (i = 0; i < cfg->line_outs; i++) {
3165 if (spec->private_dac_nids[i])
3166 spec->multiout.num_dacs++;
Takashi Iwai0a34b422011-12-07 17:20:30 +01003167 else {
Takashi Iwai3af9ee62011-06-27 12:34:01 +02003168 memmove(spec->private_dac_nids + i,
3169 spec->private_dac_nids + i + 1,
3170 sizeof(hda_nid_t) * (cfg->line_outs - i - 1));
Takashi Iwai0a34b422011-12-07 17:20:30 +01003171 spec->private_dac_nids[cfg->line_outs - 1] = 0;
3172 }
Takashi Iwai3af9ee62011-06-27 12:34:01 +02003173 }
3174
Takashi Iwai276dd702012-02-17 16:17:03 +01003175 if (fill_mio_first &&
3176 cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
Takashi Iwaic2674682011-08-24 17:57:44 +02003177 /* try to fill multi-io first */
Takashi Iwai276dd702012-02-17 16:17:03 +01003178 err = alc_auto_fill_multi_ios(codec, cfg->line_out_pins[0], false, 0);
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01003179 if (err < 0)
3180 return err;
Takashi Iwai276dd702012-02-17 16:17:03 +01003181 /* we don't count badness at this stage yet */
Takashi Iwai23c09b02011-08-19 09:05:35 +02003182 }
Takashi Iwaic2674682011-08-24 17:57:44 +02003183
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01003184 if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
Takashi Iwaidc31b582012-02-17 17:27:53 +01003185 err = alc_auto_fill_dacs(codec, cfg->hp_outs, cfg->hp_pins,
3186 spec->multiout.hp_out_nid,
3187 &extra_out_badness);
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01003188 if (err < 0)
3189 return err;
3190 badness += err;
3191 }
Takashi Iwai0a34b422011-12-07 17:20:30 +01003192 if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
Takashi Iwaidc31b582012-02-17 17:27:53 +01003193 err = alc_auto_fill_dacs(codec, cfg->speaker_outs,
3194 cfg->speaker_pins,
3195 spec->multiout.extra_out_nid,
3196 &extra_out_badness);
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01003197 if (err < 0)
3198 return err;
3199 badness += err;
3200 }
Takashi Iwai276dd702012-02-17 16:17:03 +01003201 if (cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
3202 err = alc_auto_fill_multi_ios(codec, cfg->line_out_pins[0], false, 0);
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01003203 if (err < 0)
3204 return err;
3205 badness += err;
3206 }
Takashi Iwai276dd702012-02-17 16:17:03 +01003207 if (cfg->hp_outs && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
3208 /* try multi-ios with HP + inputs */
Takashi Iwaif5682912012-02-21 12:37:00 +01003209 int offset = 0;
3210 if (cfg->line_outs >= 3)
3211 offset = 1;
3212 err = alc_auto_fill_multi_ios(codec, cfg->hp_pins[0], false,
3213 offset);
Takashi Iwai276dd702012-02-17 16:17:03 +01003214 if (err < 0)
3215 return err;
3216 badness += err;
3217 }
3218
3219 if (spec->multi_ios == 2) {
3220 for (i = 0; i < 2; i++)
3221 spec->private_dac_nids[spec->multiout.num_dacs++] =
3222 spec->multi_io[i].dac;
3223 spec->ext_channel_count = 2;
3224 } else if (spec->multi_ios) {
3225 spec->multi_ios = 0;
3226 badness += BAD_MULTI_IO;
3227 }
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01003228
3229 return badness;
3230}
3231
3232#define DEBUG_BADNESS
3233
3234#ifdef DEBUG_BADNESS
3235#define debug_badness snd_printdd
3236#else
3237#define debug_badness(...)
3238#endif
3239
3240static void debug_show_configs(struct alc_spec *spec, struct auto_pin_cfg *cfg)
3241{
3242 debug_badness("multi_outs = %x/%x/%x/%x : %x/%x/%x/%x\n",
3243 cfg->line_out_pins[0], cfg->line_out_pins[1],
3244 cfg->line_out_pins[2], cfg->line_out_pins[2],
3245 spec->multiout.dac_nids[0],
3246 spec->multiout.dac_nids[1],
3247 spec->multiout.dac_nids[2],
3248 spec->multiout.dac_nids[3]);
Takashi Iwai6f453042012-02-17 14:09:20 +01003249 if (spec->multi_ios > 0)
3250 debug_badness("multi_ios(%d) = %x/%x : %x/%x\n",
3251 spec->multi_ios,
3252 spec->multi_io[0].pin, spec->multi_io[1].pin,
3253 spec->multi_io[0].dac, spec->multi_io[1].dac);
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01003254 debug_badness("hp_outs = %x/%x/%x/%x : %x/%x/%x/%x\n",
3255 cfg->hp_pins[0], cfg->hp_pins[1],
3256 cfg->hp_pins[2], cfg->hp_pins[2],
3257 spec->multiout.hp_out_nid[0],
3258 spec->multiout.hp_out_nid[1],
3259 spec->multiout.hp_out_nid[2],
3260 spec->multiout.hp_out_nid[3]);
3261 debug_badness("spk_outs = %x/%x/%x/%x : %x/%x/%x/%x\n",
3262 cfg->speaker_pins[0], cfg->speaker_pins[1],
3263 cfg->speaker_pins[2], cfg->speaker_pins[3],
3264 spec->multiout.extra_out_nid[0],
3265 spec->multiout.extra_out_nid[1],
3266 spec->multiout.extra_out_nid[2],
3267 spec->multiout.extra_out_nid[3]);
3268}
3269
Takashi Iwai463419d2012-12-05 14:17:37 +01003270/* find all available DACs of the codec */
3271static void alc_fill_all_nids(struct hda_codec *codec)
3272{
3273 struct alc_spec *spec = codec->spec;
3274 int i;
3275 hda_nid_t nid = codec->start_nid;
3276
3277 spec->num_all_dacs = 0;
3278 memset(spec->all_dacs, 0, sizeof(spec->all_dacs));
3279 for (i = 0; i < codec->num_nodes; i++, nid++) {
3280 if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_AUD_OUT)
3281 continue;
3282 if (spec->num_all_dacs >= ARRAY_SIZE(spec->all_dacs)) {
3283 snd_printk(KERN_ERR "hda: Too many DACs!\n");
3284 break;
3285 }
3286 spec->all_dacs[spec->num_all_dacs++] = nid;
3287 }
3288}
3289
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01003290static int alc_auto_fill_dac_nids(struct hda_codec *codec)
3291{
3292 struct alc_spec *spec = codec->spec;
3293 struct auto_pin_cfg *cfg = &spec->autocfg;
3294 struct auto_pin_cfg *best_cfg;
3295 int best_badness = INT_MAX;
3296 int badness;
Takashi Iwai276dd702012-02-17 16:17:03 +01003297 bool fill_hardwired = true, fill_mio_first = true;
3298 bool best_wired = true, best_mio = true;
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01003299 bool hp_spk_swapped = false;
3300
Takashi Iwai463419d2012-12-05 14:17:37 +01003301 alc_fill_all_nids(codec);
3302
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01003303 best_cfg = kmalloc(sizeof(*best_cfg), GFP_KERNEL);
3304 if (!best_cfg)
3305 return -ENOMEM;
3306 *best_cfg = *cfg;
3307
3308 for (;;) {
Takashi Iwai276dd702012-02-17 16:17:03 +01003309 badness = fill_and_eval_dacs(codec, fill_hardwired,
3310 fill_mio_first);
Jesper Juhl7d7eb9e2012-04-12 22:11:25 +02003311 if (badness < 0) {
3312 kfree(best_cfg);
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01003313 return badness;
Jesper Juhl7d7eb9e2012-04-12 22:11:25 +02003314 }
Takashi Iwai276dd702012-02-17 16:17:03 +01003315 debug_badness("==> lo_type=%d, wired=%d, mio=%d, badness=0x%x\n",
3316 cfg->line_out_type, fill_hardwired, fill_mio_first,
3317 badness);
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01003318 debug_show_configs(spec, cfg);
3319 if (badness < best_badness) {
3320 best_badness = badness;
3321 *best_cfg = *cfg;
3322 best_wired = fill_hardwired;
Takashi Iwai276dd702012-02-17 16:17:03 +01003323 best_mio = fill_mio_first;
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01003324 }
3325 if (!badness)
3326 break;
Takashi Iwai276dd702012-02-17 16:17:03 +01003327 fill_mio_first = !fill_mio_first;
3328 if (!fill_mio_first)
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01003329 continue;
Takashi Iwai276dd702012-02-17 16:17:03 +01003330 fill_hardwired = !fill_hardwired;
3331 if (!fill_hardwired)
3332 continue;
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01003333 if (hp_spk_swapped)
3334 break;
3335 hp_spk_swapped = true;
3336 if (cfg->speaker_outs > 0 &&
Takashi Iwai0a34b422011-12-07 17:20:30 +01003337 cfg->line_out_type == AUTO_PIN_HP_OUT) {
3338 cfg->hp_outs = cfg->line_outs;
3339 memcpy(cfg->hp_pins, cfg->line_out_pins,
3340 sizeof(cfg->hp_pins));
3341 cfg->line_outs = cfg->speaker_outs;
3342 memcpy(cfg->line_out_pins, cfg->speaker_pins,
3343 sizeof(cfg->speaker_pins));
3344 cfg->speaker_outs = 0;
3345 memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins));
3346 cfg->line_out_type = AUTO_PIN_SPEAKER_OUT;
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01003347 fill_hardwired = true;
3348 continue;
Jesper Juhl7d7eb9e2012-04-12 22:11:25 +02003349 }
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01003350 if (cfg->hp_outs > 0 &&
3351 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
3352 cfg->speaker_outs = cfg->line_outs;
3353 memcpy(cfg->speaker_pins, cfg->line_out_pins,
3354 sizeof(cfg->speaker_pins));
3355 cfg->line_outs = cfg->hp_outs;
3356 memcpy(cfg->line_out_pins, cfg->hp_pins,
3357 sizeof(cfg->hp_pins));
3358 cfg->hp_outs = 0;
3359 memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins));
3360 cfg->line_out_type = AUTO_PIN_HP_OUT;
3361 fill_hardwired = true;
3362 continue;
Jesper Juhl7d7eb9e2012-04-12 22:11:25 +02003363 }
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01003364 break;
Takashi Iwai0a34b422011-12-07 17:20:30 +01003365 }
Takashi Iwaic2674682011-08-24 17:57:44 +02003366
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01003367 if (badness) {
3368 *cfg = *best_cfg;
Takashi Iwai276dd702012-02-17 16:17:03 +01003369 fill_and_eval_dacs(codec, best_wired, best_mio);
Takashi Iwai07b18f62011-11-10 15:42:54 +01003370 }
Takashi Iwai276dd702012-02-17 16:17:03 +01003371 debug_badness("==> Best config: lo_type=%d, wired=%d, mio=%d\n",
3372 cfg->line_out_type, best_wired, best_mio);
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01003373 debug_show_configs(spec, cfg);
Takashi Iwai07b18f62011-11-10 15:42:54 +01003374
Takashi Iwaiba8111272012-12-06 18:06:23 +01003375 if (cfg->line_out_pins[0]) {
Takashi Iwai6518f7a2012-12-14 17:34:51 +01003376 struct nid_path *path = get_nid_path(codec,
3377 spec->multiout.dac_nids[0],
3378 cfg->line_out_pins[0]);
Takashi Iwaiba8111272012-12-06 18:06:23 +01003379 if (path)
3380 spec->vmaster_nid = alc_look_for_out_vol_nid(codec, path);
3381 }
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01003382
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01003383 kfree(best_cfg);
Takashi Iwai23c09b02011-08-19 09:05:35 +02003384 return 0;
3385}
3386
Takashi Iwai792cf2f2012-12-10 16:04:30 +01003387/* replace the channels in the composed amp value with the given number */
3388static unsigned int amp_val_replace_channels(unsigned int val, unsigned int chs)
3389{
3390 val &= ~(0x3U << 16);
3391 val |= chs << 16;
3392 return val;
3393}
3394
Takashi Iwai343a04b2011-07-06 14:28:39 +02003395static int alc_auto_add_vol_ctl(struct hda_codec *codec,
Takashi Iwaiba8111272012-12-06 18:06:23 +01003396 const char *pfx, int cidx,
Takashi Iwai792cf2f2012-12-10 16:04:30 +01003397 unsigned int chs,
Takashi Iwaiba8111272012-12-06 18:06:23 +01003398 struct nid_path *path)
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003399{
Takashi Iwai527e4d72011-10-27 16:33:27 +02003400 unsigned int val;
Takashi Iwai792cf2f2012-12-10 16:04:30 +01003401 if (!path)
Takashi Iwaiafcd5512011-07-08 11:07:59 +02003402 return 0;
Takashi Iwai792cf2f2012-12-10 16:04:30 +01003403 val = path->ctls[NID_PATH_VOL_CTL];
3404 if (!val)
Takashi Iwai527e4d72011-10-27 16:33:27 +02003405 return 0;
Takashi Iwai792cf2f2012-12-10 16:04:30 +01003406 val = amp_val_replace_channels(val, chs);
3407 return __add_pb_vol_ctrl(codec->spec, ALC_CTL_WIDGET_VOL, pfx, cidx, val);
3408}
3409
3410/* return the channel bits suitable for the given path->ctls[] */
3411static int get_default_ch_nums(struct hda_codec *codec, struct nid_path *path,
3412 int type)
3413{
3414 int chs = 1; /* mono (left only) */
3415 if (path) {
3416 hda_nid_t nid = get_amp_nid_(path->ctls[type]);
3417 if (nid && (get_wcaps(codec, nid) & AC_WCAP_STEREO))
3418 chs = 3; /* stereo */
3419 }
3420 return chs;
Takashi Iwai7085ec12009-10-02 09:03:58 +02003421}
3422
Takashi Iwaie29d3772011-11-14 17:13:23 +01003423static int alc_auto_add_stereo_vol(struct hda_codec *codec,
3424 const char *pfx, int cidx,
Takashi Iwai792cf2f2012-12-10 16:04:30 +01003425 struct nid_path *path)
Takashi Iwaie29d3772011-11-14 17:13:23 +01003426{
Takashi Iwai792cf2f2012-12-10 16:04:30 +01003427 int chs = get_default_ch_nums(codec, path, NID_PATH_VOL_CTL);
3428 return alc_auto_add_vol_ctl(codec, pfx, cidx, chs, path);
Takashi Iwaie29d3772011-11-14 17:13:23 +01003429}
Takashi Iwai97aaab72011-07-06 14:02:55 +02003430
3431/* create a mute-switch for the given mixer widget;
3432 * if it has multiple sources (e.g. DAC and loopback), create a bind-mute
3433 */
Takashi Iwai343a04b2011-07-06 14:28:39 +02003434static int alc_auto_add_sw_ctl(struct hda_codec *codec,
Takashi Iwaiba8111272012-12-06 18:06:23 +01003435 const char *pfx, int cidx,
Takashi Iwai792cf2f2012-12-10 16:04:30 +01003436 unsigned int chs,
Takashi Iwaiba8111272012-12-06 18:06:23 +01003437 struct nid_path *path)
Takashi Iwai7085ec12009-10-02 09:03:58 +02003438{
Takashi Iwai792cf2f2012-12-10 16:04:30 +01003439 unsigned int val;
3440 int type = ALC_CTL_WIDGET_MUTE;
3441
3442 if (!path)
Takashi Iwaiafcd5512011-07-08 11:07:59 +02003443 return 0;
Takashi Iwai792cf2f2012-12-10 16:04:30 +01003444 val = path->ctls[NID_PATH_MUTE_CTL];
3445 if (!val)
3446 return 0;
3447 val = amp_val_replace_channels(val, chs);
3448 if (get_amp_direction_(val) == HDA_INPUT) {
3449 hda_nid_t nid = get_amp_nid_(val);
Takashi Iwai9366ede2012-12-13 16:43:52 +01003450 int nums = snd_hda_get_num_conns(codec, nid);
3451 if (nums > 1) {
Takashi Iwai792cf2f2012-12-10 16:04:30 +01003452 type = ALC_CTL_BIND_MUTE;
Takashi Iwai9366ede2012-12-13 16:43:52 +01003453 val |= nums << 19;
Takashi Iwai792cf2f2012-12-10 16:04:30 +01003454 }
Takashi Iwai97aaab72011-07-06 14:02:55 +02003455 }
3456 return __add_pb_sw_ctrl(codec->spec, type, pfx, cidx, val);
Takashi Iwai7085ec12009-10-02 09:03:58 +02003457}
3458
Takashi Iwaie29d3772011-11-14 17:13:23 +01003459static int alc_auto_add_stereo_sw(struct hda_codec *codec, const char *pfx,
Takashi Iwai792cf2f2012-12-10 16:04:30 +01003460 int cidx, struct nid_path *path)
Takashi Iwaie29d3772011-11-14 17:13:23 +01003461{
Takashi Iwai792cf2f2012-12-10 16:04:30 +01003462 int chs = get_default_ch_nums(codec, path, NID_PATH_MUTE_CTL);
3463 return alc_auto_add_sw_ctl(codec, pfx, cidx, chs, path);
Takashi Iwaie29d3772011-11-14 17:13:23 +01003464}
Takashi Iwai7085ec12009-10-02 09:03:58 +02003465
Takashi Iwaiafcd5512011-07-08 11:07:59 +02003466static hda_nid_t alc_look_for_out_mute_nid(struct hda_codec *codec,
Takashi Iwaiba8111272012-12-06 18:06:23 +01003467 struct nid_path *path)
Takashi Iwaiafcd5512011-07-08 11:07:59 +02003468{
Takashi Iwaiba8111272012-12-06 18:06:23 +01003469 int i;
3470
3471 for (i = path->depth - 1; i >= 0; i--) {
3472 if (nid_has_mute(codec, path->path[i], HDA_OUTPUT))
3473 return path->path[i];
3474 if (i != path->depth - 1 && i != 0 &&
3475 nid_has_mute(codec, path->path[i], HDA_INPUT))
3476 return path->path[i];
3477 }
Takashi Iwaiafcd5512011-07-08 11:07:59 +02003478 return 0;
3479}
3480
3481static hda_nid_t alc_look_for_out_vol_nid(struct hda_codec *codec,
Takashi Iwaiba8111272012-12-06 18:06:23 +01003482 struct nid_path *path)
Takashi Iwaiafcd5512011-07-08 11:07:59 +02003483{
Takashi Iwaiba8111272012-12-06 18:06:23 +01003484 int i;
3485
3486 for (i = path->depth - 1; i >= 0; i--) {
3487 if (nid_has_volume(codec, path->path[i], HDA_OUTPUT))
3488 return path->path[i];
3489 }
Takashi Iwaiafcd5512011-07-08 11:07:59 +02003490 return 0;
3491}
3492
Takashi Iwai7085ec12009-10-02 09:03:58 +02003493/* add playback controls from the parsed DAC table */
Takashi Iwai343a04b2011-07-06 14:28:39 +02003494static int alc_auto_create_multi_out_ctls(struct hda_codec *codec,
Takashi Iwai7085ec12009-10-02 09:03:58 +02003495 const struct auto_pin_cfg *cfg)
3496{
3497 struct alc_spec *spec = codec->spec;
Takashi Iwaice764ab2011-04-27 16:35:23 +02003498 int i, err, noutputs;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003499
Takashi Iwaice764ab2011-04-27 16:35:23 +02003500 noutputs = cfg->line_outs;
Takashi Iwaib90bf1d2012-01-19 11:42:55 +01003501 if (spec->multi_ios > 0 && cfg->line_outs < 3)
Takashi Iwaice764ab2011-04-27 16:35:23 +02003502 noutputs += spec->multi_ios;
3503
3504 for (i = 0; i < noutputs; i++) {
Takashi Iwai6843ca12011-06-24 11:03:58 +02003505 const char *name;
3506 int index;
Takashi Iwaiafcd5512011-07-08 11:07:59 +02003507 hda_nid_t dac, pin;
Takashi Iwaiba8111272012-12-06 18:06:23 +01003508 struct nid_path *path;
Takashi Iwaiafcd5512011-07-08 11:07:59 +02003509
3510 dac = spec->multiout.dac_nids[i];
3511 if (!dac)
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003512 continue;
Takashi Iwai689cabf2012-02-21 12:35:27 +01003513 if (i >= cfg->line_outs) {
Takashi Iwaice764ab2011-04-27 16:35:23 +02003514 pin = spec->multi_io[i - 1].pin;
Takashi Iwai689cabf2012-02-21 12:35:27 +01003515 index = 0;
3516 name = channel_name[i];
3517 } else {
Takashi Iwaice764ab2011-04-27 16:35:23 +02003518 pin = cfg->line_out_pins[i];
Takashi Iwai689cabf2012-02-21 12:35:27 +01003519 name = alc_get_line_out_pfx(spec, i, true, &index);
3520 }
Takashi Iwaiafcd5512011-07-08 11:07:59 +02003521
Takashi Iwai6518f7a2012-12-14 17:34:51 +01003522 path = get_nid_path(codec, dac, pin);
Takashi Iwaiba8111272012-12-06 18:06:23 +01003523 if (!path)
3524 continue;
Takashi Iwai9c4e84d2011-08-24 17:27:52 +02003525 if (!name || !strcmp(name, "CLFE")) {
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003526 /* Center/LFE */
Takashi Iwai792cf2f2012-12-10 16:04:30 +01003527 err = alc_auto_add_vol_ctl(codec, "Center", 0, 1, path);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003528 if (err < 0)
3529 return err;
Takashi Iwai792cf2f2012-12-10 16:04:30 +01003530 err = alc_auto_add_vol_ctl(codec, "LFE", 0, 2, path);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003531 if (err < 0)
3532 return err;
Takashi Iwai792cf2f2012-12-10 16:04:30 +01003533 err = alc_auto_add_sw_ctl(codec, "Center", 0, 1, path);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003534 if (err < 0)
3535 return err;
Takashi Iwai792cf2f2012-12-10 16:04:30 +01003536 err = alc_auto_add_sw_ctl(codec, "LFE", 0, 2, path);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003537 if (err < 0)
3538 return err;
3539 } else {
Takashi Iwai792cf2f2012-12-10 16:04:30 +01003540 err = alc_auto_add_stereo_vol(codec, name, index, path);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003541 if (err < 0)
3542 return err;
Takashi Iwai792cf2f2012-12-10 16:04:30 +01003543 err = alc_auto_add_stereo_sw(codec, name, index, path);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003544 if (err < 0)
3545 return err;
3546 }
3547 }
3548 return 0;
3549}
3550
Takashi Iwai343a04b2011-07-06 14:28:39 +02003551static int alc_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
Takashi Iwai766ddee2011-12-07 16:55:19 +01003552 hda_nid_t dac, const char *pfx,
3553 int cidx)
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003554{
Takashi Iwaiba8111272012-12-06 18:06:23 +01003555 struct nid_path *path;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003556 int err;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003557
Takashi Iwai6518f7a2012-12-14 17:34:51 +01003558 path = get_nid_path(codec, dac, pin);
Takashi Iwaiba8111272012-12-06 18:06:23 +01003559 if (!path)
3560 return 0;
Takashi Iwai792cf2f2012-12-10 16:04:30 +01003561 /* bind volume control will be created in the case of dac = 0 */
3562 if (dac) {
3563 err = alc_auto_add_stereo_vol(codec, pfx, cidx, path);
3564 if (err < 0)
3565 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +02003566 }
Takashi Iwai792cf2f2012-12-10 16:04:30 +01003567 err = alc_auto_add_stereo_sw(codec, pfx, cidx, path);
Takashi Iwai7085ec12009-10-02 09:03:58 +02003568 if (err < 0)
3569 return err;
Takashi Iwai3af9ee62011-06-27 12:34:01 +02003570 return 0;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003571}
3572
Takashi Iwai23c09b02011-08-19 09:05:35 +02003573static struct hda_bind_ctls *new_bind_ctl(struct hda_codec *codec,
3574 unsigned int nums,
3575 struct hda_ctl_ops *ops)
3576{
3577 struct alc_spec *spec = codec->spec;
3578 struct hda_bind_ctls **ctlp, *ctl;
Takashi Iwai23c09b02011-08-19 09:05:35 +02003579 ctlp = snd_array_new(&spec->bind_ctls);
3580 if (!ctlp)
3581 return NULL;
3582 ctl = kzalloc(sizeof(*ctl) + sizeof(long) * (nums + 1), GFP_KERNEL);
3583 *ctlp = ctl;
3584 if (ctl)
3585 ctl->ops = ops;
3586 return ctl;
3587}
3588
3589/* add playback controls for speaker and HP outputs */
3590static int alc_auto_create_extra_outs(struct hda_codec *codec, int num_pins,
3591 const hda_nid_t *pins,
3592 const hda_nid_t *dacs,
3593 const char *pfx)
3594{
3595 struct alc_spec *spec = codec->spec;
3596 struct hda_bind_ctls *ctl;
3597 char name[32];
3598 int i, n, err;
3599
3600 if (!num_pins || !pins[0])
3601 return 0;
3602
Takashi Iwai527e4d72011-10-27 16:33:27 +02003603 if (num_pins == 1) {
3604 hda_nid_t dac = *dacs;
3605 if (!dac)
3606 dac = spec->multiout.dac_nids[0];
Takashi Iwai766ddee2011-12-07 16:55:19 +01003607 return alc_auto_create_extra_out(codec, *pins, dac, pfx, 0);
Takashi Iwai527e4d72011-10-27 16:33:27 +02003608 }
Takashi Iwai23c09b02011-08-19 09:05:35 +02003609
Takashi Iwai23c09b02011-08-19 09:05:35 +02003610 for (i = 0; i < num_pins; i++) {
Takashi Iwaic96f0bf2012-02-21 12:12:57 +01003611 hda_nid_t dac;
3612 if (dacs[num_pins - 1])
3613 dac = dacs[i]; /* with individual volumes */
3614 else
3615 dac = 0;
3616 if (num_pins == 2 && i == 1 && !strcmp(pfx, "Speaker")) {
3617 err = alc_auto_create_extra_out(codec, pins[i], dac,
3618 "Bass Speaker", 0);
3619 } else if (num_pins >= 3) {
3620 snprintf(name, sizeof(name), "%s %s",
3621 pfx, channel_name[i]);
3622 err = alc_auto_create_extra_out(codec, pins[i], dac,
3623 name, 0);
3624 } else {
3625 err = alc_auto_create_extra_out(codec, pins[i], dac,
3626 pfx, i);
3627 }
Takashi Iwai23c09b02011-08-19 09:05:35 +02003628 if (err < 0)
3629 return err;
3630 }
Takashi Iwaic96f0bf2012-02-21 12:12:57 +01003631 if (dacs[num_pins - 1])
3632 return 0;
Takashi Iwai23c09b02011-08-19 09:05:35 +02003633
Takashi Iwaic96f0bf2012-02-21 12:12:57 +01003634 /* Let's create a bind-controls for volumes */
Takashi Iwai23c09b02011-08-19 09:05:35 +02003635 ctl = new_bind_ctl(codec, num_pins, &snd_hda_bind_vol);
3636 if (!ctl)
3637 return -ENOMEM;
3638 n = 0;
3639 for (i = 0; i < num_pins; i++) {
3640 hda_nid_t vol;
Takashi Iwaiba8111272012-12-06 18:06:23 +01003641 struct nid_path *path;
Takashi Iwai23c09b02011-08-19 09:05:35 +02003642 if (!pins[i] || !dacs[i])
3643 continue;
Takashi Iwai6518f7a2012-12-14 17:34:51 +01003644 path = get_nid_path(codec, dacs[i], pins[i]);
Takashi Iwaiba8111272012-12-06 18:06:23 +01003645 if (!path)
3646 continue;
3647 vol = alc_look_for_out_vol_nid(codec, path);
Takashi Iwai23c09b02011-08-19 09:05:35 +02003648 if (vol)
3649 ctl->values[n++] =
3650 HDA_COMPOSE_AMP_VAL(vol, 3, 0, HDA_OUTPUT);
3651 }
3652 if (n) {
3653 snprintf(name, sizeof(name), "%s Playback Volume", pfx);
3654 err = add_control(spec, ALC_CTL_BIND_VOL, name, 0, (long)ctl);
3655 if (err < 0)
3656 return err;
3657 }
3658 return 0;
3659}
3660
Takashi Iwai343a04b2011-07-06 14:28:39 +02003661static int alc_auto_create_hp_out(struct hda_codec *codec)
3662{
3663 struct alc_spec *spec = codec->spec;
Takashi Iwaie23832a2011-08-23 18:16:56 +02003664 return alc_auto_create_extra_outs(codec, spec->autocfg.hp_outs,
3665 spec->autocfg.hp_pins,
3666 spec->multiout.hp_out_nid,
3667 "Headphone");
Takashi Iwai343a04b2011-07-06 14:28:39 +02003668}
3669
3670static int alc_auto_create_speaker_out(struct hda_codec *codec)
3671{
3672 struct alc_spec *spec = codec->spec;
Takashi Iwai23c09b02011-08-19 09:05:35 +02003673 return alc_auto_create_extra_outs(codec, spec->autocfg.speaker_outs,
3674 spec->autocfg.speaker_pins,
3675 spec->multiout.extra_out_nid,
3676 "Speaker");
Takashi Iwai343a04b2011-07-06 14:28:39 +02003677}
3678
Takashi Iwai130e5f02012-12-14 16:09:29 +01003679/* check whether a control with the given (nid, dir, idx) was assigned */
3680static bool is_ctl_associated(struct hda_codec *codec, hda_nid_t nid,
3681 int dir, int idx)
Takashi Iwai78e635c2012-12-10 17:07:16 +01003682{
Takashi Iwai130e5f02012-12-14 16:09:29 +01003683 struct alc_spec *spec = codec->spec;
Takashi Iwaic9967f12012-12-14 16:39:22 +01003684 int i, type;
3685
3686 for (i = 0; i < spec->paths.used; i++) {
3687 struct nid_path *p = snd_array_elem(&spec->paths, i);
3688 if (p->depth <= 0)
3689 continue;
Takashi Iwai8dd48672012-12-14 18:19:04 +01003690 for (type = 0; type < NID_PATH_NUM_CTLS; type++) {
Takashi Iwaic9967f12012-12-14 16:39:22 +01003691 unsigned int val = p->ctls[type];
3692 if (get_amp_nid_(val) == nid &&
3693 get_amp_direction_(val) == dir &&
3694 get_amp_index_(val) == idx)
3695 return true;
3696 }
3697 }
3698 return false;
Takashi Iwai130e5f02012-12-14 16:09:29 +01003699}
3700
3701/* can have the amp-in capability? */
3702static bool has_amp_in(struct hda_codec *codec, struct nid_path *path, int idx)
3703{
3704 hda_nid_t nid = path->path[idx];
3705 unsigned int caps = get_wcaps(codec, nid);
3706 unsigned int type = get_wcaps_type(caps);
3707
3708 if (!(caps & AC_WCAP_IN_AMP))
3709 return false;
3710 if (type == AC_WID_PIN && idx > 0) /* only for input pins */
3711 return false;
3712 return true;
3713}
3714
3715/* can have the amp-out capability? */
3716static bool has_amp_out(struct hda_codec *codec, struct nid_path *path, int idx)
3717{
3718 hda_nid_t nid = path->path[idx];
3719 unsigned int caps = get_wcaps(codec, nid);
3720 unsigned int type = get_wcaps_type(caps);
3721
3722 if (!(caps & AC_WCAP_OUT_AMP))
3723 return false;
3724 if (type == AC_WID_PIN && !idx) /* only for output pins */
3725 return false;
3726 return true;
3727}
3728
Takashi Iwaic9967f12012-12-14 16:39:22 +01003729/* check whether the given (nid,dir,idx) is active */
3730static bool is_active_nid(struct hda_codec *codec, hda_nid_t nid,
3731 unsigned int idx, unsigned int dir)
Takashi Iwai130e5f02012-12-14 16:09:29 +01003732{
Takashi Iwaic9967f12012-12-14 16:39:22 +01003733 struct alc_spec *spec = codec->spec;
Takashi Iwai130e5f02012-12-14 16:09:29 +01003734 int i, n;
3735
Takashi Iwaic9967f12012-12-14 16:39:22 +01003736 for (n = 0; n < spec->paths.used; n++) {
3737 struct nid_path *path = snd_array_elem(&spec->paths, n);
Takashi Iwai130e5f02012-12-14 16:09:29 +01003738 if (!path->active)
3739 continue;
3740 for (i = 0; i < path->depth; i++) {
3741 if (path->path[i] == nid) {
3742 if (dir == HDA_OUTPUT || path->idx[i] == idx)
3743 return true;
3744 break;
3745 }
3746 }
3747 }
3748 return false;
3749}
3750
Takashi Iwai130e5f02012-12-14 16:09:29 +01003751/* get the default amp value for the target state */
3752static int get_amp_val_to_activate(struct hda_codec *codec, hda_nid_t nid,
3753 int dir, bool enable)
3754{
3755 unsigned int caps;
Takashi Iwai78e635c2012-12-10 17:07:16 +01003756 unsigned int val = 0;
3757
3758 caps = query_amp_caps(codec, nid, dir);
3759 if (caps & AC_AMPCAP_NUM_STEPS) {
Takashi Iwai130e5f02012-12-14 16:09:29 +01003760 /* set to 0dB */
3761 if (enable)
3762 val = (caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT;
Takashi Iwai78e635c2012-12-10 17:07:16 +01003763 }
3764 if (caps & AC_AMPCAP_MUTE) {
Takashi Iwai130e5f02012-12-14 16:09:29 +01003765 if (!enable)
Takashi Iwai78e635c2012-12-10 17:07:16 +01003766 val |= HDA_AMP_MUTE;
3767 }
3768 return val;
3769}
3770
Takashi Iwai130e5f02012-12-14 16:09:29 +01003771/* initialize the amp value (only at the first time) */
3772static void init_amp(struct hda_codec *codec, hda_nid_t nid, int dir, int idx)
3773{
3774 int val = get_amp_val_to_activate(codec, nid, dir, false);
3775 snd_hda_codec_amp_init_stereo(codec, nid, dir, idx, 0xff, val);
3776}
3777
3778static void activate_amp(struct hda_codec *codec, hda_nid_t nid, int dir,
3779 int idx, bool enable)
3780{
3781 int val;
3782 if (is_ctl_associated(codec, nid, dir, idx) ||
3783 is_active_nid(codec, nid, dir, idx))
3784 return;
3785 val = get_amp_val_to_activate(codec, nid, dir, enable);
3786 snd_hda_codec_amp_stereo(codec, nid, dir, idx, 0xff, val);
3787}
3788
3789static void activate_amp_out(struct hda_codec *codec, struct nid_path *path,
3790 int i, bool enable)
3791{
3792 hda_nid_t nid = path->path[i];
3793 init_amp(codec, nid, HDA_OUTPUT, 0);
3794 activate_amp(codec, nid, HDA_OUTPUT, 0, enable);
3795}
3796
3797static void activate_amp_in(struct hda_codec *codec, struct nid_path *path,
Takashi Iwai666a70d2012-12-17 20:29:29 +01003798 int i, bool enable, bool add_aamix)
Takashi Iwai130e5f02012-12-14 16:09:29 +01003799{
3800 struct alc_spec *spec = codec->spec;
3801 hda_nid_t conn[16];
Takashi Iwai0250f7c2012-12-14 17:53:29 +01003802 int n, nums, idx;
Takashi Iwai666a70d2012-12-17 20:29:29 +01003803 int type;
Takashi Iwai130e5f02012-12-14 16:09:29 +01003804 hda_nid_t nid = path->path[i];
3805
3806 nums = snd_hda_get_connections(codec, nid, conn, ARRAY_SIZE(conn));
Takashi Iwai666a70d2012-12-17 20:29:29 +01003807 type = get_wcaps_type(get_wcaps(codec, nid));
3808 if (type == AC_WID_PIN ||
3809 (type == AC_WID_AUD_IN && codec->single_adc_amp)) {
Takashi Iwai0250f7c2012-12-14 17:53:29 +01003810 nums = 1;
3811 idx = 0;
3812 } else
3813 idx = path->idx[i];
3814
Takashi Iwai130e5f02012-12-14 16:09:29 +01003815 for (n = 0; n < nums; n++)
3816 init_amp(codec, nid, HDA_INPUT, n);
3817
Takashi Iwai0250f7c2012-12-14 17:53:29 +01003818 if (is_ctl_associated(codec, nid, HDA_INPUT, idx))
Takashi Iwai130e5f02012-12-14 16:09:29 +01003819 return;
3820
3821 /* here is a little bit tricky in comparison with activate_amp_out();
3822 * when aa-mixer is available, we need to enable the path as well
3823 */
3824 for (n = 0; n < nums; n++) {
Takashi Iwai666a70d2012-12-17 20:29:29 +01003825 if (n != idx && (!add_aamix || conn[n] != spec->mixer_nid))
Takashi Iwai130e5f02012-12-14 16:09:29 +01003826 continue;
3827 activate_amp(codec, nid, HDA_INPUT, n, enable);
3828 }
3829}
3830
3831static void activate_path(struct hda_codec *codec, struct nid_path *path,
Takashi Iwai666a70d2012-12-17 20:29:29 +01003832 bool enable, bool add_aamix)
Takashi Iwai130e5f02012-12-14 16:09:29 +01003833{
3834 int i;
3835
Takashi Iwai130e5f02012-12-14 16:09:29 +01003836 if (!enable)
3837 path->active = false;
3838
3839 for (i = path->depth - 1; i >= 0; i--) {
Takashi Iwai183a4442012-12-17 18:00:02 +01003840 if (enable && path->multi[i])
Takashi Iwai130e5f02012-12-14 16:09:29 +01003841 snd_hda_codec_write_cache(codec, path->path[i], 0,
3842 AC_VERB_SET_CONNECT_SEL,
3843 path->idx[i]);
3844 if (has_amp_in(codec, path, i))
Takashi Iwai666a70d2012-12-17 20:29:29 +01003845 activate_amp_in(codec, path, i, enable, add_aamix);
Takashi Iwai130e5f02012-12-14 16:09:29 +01003846 if (has_amp_out(codec, path, i))
3847 activate_amp_out(codec, path, i, enable);
3848 }
3849
3850 if (enable)
3851 path->active = true;
3852}
3853
Takashi Iwai78e635c2012-12-10 17:07:16 +01003854/* configure the path from the given dac to the pin as the proper output */
3855static void alc_auto_set_output_and_unmute(struct hda_codec *codec,
3856 hda_nid_t pin, int pin_type,
Takashi Iwai130e5f02012-12-14 16:09:29 +01003857 hda_nid_t dac)
Takashi Iwai78e635c2012-12-10 17:07:16 +01003858{
Takashi Iwaiba8111272012-12-06 18:06:23 +01003859 struct nid_path *path;
Takashi Iwai7085ec12009-10-02 09:03:58 +02003860
Takashi Iwai130e5f02012-12-14 16:09:29 +01003861 snd_hda_set_pin_ctl_cache(codec, pin, pin_type);
Takashi Iwai6518f7a2012-12-14 17:34:51 +01003862 path = get_nid_path(codec, dac, pin);
Takashi Iwaiba8111272012-12-06 18:06:23 +01003863 if (!path)
3864 return;
Takashi Iwai3ebf1e92012-12-14 18:04:37 +01003865 if (path->active)
3866 return;
Takashi Iwai666a70d2012-12-17 20:29:29 +01003867 activate_path(codec, path, true, true);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003868}
3869
Takashi Iwai343a04b2011-07-06 14:28:39 +02003870static void alc_auto_init_multi_out(struct hda_codec *codec)
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003871{
3872 struct alc_spec *spec = codec->spec;
Takashi Iwai7085ec12009-10-02 09:03:58 +02003873 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003874 int i;
3875
3876 for (i = 0; i <= HDA_SIDE; i++) {
3877 hda_nid_t nid = spec->autocfg.line_out_pins[i];
3878 if (nid)
Takashi Iwai343a04b2011-07-06 14:28:39 +02003879 alc_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwai130e5f02012-12-14 16:09:29 +01003880 spec->multiout.dac_nids[i]);
Takashi Iwai78e635c2012-12-10 17:07:16 +01003881
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003882 }
3883}
3884
Takashi Iwai343a04b2011-07-06 14:28:39 +02003885static void alc_auto_init_extra_out(struct hda_codec *codec)
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003886{
3887 struct alc_spec *spec = codec->spec;
Takashi Iwai8cd07752011-08-23 15:16:22 +02003888 int i;
Takashi Iwai675c1aa2011-08-23 12:36:28 +02003889 hda_nid_t pin, dac;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003890
David Henningsson636030e2011-10-12 19:26:03 +02003891 for (i = 0; i < spec->autocfg.hp_outs; i++) {
Takashi Iwai716eef02011-10-21 15:07:42 +02003892 if (spec->autocfg.line_out_type == AUTO_PIN_HP_OUT)
3893 break;
Takashi Iwaie23832a2011-08-23 18:16:56 +02003894 pin = spec->autocfg.hp_pins[i];
3895 if (!pin)
3896 break;
3897 dac = spec->multiout.hp_out_nid[i];
3898 if (!dac) {
3899 if (i > 0 && spec->multiout.hp_out_nid[0])
3900 dac = spec->multiout.hp_out_nid[0];
3901 else
3902 dac = spec->multiout.dac_nids[0];
3903 }
Takashi Iwai130e5f02012-12-14 16:09:29 +01003904 alc_auto_set_output_and_unmute(codec, pin, PIN_HP, dac);
Takashi Iwai675c1aa2011-08-23 12:36:28 +02003905 }
Takashi Iwai8cd07752011-08-23 15:16:22 +02003906 for (i = 0; i < spec->autocfg.speaker_outs; i++) {
Takashi Iwai716eef02011-10-21 15:07:42 +02003907 if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT)
3908 break;
Takashi Iwai8cd07752011-08-23 15:16:22 +02003909 pin = spec->autocfg.speaker_pins[i];
3910 if (!pin)
3911 break;
3912 dac = spec->multiout.extra_out_nid[i];
3913 if (!dac) {
3914 if (i > 0 && spec->multiout.extra_out_nid[0])
3915 dac = spec->multiout.extra_out_nid[0];
3916 else
3917 dac = spec->multiout.dac_nids[0];
3918 }
Takashi Iwai130e5f02012-12-14 16:09:29 +01003919 alc_auto_set_output_and_unmute(codec, pin, PIN_OUT, dac);
Takashi Iwai675c1aa2011-08-23 12:36:28 +02003920 }
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003921}
3922
Takashi Iwai276dd702012-02-17 16:17:03 +01003923/* check whether the given pin can be a multi-io pin */
3924static bool can_be_multiio_pin(struct hda_codec *codec,
3925 unsigned int location, hda_nid_t nid)
3926{
3927 unsigned int defcfg, caps;
3928
3929 defcfg = snd_hda_codec_get_pincfg(codec, nid);
3930 if (get_defcfg_connect(defcfg) != AC_JACK_PORT_COMPLEX)
3931 return false;
3932 if (location && get_defcfg_location(defcfg) != location)
3933 return false;
3934 caps = snd_hda_query_pin_caps(codec, nid);
3935 if (!(caps & AC_PINCAP_OUT))
3936 return false;
3937 return true;
3938}
3939
Takashi Iwaice764ab2011-04-27 16:35:23 +02003940/*
3941 * multi-io helper
Takashi Iwai276dd702012-02-17 16:17:03 +01003942 *
3943 * When hardwired is set, try to fill ony hardwired pins, and returns
3944 * zero if any pins are filled, non-zero if nothing found.
3945 * When hardwired is off, try to fill possible input pins, and returns
3946 * the badness value.
Takashi Iwaice764ab2011-04-27 16:35:23 +02003947 */
3948static int alc_auto_fill_multi_ios(struct hda_codec *codec,
Takashi Iwai276dd702012-02-17 16:17:03 +01003949 hda_nid_t reference_pin,
3950 bool hardwired, int offset)
Takashi Iwaice764ab2011-04-27 16:35:23 +02003951{
3952 struct alc_spec *spec = codec->spec;
3953 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwai276dd702012-02-17 16:17:03 +01003954 int type, i, j, dacs, num_pins, old_pins;
3955 unsigned int defcfg = snd_hda_codec_get_pincfg(codec, reference_pin);
3956 unsigned int location = get_defcfg_location(defcfg);
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01003957 int badness = 0;
Takashi Iwaice764ab2011-04-27 16:35:23 +02003958
Takashi Iwai276dd702012-02-17 16:17:03 +01003959 old_pins = spec->multi_ios;
3960 if (old_pins >= 2)
3961 goto end_fill;
3962
3963 num_pins = 0;
3964 for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) {
3965 for (i = 0; i < cfg->num_inputs; i++) {
3966 if (cfg->inputs[i].type != type)
3967 continue;
3968 if (can_be_multiio_pin(codec, location,
3969 cfg->inputs[i].pin))
3970 num_pins++;
3971 }
3972 }
3973 if (num_pins < 2)
3974 goto end_fill;
3975
Takashi Iwai07b18f62011-11-10 15:42:54 +01003976 dacs = spec->multiout.num_dacs;
Takashi Iwaice764ab2011-04-27 16:35:23 +02003977 for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) {
3978 for (i = 0; i < cfg->num_inputs; i++) {
3979 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai07b18f62011-11-10 15:42:54 +01003980 hda_nid_t dac = 0;
Takashi Iwai276dd702012-02-17 16:17:03 +01003981
Takashi Iwaice764ab2011-04-27 16:35:23 +02003982 if (cfg->inputs[i].type != type)
3983 continue;
Takashi Iwai276dd702012-02-17 16:17:03 +01003984 if (!can_be_multiio_pin(codec, location, nid))
Takashi Iwaice764ab2011-04-27 16:35:23 +02003985 continue;
Takashi Iwai276dd702012-02-17 16:17:03 +01003986 for (j = 0; j < spec->multi_ios; j++) {
3987 if (nid == spec->multi_io[j].pin)
3988 break;
3989 }
3990 if (j < spec->multi_ios)
Takashi Iwaice764ab2011-04-27 16:35:23 +02003991 continue;
Takashi Iwai276dd702012-02-17 16:17:03 +01003992
3993 if (offset && offset + spec->multi_ios < dacs) {
3994 dac = spec->private_dac_nids[offset + spec->multi_ios];
Takashi Iwai9c640762012-12-14 16:15:56 +01003995 if (!is_reachable_path(codec, dac, nid))
Takashi Iwai07b18f62011-11-10 15:42:54 +01003996 dac = 0;
3997 }
Takashi Iwai276dd702012-02-17 16:17:03 +01003998 if (hardwired)
3999 dac = get_dac_if_single(codec, nid);
4000 else if (!dac)
Takashi Iwaifef7fbb2012-12-14 16:54:44 +01004001 dac = alc_auto_look_for_dac(codec, nid, false);
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01004002 if (!dac) {
Takashi Iwai276dd702012-02-17 16:17:03 +01004003 badness++;
Takashi Iwaice764ab2011-04-27 16:35:23 +02004004 continue;
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01004005 }
Takashi Iwai965cceb2012-12-18 11:46:37 +01004006 if (!add_new_nid_path(codec, dac, nid, 0)) {
Takashi Iwai30dcd3b2012-12-06 15:45:38 +01004007 badness++;
4008 continue;
4009 }
Takashi Iwai276dd702012-02-17 16:17:03 +01004010 spec->multi_io[spec->multi_ios].pin = nid;
4011 spec->multi_io[spec->multi_ios].dac = dac;
4012 spec->multi_ios++;
4013 if (spec->multi_ios >= 2)
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01004014 break;
Takashi Iwaice764ab2011-04-27 16:35:23 +02004015 }
4016 }
Takashi Iwai276dd702012-02-17 16:17:03 +01004017 end_fill:
4018 if (badness)
4019 badness = BAD_MULTI_IO;
4020 if (old_pins == spec->multi_ios) {
4021 if (hardwired)
4022 return 1; /* nothing found */
4023 else
4024 return badness; /* no badness if nothing found */
4025 }
4026 if (!hardwired && spec->multi_ios < 2) {
Takashi Iwai30dcd3b2012-12-06 15:45:38 +01004027 /* cancel newly assigned paths */
Takashi Iwaic9967f12012-12-14 16:39:22 +01004028 spec->paths.used -= spec->multi_ios - old_pins;
Takashi Iwai276dd702012-02-17 16:17:03 +01004029 spec->multi_ios = old_pins;
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01004030 return badness;
Takashi Iwaic2674682011-08-24 17:57:44 +02004031 }
Takashi Iwai1c4a54b2012-02-16 16:45:59 +01004032
Takashi Iwai792cf2f2012-12-10 16:04:30 +01004033 /* assign volume and mute controls */
4034 for (i = old_pins; i < spec->multi_ios; i++)
4035 badness += assign_out_path_ctls(codec, spec->multi_io[i].pin,
4036 spec->multi_io[i].dac);
4037
4038 return badness;
Takashi Iwaice764ab2011-04-27 16:35:23 +02004039}
4040
4041static int alc_auto_ch_mode_info(struct snd_kcontrol *kcontrol,
4042 struct snd_ctl_elem_info *uinfo)
4043{
4044 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4045 struct alc_spec *spec = codec->spec;
4046
4047 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
4048 uinfo->count = 1;
4049 uinfo->value.enumerated.items = spec->multi_ios + 1;
4050 if (uinfo->value.enumerated.item > spec->multi_ios)
4051 uinfo->value.enumerated.item = spec->multi_ios;
4052 sprintf(uinfo->value.enumerated.name, "%dch",
4053 (uinfo->value.enumerated.item + 1) * 2);
4054 return 0;
4055}
4056
4057static int alc_auto_ch_mode_get(struct snd_kcontrol *kcontrol,
4058 struct snd_ctl_elem_value *ucontrol)
4059{
4060 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4061 struct alc_spec *spec = codec->spec;
4062 ucontrol->value.enumerated.item[0] = (spec->ext_channel_count - 1) / 2;
4063 return 0;
4064}
4065
4066static int alc_set_multi_io(struct hda_codec *codec, int idx, bool output)
4067{
4068 struct alc_spec *spec = codec->spec;
4069 hda_nid_t nid = spec->multi_io[idx].pin;
Takashi Iwai130e5f02012-12-14 16:09:29 +01004070 struct nid_path *path;
4071
Takashi Iwai6518f7a2012-12-14 17:34:51 +01004072 path = get_nid_path(codec, spec->multi_io[idx].dac, nid);
Takashi Iwai130e5f02012-12-14 16:09:29 +01004073 if (!path)
4074 return -EINVAL;
Takashi Iwaice764ab2011-04-27 16:35:23 +02004075
Takashi Iwai3ebf1e92012-12-14 18:04:37 +01004076 if (path->active == output)
4077 return 0;
Takashi Iwai130e5f02012-12-14 16:09:29 +01004078
Takashi Iwaice764ab2011-04-27 16:35:23 +02004079 if (output) {
Takashi Iwaicdd03ce2012-04-20 12:34:50 +02004080 snd_hda_set_pin_ctl_cache(codec, nid, PIN_OUT);
Takashi Iwai666a70d2012-12-17 20:29:29 +01004081 activate_path(codec, path, true, true);
Takashi Iwaice764ab2011-04-27 16:35:23 +02004082 } else {
Takashi Iwai666a70d2012-12-17 20:29:29 +01004083 activate_path(codec, path, false, true);
Takashi Iwaicdd03ce2012-04-20 12:34:50 +02004084 snd_hda_set_pin_ctl_cache(codec, nid,
4085 spec->multi_io[idx].ctl_in);
Takashi Iwaice764ab2011-04-27 16:35:23 +02004086 }
4087 return 0;
4088}
4089
4090static int alc_auto_ch_mode_put(struct snd_kcontrol *kcontrol,
4091 struct snd_ctl_elem_value *ucontrol)
4092{
4093 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4094 struct alc_spec *spec = codec->spec;
4095 int i, ch;
4096
4097 ch = ucontrol->value.enumerated.item[0];
4098 if (ch < 0 || ch > spec->multi_ios)
4099 return -EINVAL;
4100 if (ch == (spec->ext_channel_count - 1) / 2)
4101 return 0;
4102 spec->ext_channel_count = (ch + 1) * 2;
4103 for (i = 0; i < spec->multi_ios; i++)
4104 alc_set_multi_io(codec, i, i < ch);
Takashi Iwaib6adb572012-12-03 10:30:58 +01004105 spec->multiout.max_channels = max(spec->ext_channel_count,
4106 spec->const_channel_count);
4107 if (spec->need_dac_fix)
Takashi Iwai7b1655f2011-07-14 15:31:21 +02004108 spec->multiout.num_dacs = spec->multiout.max_channels / 2;
Takashi Iwaice764ab2011-04-27 16:35:23 +02004109 return 1;
4110}
4111
Takashi Iwaia9111322011-05-02 11:30:18 +02004112static const struct snd_kcontrol_new alc_auto_channel_mode_enum = {
Takashi Iwaice764ab2011-04-27 16:35:23 +02004113 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4114 .name = "Channel Mode",
4115 .info = alc_auto_ch_mode_info,
4116 .get = alc_auto_ch_mode_get,
4117 .put = alc_auto_ch_mode_put,
4118};
4119
Takashi Iwai23c09b02011-08-19 09:05:35 +02004120static int alc_auto_add_multi_channel_mode(struct hda_codec *codec)
Takashi Iwaice764ab2011-04-27 16:35:23 +02004121{
4122 struct alc_spec *spec = codec->spec;
Takashi Iwaice764ab2011-04-27 16:35:23 +02004123
Takashi Iwaic2674682011-08-24 17:57:44 +02004124 if (spec->multi_ios > 0) {
Takashi Iwai668d1e92012-11-29 14:10:17 +01004125 if (!alc_kcontrol_new(spec, "Channel Mode",
4126 &alc_auto_channel_mode_enum))
Takashi Iwaice764ab2011-04-27 16:35:23 +02004127 return -ENOMEM;
Takashi Iwaice764ab2011-04-27 16:35:23 +02004128 }
4129 return 0;
4130}
4131
Takashi Iwai3ebf1e92012-12-14 18:04:37 +01004132static void alc_auto_init_multi_io(struct hda_codec *codec)
4133{
4134 struct alc_spec *spec = codec->spec;
4135 int i;
4136
4137 for (i = 0; i < spec->multi_ios; i++) {
4138 hda_nid_t pin = spec->multi_io[i].pin;
4139 struct nid_path *path;
4140 path = get_nid_path(codec, spec->multi_io[i].dac, pin);
4141 if (!path)
4142 continue;
4143 if (!spec->multi_io[i].ctl_in)
4144 spec->multi_io[i].ctl_in =
4145 snd_hda_codec_update_cache(codec, pin, 0,
4146 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
Takashi Iwai666a70d2012-12-17 20:29:29 +01004147 activate_path(codec, path, path->active, true);
Takashi Iwai3ebf1e92012-12-14 18:04:37 +01004148 }
4149}
4150
Takashi Iwai1d045db2011-07-07 18:23:21 +02004151/*
4152 * initialize ADC paths
4153 */
Takashi Iwai1d045db2011-07-07 18:23:21 +02004154static void alc_auto_init_input_src(struct hda_codec *codec)
4155{
4156 struct alc_spec *spec = codec->spec;
Takashi Iwai27d31532012-12-18 08:57:05 +01004157 struct hda_input_mux *imux = &spec->input_mux;
Takashi Iwai666a70d2012-12-17 20:29:29 +01004158 struct nid_path *path;
4159 int i, c, nums;
Takashi Iwai1d045db2011-07-07 18:23:21 +02004160
Takashi Iwai1d045db2011-07-07 18:23:21 +02004161 if (spec->dyn_adc_switch)
4162 nums = 1;
4163 else
4164 nums = spec->num_adc_nids;
Takashi Iwai666a70d2012-12-17 20:29:29 +01004165
4166 for (c = 0; c < nums; c++) {
4167 for (i = 0; i < imux->num_items; i++) {
4168 path = get_nid_path(codec, spec->imux_pins[i],
4169 get_adc_nid(codec, c, i));
4170 if (path) {
4171 bool active = path->active;
4172 if (i == spec->cur_mux[c])
4173 active = true;
4174 activate_path(codec, path, active, false);
4175 }
4176 }
4177 }
4178
4179 alc_inv_dmic_sync(codec, true);
4180 if (spec->shared_mic_hp)
4181 update_shared_mic_hp(codec, spec->cur_mux[0]);
Takashi Iwai1d045db2011-07-07 18:23:21 +02004182}
4183
4184/* add mic boosts if needed */
4185static int alc_auto_add_mic_boost(struct hda_codec *codec)
4186{
4187 struct alc_spec *spec = codec->spec;
4188 struct auto_pin_cfg *cfg = &spec->autocfg;
4189 int i, err;
4190 int type_idx = 0;
4191 hda_nid_t nid;
4192 const char *prev_label = NULL;
4193
4194 for (i = 0; i < cfg->num_inputs; i++) {
4195 if (cfg->inputs[i].type > AUTO_PIN_MIC)
4196 break;
4197 nid = cfg->inputs[i].pin;
4198 if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) {
4199 const char *label;
4200 char boost_label[32];
Takashi Iwai8dd48672012-12-14 18:19:04 +01004201 struct nid_path *path;
4202 unsigned int val;
Takashi Iwai1d045db2011-07-07 18:23:21 +02004203
4204 label = hda_get_autocfg_input_label(codec, cfg, i);
Takashi Iwai24de1832011-11-07 17:13:39 +01004205 if (spec->shared_mic_hp && !strcmp(label, "Misc"))
4206 label = "Headphone Mic";
Takashi Iwai1d045db2011-07-07 18:23:21 +02004207 if (prev_label && !strcmp(label, prev_label))
4208 type_idx++;
4209 else
4210 type_idx = 0;
4211 prev_label = label;
4212
4213 snprintf(boost_label, sizeof(boost_label),
4214 "%s Boost Volume", label);
Takashi Iwai8dd48672012-12-14 18:19:04 +01004215 val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT);
Takashi Iwai1d045db2011-07-07 18:23:21 +02004216 err = add_control(spec, ALC_CTL_WIDGET_VOL,
Takashi Iwai8dd48672012-12-14 18:19:04 +01004217 boost_label, type_idx, val);
Takashi Iwai1d045db2011-07-07 18:23:21 +02004218 if (err < 0)
4219 return err;
Takashi Iwai8dd48672012-12-14 18:19:04 +01004220
4221 path = get_nid_path(codec, nid, 0);
4222 if (path)
4223 path->ctls[NID_PATH_BOOST_CTL] = val;
Takashi Iwai1d045db2011-07-07 18:23:21 +02004224 }
4225 }
4226 return 0;
4227}
4228
Takashi Iwai1d045db2011-07-07 18:23:21 +02004229/*
Takashi Iwaie4770622011-07-08 11:11:35 +02004230 * standard auto-parser initializations
4231 */
4232static void alc_auto_init_std(struct hda_codec *codec)
4233{
Takashi Iwaie4770622011-07-08 11:11:35 +02004234 alc_auto_init_multi_out(codec);
4235 alc_auto_init_extra_out(codec);
Takashi Iwai3ebf1e92012-12-14 18:04:37 +01004236 alc_auto_init_multi_io(codec);
Takashi Iwaie4770622011-07-08 11:11:35 +02004237 alc_auto_init_analog_input(codec);
4238 alc_auto_init_input_src(codec);
4239 alc_auto_init_digital(codec);
David Henningssona7a0a642012-07-05 12:00:12 +02004240 alc_inithook(codec);
Takashi Iwaie4770622011-07-08 11:11:35 +02004241}
4242
4243/*
Takashi Iwai1d045db2011-07-07 18:23:21 +02004244 * Digital-beep handlers
4245 */
4246#ifdef CONFIG_SND_HDA_INPUT_BEEP
4247#define set_beep_amp(spec, nid, idx, dir) \
4248 ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir))
4249
4250static const struct snd_pci_quirk beep_white_list[] = {
Duncan Roe71100052012-10-10 14:19:50 +02004251 SND_PCI_QUIRK(0x1043, 0x103c, "ASUS", 1),
Takashi Iwai1d045db2011-07-07 18:23:21 +02004252 SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1),
4253 SND_PCI_QUIRK(0x1043, 0x83ce, "EeePC", 1),
4254 SND_PCI_QUIRK(0x1043, 0x831a, "EeePC", 1),
4255 SND_PCI_QUIRK(0x1043, 0x834a, "EeePC", 1),
Takashi Iwai78f8baf2012-03-06 14:02:32 +01004256 SND_PCI_QUIRK(0x1458, 0xa002, "GA-MA790X", 1),
Takashi Iwai1d045db2011-07-07 18:23:21 +02004257 SND_PCI_QUIRK(0x8086, 0xd613, "Intel", 1),
4258 {}
4259};
4260
4261static inline int has_cdefine_beep(struct hda_codec *codec)
4262{
4263 struct alc_spec *spec = codec->spec;
4264 const struct snd_pci_quirk *q;
4265 q = snd_pci_quirk_lookup(codec->bus->pci, beep_white_list);
4266 if (q)
4267 return q->value;
4268 return spec->cdefine.enable_pcbeep;
4269}
4270#else
4271#define set_beep_amp(spec, nid, idx, dir) /* NOP */
4272#define has_cdefine_beep(codec) 0
4273#endif
4274
4275/* parse the BIOS configuration and set up the alc_spec */
4276/* return 1 if successful, 0 if the proper config is not found,
4277 * or a negative error code
4278 */
Takashi Iwai3e6179b2011-07-08 16:55:13 +02004279static int alc_parse_auto_config(struct hda_codec *codec,
4280 const hda_nid_t *ignore_nids,
4281 const hda_nid_t *ssid_nids)
Takashi Iwai1d045db2011-07-07 18:23:21 +02004282{
4283 struct alc_spec *spec = codec->spec;
Takashi Iwai23c09b02011-08-19 09:05:35 +02004284 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwai1d045db2011-07-07 18:23:21 +02004285 int err;
Takashi Iwai1d045db2011-07-07 18:23:21 +02004286
Takashi Iwai53c334a2011-08-23 18:27:14 +02004287 err = snd_hda_parse_pin_defcfg(codec, cfg, ignore_nids,
4288 spec->parse_flags);
Takashi Iwai1d045db2011-07-07 18:23:21 +02004289 if (err < 0)
4290 return err;
Takashi Iwai23c09b02011-08-19 09:05:35 +02004291 if (!cfg->line_outs) {
4292 if (cfg->dig_outs || cfg->dig_in_pin) {
Takashi Iwai3e6179b2011-07-08 16:55:13 +02004293 spec->multiout.max_channels = 2;
4294 spec->no_analog = 1;
4295 goto dig_only;
4296 }
Takashi Iwai1d045db2011-07-07 18:23:21 +02004297 return 0; /* can't find valid BIOS pin config */
Takashi Iwai3e6179b2011-07-08 16:55:13 +02004298 }
Takashi Iwai23c09b02011-08-19 09:05:35 +02004299
Takashi Iwaie427c232012-07-29 10:04:08 +02004300 if (!spec->no_primary_hp &&
4301 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT &&
Takashi Iwai06503672011-10-06 08:27:19 +02004302 cfg->line_outs <= cfg->hp_outs) {
Takashi Iwai23c09b02011-08-19 09:05:35 +02004303 /* use HP as primary out */
4304 cfg->speaker_outs = cfg->line_outs;
4305 memcpy(cfg->speaker_pins, cfg->line_out_pins,
4306 sizeof(cfg->speaker_pins));
4307 cfg->line_outs = cfg->hp_outs;
4308 memcpy(cfg->line_out_pins, cfg->hp_pins, sizeof(cfg->hp_pins));
4309 cfg->hp_outs = 0;
4310 memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins));
4311 cfg->line_out_type = AUTO_PIN_HP_OUT;
4312 }
4313
Takashi Iwai1d045db2011-07-07 18:23:21 +02004314 err = alc_auto_fill_dac_nids(codec);
4315 if (err < 0)
4316 return err;
Takashi Iwai23c09b02011-08-19 09:05:35 +02004317 err = alc_auto_add_multi_channel_mode(codec);
Takashi Iwai3e6179b2011-07-08 16:55:13 +02004318 if (err < 0)
4319 return err;
Takashi Iwai23c09b02011-08-19 09:05:35 +02004320 err = alc_auto_create_multi_out_ctls(codec, cfg);
Takashi Iwai1d045db2011-07-07 18:23:21 +02004321 if (err < 0)
4322 return err;
4323 err = alc_auto_create_hp_out(codec);
4324 if (err < 0)
4325 return err;
4326 err = alc_auto_create_speaker_out(codec);
4327 if (err < 0)
4328 return err;
Takashi Iwai24de1832011-11-07 17:13:39 +01004329 err = alc_auto_create_shared_input(codec);
4330 if (err < 0)
4331 return err;
Takashi Iwai1d045db2011-07-07 18:23:21 +02004332 err = alc_auto_create_input_ctls(codec);
4333 if (err < 0)
4334 return err;
4335
Takashi Iwaib6adb572012-12-03 10:30:58 +01004336 /* check the multiple speaker pins */
4337 if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
4338 spec->const_channel_count = cfg->line_outs * 2;
4339 else
4340 spec->const_channel_count = cfg->speaker_outs * 2;
4341
4342 if (spec->multi_ios > 0)
4343 spec->multiout.max_channels = max(spec->ext_channel_count,
4344 spec->const_channel_count);
4345 else
4346 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
Takashi Iwai1d045db2011-07-07 18:23:21 +02004347
Takashi Iwai3e6179b2011-07-08 16:55:13 +02004348 dig_only:
Takashi Iwai1d045db2011-07-07 18:23:21 +02004349 alc_auto_parse_digital(codec);
4350
Takashi Iwai3e6179b2011-07-08 16:55:13 +02004351 if (ssid_nids)
4352 alc_ssid_check(codec, ssid_nids);
4353
4354 if (!spec->no_analog) {
Takashi Iwai666a70d2012-12-17 20:29:29 +01004355 err = alc_init_automute(codec);
Takashi Iwai475c3d22012-11-30 08:31:30 +01004356 if (err < 0)
4357 return err;
Takashi Iwai666a70d2012-12-17 20:29:29 +01004358
4359 err = check_dyn_adc_switch(codec);
4360 if (err < 0)
4361 return err;
4362
4363 if (!spec->shared_mic_hp) {
4364 err = alc_init_auto_mic(codec);
4365 if (err < 0)
4366 return err;
4367 }
4368
4369 err = create_capture_mixers(codec);
4370 if (err < 0)
4371 return err;
4372
Takashi Iwai3e6179b2011-07-08 16:55:13 +02004373 err = alc_auto_add_mic_boost(codec);
4374 if (err < 0)
4375 return err;
4376 }
4377
Takashi Iwai1d045db2011-07-07 18:23:21 +02004378 if (spec->kctls.list)
4379 add_mixer(spec, spec->kctls.list);
4380
Takashi Iwai1d045db2011-07-07 18:23:21 +02004381 return 1;
4382}
4383
Takashi Iwai3de95172012-05-07 18:03:15 +02004384/* common preparation job for alc_spec */
4385static int alc_alloc_spec(struct hda_codec *codec, hda_nid_t mixer_nid)
4386{
4387 struct alc_spec *spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4388 int err;
4389
4390 if (!spec)
4391 return -ENOMEM;
4392 codec->spec = spec;
Takashi Iwai1098b7c2012-12-17 20:03:15 +01004393 codec->single_adc_amp = 1;
Takashi Iwai3de95172012-05-07 18:03:15 +02004394 spec->mixer_nid = mixer_nid;
Takashi Iwaiee48df52012-06-26 14:54:32 +02004395 snd_hda_gen_init(&spec->gen);
Takashi Iwai361dab32012-05-09 14:35:27 +02004396 snd_array_init(&spec->kctls, sizeof(struct snd_kcontrol_new), 32);
4397 snd_array_init(&spec->bind_ctls, sizeof(struct hda_bind_ctls *), 8);
Takashi Iwaic9967f12012-12-14 16:39:22 +01004398 snd_array_init(&spec->paths, sizeof(struct nid_path), 8);
Takashi Iwai3de95172012-05-07 18:03:15 +02004399
4400 err = alc_codec_rename_from_preset(codec);
4401 if (err < 0) {
4402 kfree(spec);
4403 return err;
4404 }
4405 return 0;
4406}
4407
Takashi Iwai3e6179b2011-07-08 16:55:13 +02004408static int alc880_parse_auto_config(struct hda_codec *codec)
4409{
4410 static const hda_nid_t alc880_ignore[] = { 0x1d, 0 };
Jesper Juhl7d7eb9e2012-04-12 22:11:25 +02004411 static const hda_nid_t alc880_ssids[] = { 0x15, 0x1b, 0x14, 0 };
Takashi Iwai3e6179b2011-07-08 16:55:13 +02004412 return alc_parse_auto_config(codec, alc880_ignore, alc880_ssids);
4413}
4414
Takashi Iwai1d045db2011-07-07 18:23:21 +02004415/*
Takashi Iwaiee3b2962011-11-15 14:26:54 +01004416 * ALC880 fix-ups
4417 */
4418enum {
Takashi Iwai411225a2012-02-20 17:48:19 +01004419 ALC880_FIXUP_GPIO1,
Takashi Iwaiee3b2962011-11-15 14:26:54 +01004420 ALC880_FIXUP_GPIO2,
4421 ALC880_FIXUP_MEDION_RIM,
Takashi Iwaidc6af522012-02-17 16:18:59 +01004422 ALC880_FIXUP_LG,
Takashi Iwaif02aab52012-02-17 16:33:56 +01004423 ALC880_FIXUP_W810,
Takashi Iwai27e917f2012-02-17 17:49:54 +01004424 ALC880_FIXUP_EAPD_COEF,
Takashi Iwaib9368f52012-02-17 17:54:44 +01004425 ALC880_FIXUP_TCL_S700,
Takashi Iwaicf5a2272012-02-20 16:31:07 +01004426 ALC880_FIXUP_VOL_KNOB,
4427 ALC880_FIXUP_FUJITSU,
Takashi Iwaiba533812012-02-20 16:36:52 +01004428 ALC880_FIXUP_F1734,
Takashi Iwai817de922012-02-20 17:20:48 +01004429 ALC880_FIXUP_UNIWILL,
Takashi Iwai967b88c2012-02-20 17:31:02 +01004430 ALC880_FIXUP_UNIWILL_DIG,
Takashi Iwai96e225f2012-02-20 17:41:51 +01004431 ALC880_FIXUP_Z71V,
Takashi Iwai67b6ec32012-02-20 18:20:42 +01004432 ALC880_FIXUP_3ST_BASE,
4433 ALC880_FIXUP_3ST,
4434 ALC880_FIXUP_3ST_DIG,
4435 ALC880_FIXUP_5ST_BASE,
4436 ALC880_FIXUP_5ST,
4437 ALC880_FIXUP_5ST_DIG,
4438 ALC880_FIXUP_6ST_BASE,
4439 ALC880_FIXUP_6ST,
4440 ALC880_FIXUP_6ST_DIG,
Takashi Iwaiee3b2962011-11-15 14:26:54 +01004441};
4442
Takashi Iwaicf5a2272012-02-20 16:31:07 +01004443/* enable the volume-knob widget support on NID 0x21 */
4444static void alc880_fixup_vol_knob(struct hda_codec *codec,
4445 const struct alc_fixup *fix, int action)
4446{
4447 if (action == ALC_FIXUP_ACT_PROBE)
David Henningsson29adc4b2012-09-25 11:31:00 +02004448 snd_hda_jack_detect_enable_callback(codec, 0x21, ALC_DCVOL_EVENT, alc_update_knob_master);
Takashi Iwaicf5a2272012-02-20 16:31:07 +01004449}
4450
Takashi Iwaiee3b2962011-11-15 14:26:54 +01004451static const struct alc_fixup alc880_fixups[] = {
Takashi Iwai411225a2012-02-20 17:48:19 +01004452 [ALC880_FIXUP_GPIO1] = {
4453 .type = ALC_FIXUP_VERBS,
4454 .v.verbs = alc_gpio1_init_verbs,
4455 },
Takashi Iwaiee3b2962011-11-15 14:26:54 +01004456 [ALC880_FIXUP_GPIO2] = {
4457 .type = ALC_FIXUP_VERBS,
4458 .v.verbs = alc_gpio2_init_verbs,
4459 },
4460 [ALC880_FIXUP_MEDION_RIM] = {
4461 .type = ALC_FIXUP_VERBS,
4462 .v.verbs = (const struct hda_verb[]) {
4463 { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
4464 { 0x20, AC_VERB_SET_PROC_COEF, 0x3060 },
4465 { }
4466 },
4467 .chained = true,
4468 .chain_id = ALC880_FIXUP_GPIO2,
4469 },
Takashi Iwaidc6af522012-02-17 16:18:59 +01004470 [ALC880_FIXUP_LG] = {
4471 .type = ALC_FIXUP_PINS,
4472 .v.pins = (const struct alc_pincfg[]) {
4473 /* disable bogus unused pins */
4474 { 0x16, 0x411111f0 },
4475 { 0x18, 0x411111f0 },
4476 { 0x1a, 0x411111f0 },
4477 { }
4478 }
4479 },
Takashi Iwaif02aab52012-02-17 16:33:56 +01004480 [ALC880_FIXUP_W810] = {
4481 .type = ALC_FIXUP_PINS,
4482 .v.pins = (const struct alc_pincfg[]) {
4483 /* disable bogus unused pins */
4484 { 0x17, 0x411111f0 },
4485 { }
4486 },
4487 .chained = true,
4488 .chain_id = ALC880_FIXUP_GPIO2,
4489 },
Takashi Iwai27e917f2012-02-17 17:49:54 +01004490 [ALC880_FIXUP_EAPD_COEF] = {
4491 .type = ALC_FIXUP_VERBS,
4492 .v.verbs = (const struct hda_verb[]) {
4493 /* change to EAPD mode */
4494 { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
4495 { 0x20, AC_VERB_SET_PROC_COEF, 0x3060 },
4496 {}
4497 },
4498 },
Takashi Iwaib9368f52012-02-17 17:54:44 +01004499 [ALC880_FIXUP_TCL_S700] = {
4500 .type = ALC_FIXUP_VERBS,
4501 .v.verbs = (const struct hda_verb[]) {
4502 /* change to EAPD mode */
4503 { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
4504 { 0x20, AC_VERB_SET_PROC_COEF, 0x3070 },
4505 {}
4506 },
4507 .chained = true,
4508 .chain_id = ALC880_FIXUP_GPIO2,
4509 },
Takashi Iwaicf5a2272012-02-20 16:31:07 +01004510 [ALC880_FIXUP_VOL_KNOB] = {
4511 .type = ALC_FIXUP_FUNC,
4512 .v.func = alc880_fixup_vol_knob,
4513 },
4514 [ALC880_FIXUP_FUJITSU] = {
4515 /* override all pins as BIOS on old Amilo is broken */
4516 .type = ALC_FIXUP_PINS,
4517 .v.pins = (const struct alc_pincfg[]) {
4518 { 0x14, 0x0121411f }, /* HP */
4519 { 0x15, 0x99030120 }, /* speaker */
4520 { 0x16, 0x99030130 }, /* bass speaker */
4521 { 0x17, 0x411111f0 }, /* N/A */
4522 { 0x18, 0x411111f0 }, /* N/A */
4523 { 0x19, 0x01a19950 }, /* mic-in */
4524 { 0x1a, 0x411111f0 }, /* N/A */
4525 { 0x1b, 0x411111f0 }, /* N/A */
4526 { 0x1c, 0x411111f0 }, /* N/A */
4527 { 0x1d, 0x411111f0 }, /* N/A */
4528 { 0x1e, 0x01454140 }, /* SPDIF out */
4529 { }
4530 },
4531 .chained = true,
4532 .chain_id = ALC880_FIXUP_VOL_KNOB,
4533 },
Takashi Iwaiba533812012-02-20 16:36:52 +01004534 [ALC880_FIXUP_F1734] = {
4535 /* almost compatible with FUJITSU, but no bass and SPDIF */
4536 .type = ALC_FIXUP_PINS,
4537 .v.pins = (const struct alc_pincfg[]) {
4538 { 0x14, 0x0121411f }, /* HP */
4539 { 0x15, 0x99030120 }, /* speaker */
4540 { 0x16, 0x411111f0 }, /* N/A */
4541 { 0x17, 0x411111f0 }, /* N/A */
4542 { 0x18, 0x411111f0 }, /* N/A */
4543 { 0x19, 0x01a19950 }, /* mic-in */
4544 { 0x1a, 0x411111f0 }, /* N/A */
4545 { 0x1b, 0x411111f0 }, /* N/A */
4546 { 0x1c, 0x411111f0 }, /* N/A */
4547 { 0x1d, 0x411111f0 }, /* N/A */
4548 { 0x1e, 0x411111f0 }, /* N/A */
4549 { }
4550 },
4551 .chained = true,
4552 .chain_id = ALC880_FIXUP_VOL_KNOB,
4553 },
Takashi Iwai817de922012-02-20 17:20:48 +01004554 [ALC880_FIXUP_UNIWILL] = {
4555 /* need to fix HP and speaker pins to be parsed correctly */
4556 .type = ALC_FIXUP_PINS,
4557 .v.pins = (const struct alc_pincfg[]) {
4558 { 0x14, 0x0121411f }, /* HP */
4559 { 0x15, 0x99030120 }, /* speaker */
4560 { 0x16, 0x99030130 }, /* bass speaker */
4561 { }
4562 },
4563 },
Takashi Iwai967b88c2012-02-20 17:31:02 +01004564 [ALC880_FIXUP_UNIWILL_DIG] = {
4565 .type = ALC_FIXUP_PINS,
4566 .v.pins = (const struct alc_pincfg[]) {
4567 /* disable bogus unused pins */
4568 { 0x17, 0x411111f0 },
4569 { 0x19, 0x411111f0 },
4570 { 0x1b, 0x411111f0 },
4571 { 0x1f, 0x411111f0 },
4572 { }
4573 }
4574 },
Takashi Iwai96e225f2012-02-20 17:41:51 +01004575 [ALC880_FIXUP_Z71V] = {
4576 .type = ALC_FIXUP_PINS,
4577 .v.pins = (const struct alc_pincfg[]) {
4578 /* set up the whole pins as BIOS is utterly broken */
4579 { 0x14, 0x99030120 }, /* speaker */
4580 { 0x15, 0x0121411f }, /* HP */
4581 { 0x16, 0x411111f0 }, /* N/A */
4582 { 0x17, 0x411111f0 }, /* N/A */
4583 { 0x18, 0x01a19950 }, /* mic-in */
4584 { 0x19, 0x411111f0 }, /* N/A */
4585 { 0x1a, 0x01813031 }, /* line-in */
4586 { 0x1b, 0x411111f0 }, /* N/A */
4587 { 0x1c, 0x411111f0 }, /* N/A */
4588 { 0x1d, 0x411111f0 }, /* N/A */
4589 { 0x1e, 0x0144111e }, /* SPDIF */
4590 { }
4591 }
4592 },
Takashi Iwai67b6ec32012-02-20 18:20:42 +01004593 [ALC880_FIXUP_3ST_BASE] = {
4594 .type = ALC_FIXUP_PINS,
4595 .v.pins = (const struct alc_pincfg[]) {
4596 { 0x14, 0x01014010 }, /* line-out */
4597 { 0x15, 0x411111f0 }, /* N/A */
4598 { 0x16, 0x411111f0 }, /* N/A */
4599 { 0x17, 0x411111f0 }, /* N/A */
4600 { 0x18, 0x01a19c30 }, /* mic-in */
4601 { 0x19, 0x0121411f }, /* HP */
4602 { 0x1a, 0x01813031 }, /* line-in */
4603 { 0x1b, 0x02a19c40 }, /* front-mic */
4604 { 0x1c, 0x411111f0 }, /* N/A */
4605 { 0x1d, 0x411111f0 }, /* N/A */
4606 /* 0x1e is filled in below */
4607 { 0x1f, 0x411111f0 }, /* N/A */
4608 { }
4609 }
4610 },
4611 [ALC880_FIXUP_3ST] = {
4612 .type = ALC_FIXUP_PINS,
4613 .v.pins = (const struct alc_pincfg[]) {
4614 { 0x1e, 0x411111f0 }, /* N/A */
4615 { }
4616 },
4617 .chained = true,
4618 .chain_id = ALC880_FIXUP_3ST_BASE,
4619 },
4620 [ALC880_FIXUP_3ST_DIG] = {
4621 .type = ALC_FIXUP_PINS,
4622 .v.pins = (const struct alc_pincfg[]) {
4623 { 0x1e, 0x0144111e }, /* SPDIF */
4624 { }
4625 },
4626 .chained = true,
4627 .chain_id = ALC880_FIXUP_3ST_BASE,
4628 },
4629 [ALC880_FIXUP_5ST_BASE] = {
4630 .type = ALC_FIXUP_PINS,
4631 .v.pins = (const struct alc_pincfg[]) {
4632 { 0x14, 0x01014010 }, /* front */
4633 { 0x15, 0x411111f0 }, /* N/A */
4634 { 0x16, 0x01011411 }, /* CLFE */
4635 { 0x17, 0x01016412 }, /* surr */
4636 { 0x18, 0x01a19c30 }, /* mic-in */
4637 { 0x19, 0x0121411f }, /* HP */
4638 { 0x1a, 0x01813031 }, /* line-in */
4639 { 0x1b, 0x02a19c40 }, /* front-mic */
4640 { 0x1c, 0x411111f0 }, /* N/A */
4641 { 0x1d, 0x411111f0 }, /* N/A */
4642 /* 0x1e is filled in below */
4643 { 0x1f, 0x411111f0 }, /* N/A */
4644 { }
4645 }
4646 },
4647 [ALC880_FIXUP_5ST] = {
4648 .type = ALC_FIXUP_PINS,
4649 .v.pins = (const struct alc_pincfg[]) {
4650 { 0x1e, 0x411111f0 }, /* N/A */
4651 { }
4652 },
4653 .chained = true,
4654 .chain_id = ALC880_FIXUP_5ST_BASE,
4655 },
4656 [ALC880_FIXUP_5ST_DIG] = {
4657 .type = ALC_FIXUP_PINS,
4658 .v.pins = (const struct alc_pincfg[]) {
4659 { 0x1e, 0x0144111e }, /* SPDIF */
4660 { }
4661 },
4662 .chained = true,
4663 .chain_id = ALC880_FIXUP_5ST_BASE,
4664 },
4665 [ALC880_FIXUP_6ST_BASE] = {
4666 .type = ALC_FIXUP_PINS,
4667 .v.pins = (const struct alc_pincfg[]) {
4668 { 0x14, 0x01014010 }, /* front */
4669 { 0x15, 0x01016412 }, /* surr */
4670 { 0x16, 0x01011411 }, /* CLFE */
4671 { 0x17, 0x01012414 }, /* side */
4672 { 0x18, 0x01a19c30 }, /* mic-in */
4673 { 0x19, 0x02a19c40 }, /* front-mic */
4674 { 0x1a, 0x01813031 }, /* line-in */
4675 { 0x1b, 0x0121411f }, /* HP */
4676 { 0x1c, 0x411111f0 }, /* N/A */
4677 { 0x1d, 0x411111f0 }, /* N/A */
4678 /* 0x1e is filled in below */
4679 { 0x1f, 0x411111f0 }, /* N/A */
4680 { }
4681 }
4682 },
4683 [ALC880_FIXUP_6ST] = {
4684 .type = ALC_FIXUP_PINS,
4685 .v.pins = (const struct alc_pincfg[]) {
4686 { 0x1e, 0x411111f0 }, /* N/A */
4687 { }
4688 },
4689 .chained = true,
4690 .chain_id = ALC880_FIXUP_6ST_BASE,
4691 },
4692 [ALC880_FIXUP_6ST_DIG] = {
4693 .type = ALC_FIXUP_PINS,
4694 .v.pins = (const struct alc_pincfg[]) {
4695 { 0x1e, 0x0144111e }, /* SPDIF */
4696 { }
4697 },
4698 .chained = true,
4699 .chain_id = ALC880_FIXUP_6ST_BASE,
4700 },
Takashi Iwaiee3b2962011-11-15 14:26:54 +01004701};
4702
4703static const struct snd_pci_quirk alc880_fixup_tbl[] = {
Takashi Iwaif02aab52012-02-17 16:33:56 +01004704 SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_FIXUP_W810),
Takashi Iwai96e225f2012-02-20 17:41:51 +01004705 SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_FIXUP_Z71V),
Takashi Iwai29e3fdc2012-02-20 17:56:57 +01004706 SND_PCI_QUIRK_VENDOR(0x1043, "ASUS", ALC880_FIXUP_GPIO1),
4707 SND_PCI_QUIRK(0x1558, 0x5401, "Clevo GPIO2", ALC880_FIXUP_GPIO2),
Takashi Iwai27e917f2012-02-17 17:49:54 +01004708 SND_PCI_QUIRK_VENDOR(0x1558, "Clevo", ALC880_FIXUP_EAPD_COEF),
Takashi Iwai967b88c2012-02-20 17:31:02 +01004709 SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_FIXUP_UNIWILL_DIG),
Takashi Iwaiba533812012-02-20 16:36:52 +01004710 SND_PCI_QUIRK(0x1584, 0x9054, "Uniwill", ALC880_FIXUP_F1734),
Takashi Iwai817de922012-02-20 17:20:48 +01004711 SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_FIXUP_UNIWILL),
Takashi Iwai7833c7e2012-02-20 17:11:38 +01004712 SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_FIXUP_VOL_KNOB),
Takashi Iwaif02aab52012-02-17 16:33:56 +01004713 SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_FIXUP_W810),
Takashi Iwaiee3b2962011-11-15 14:26:54 +01004714 SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_FIXUP_MEDION_RIM),
Takashi Iwaiba533812012-02-20 16:36:52 +01004715 SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_FIXUP_F1734),
Takashi Iwaicf5a2272012-02-20 16:31:07 +01004716 SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FIXUP_FUJITSU),
Takashi Iwaiba533812012-02-20 16:36:52 +01004717 SND_PCI_QUIRK(0x1734, 0x10ac, "FSC AMILO Xi 1526", ALC880_FIXUP_F1734),
Takashi Iwaicf5a2272012-02-20 16:31:07 +01004718 SND_PCI_QUIRK(0x1734, 0x10b0, "FSC Amilo Pi1556", ALC880_FIXUP_FUJITSU),
Takashi Iwaidc6af522012-02-17 16:18:59 +01004719 SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_FIXUP_LG),
4720 SND_PCI_QUIRK(0x1854, 0x005f, "LG P1 Express", ALC880_FIXUP_LG),
4721 SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_FIXUP_LG),
Takashi Iwaib9368f52012-02-17 17:54:44 +01004722 SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_FIXUP_TCL_S700),
Takashi Iwai67b6ec32012-02-20 18:20:42 +01004723
4724 /* Below is the copied entries from alc880_quirks.c.
4725 * It's not quite sure whether BIOS sets the correct pin-config table
4726 * on these machines, thus they are kept to be compatible with
4727 * the old static quirks. Once when it's confirmed to work without
4728 * these overrides, it'd be better to remove.
4729 */
4730 SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_FIXUP_5ST_DIG),
4731 SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_FIXUP_6ST),
4732 SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_FIXUP_3ST_DIG),
4733 SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_FIXUP_6ST_DIG),
4734 SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_FIXUP_6ST_DIG),
4735 SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_FIXUP_6ST_DIG),
4736 SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_FIXUP_3ST_DIG),
4737 SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_FIXUP_3ST),
4738 SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_FIXUP_6ST_DIG),
4739 SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_FIXUP_3ST),
4740 SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_FIXUP_3ST),
4741 SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_FIXUP_5ST),
4742 SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_FIXUP_5ST),
4743 SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_FIXUP_5ST),
4744 SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_FIXUP_6ST_DIG),
4745 SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_FIXUP_6ST_DIG),
4746 SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_FIXUP_6ST_DIG),
4747 SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_FIXUP_6ST_DIG),
4748 SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_FIXUP_5ST_DIG),
4749 SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_FIXUP_5ST_DIG),
4750 SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_FIXUP_5ST_DIG),
4751 SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_FIXUP_6ST_DIG), /* broken BIOS */
4752 SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_FIXUP_6ST_DIG),
4753 SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_FIXUP_5ST_DIG),
4754 SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_FIXUP_5ST_DIG),
4755 SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_FIXUP_5ST_DIG),
4756 SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_FIXUP_3ST_DIG),
4757 SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_FIXUP_5ST_DIG),
4758 SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_FIXUP_3ST_DIG),
4759 SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_FIXUP_3ST_DIG),
4760 SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_FIXUP_5ST_DIG),
4761 SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_FIXUP_5ST_DIG),
4762 SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_FIXUP_5ST_DIG),
4763 /* default Intel */
4764 SND_PCI_QUIRK_VENDOR(0x8086, "Intel mobo", ALC880_FIXUP_3ST),
4765 SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_FIXUP_5ST_DIG),
4766 SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_FIXUP_6ST_DIG),
4767 {}
4768};
4769
4770static const struct alc_model_fixup alc880_fixup_models[] = {
4771 {.id = ALC880_FIXUP_3ST, .name = "3stack"},
4772 {.id = ALC880_FIXUP_3ST_DIG, .name = "3stack-digout"},
4773 {.id = ALC880_FIXUP_5ST, .name = "5stack"},
4774 {.id = ALC880_FIXUP_5ST_DIG, .name = "5stack-digout"},
4775 {.id = ALC880_FIXUP_6ST, .name = "6stack"},
4776 {.id = ALC880_FIXUP_6ST_DIG, .name = "6stack-digout"},
Takashi Iwaiee3b2962011-11-15 14:26:54 +01004777 {}
4778};
4779
4780
4781/*
Takashi Iwai1d045db2011-07-07 18:23:21 +02004782 * OK, here we have finally the patch for ALC880
4783 */
Takashi Iwai1d045db2011-07-07 18:23:21 +02004784static int patch_alc880(struct hda_codec *codec)
4785{
4786 struct alc_spec *spec;
Takashi Iwai1d045db2011-07-07 18:23:21 +02004787 int err;
4788
Takashi Iwai3de95172012-05-07 18:03:15 +02004789 err = alc_alloc_spec(codec, 0x0b);
4790 if (err < 0)
4791 return err;
Takashi Iwai1d045db2011-07-07 18:23:21 +02004792
Takashi Iwai3de95172012-05-07 18:03:15 +02004793 spec = codec->spec;
Takashi Iwai7b1655f2011-07-14 15:31:21 +02004794 spec->need_dac_fix = 1;
Takashi Iwai1d045db2011-07-07 18:23:21 +02004795
Takashi Iwai67b6ec32012-02-20 18:20:42 +01004796 alc_pick_fixup(codec, alc880_fixup_models, alc880_fixup_tbl,
4797 alc880_fixups);
4798 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
Takashi Iwai1d045db2011-07-07 18:23:21 +02004799
Takashi Iwai67b6ec32012-02-20 18:20:42 +01004800 /* automatic parse from the BIOS config */
4801 err = alc880_parse_auto_config(codec);
4802 if (err < 0)
4803 goto error;
Takashi Iwai1d045db2011-07-07 18:23:21 +02004804
Takashi Iwai3e6179b2011-07-08 16:55:13 +02004805 if (!spec->no_analog) {
4806 err = snd_hda_attach_beep_device(codec, 0x1);
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02004807 if (err < 0)
4808 goto error;
Takashi Iwai3e6179b2011-07-08 16:55:13 +02004809 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
4810 }
Takashi Iwai1d045db2011-07-07 18:23:21 +02004811
Takashi Iwai1d045db2011-07-07 18:23:21 +02004812 codec->patch_ops = alc_patch_ops;
David Henningsson29adc4b2012-09-25 11:31:00 +02004813 codec->patch_ops.unsol_event = alc880_unsol_event;
4814
Takashi Iwai1d045db2011-07-07 18:23:21 +02004815
Takashi Iwai589876e2012-02-20 15:47:55 +01004816 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
4817
Takashi Iwai1d045db2011-07-07 18:23:21 +02004818 return 0;
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02004819
4820 error:
4821 alc_free(codec);
4822 return err;
Takashi Iwai1d045db2011-07-07 18:23:21 +02004823}
4824
4825
4826/*
4827 * ALC260 support
4828 */
Takashi Iwai1d045db2011-07-07 18:23:21 +02004829static int alc260_parse_auto_config(struct hda_codec *codec)
4830{
Takashi Iwai1d045db2011-07-07 18:23:21 +02004831 static const hda_nid_t alc260_ignore[] = { 0x17, 0 };
Takashi Iwai3e6179b2011-07-08 16:55:13 +02004832 static const hda_nid_t alc260_ssids[] = { 0x10, 0x15, 0x0f, 0 };
4833 return alc_parse_auto_config(codec, alc260_ignore, alc260_ssids);
Takashi Iwai1d045db2011-07-07 18:23:21 +02004834}
4835
Takashi Iwai1d045db2011-07-07 18:23:21 +02004836/*
4837 * Pin config fixes
4838 */
4839enum {
Takashi Iwaica8f0422012-02-16 11:51:19 +01004840 ALC260_FIXUP_HP_DC5750,
4841 ALC260_FIXUP_HP_PIN_0F,
4842 ALC260_FIXUP_COEF,
Takashi Iwai15317ab2012-02-16 12:02:53 +01004843 ALC260_FIXUP_GPIO1,
Takashi Iwai20f7d922012-02-16 12:35:16 +01004844 ALC260_FIXUP_GPIO1_TOGGLE,
4845 ALC260_FIXUP_REPLACER,
Takashi Iwai0a1c4fa2012-02-16 12:42:30 +01004846 ALC260_FIXUP_HP_B1900,
Takashi Iwai118cb4a2012-04-19 07:33:27 +02004847 ALC260_FIXUP_KN1,
Takashi Iwai1d045db2011-07-07 18:23:21 +02004848};
4849
Takashi Iwai20f7d922012-02-16 12:35:16 +01004850static void alc260_gpio1_automute(struct hda_codec *codec)
4851{
4852 struct alc_spec *spec = codec->spec;
4853 snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
4854 spec->hp_jack_present);
4855}
4856
4857static void alc260_fixup_gpio1_toggle(struct hda_codec *codec,
4858 const struct alc_fixup *fix, int action)
4859{
4860 struct alc_spec *spec = codec->spec;
4861 if (action == ALC_FIXUP_ACT_PROBE) {
4862 /* although the machine has only one output pin, we need to
4863 * toggle GPIO1 according to the jack state
4864 */
4865 spec->automute_hook = alc260_gpio1_automute;
4866 spec->detect_hp = 1;
4867 spec->automute_speaker = 1;
4868 spec->autocfg.hp_pins[0] = 0x0f; /* copy it for automute */
David Henningsson29adc4b2012-09-25 11:31:00 +02004869 snd_hda_jack_detect_enable_callback(codec, 0x0f, ALC_HP_EVENT,
4870 alc_hp_automute);
Takashi Iwai23d30f22012-05-07 17:17:32 +02004871 snd_hda_gen_add_verbs(&spec->gen, alc_gpio1_init_verbs);
Takashi Iwai20f7d922012-02-16 12:35:16 +01004872 }
4873}
4874
Takashi Iwai118cb4a2012-04-19 07:33:27 +02004875static void alc260_fixup_kn1(struct hda_codec *codec,
4876 const struct alc_fixup *fix, int action)
4877{
4878 struct alc_spec *spec = codec->spec;
4879 static const struct alc_pincfg pincfgs[] = {
4880 { 0x0f, 0x02214000 }, /* HP/speaker */
4881 { 0x12, 0x90a60160 }, /* int mic */
4882 { 0x13, 0x02a19000 }, /* ext mic */
4883 { 0x18, 0x01446000 }, /* SPDIF out */
4884 /* disable bogus I/O pins */
4885 { 0x10, 0x411111f0 },
4886 { 0x11, 0x411111f0 },
4887 { 0x14, 0x411111f0 },
4888 { 0x15, 0x411111f0 },
4889 { 0x16, 0x411111f0 },
4890 { 0x17, 0x411111f0 },
4891 { 0x19, 0x411111f0 },
4892 { }
4893 };
4894
4895 switch (action) {
4896 case ALC_FIXUP_ACT_PRE_PROBE:
4897 alc_apply_pincfgs(codec, pincfgs);
4898 break;
4899 case ALC_FIXUP_ACT_PROBE:
4900 spec->init_amp = ALC_INIT_NONE;
4901 break;
4902 }
4903}
4904
Takashi Iwai1d045db2011-07-07 18:23:21 +02004905static const struct alc_fixup alc260_fixups[] = {
Takashi Iwaica8f0422012-02-16 11:51:19 +01004906 [ALC260_FIXUP_HP_DC5750] = {
Takashi Iwai1d045db2011-07-07 18:23:21 +02004907 .type = ALC_FIXUP_PINS,
4908 .v.pins = (const struct alc_pincfg[]) {
4909 { 0x11, 0x90130110 }, /* speaker */
4910 { }
4911 }
4912 },
Takashi Iwaica8f0422012-02-16 11:51:19 +01004913 [ALC260_FIXUP_HP_PIN_0F] = {
4914 .type = ALC_FIXUP_PINS,
4915 .v.pins = (const struct alc_pincfg[]) {
4916 { 0x0f, 0x01214000 }, /* HP */
4917 { }
4918 }
4919 },
4920 [ALC260_FIXUP_COEF] = {
4921 .type = ALC_FIXUP_VERBS,
4922 .v.verbs = (const struct hda_verb[]) {
4923 { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
4924 { 0x20, AC_VERB_SET_PROC_COEF, 0x3040 },
4925 { }
4926 },
4927 .chained = true,
4928 .chain_id = ALC260_FIXUP_HP_PIN_0F,
4929 },
Takashi Iwai15317ab2012-02-16 12:02:53 +01004930 [ALC260_FIXUP_GPIO1] = {
4931 .type = ALC_FIXUP_VERBS,
4932 .v.verbs = alc_gpio1_init_verbs,
4933 },
Takashi Iwai20f7d922012-02-16 12:35:16 +01004934 [ALC260_FIXUP_GPIO1_TOGGLE] = {
4935 .type = ALC_FIXUP_FUNC,
4936 .v.func = alc260_fixup_gpio1_toggle,
4937 .chained = true,
4938 .chain_id = ALC260_FIXUP_HP_PIN_0F,
4939 },
4940 [ALC260_FIXUP_REPLACER] = {
4941 .type = ALC_FIXUP_VERBS,
4942 .v.verbs = (const struct hda_verb[]) {
4943 { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
4944 { 0x20, AC_VERB_SET_PROC_COEF, 0x3050 },
4945 { }
4946 },
4947 .chained = true,
4948 .chain_id = ALC260_FIXUP_GPIO1_TOGGLE,
4949 },
Takashi Iwai0a1c4fa2012-02-16 12:42:30 +01004950 [ALC260_FIXUP_HP_B1900] = {
4951 .type = ALC_FIXUP_FUNC,
4952 .v.func = alc260_fixup_gpio1_toggle,
4953 .chained = true,
4954 .chain_id = ALC260_FIXUP_COEF,
Takashi Iwai118cb4a2012-04-19 07:33:27 +02004955 },
4956 [ALC260_FIXUP_KN1] = {
4957 .type = ALC_FIXUP_FUNC,
4958 .v.func = alc260_fixup_kn1,
4959 },
Takashi Iwai1d045db2011-07-07 18:23:21 +02004960};
4961
4962static const struct snd_pci_quirk alc260_fixup_tbl[] = {
Takashi Iwai15317ab2012-02-16 12:02:53 +01004963 SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_FIXUP_GPIO1),
Takashi Iwaica8f0422012-02-16 11:51:19 +01004964 SND_PCI_QUIRK(0x1025, 0x007f, "Acer Aspire 9500", ALC260_FIXUP_COEF),
Takashi Iwai15317ab2012-02-16 12:02:53 +01004965 SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_FIXUP_GPIO1),
Takashi Iwaica8f0422012-02-16 11:51:19 +01004966 SND_PCI_QUIRK(0x103c, 0x280a, "HP dc5750", ALC260_FIXUP_HP_DC5750),
Takashi Iwai0a1c4fa2012-02-16 12:42:30 +01004967 SND_PCI_QUIRK(0x103c, 0x30ba, "HP Presario B1900", ALC260_FIXUP_HP_B1900),
Takashi Iwaib1f58082012-02-16 12:45:03 +01004968 SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FIXUP_GPIO1),
Takashi Iwai118cb4a2012-04-19 07:33:27 +02004969 SND_PCI_QUIRK(0x152d, 0x0729, "Quanta KN1", ALC260_FIXUP_KN1),
Takashi Iwai20f7d922012-02-16 12:35:16 +01004970 SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_FIXUP_REPLACER),
Takashi Iwaica8f0422012-02-16 11:51:19 +01004971 SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_FIXUP_COEF),
Takashi Iwai1d045db2011-07-07 18:23:21 +02004972 {}
4973};
4974
4975/*
4976 */
Takashi Iwai1d045db2011-07-07 18:23:21 +02004977static int patch_alc260(struct hda_codec *codec)
4978{
4979 struct alc_spec *spec;
Takashi Iwaic3c2c9e2012-02-16 12:59:55 +01004980 int err;
Takashi Iwai1d045db2011-07-07 18:23:21 +02004981
Takashi Iwai3de95172012-05-07 18:03:15 +02004982 err = alc_alloc_spec(codec, 0x07);
4983 if (err < 0)
4984 return err;
Takashi Iwai1d045db2011-07-07 18:23:21 +02004985
Takashi Iwai3de95172012-05-07 18:03:15 +02004986 spec = codec->spec;
Takashi Iwai1d045db2011-07-07 18:23:21 +02004987
Takashi Iwaic3c2c9e2012-02-16 12:59:55 +01004988 alc_pick_fixup(codec, NULL, alc260_fixup_tbl, alc260_fixups);
4989 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
Takashi Iwai1d045db2011-07-07 18:23:21 +02004990
Takashi Iwaic3c2c9e2012-02-16 12:59:55 +01004991 /* automatic parse from the BIOS config */
4992 err = alc260_parse_auto_config(codec);
4993 if (err < 0)
4994 goto error;
Takashi Iwai1d045db2011-07-07 18:23:21 +02004995
Takashi Iwai3e6179b2011-07-08 16:55:13 +02004996 if (!spec->no_analog) {
4997 err = snd_hda_attach_beep_device(codec, 0x1);
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02004998 if (err < 0)
4999 goto error;
Takashi Iwai3e6179b2011-07-08 16:55:13 +02005000 set_beep_amp(spec, 0x07, 0x05, HDA_INPUT);
5001 }
Takashi Iwai1d045db2011-07-07 18:23:21 +02005002
Takashi Iwai1d045db2011-07-07 18:23:21 +02005003 codec->patch_ops = alc_patch_ops;
Takashi Iwai1d045db2011-07-07 18:23:21 +02005004 spec->shutup = alc_eapd_shutup;
Takashi Iwai1d045db2011-07-07 18:23:21 +02005005
Takashi Iwai589876e2012-02-20 15:47:55 +01005006 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
5007
Takashi Iwai1d045db2011-07-07 18:23:21 +02005008 return 0;
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02005009
5010 error:
5011 alc_free(codec);
5012 return err;
Takashi Iwai1d045db2011-07-07 18:23:21 +02005013}
5014
5015
5016/*
5017 * ALC882/883/885/888/889 support
5018 *
5019 * ALC882 is almost identical with ALC880 but has cleaner and more flexible
5020 * configuration. Each pin widget can choose any input DACs and a mixer.
5021 * Each ADC is connected from a mixer of all inputs. This makes possible
5022 * 6-channel independent captures.
5023 *
5024 * In addition, an independent DAC for the multi-playback (not used in this
5025 * driver yet).
5026 */
Takashi Iwai1d045db2011-07-07 18:23:21 +02005027
5028/*
5029 * Pin config fixes
5030 */
5031enum {
Takashi Iwai5c0ebfb2011-11-07 17:59:13 +01005032 ALC882_FIXUP_ABIT_AW9D_MAX,
5033 ALC882_FIXUP_LENOVO_Y530,
5034 ALC882_FIXUP_PB_M5210,
5035 ALC882_FIXUP_ACER_ASPIRE_7736,
5036 ALC882_FIXUP_ASUS_W90V,
Marton Balint8f239212012-03-05 21:33:23 +01005037 ALC889_FIXUP_CD,
Takashi Iwai5c0ebfb2011-11-07 17:59:13 +01005038 ALC889_FIXUP_VAIO_TT,
Takashi Iwai0e7cc2e2011-11-09 12:42:48 +01005039 ALC888_FIXUP_EEE1601,
Takashi Iwai177943a2011-11-09 12:55:18 +01005040 ALC882_FIXUP_EAPD,
Takashi Iwai7a6069b2011-11-09 15:22:01 +01005041 ALC883_FIXUP_EAPD,
Takashi Iwai8812c4f2011-11-09 17:39:15 +01005042 ALC883_FIXUP_ACER_EAPD,
Takashi Iwai1a97b7f2012-02-21 11:11:48 +01005043 ALC882_FIXUP_GPIO1,
5044 ALC882_FIXUP_GPIO2,
Takashi Iwaieb844d52011-11-09 18:03:07 +01005045 ALC882_FIXUP_GPIO3,
Takashi Iwai68ef0562011-11-09 18:24:44 +01005046 ALC889_FIXUP_COEF,
5047 ALC882_FIXUP_ASUS_W2JC,
Takashi Iwaic3e837b2011-11-10 16:01:47 +01005048 ALC882_FIXUP_ACER_ASPIRE_4930G,
5049 ALC882_FIXUP_ACER_ASPIRE_8930G,
5050 ALC882_FIXUP_ASPIRE_8930G_VERBS,
Takashi Iwai56710872011-11-14 17:42:11 +01005051 ALC885_FIXUP_MACPRO_GPIO,
Takashi Iwai02a237b2012-02-13 15:25:07 +01005052 ALC889_FIXUP_DAC_ROUTE,
Takashi Iwai1a97b7f2012-02-21 11:11:48 +01005053 ALC889_FIXUP_MBP_VREF,
5054 ALC889_FIXUP_IMAC91_VREF,
Takashi Iwai6e72aa52012-06-25 10:52:25 +02005055 ALC882_FIXUP_INV_DMIC,
Takashi Iwaie427c232012-07-29 10:04:08 +02005056 ALC882_FIXUP_NO_PRIMARY_HP,
Takashi Iwai1d045db2011-07-07 18:23:21 +02005057};
5058
Takashi Iwai68ef0562011-11-09 18:24:44 +01005059static void alc889_fixup_coef(struct hda_codec *codec,
5060 const struct alc_fixup *fix, int action)
5061{
5062 if (action != ALC_FIXUP_ACT_INIT)
5063 return;
5064 alc889_coef_init(codec);
5065}
5066
Takashi Iwai56710872011-11-14 17:42:11 +01005067/* toggle speaker-output according to the hp-jack state */
5068static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted)
5069{
5070 unsigned int gpiostate, gpiomask, gpiodir;
5071
5072 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
5073 AC_VERB_GET_GPIO_DATA, 0);
5074
5075 if (!muted)
5076 gpiostate |= (1 << pin);
5077 else
5078 gpiostate &= ~(1 << pin);
5079
5080 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
5081 AC_VERB_GET_GPIO_MASK, 0);
5082 gpiomask |= (1 << pin);
5083
5084 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
5085 AC_VERB_GET_GPIO_DIRECTION, 0);
5086 gpiodir |= (1 << pin);
5087
5088
5089 snd_hda_codec_write(codec, codec->afg, 0,
5090 AC_VERB_SET_GPIO_MASK, gpiomask);
5091 snd_hda_codec_write(codec, codec->afg, 0,
5092 AC_VERB_SET_GPIO_DIRECTION, gpiodir);
5093
5094 msleep(1);
5095
5096 snd_hda_codec_write(codec, codec->afg, 0,
5097 AC_VERB_SET_GPIO_DATA, gpiostate);
5098}
5099
5100/* set up GPIO at initialization */
5101static void alc885_fixup_macpro_gpio(struct hda_codec *codec,
5102 const struct alc_fixup *fix, int action)
5103{
5104 if (action != ALC_FIXUP_ACT_INIT)
5105 return;
5106 alc882_gpio_mute(codec, 0, 0);
5107 alc882_gpio_mute(codec, 1, 0);
5108}
5109
Takashi Iwai02a237b2012-02-13 15:25:07 +01005110/* Fix the connection of some pins for ALC889:
5111 * At least, Acer Aspire 5935 shows the connections to DAC3/4 don't
5112 * work correctly (bko#42740)
5113 */
5114static void alc889_fixup_dac_route(struct hda_codec *codec,
5115 const struct alc_fixup *fix, int action)
5116{
5117 if (action == ALC_FIXUP_ACT_PRE_PROBE) {
Takashi Iwaief8d60f2012-02-17 10:12:38 +01005118 /* fake the connections during parsing the tree */
Takashi Iwai02a237b2012-02-13 15:25:07 +01005119 hda_nid_t conn1[2] = { 0x0c, 0x0d };
5120 hda_nid_t conn2[2] = { 0x0e, 0x0f };
5121 snd_hda_override_conn_list(codec, 0x14, 2, conn1);
5122 snd_hda_override_conn_list(codec, 0x15, 2, conn1);
5123 snd_hda_override_conn_list(codec, 0x18, 2, conn2);
5124 snd_hda_override_conn_list(codec, 0x1a, 2, conn2);
Takashi Iwaief8d60f2012-02-17 10:12:38 +01005125 } else if (action == ALC_FIXUP_ACT_PROBE) {
5126 /* restore the connections */
5127 hda_nid_t conn[5] = { 0x0c, 0x0d, 0x0e, 0x0f, 0x26 };
5128 snd_hda_override_conn_list(codec, 0x14, 5, conn);
5129 snd_hda_override_conn_list(codec, 0x15, 5, conn);
5130 snd_hda_override_conn_list(codec, 0x18, 5, conn);
5131 snd_hda_override_conn_list(codec, 0x1a, 5, conn);
Takashi Iwai02a237b2012-02-13 15:25:07 +01005132 }
5133}
5134
Takashi Iwai1a97b7f2012-02-21 11:11:48 +01005135/* Set VREF on HP pin */
5136static void alc889_fixup_mbp_vref(struct hda_codec *codec,
5137 const struct alc_fixup *fix, int action)
5138{
5139 struct alc_spec *spec = codec->spec;
5140 static hda_nid_t nids[2] = { 0x14, 0x15 };
5141 int i;
5142
5143 if (action != ALC_FIXUP_ACT_INIT)
5144 return;
5145 for (i = 0; i < ARRAY_SIZE(nids); i++) {
5146 unsigned int val = snd_hda_codec_get_pincfg(codec, nids[i]);
5147 if (get_defcfg_device(val) != AC_JACK_HP_OUT)
5148 continue;
5149 val = snd_hda_codec_read(codec, nids[i], 0,
5150 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
5151 val |= AC_PINCTL_VREF_80;
Takashi Iwaicdd03ce2012-04-20 12:34:50 +02005152 snd_hda_set_pin_ctl(codec, nids[i], val);
Takashi Iwai1a97b7f2012-02-21 11:11:48 +01005153 spec->keep_vref_in_automute = 1;
5154 break;
5155 }
5156}
5157
5158/* Set VREF on speaker pins on imac91 */
5159static void alc889_fixup_imac91_vref(struct hda_codec *codec,
5160 const struct alc_fixup *fix, int action)
5161{
5162 struct alc_spec *spec = codec->spec;
5163 static hda_nid_t nids[2] = { 0x18, 0x1a };
5164 int i;
5165
5166 if (action != ALC_FIXUP_ACT_INIT)
5167 return;
5168 for (i = 0; i < ARRAY_SIZE(nids); i++) {
5169 unsigned int val;
5170 val = snd_hda_codec_read(codec, nids[i], 0,
5171 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
5172 val |= AC_PINCTL_VREF_50;
Takashi Iwaicdd03ce2012-04-20 12:34:50 +02005173 snd_hda_set_pin_ctl(codec, nids[i], val);
Takashi Iwai1a97b7f2012-02-21 11:11:48 +01005174 }
5175 spec->keep_vref_in_automute = 1;
5176}
5177
Takashi Iwaie427c232012-07-29 10:04:08 +02005178/* Don't take HP output as primary
5179 * strangely, the speaker output doesn't work on VAIO Z through DAC 0x05
5180 */
5181static void alc882_fixup_no_primary_hp(struct hda_codec *codec,
5182 const struct alc_fixup *fix, int action)
5183{
5184 struct alc_spec *spec = codec->spec;
5185 if (action == ALC_FIXUP_ACT_PRE_PROBE)
5186 spec->no_primary_hp = 1;
5187}
5188
Takashi Iwai1d045db2011-07-07 18:23:21 +02005189static const struct alc_fixup alc882_fixups[] = {
Takashi Iwai5c0ebfb2011-11-07 17:59:13 +01005190 [ALC882_FIXUP_ABIT_AW9D_MAX] = {
Takashi Iwai1d045db2011-07-07 18:23:21 +02005191 .type = ALC_FIXUP_PINS,
5192 .v.pins = (const struct alc_pincfg[]) {
5193 { 0x15, 0x01080104 }, /* side */
5194 { 0x16, 0x01011012 }, /* rear */
5195 { 0x17, 0x01016011 }, /* clfe */
5196 { }
5197 }
5198 },
Takashi Iwai5c0ebfb2011-11-07 17:59:13 +01005199 [ALC882_FIXUP_LENOVO_Y530] = {
Takashi Iwai1d045db2011-07-07 18:23:21 +02005200 .type = ALC_FIXUP_PINS,
5201 .v.pins = (const struct alc_pincfg[]) {
5202 { 0x15, 0x99130112 }, /* rear int speakers */
5203 { 0x16, 0x99130111 }, /* subwoofer */
5204 { }
5205 }
5206 },
Takashi Iwai5c0ebfb2011-11-07 17:59:13 +01005207 [ALC882_FIXUP_PB_M5210] = {
Takashi Iwai1d045db2011-07-07 18:23:21 +02005208 .type = ALC_FIXUP_VERBS,
5209 .v.verbs = (const struct hda_verb[]) {
5210 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 },
5211 {}
5212 }
5213 },
Takashi Iwai5c0ebfb2011-11-07 17:59:13 +01005214 [ALC882_FIXUP_ACER_ASPIRE_7736] = {
Takashi Iwai23d30f22012-05-07 17:17:32 +02005215 .type = ALC_FIXUP_FUNC,
5216 .v.func = alc_fixup_sku_ignore,
Takashi Iwai1d045db2011-07-07 18:23:21 +02005217 },
Takashi Iwai5c0ebfb2011-11-07 17:59:13 +01005218 [ALC882_FIXUP_ASUS_W90V] = {
Takashi Iwai5cdf7452011-10-26 23:04:08 +02005219 .type = ALC_FIXUP_PINS,
5220 .v.pins = (const struct alc_pincfg[]) {
5221 { 0x16, 0x99130110 }, /* fix sequence for CLFE */
5222 { }
5223 }
5224 },
Marton Balint8f239212012-03-05 21:33:23 +01005225 [ALC889_FIXUP_CD] = {
5226 .type = ALC_FIXUP_PINS,
5227 .v.pins = (const struct alc_pincfg[]) {
5228 { 0x1c, 0x993301f0 }, /* CD */
5229 { }
5230 }
5231 },
Takashi Iwai5c0ebfb2011-11-07 17:59:13 +01005232 [ALC889_FIXUP_VAIO_TT] = {
5233 .type = ALC_FIXUP_PINS,
5234 .v.pins = (const struct alc_pincfg[]) {
5235 { 0x17, 0x90170111 }, /* hidden surround speaker */
5236 { }
5237 }
5238 },
Takashi Iwai0e7cc2e2011-11-09 12:42:48 +01005239 [ALC888_FIXUP_EEE1601] = {
5240 .type = ALC_FIXUP_VERBS,
5241 .v.verbs = (const struct hda_verb[]) {
5242 { 0x20, AC_VERB_SET_COEF_INDEX, 0x0b },
5243 { 0x20, AC_VERB_SET_PROC_COEF, 0x0838 },
5244 { }
5245 }
Takashi Iwai177943a2011-11-09 12:55:18 +01005246 },
5247 [ALC882_FIXUP_EAPD] = {
5248 .type = ALC_FIXUP_VERBS,
5249 .v.verbs = (const struct hda_verb[]) {
5250 /* change to EAPD mode */
5251 { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
5252 { 0x20, AC_VERB_SET_PROC_COEF, 0x3060 },
5253 { }
5254 }
5255 },
Takashi Iwai7a6069b2011-11-09 15:22:01 +01005256 [ALC883_FIXUP_EAPD] = {
5257 .type = ALC_FIXUP_VERBS,
5258 .v.verbs = (const struct hda_verb[]) {
5259 /* change to EAPD mode */
5260 { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
5261 { 0x20, AC_VERB_SET_PROC_COEF, 0x3070 },
5262 { }
5263 }
5264 },
Takashi Iwai8812c4f2011-11-09 17:39:15 +01005265 [ALC883_FIXUP_ACER_EAPD] = {
5266 .type = ALC_FIXUP_VERBS,
5267 .v.verbs = (const struct hda_verb[]) {
5268 /* eanable EAPD on Acer laptops */
5269 { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
5270 { 0x20, AC_VERB_SET_PROC_COEF, 0x3050 },
5271 { }
5272 }
5273 },
Takashi Iwai1a97b7f2012-02-21 11:11:48 +01005274 [ALC882_FIXUP_GPIO1] = {
5275 .type = ALC_FIXUP_VERBS,
5276 .v.verbs = alc_gpio1_init_verbs,
5277 },
5278 [ALC882_FIXUP_GPIO2] = {
5279 .type = ALC_FIXUP_VERBS,
5280 .v.verbs = alc_gpio2_init_verbs,
5281 },
Takashi Iwaieb844d52011-11-09 18:03:07 +01005282 [ALC882_FIXUP_GPIO3] = {
5283 .type = ALC_FIXUP_VERBS,
5284 .v.verbs = alc_gpio3_init_verbs,
5285 },
Takashi Iwai68ef0562011-11-09 18:24:44 +01005286 [ALC882_FIXUP_ASUS_W2JC] = {
5287 .type = ALC_FIXUP_VERBS,
5288 .v.verbs = alc_gpio1_init_verbs,
5289 .chained = true,
5290 .chain_id = ALC882_FIXUP_EAPD,
5291 },
5292 [ALC889_FIXUP_COEF] = {
5293 .type = ALC_FIXUP_FUNC,
5294 .v.func = alc889_fixup_coef,
5295 },
Takashi Iwaic3e837b2011-11-10 16:01:47 +01005296 [ALC882_FIXUP_ACER_ASPIRE_4930G] = {
5297 .type = ALC_FIXUP_PINS,
5298 .v.pins = (const struct alc_pincfg[]) {
5299 { 0x16, 0x99130111 }, /* CLFE speaker */
5300 { 0x17, 0x99130112 }, /* surround speaker */
5301 { }
Takashi Iwai038d4fe2012-04-11 17:18:12 +02005302 },
5303 .chained = true,
5304 .chain_id = ALC882_FIXUP_GPIO1,
Takashi Iwaic3e837b2011-11-10 16:01:47 +01005305 },
5306 [ALC882_FIXUP_ACER_ASPIRE_8930G] = {
5307 .type = ALC_FIXUP_PINS,
5308 .v.pins = (const struct alc_pincfg[]) {
5309 { 0x16, 0x99130111 }, /* CLFE speaker */
5310 { 0x1b, 0x99130112 }, /* surround speaker */
5311 { }
5312 },
5313 .chained = true,
5314 .chain_id = ALC882_FIXUP_ASPIRE_8930G_VERBS,
5315 },
5316 [ALC882_FIXUP_ASPIRE_8930G_VERBS] = {
5317 /* additional init verbs for Acer Aspire 8930G */
5318 .type = ALC_FIXUP_VERBS,
5319 .v.verbs = (const struct hda_verb[]) {
5320 /* Enable all DACs */
5321 /* DAC DISABLE/MUTE 1? */
5322 /* setting bits 1-5 disables DAC nids 0x02-0x06
5323 * apparently. Init=0x38 */
5324 { 0x20, AC_VERB_SET_COEF_INDEX, 0x03 },
5325 { 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
5326 /* DAC DISABLE/MUTE 2? */
5327 /* some bit here disables the other DACs.
5328 * Init=0x4900 */
5329 { 0x20, AC_VERB_SET_COEF_INDEX, 0x08 },
5330 { 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
5331 /* DMIC fix
5332 * This laptop has a stereo digital microphone.
5333 * The mics are only 1cm apart which makes the stereo
5334 * useless. However, either the mic or the ALC889
5335 * makes the signal become a difference/sum signal
5336 * instead of standard stereo, which is annoying.
5337 * So instead we flip this bit which makes the
5338 * codec replicate the sum signal to both channels,
5339 * turning it into a normal mono mic.
5340 */
5341 /* DMIC_CONTROL? Init value = 0x0001 */
5342 { 0x20, AC_VERB_SET_COEF_INDEX, 0x0b },
5343 { 0x20, AC_VERB_SET_PROC_COEF, 0x0003 },
5344 { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
5345 { 0x20, AC_VERB_SET_PROC_COEF, 0x3050 },
5346 { }
Takashi Iwai038d4fe2012-04-11 17:18:12 +02005347 },
5348 .chained = true,
5349 .chain_id = ALC882_FIXUP_GPIO1,
Takashi Iwaic3e837b2011-11-10 16:01:47 +01005350 },
Takashi Iwai56710872011-11-14 17:42:11 +01005351 [ALC885_FIXUP_MACPRO_GPIO] = {
5352 .type = ALC_FIXUP_FUNC,
5353 .v.func = alc885_fixup_macpro_gpio,
5354 },
Takashi Iwai02a237b2012-02-13 15:25:07 +01005355 [ALC889_FIXUP_DAC_ROUTE] = {
5356 .type = ALC_FIXUP_FUNC,
5357 .v.func = alc889_fixup_dac_route,
5358 },
Takashi Iwai1a97b7f2012-02-21 11:11:48 +01005359 [ALC889_FIXUP_MBP_VREF] = {
5360 .type = ALC_FIXUP_FUNC,
5361 .v.func = alc889_fixup_mbp_vref,
5362 .chained = true,
5363 .chain_id = ALC882_FIXUP_GPIO1,
5364 },
5365 [ALC889_FIXUP_IMAC91_VREF] = {
5366 .type = ALC_FIXUP_FUNC,
5367 .v.func = alc889_fixup_imac91_vref,
5368 .chained = true,
5369 .chain_id = ALC882_FIXUP_GPIO1,
5370 },
Takashi Iwai6e72aa52012-06-25 10:52:25 +02005371 [ALC882_FIXUP_INV_DMIC] = {
5372 .type = ALC_FIXUP_FUNC,
5373 .v.func = alc_fixup_inv_dmic_0x12,
5374 },
Takashi Iwaie427c232012-07-29 10:04:08 +02005375 [ALC882_FIXUP_NO_PRIMARY_HP] = {
5376 .type = ALC_FIXUP_FUNC,
5377 .v.func = alc882_fixup_no_primary_hp,
5378 },
Takashi Iwai1d045db2011-07-07 18:23:21 +02005379};
5380
5381static const struct snd_pci_quirk alc882_fixup_tbl[] = {
Takashi Iwai8812c4f2011-11-09 17:39:15 +01005382 SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_FIXUP_ACER_EAPD),
5383 SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_FIXUP_ACER_EAPD),
5384 SND_PCI_QUIRK(0x1025, 0x010a, "Acer Ferrari 5000", ALC883_FIXUP_ACER_EAPD),
5385 SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_FIXUP_ACER_EAPD),
5386 SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_FIXUP_ACER_EAPD),
5387 SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_FIXUP_ACER_EAPD),
Takashi Iwaic3e837b2011-11-10 16:01:47 +01005388 SND_PCI_QUIRK(0x1025, 0x013e, "Acer Aspire 4930G",
5389 ALC882_FIXUP_ACER_ASPIRE_4930G),
5390 SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G",
5391 ALC882_FIXUP_ACER_ASPIRE_4930G),
5392 SND_PCI_QUIRK(0x1025, 0x0145, "Acer Aspire 8930G",
5393 ALC882_FIXUP_ACER_ASPIRE_8930G),
5394 SND_PCI_QUIRK(0x1025, 0x0146, "Acer Aspire 6935G",
5395 ALC882_FIXUP_ACER_ASPIRE_8930G),
5396 SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G",
5397 ALC882_FIXUP_ACER_ASPIRE_4930G),
5398 SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G",
5399 ALC882_FIXUP_ACER_ASPIRE_4930G),
5400 SND_PCI_QUIRK(0x1025, 0x0142, "Acer Aspire 7730G",
5401 ALC882_FIXUP_ACER_ASPIRE_4930G),
Takashi Iwai5c0ebfb2011-11-07 17:59:13 +01005402 SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", ALC882_FIXUP_PB_M5210),
Takashi Iwaif5c53d82012-05-07 10:07:33 +02005403 SND_PCI_QUIRK(0x1025, 0x021e, "Acer Aspire 5739G",
5404 ALC882_FIXUP_ACER_ASPIRE_4930G),
Takashi Iwai02a237b2012-02-13 15:25:07 +01005405 SND_PCI_QUIRK(0x1025, 0x0259, "Acer Aspire 5935", ALC889_FIXUP_DAC_ROUTE),
Takashi Iwaife97da12012-04-12 08:00:19 +02005406 SND_PCI_QUIRK(0x1025, 0x026b, "Acer Aspire 8940G", ALC882_FIXUP_ACER_ASPIRE_8930G),
Takashi Iwaiac9b1cd2011-11-09 17:45:55 +01005407 SND_PCI_QUIRK(0x1025, 0x0296, "Acer Aspire 7736z", ALC882_FIXUP_ACER_ASPIRE_7736),
Takashi Iwai177943a2011-11-09 12:55:18 +01005408 SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_FIXUP_EAPD),
Takashi Iwai5c0ebfb2011-11-07 17:59:13 +01005409 SND_PCI_QUIRK(0x1043, 0x1873, "ASUS W90V", ALC882_FIXUP_ASUS_W90V),
Takashi Iwai68ef0562011-11-09 18:24:44 +01005410 SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_FIXUP_ASUS_W2JC),
Takashi Iwai0e7cc2e2011-11-09 12:42:48 +01005411 SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_FIXUP_EEE1601),
Takashi Iwaiac9b1cd2011-11-09 17:45:55 +01005412 SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC889_FIXUP_VAIO_TT),
Takashi Iwaie427c232012-07-29 10:04:08 +02005413 SND_PCI_QUIRK(0x104d, 0x905a, "Sony Vaio Z", ALC882_FIXUP_NO_PRIMARY_HP),
Takashi Iwai56710872011-11-14 17:42:11 +01005414
5415 /* All Apple entries are in codec SSIDs */
Takashi Iwai1a97b7f2012-02-21 11:11:48 +01005416 SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC889_FIXUP_MBP_VREF),
5417 SND_PCI_QUIRK(0x106b, 0x00a1, "Macbook", ALC889_FIXUP_MBP_VREF),
5418 SND_PCI_QUIRK(0x106b, 0x00a4, "MacbookPro 4,1", ALC889_FIXUP_MBP_VREF),
Takashi Iwai56710872011-11-14 17:42:11 +01005419 SND_PCI_QUIRK(0x106b, 0x0c00, "Mac Pro", ALC885_FIXUP_MACPRO_GPIO),
5420 SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_FIXUP_MACPRO_GPIO),
5421 SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_FIXUP_MACPRO_GPIO),
Takashi Iwai1a97b7f2012-02-21 11:11:48 +01005422 SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC889_FIXUP_MBP_VREF),
5423 SND_PCI_QUIRK(0x106b, 0x3000, "iMac", ALC889_FIXUP_MBP_VREF),
Takashi Iwai56710872011-11-14 17:42:11 +01005424 SND_PCI_QUIRK(0x106b, 0x3200, "iMac 7,1 Aluminum", ALC882_FIXUP_EAPD),
Takashi Iwai1a97b7f2012-02-21 11:11:48 +01005425 SND_PCI_QUIRK(0x106b, 0x3400, "MacBookAir 1,1", ALC889_FIXUP_MBP_VREF),
5426 SND_PCI_QUIRK(0x106b, 0x3500, "MacBookAir 2,1", ALC889_FIXUP_MBP_VREF),
5427 SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889_FIXUP_MBP_VREF),
5428 SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC889_FIXUP_MBP_VREF),
Takashi Iwai56710872011-11-14 17:42:11 +01005429 SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_FIXUP_MACPRO_GPIO),
Takashi Iwai1a97b7f2012-02-21 11:11:48 +01005430 SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC889_FIXUP_IMAC91_VREF),
5431 SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC889_FIXUP_IMAC91_VREF),
5432 SND_PCI_QUIRK(0x106b, 0x4100, "Macmini 3,1", ALC889_FIXUP_IMAC91_VREF),
Josh Boyer29ebe402012-04-12 13:55:36 -04005433 SND_PCI_QUIRK(0x106b, 0x4200, "Mac Pro 5,1", ALC885_FIXUP_MACPRO_GPIO),
Takashi Iwai05193632012-11-12 10:07:36 +01005434 SND_PCI_QUIRK(0x106b, 0x4300, "iMac 9,1", ALC889_FIXUP_IMAC91_VREF),
Takashi Iwai1a97b7f2012-02-21 11:11:48 +01005435 SND_PCI_QUIRK(0x106b, 0x4600, "MacbookPro 5,2", ALC889_FIXUP_IMAC91_VREF),
5436 SND_PCI_QUIRK(0x106b, 0x4900, "iMac 9,1 Aluminum", ALC889_FIXUP_IMAC91_VREF),
5437 SND_PCI_QUIRK(0x106b, 0x4a00, "Macbook 5,2", ALC889_FIXUP_IMAC91_VREF),
Takashi Iwai56710872011-11-14 17:42:11 +01005438
Takashi Iwai7a6069b2011-11-09 15:22:01 +01005439 SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC882_FIXUP_EAPD),
Takashi Iwaibca40132012-05-07 11:13:14 +02005440 SND_PCI_QUIRK(0x1462, 0x7350, "MSI-7350", ALC889_FIXUP_CD),
Takashi Iwaieb844d52011-11-09 18:03:07 +01005441 SND_PCI_QUIRK_VENDOR(0x1462, "MSI", ALC882_FIXUP_GPIO3),
Marton Balint8f239212012-03-05 21:33:23 +01005442 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte EP45-DS3", ALC889_FIXUP_CD),
Takashi Iwai5c0ebfb2011-11-07 17:59:13 +01005443 SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", ALC882_FIXUP_ABIT_AW9D_MAX),
Takashi Iwai7a6069b2011-11-09 15:22:01 +01005444 SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC882_FIXUP_EAPD),
5445 SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_FIXUP_EAPD),
Takashi Iwaiac9b1cd2011-11-09 17:45:55 +01005446 SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Y530", ALC882_FIXUP_LENOVO_Y530),
Takashi Iwai68ef0562011-11-09 18:24:44 +01005447 SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC889_FIXUP_COEF),
Takashi Iwai1d045db2011-07-07 18:23:21 +02005448 {}
5449};
5450
Takashi Iwai912093b2012-04-11 14:03:41 +02005451static const struct alc_model_fixup alc882_fixup_models[] = {
5452 {.id = ALC882_FIXUP_ACER_ASPIRE_4930G, .name = "acer-aspire-4930g"},
5453 {.id = ALC882_FIXUP_ACER_ASPIRE_8930G, .name = "acer-aspire-8930g"},
5454 {.id = ALC883_FIXUP_ACER_EAPD, .name = "acer-aspire"},
Takashi Iwai6e72aa52012-06-25 10:52:25 +02005455 {.id = ALC882_FIXUP_INV_DMIC, .name = "inv-dmic"},
Takashi Iwaie427c232012-07-29 10:04:08 +02005456 {.id = ALC882_FIXUP_NO_PRIMARY_HP, .name = "no-primary-hp"},
Takashi Iwai912093b2012-04-11 14:03:41 +02005457 {}
5458};
5459
Takashi Iwai1d045db2011-07-07 18:23:21 +02005460/*
5461 * BIOS auto configuration
5462 */
5463/* almost identical with ALC880 parser... */
5464static int alc882_parse_auto_config(struct hda_codec *codec)
5465{
Takashi Iwai1d045db2011-07-07 18:23:21 +02005466 static const hda_nid_t alc882_ignore[] = { 0x1d, 0 };
Takashi Iwai3e6179b2011-07-08 16:55:13 +02005467 static const hda_nid_t alc882_ssids[] = { 0x15, 0x1b, 0x14, 0 };
5468 return alc_parse_auto_config(codec, alc882_ignore, alc882_ssids);
Takashi Iwai1d045db2011-07-07 18:23:21 +02005469}
5470
Takashi Iwai1d045db2011-07-07 18:23:21 +02005471/*
5472 */
Takashi Iwai1d045db2011-07-07 18:23:21 +02005473static int patch_alc882(struct hda_codec *codec)
5474{
5475 struct alc_spec *spec;
Takashi Iwai1a97b7f2012-02-21 11:11:48 +01005476 int err;
Takashi Iwai1d045db2011-07-07 18:23:21 +02005477
Takashi Iwai3de95172012-05-07 18:03:15 +02005478 err = alc_alloc_spec(codec, 0x0b);
5479 if (err < 0)
5480 return err;
Takashi Iwai1d045db2011-07-07 18:23:21 +02005481
Takashi Iwai3de95172012-05-07 18:03:15 +02005482 spec = codec->spec;
Takashi Iwai1d045db2011-07-07 18:23:21 +02005483
5484 switch (codec->vendor_id) {
5485 case 0x10ec0882:
5486 case 0x10ec0885:
5487 break;
5488 default:
5489 /* ALC883 and variants */
5490 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
5491 break;
5492 }
5493
Takashi Iwai912093b2012-04-11 14:03:41 +02005494 alc_pick_fixup(codec, alc882_fixup_models, alc882_fixup_tbl,
5495 alc882_fixups);
Takashi Iwai1a97b7f2012-02-21 11:11:48 +01005496 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
Takashi Iwai1d045db2011-07-07 18:23:21 +02005497
5498 alc_auto_parse_customize_define(codec);
5499
Takashi Iwai1a97b7f2012-02-21 11:11:48 +01005500 /* automatic parse from the BIOS config */
5501 err = alc882_parse_auto_config(codec);
5502 if (err < 0)
5503 goto error;
Takashi Iwai1d045db2011-07-07 18:23:21 +02005504
Takashi Iwai3e6179b2011-07-08 16:55:13 +02005505 if (!spec->no_analog && has_cdefine_beep(codec)) {
5506 err = snd_hda_attach_beep_device(codec, 0x1);
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02005507 if (err < 0)
5508 goto error;
Takashi Iwai1d045db2011-07-07 18:23:21 +02005509 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Takashi Iwai3e6179b2011-07-08 16:55:13 +02005510 }
Takashi Iwai1d045db2011-07-07 18:23:21 +02005511
Takashi Iwai1d045db2011-07-07 18:23:21 +02005512 codec->patch_ops = alc_patch_ops;
Takashi Iwai1d045db2011-07-07 18:23:21 +02005513
Takashi Iwai589876e2012-02-20 15:47:55 +01005514 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
5515
Takashi Iwai1d045db2011-07-07 18:23:21 +02005516 return 0;
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02005517
5518 error:
5519 alc_free(codec);
5520 return err;
Takashi Iwai1d045db2011-07-07 18:23:21 +02005521}
5522
5523
5524/*
5525 * ALC262 support
5526 */
Takashi Iwai1d045db2011-07-07 18:23:21 +02005527static int alc262_parse_auto_config(struct hda_codec *codec)
5528{
Takashi Iwai1d045db2011-07-07 18:23:21 +02005529 static const hda_nid_t alc262_ignore[] = { 0x1d, 0 };
Takashi Iwai3e6179b2011-07-08 16:55:13 +02005530 static const hda_nid_t alc262_ssids[] = { 0x15, 0x1b, 0x14, 0 };
5531 return alc_parse_auto_config(codec, alc262_ignore, alc262_ssids);
Takashi Iwai1d045db2011-07-07 18:23:21 +02005532}
5533
5534/*
5535 * Pin config fixes
5536 */
5537enum {
Takashi Iwaiea4e7af2011-11-07 12:23:55 +01005538 ALC262_FIXUP_FSC_H270,
5539 ALC262_FIXUP_HP_Z200,
5540 ALC262_FIXUP_TYAN,
Takashi Iwaic4701502011-11-07 14:20:07 +01005541 ALC262_FIXUP_LENOVO_3000,
Takashi Iwaib42590b2011-11-07 14:41:01 +01005542 ALC262_FIXUP_BENQ,
5543 ALC262_FIXUP_BENQ_T31,
Takashi Iwai6e72aa52012-06-25 10:52:25 +02005544 ALC262_FIXUP_INV_DMIC,
Takashi Iwai1d045db2011-07-07 18:23:21 +02005545};
5546
5547static const struct alc_fixup alc262_fixups[] = {
Takashi Iwaiea4e7af2011-11-07 12:23:55 +01005548 [ALC262_FIXUP_FSC_H270] = {
Takashi Iwai1d045db2011-07-07 18:23:21 +02005549 .type = ALC_FIXUP_PINS,
5550 .v.pins = (const struct alc_pincfg[]) {
5551 { 0x14, 0x99130110 }, /* speaker */
5552 { 0x15, 0x0221142f }, /* front HP */
5553 { 0x1b, 0x0121141f }, /* rear HP */
5554 { }
5555 }
5556 },
Takashi Iwaiea4e7af2011-11-07 12:23:55 +01005557 [ALC262_FIXUP_HP_Z200] = {
Takashi Iwai1d045db2011-07-07 18:23:21 +02005558 .type = ALC_FIXUP_PINS,
5559 .v.pins = (const struct alc_pincfg[]) {
5560 { 0x16, 0x99130120 }, /* internal speaker */
5561 { }
5562 }
5563 },
Takashi Iwaiea4e7af2011-11-07 12:23:55 +01005564 [ALC262_FIXUP_TYAN] = {
5565 .type = ALC_FIXUP_PINS,
5566 .v.pins = (const struct alc_pincfg[]) {
5567 { 0x14, 0x1993e1f0 }, /* int AUX */
5568 { }
5569 }
5570 },
Takashi Iwaic4701502011-11-07 14:20:07 +01005571 [ALC262_FIXUP_LENOVO_3000] = {
5572 .type = ALC_FIXUP_VERBS,
5573 .v.verbs = (const struct hda_verb[]) {
5574 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 },
Takashi Iwaib42590b2011-11-07 14:41:01 +01005575 {}
5576 },
5577 .chained = true,
5578 .chain_id = ALC262_FIXUP_BENQ,
5579 },
5580 [ALC262_FIXUP_BENQ] = {
5581 .type = ALC_FIXUP_VERBS,
5582 .v.verbs = (const struct hda_verb[]) {
Takashi Iwaic4701502011-11-07 14:20:07 +01005583 { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
5584 { 0x20, AC_VERB_SET_PROC_COEF, 0x3070 },
5585 {}
5586 }
5587 },
Takashi Iwaib42590b2011-11-07 14:41:01 +01005588 [ALC262_FIXUP_BENQ_T31] = {
5589 .type = ALC_FIXUP_VERBS,
5590 .v.verbs = (const struct hda_verb[]) {
5591 { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
5592 { 0x20, AC_VERB_SET_PROC_COEF, 0x3050 },
5593 {}
5594 }
5595 },
Takashi Iwai6e72aa52012-06-25 10:52:25 +02005596 [ALC262_FIXUP_INV_DMIC] = {
5597 .type = ALC_FIXUP_FUNC,
5598 .v.func = alc_fixup_inv_dmic_0x12,
5599 },
Takashi Iwai1d045db2011-07-07 18:23:21 +02005600};
5601
5602static const struct snd_pci_quirk alc262_fixup_tbl[] = {
Takashi Iwaiea4e7af2011-11-07 12:23:55 +01005603 SND_PCI_QUIRK(0x103c, 0x170b, "HP Z200", ALC262_FIXUP_HP_Z200),
Takashi Iwai3dcd3be2011-11-07 14:59:40 +01005604 SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FIXUP_BENQ),
5605 SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FIXUP_BENQ),
Takashi Iwaiea4e7af2011-11-07 12:23:55 +01005606 SND_PCI_QUIRK(0x10f1, 0x2915, "Tyan Thunder n6650W", ALC262_FIXUP_TYAN),
5607 SND_PCI_QUIRK(0x1734, 0x1147, "FSC Celsius H270", ALC262_FIXUP_FSC_H270),
Takashi Iwaic4701502011-11-07 14:20:07 +01005608 SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000", ALC262_FIXUP_LENOVO_3000),
Takashi Iwaib42590b2011-11-07 14:41:01 +01005609 SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_FIXUP_BENQ),
5610 SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_FIXUP_BENQ_T31),
Takashi Iwai1d045db2011-07-07 18:23:21 +02005611 {}
5612};
5613
Takashi Iwai6e72aa52012-06-25 10:52:25 +02005614static const struct alc_model_fixup alc262_fixup_models[] = {
5615 {.id = ALC262_FIXUP_INV_DMIC, .name = "inv-dmic"},
5616 {}
5617};
Takashi Iwai1d045db2011-07-07 18:23:21 +02005618
Takashi Iwai1d045db2011-07-07 18:23:21 +02005619/*
5620 */
Takashi Iwai1d045db2011-07-07 18:23:21 +02005621static int patch_alc262(struct hda_codec *codec)
5622{
5623 struct alc_spec *spec;
Takashi Iwai1d045db2011-07-07 18:23:21 +02005624 int err;
5625
Takashi Iwai3de95172012-05-07 18:03:15 +02005626 err = alc_alloc_spec(codec, 0x0b);
5627 if (err < 0)
5628 return err;
Takashi Iwai1d045db2011-07-07 18:23:21 +02005629
Takashi Iwai3de95172012-05-07 18:03:15 +02005630 spec = codec->spec;
Takashi Iwai37c04202012-12-18 14:22:45 +01005631 spec->shared_mic_vref_pin = 0x18;
Takashi Iwai1d045db2011-07-07 18:23:21 +02005632
5633#if 0
5634 /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is
5635 * under-run
5636 */
5637 {
5638 int tmp;
5639 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
5640 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
5641 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
5642 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80);
5643 }
5644#endif
Takashi Iwai1d045db2011-07-07 18:23:21 +02005645 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
5646
Takashi Iwai6e72aa52012-06-25 10:52:25 +02005647 alc_pick_fixup(codec, alc262_fixup_models, alc262_fixup_tbl,
5648 alc262_fixups);
Takashi Iwai42399f72011-11-07 17:18:44 +01005649 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
Takashi Iwai1d045db2011-07-07 18:23:21 +02005650
Takashi Iwaiaf741c12012-05-07 18:09:48 +02005651 alc_auto_parse_customize_define(codec);
5652
Takashi Iwai42399f72011-11-07 17:18:44 +01005653 /* automatic parse from the BIOS config */
5654 err = alc262_parse_auto_config(codec);
5655 if (err < 0)
5656 goto error;
Takashi Iwai3e6179b2011-07-08 16:55:13 +02005657
Takashi Iwai1d045db2011-07-07 18:23:21 +02005658 if (!spec->no_analog && has_cdefine_beep(codec)) {
5659 err = snd_hda_attach_beep_device(codec, 0x1);
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02005660 if (err < 0)
5661 goto error;
Takashi Iwai1d045db2011-07-07 18:23:21 +02005662 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Takashi Iwai3e6179b2011-07-08 16:55:13 +02005663 }
Takashi Iwai1d045db2011-07-07 18:23:21 +02005664
Takashi Iwai1d045db2011-07-07 18:23:21 +02005665 codec->patch_ops = alc_patch_ops;
Takashi Iwai1d045db2011-07-07 18:23:21 +02005666 spec->shutup = alc_eapd_shutup;
5667
Takashi Iwai589876e2012-02-20 15:47:55 +01005668 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
5669
Takashi Iwai1d045db2011-07-07 18:23:21 +02005670 return 0;
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02005671
5672 error:
5673 alc_free(codec);
5674 return err;
Takashi Iwai1d045db2011-07-07 18:23:21 +02005675}
5676
5677/*
5678 * ALC268
5679 */
Takashi Iwai1d045db2011-07-07 18:23:21 +02005680/* bind Beep switches of both NID 0x0f and 0x10 */
5681static const struct hda_bind_ctls alc268_bind_beep_sw = {
5682 .ops = &snd_hda_bind_sw,
5683 .values = {
5684 HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT),
5685 HDA_COMPOSE_AMP_VAL(0x10, 3, 1, HDA_INPUT),
5686 0
5687 },
5688};
5689
5690static const struct snd_kcontrol_new alc268_beep_mixer[] = {
5691 HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT),
5692 HDA_BIND_SW("Beep Playback Switch", &alc268_bind_beep_sw),
5693 { }
5694};
5695
5696/* set PCBEEP vol = 0, mute connections */
5697static const struct hda_verb alc268_beep_init_verbs[] = {
5698 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5699 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5700 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5701 { }
5702};
5703
Takashi Iwai6e72aa52012-06-25 10:52:25 +02005704enum {
5705 ALC268_FIXUP_INV_DMIC,
Takashi Iwaicb766402012-10-20 10:55:21 +02005706 ALC268_FIXUP_HP_EAPD,
Takashi Iwai6e72aa52012-06-25 10:52:25 +02005707};
5708
5709static const struct alc_fixup alc268_fixups[] = {
5710 [ALC268_FIXUP_INV_DMIC] = {
5711 .type = ALC_FIXUP_FUNC,
5712 .v.func = alc_fixup_inv_dmic_0x12,
5713 },
Takashi Iwaicb766402012-10-20 10:55:21 +02005714 [ALC268_FIXUP_HP_EAPD] = {
5715 .type = ALC_FIXUP_VERBS,
5716 .v.verbs = (const struct hda_verb[]) {
5717 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 0},
5718 {}
5719 }
5720 },
Takashi Iwai6e72aa52012-06-25 10:52:25 +02005721};
5722
5723static const struct alc_model_fixup alc268_fixup_models[] = {
5724 {.id = ALC268_FIXUP_INV_DMIC, .name = "inv-dmic"},
Takashi Iwaicb766402012-10-20 10:55:21 +02005725 {.id = ALC268_FIXUP_HP_EAPD, .name = "hp-eapd"},
5726 {}
5727};
5728
5729static const struct snd_pci_quirk alc268_fixup_tbl[] = {
5730 /* below is codec SSID since multiple Toshiba laptops have the
5731 * same PCI SSID 1179:ff00
5732 */
5733 SND_PCI_QUIRK(0x1179, 0xff06, "Toshiba P200", ALC268_FIXUP_HP_EAPD),
Takashi Iwai6e72aa52012-06-25 10:52:25 +02005734 {}
5735};
5736
Takashi Iwai1d045db2011-07-07 18:23:21 +02005737/*
5738 * BIOS auto configuration
5739 */
5740static int alc268_parse_auto_config(struct hda_codec *codec)
5741{
Takashi Iwai3e6179b2011-07-08 16:55:13 +02005742 static const hda_nid_t alc268_ssids[] = { 0x15, 0x1b, 0x14, 0 };
Takashi Iwai1d045db2011-07-07 18:23:21 +02005743 struct alc_spec *spec = codec->spec;
Takashi Iwai3e6179b2011-07-08 16:55:13 +02005744 int err = alc_parse_auto_config(codec, NULL, alc268_ssids);
5745 if (err > 0) {
5746 if (!spec->no_analog && spec->autocfg.speaker_pins[0] != 0x1d) {
5747 add_mixer(spec, alc268_beep_mixer);
Takashi Iwai23d30f22012-05-07 17:17:32 +02005748 snd_hda_gen_add_verbs(&spec->gen, alc268_beep_init_verbs);
Takashi Iwai1d045db2011-07-07 18:23:21 +02005749 }
Takashi Iwai1d045db2011-07-07 18:23:21 +02005750 }
Takashi Iwai3e6179b2011-07-08 16:55:13 +02005751 return err;
Takashi Iwai1d045db2011-07-07 18:23:21 +02005752}
5753
Takashi Iwai1d045db2011-07-07 18:23:21 +02005754/*
5755 */
Takashi Iwai1d045db2011-07-07 18:23:21 +02005756static int patch_alc268(struct hda_codec *codec)
5757{
5758 struct alc_spec *spec;
Takashi Iwai1d045db2011-07-07 18:23:21 +02005759 int i, has_beep, err;
5760
Takashi Iwai1d045db2011-07-07 18:23:21 +02005761 /* ALC268 has no aa-loopback mixer */
Takashi Iwai3de95172012-05-07 18:03:15 +02005762 err = alc_alloc_spec(codec, 0);
5763 if (err < 0)
5764 return err;
5765
5766 spec = codec->spec;
Takashi Iwai1d045db2011-07-07 18:23:21 +02005767
Takashi Iwaicb766402012-10-20 10:55:21 +02005768 alc_pick_fixup(codec, alc268_fixup_models, alc268_fixup_tbl, alc268_fixups);
Takashi Iwai6e72aa52012-06-25 10:52:25 +02005769 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
5770
Takashi Iwai6ebb8052011-08-16 15:15:40 +02005771 /* automatic parse from the BIOS config */
5772 err = alc268_parse_auto_config(codec);
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02005773 if (err < 0)
5774 goto error;
Takashi Iwai1d045db2011-07-07 18:23:21 +02005775
Takashi Iwai1d045db2011-07-07 18:23:21 +02005776 has_beep = 0;
5777 for (i = 0; i < spec->num_mixers; i++) {
5778 if (spec->mixers[i] == alc268_beep_mixer) {
5779 has_beep = 1;
5780 break;
5781 }
5782 }
5783
5784 if (has_beep) {
5785 err = snd_hda_attach_beep_device(codec, 0x1);
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02005786 if (err < 0)
5787 goto error;
Takashi Iwai1d045db2011-07-07 18:23:21 +02005788 if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
5789 /* override the amp caps for beep generator */
5790 snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT,
5791 (0x0c << AC_AMPCAP_OFFSET_SHIFT) |
5792 (0x0c << AC_AMPCAP_NUM_STEPS_SHIFT) |
5793 (0x07 << AC_AMPCAP_STEP_SIZE_SHIFT) |
5794 (0 << AC_AMPCAP_MUTE_SHIFT));
5795 }
5796
Takashi Iwai1d045db2011-07-07 18:23:21 +02005797 codec->patch_ops = alc_patch_ops;
Takashi Iwai1d045db2011-07-07 18:23:21 +02005798 spec->shutup = alc_eapd_shutup;
5799
Takashi Iwai6e72aa52012-06-25 10:52:25 +02005800 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
5801
Takashi Iwai1d045db2011-07-07 18:23:21 +02005802 return 0;
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02005803
5804 error:
5805 alc_free(codec);
5806 return err;
Takashi Iwai1d045db2011-07-07 18:23:21 +02005807}
5808
5809/*
5810 * ALC269
5811 */
Takashi Iwai1d045db2011-07-07 18:23:21 +02005812static const struct hda_pcm_stream alc269_44k_pcm_analog_playback = {
5813 .substreams = 1,
5814 .channels_min = 2,
5815 .channels_max = 8,
5816 .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
5817 /* NID is set in alc_build_pcms */
5818 .ops = {
5819 .open = alc_playback_pcm_open,
5820 .prepare = alc_playback_pcm_prepare,
5821 .cleanup = alc_playback_pcm_cleanup
5822 },
5823};
5824
5825static const struct hda_pcm_stream alc269_44k_pcm_analog_capture = {
5826 .substreams = 1,
5827 .channels_min = 2,
5828 .channels_max = 2,
5829 .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
5830 /* NID is set in alc_build_pcms */
5831};
5832
Takashi Iwai1d045db2011-07-07 18:23:21 +02005833/* different alc269-variants */
5834enum {
5835 ALC269_TYPE_ALC269VA,
5836 ALC269_TYPE_ALC269VB,
5837 ALC269_TYPE_ALC269VC,
Kailang Yangadcc70b2012-05-25 08:08:38 +02005838 ALC269_TYPE_ALC269VD,
Kailang Yang065380f2013-01-10 10:25:48 +01005839 ALC269_TYPE_ALC280,
5840 ALC269_TYPE_ALC282,
5841 ALC269_TYPE_ALC284,
Takashi Iwai1d045db2011-07-07 18:23:21 +02005842};
5843
5844/*
5845 * BIOS auto configuration
5846 */
5847static int alc269_parse_auto_config(struct hda_codec *codec)
5848{
Takashi Iwai1d045db2011-07-07 18:23:21 +02005849 static const hda_nid_t alc269_ignore[] = { 0x1d, 0 };
Takashi Iwai3e6179b2011-07-08 16:55:13 +02005850 static const hda_nid_t alc269_ssids[] = { 0, 0x1b, 0x14, 0x21 };
5851 static const hda_nid_t alc269va_ssids[] = { 0x15, 0x1b, 0x14, 0 };
5852 struct alc_spec *spec = codec->spec;
Kailang Yangadcc70b2012-05-25 08:08:38 +02005853 const hda_nid_t *ssids;
5854
5855 switch (spec->codec_variant) {
5856 case ALC269_TYPE_ALC269VA:
5857 case ALC269_TYPE_ALC269VC:
Kailang Yang065380f2013-01-10 10:25:48 +01005858 case ALC269_TYPE_ALC280:
5859 case ALC269_TYPE_ALC284:
Kailang Yangadcc70b2012-05-25 08:08:38 +02005860 ssids = alc269va_ssids;
5861 break;
5862 case ALC269_TYPE_ALC269VB:
5863 case ALC269_TYPE_ALC269VD:
Kailang Yang065380f2013-01-10 10:25:48 +01005864 case ALC269_TYPE_ALC282:
Kailang Yangadcc70b2012-05-25 08:08:38 +02005865 ssids = alc269_ssids;
5866 break;
5867 default:
5868 ssids = alc269_ssids;
5869 break;
5870 }
Takashi Iwai1d045db2011-07-07 18:23:21 +02005871
Takashi Iwai3e6179b2011-07-08 16:55:13 +02005872 return alc_parse_auto_config(codec, alc269_ignore, ssids);
Takashi Iwai1d045db2011-07-07 18:23:21 +02005873}
5874
Kailang Yang1387e2d2012-11-08 10:23:18 +01005875static void alc269vb_toggle_power_output(struct hda_codec *codec, int power_up)
Takashi Iwai1d045db2011-07-07 18:23:21 +02005876{
5877 int val = alc_read_coef_idx(codec, 0x04);
5878 if (power_up)
5879 val |= 1 << 11;
5880 else
5881 val &= ~(1 << 11);
5882 alc_write_coef_idx(codec, 0x04, val);
5883}
5884
5885static void alc269_shutup(struct hda_codec *codec)
5886{
Kailang Yangadcc70b2012-05-25 08:08:38 +02005887 struct alc_spec *spec = codec->spec;
5888
5889 if (spec->codec_variant != ALC269_TYPE_ALC269VB)
5890 return;
5891
Kailang Yang1387e2d2012-11-08 10:23:18 +01005892 if (spec->codec_variant == ALC269_TYPE_ALC269VB)
5893 alc269vb_toggle_power_output(codec, 0);
5894 if (spec->codec_variant == ALC269_TYPE_ALC269VB &&
5895 (alc_get_coef0(codec) & 0x00ff) == 0x018) {
Takashi Iwai1d045db2011-07-07 18:23:21 +02005896 msleep(150);
5897 }
5898}
5899
Takashi Iwai2a439522011-07-26 09:52:50 +02005900#ifdef CONFIG_PM
Takashi Iwai1d045db2011-07-07 18:23:21 +02005901static int alc269_resume(struct hda_codec *codec)
5902{
Kailang Yangadcc70b2012-05-25 08:08:38 +02005903 struct alc_spec *spec = codec->spec;
5904
Kailang Yang1387e2d2012-11-08 10:23:18 +01005905 if (spec->codec_variant == ALC269_TYPE_ALC269VB)
5906 alc269vb_toggle_power_output(codec, 0);
5907 if (spec->codec_variant == ALC269_TYPE_ALC269VB &&
Kailang Yangadcc70b2012-05-25 08:08:38 +02005908 (alc_get_coef0(codec) & 0x00ff) == 0x018) {
Takashi Iwai1d045db2011-07-07 18:23:21 +02005909 msleep(150);
5910 }
5911
5912 codec->patch_ops.init(codec);
5913
Kailang Yang1387e2d2012-11-08 10:23:18 +01005914 if (spec->codec_variant == ALC269_TYPE_ALC269VB)
5915 alc269vb_toggle_power_output(codec, 1);
5916 if (spec->codec_variant == ALC269_TYPE_ALC269VB &&
Kailang Yangadcc70b2012-05-25 08:08:38 +02005917 (alc_get_coef0(codec) & 0x00ff) == 0x017) {
Takashi Iwai1d045db2011-07-07 18:23:21 +02005918 msleep(200);
5919 }
5920
Takashi Iwai1d045db2011-07-07 18:23:21 +02005921 snd_hda_codec_resume_amp(codec);
5922 snd_hda_codec_resume_cache(codec);
5923 hda_call_check_power_status(codec, 0x01);
5924 return 0;
5925}
Takashi Iwai2a439522011-07-26 09:52:50 +02005926#endif /* CONFIG_PM */
Takashi Iwai1d045db2011-07-07 18:23:21 +02005927
David Henningsson108cc102012-07-20 10:37:25 +02005928static void alc269_fixup_pincfg_no_hp_to_lineout(struct hda_codec *codec,
5929 const struct alc_fixup *fix, int action)
5930{
5931 struct alc_spec *spec = codec->spec;
5932
5933 if (action == ALC_FIXUP_ACT_PRE_PROBE)
5934 spec->parse_flags = HDA_PINCFG_NO_HP_FIXUP;
5935}
5936
Takashi Iwai1d045db2011-07-07 18:23:21 +02005937static void alc269_fixup_hweq(struct hda_codec *codec,
5938 const struct alc_fixup *fix, int action)
5939{
5940 int coef;
5941
5942 if (action != ALC_FIXUP_ACT_INIT)
5943 return;
5944 coef = alc_read_coef_idx(codec, 0x1e);
5945 alc_write_coef_idx(codec, 0x1e, coef | 0x80);
5946}
5947
5948static void alc271_fixup_dmic(struct hda_codec *codec,
5949 const struct alc_fixup *fix, int action)
5950{
5951 static const struct hda_verb verbs[] = {
5952 {0x20, AC_VERB_SET_COEF_INDEX, 0x0d},
5953 {0x20, AC_VERB_SET_PROC_COEF, 0x4000},
5954 {}
5955 };
5956 unsigned int cfg;
5957
5958 if (strcmp(codec->chip_name, "ALC271X"))
5959 return;
5960 cfg = snd_hda_codec_get_pincfg(codec, 0x12);
5961 if (get_defcfg_connect(cfg) == AC_JACK_PORT_FIXED)
5962 snd_hda_sequence_write(codec, verbs);
5963}
5964
Takashi Iwai017f2a12011-07-09 14:42:25 +02005965static void alc269_fixup_pcm_44k(struct hda_codec *codec,
5966 const struct alc_fixup *fix, int action)
5967{
5968 struct alc_spec *spec = codec->spec;
5969
5970 if (action != ALC_FIXUP_ACT_PROBE)
5971 return;
5972
5973 /* Due to a hardware problem on Lenovo Ideadpad, we need to
5974 * fix the sample rate of analog I/O to 44.1kHz
5975 */
5976 spec->stream_analog_playback = &alc269_44k_pcm_analog_playback;
5977 spec->stream_analog_capture = &alc269_44k_pcm_analog_capture;
5978}
5979
Takashi Iwaiadabb3e2011-08-03 07:48:37 +02005980static void alc269_fixup_stereo_dmic(struct hda_codec *codec,
5981 const struct alc_fixup *fix, int action)
5982{
5983 int coef;
5984
5985 if (action != ALC_FIXUP_ACT_INIT)
5986 return;
5987 /* The digital-mic unit sends PDM (differential signal) instead of
5988 * the standard PCM, thus you can't record a valid mono stream as is.
5989 * Below is a workaround specific to ALC269 to control the dmic
5990 * signal source as mono.
5991 */
5992 coef = alc_read_coef_idx(codec, 0x07);
5993 alc_write_coef_idx(codec, 0x07, coef | 0x80);
5994}
5995
Takashi Iwai24519912011-08-16 15:08:49 +02005996static void alc269_quanta_automute(struct hda_codec *codec)
5997{
David Henningsson42cf0d02011-09-20 12:04:56 +02005998 update_outputs(codec);
Takashi Iwai24519912011-08-16 15:08:49 +02005999
6000 snd_hda_codec_write(codec, 0x20, 0,
6001 AC_VERB_SET_COEF_INDEX, 0x0c);
6002 snd_hda_codec_write(codec, 0x20, 0,
6003 AC_VERB_SET_PROC_COEF, 0x680);
6004
6005 snd_hda_codec_write(codec, 0x20, 0,
6006 AC_VERB_SET_COEF_INDEX, 0x0c);
6007 snd_hda_codec_write(codec, 0x20, 0,
6008 AC_VERB_SET_PROC_COEF, 0x480);
6009}
6010
6011static void alc269_fixup_quanta_mute(struct hda_codec *codec,
6012 const struct alc_fixup *fix, int action)
6013{
6014 struct alc_spec *spec = codec->spec;
6015 if (action != ALC_FIXUP_ACT_PROBE)
6016 return;
6017 spec->automute_hook = alc269_quanta_automute;
6018}
6019
David Henningsson6d3cd5d2013-01-07 12:03:47 +01006020/* update mute-LED according to the speaker mute state via mic1 VREF pin */
6021static void alc269_fixup_mic1_mute_hook(void *private_data, int enabled)
6022{
6023 struct hda_codec *codec = private_data;
6024 unsigned int pinval = AC_PINCTL_IN_EN + (enabled ?
6025 AC_PINCTL_VREF_HIZ : AC_PINCTL_VREF_80);
6026 snd_hda_set_pin_ctl_cache(codec, 0x18, pinval);
6027}
6028
6029static void alc269_fixup_mic1_mute(struct hda_codec *codec,
6030 const struct alc_fixup *fix, int action)
6031{
6032 struct alc_spec *spec = codec->spec;
Takashi Iwai3bd7b642012-12-18 14:57:09 +01006033 if (action == ALC_FIXUP_ACT_PROBE)
David Henningsson6d3cd5d2013-01-07 12:03:47 +01006034 spec->vmaster_mute.hook = alc269_fixup_mic1_mute_hook;
David Henningsson6d3cd5d2013-01-07 12:03:47 +01006035}
6036
Takashi Iwai420b0fe2012-03-12 12:35:27 +01006037/* update mute-LED according to the speaker mute state via mic2 VREF pin */
6038static void alc269_fixup_mic2_mute_hook(void *private_data, int enabled)
6039{
6040 struct hda_codec *codec = private_data;
6041 unsigned int pinval = enabled ? 0x20 : 0x24;
Takashi Iwaicdd03ce2012-04-20 12:34:50 +02006042 snd_hda_set_pin_ctl_cache(codec, 0x19, pinval);
Takashi Iwai420b0fe2012-03-12 12:35:27 +01006043}
6044
6045static void alc269_fixup_mic2_mute(struct hda_codec *codec,
6046 const struct alc_fixup *fix, int action)
6047{
6048 struct alc_spec *spec = codec->spec;
Takashi Iwai3bd7b642012-12-18 14:57:09 +01006049 if (action == ALC_FIXUP_ACT_PROBE)
Takashi Iwaid2f344b2012-03-12 16:59:58 +01006050 spec->vmaster_mute.hook = alc269_fixup_mic2_mute_hook;
Takashi Iwai420b0fe2012-03-12 12:35:27 +01006051}
6052
Dylan Reid08a978d2012-11-18 22:56:40 -08006053static void alc271_hp_gate_mic_jack(struct hda_codec *codec,
6054 const struct alc_fixup *fix,
6055 int action)
6056{
6057 struct alc_spec *spec = codec->spec;
6058
6059 if (action == ALC_FIXUP_ACT_PROBE)
6060 snd_hda_jack_set_gating_jack(codec, spec->ext_mic_pin,
6061 spec->autocfg.hp_pins[0]);
6062}
David Henningsson693b6132012-06-22 19:12:10 +02006063
Takashi Iwai1d045db2011-07-07 18:23:21 +02006064enum {
6065 ALC269_FIXUP_SONY_VAIO,
6066 ALC275_FIXUP_SONY_VAIO_GPIO2,
6067 ALC269_FIXUP_DELL_M101Z,
6068 ALC269_FIXUP_SKU_IGNORE,
6069 ALC269_FIXUP_ASUS_G73JW,
6070 ALC269_FIXUP_LENOVO_EAPD,
6071 ALC275_FIXUP_SONY_HWEQ,
6072 ALC271_FIXUP_DMIC,
Takashi Iwai017f2a12011-07-09 14:42:25 +02006073 ALC269_FIXUP_PCM_44K,
Takashi Iwaiadabb3e2011-08-03 07:48:37 +02006074 ALC269_FIXUP_STEREO_DMIC,
Takashi Iwai24519912011-08-16 15:08:49 +02006075 ALC269_FIXUP_QUANTA_MUTE,
6076 ALC269_FIXUP_LIFEBOOK,
Takashi Iwaia4297b52011-08-23 18:40:12 +02006077 ALC269_FIXUP_AMIC,
6078 ALC269_FIXUP_DMIC,
6079 ALC269VB_FIXUP_AMIC,
6080 ALC269VB_FIXUP_DMIC,
David Henningsson6d3cd5d2013-01-07 12:03:47 +01006081 ALC269_FIXUP_MIC1_MUTE_LED,
Takashi Iwai420b0fe2012-03-12 12:35:27 +01006082 ALC269_FIXUP_MIC2_MUTE_LED,
David Henningsson693b6132012-06-22 19:12:10 +02006083 ALC269_FIXUP_INV_DMIC,
David Henningsson108cc102012-07-20 10:37:25 +02006084 ALC269_FIXUP_LENOVO_DOCK,
6085 ALC269_FIXUP_PINCFG_NO_HP_TO_LINEOUT,
Dylan Reid08a978d2012-11-18 22:56:40 -08006086 ALC271_FIXUP_AMIC_MIC2,
6087 ALC271_FIXUP_HP_GATE_MIC_JACK,
Takashi Iwai1d045db2011-07-07 18:23:21 +02006088};
6089
6090static const struct alc_fixup alc269_fixups[] = {
6091 [ALC269_FIXUP_SONY_VAIO] = {
6092 .type = ALC_FIXUP_VERBS,
6093 .v.verbs = (const struct hda_verb[]) {
6094 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREFGRD},
6095 {}
6096 }
6097 },
6098 [ALC275_FIXUP_SONY_VAIO_GPIO2] = {
6099 .type = ALC_FIXUP_VERBS,
6100 .v.verbs = (const struct hda_verb[]) {
6101 {0x01, AC_VERB_SET_GPIO_MASK, 0x04},
6102 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x04},
6103 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
6104 { }
6105 },
6106 .chained = true,
6107 .chain_id = ALC269_FIXUP_SONY_VAIO
6108 },
6109 [ALC269_FIXUP_DELL_M101Z] = {
6110 .type = ALC_FIXUP_VERBS,
6111 .v.verbs = (const struct hda_verb[]) {
6112 /* Enables internal speaker */
6113 {0x20, AC_VERB_SET_COEF_INDEX, 13},
6114 {0x20, AC_VERB_SET_PROC_COEF, 0x4040},
6115 {}
6116 }
6117 },
6118 [ALC269_FIXUP_SKU_IGNORE] = {
Takashi Iwai23d30f22012-05-07 17:17:32 +02006119 .type = ALC_FIXUP_FUNC,
6120 .v.func = alc_fixup_sku_ignore,
Takashi Iwai1d045db2011-07-07 18:23:21 +02006121 },
6122 [ALC269_FIXUP_ASUS_G73JW] = {
6123 .type = ALC_FIXUP_PINS,
6124 .v.pins = (const struct alc_pincfg[]) {
6125 { 0x17, 0x99130111 }, /* subwoofer */
6126 { }
6127 }
6128 },
6129 [ALC269_FIXUP_LENOVO_EAPD] = {
6130 .type = ALC_FIXUP_VERBS,
6131 .v.verbs = (const struct hda_verb[]) {
6132 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 0},
6133 {}
6134 }
6135 },
6136 [ALC275_FIXUP_SONY_HWEQ] = {
6137 .type = ALC_FIXUP_FUNC,
6138 .v.func = alc269_fixup_hweq,
6139 .chained = true,
6140 .chain_id = ALC275_FIXUP_SONY_VAIO_GPIO2
6141 },
6142 [ALC271_FIXUP_DMIC] = {
6143 .type = ALC_FIXUP_FUNC,
6144 .v.func = alc271_fixup_dmic,
6145 },
Takashi Iwai017f2a12011-07-09 14:42:25 +02006146 [ALC269_FIXUP_PCM_44K] = {
6147 .type = ALC_FIXUP_FUNC,
6148 .v.func = alc269_fixup_pcm_44k,
David Henningsson012e7eb2012-08-08 08:43:37 +02006149 .chained = true,
6150 .chain_id = ALC269_FIXUP_QUANTA_MUTE
Takashi Iwai017f2a12011-07-09 14:42:25 +02006151 },
Takashi Iwaiadabb3e2011-08-03 07:48:37 +02006152 [ALC269_FIXUP_STEREO_DMIC] = {
6153 .type = ALC_FIXUP_FUNC,
6154 .v.func = alc269_fixup_stereo_dmic,
6155 },
Takashi Iwai24519912011-08-16 15:08:49 +02006156 [ALC269_FIXUP_QUANTA_MUTE] = {
6157 .type = ALC_FIXUP_FUNC,
6158 .v.func = alc269_fixup_quanta_mute,
6159 },
6160 [ALC269_FIXUP_LIFEBOOK] = {
6161 .type = ALC_FIXUP_PINS,
6162 .v.pins = (const struct alc_pincfg[]) {
6163 { 0x1a, 0x2101103f }, /* dock line-out */
6164 { 0x1b, 0x23a11040 }, /* dock mic-in */
6165 { }
6166 },
6167 .chained = true,
6168 .chain_id = ALC269_FIXUP_QUANTA_MUTE
6169 },
Takashi Iwaia4297b52011-08-23 18:40:12 +02006170 [ALC269_FIXUP_AMIC] = {
6171 .type = ALC_FIXUP_PINS,
6172 .v.pins = (const struct alc_pincfg[]) {
6173 { 0x14, 0x99130110 }, /* speaker */
6174 { 0x15, 0x0121401f }, /* HP out */
6175 { 0x18, 0x01a19c20 }, /* mic */
6176 { 0x19, 0x99a3092f }, /* int-mic */
6177 { }
6178 },
6179 },
6180 [ALC269_FIXUP_DMIC] = {
6181 .type = ALC_FIXUP_PINS,
6182 .v.pins = (const struct alc_pincfg[]) {
6183 { 0x12, 0x99a3092f }, /* int-mic */
6184 { 0x14, 0x99130110 }, /* speaker */
6185 { 0x15, 0x0121401f }, /* HP out */
6186 { 0x18, 0x01a19c20 }, /* mic */
6187 { }
6188 },
6189 },
6190 [ALC269VB_FIXUP_AMIC] = {
6191 .type = ALC_FIXUP_PINS,
6192 .v.pins = (const struct alc_pincfg[]) {
6193 { 0x14, 0x99130110 }, /* speaker */
6194 { 0x18, 0x01a19c20 }, /* mic */
6195 { 0x19, 0x99a3092f }, /* int-mic */
6196 { 0x21, 0x0121401f }, /* HP out */
6197 { }
6198 },
6199 },
David Henningsson2267ea92012-01-03 08:45:56 +01006200 [ALC269VB_FIXUP_DMIC] = {
Takashi Iwaia4297b52011-08-23 18:40:12 +02006201 .type = ALC_FIXUP_PINS,
6202 .v.pins = (const struct alc_pincfg[]) {
6203 { 0x12, 0x99a3092f }, /* int-mic */
6204 { 0x14, 0x99130110 }, /* speaker */
6205 { 0x18, 0x01a19c20 }, /* mic */
6206 { 0x21, 0x0121401f }, /* HP out */
6207 { }
6208 },
6209 },
David Henningsson6d3cd5d2013-01-07 12:03:47 +01006210 [ALC269_FIXUP_MIC1_MUTE_LED] = {
6211 .type = ALC_FIXUP_FUNC,
6212 .v.func = alc269_fixup_mic1_mute,
6213 },
Takashi Iwai420b0fe2012-03-12 12:35:27 +01006214 [ALC269_FIXUP_MIC2_MUTE_LED] = {
6215 .type = ALC_FIXUP_FUNC,
6216 .v.func = alc269_fixup_mic2_mute,
6217 },
David Henningsson693b6132012-06-22 19:12:10 +02006218 [ALC269_FIXUP_INV_DMIC] = {
6219 .type = ALC_FIXUP_FUNC,
Takashi Iwai6e72aa52012-06-25 10:52:25 +02006220 .v.func = alc_fixup_inv_dmic_0x12,
David Henningsson693b6132012-06-22 19:12:10 +02006221 },
David Henningsson108cc102012-07-20 10:37:25 +02006222 [ALC269_FIXUP_LENOVO_DOCK] = {
6223 .type = ALC_FIXUP_PINS,
6224 .v.pins = (const struct alc_pincfg[]) {
6225 { 0x19, 0x23a11040 }, /* dock mic */
6226 { 0x1b, 0x2121103f }, /* dock headphone */
6227 { }
6228 },
6229 .chained = true,
6230 .chain_id = ALC269_FIXUP_PINCFG_NO_HP_TO_LINEOUT
6231 },
6232 [ALC269_FIXUP_PINCFG_NO_HP_TO_LINEOUT] = {
6233 .type = ALC_FIXUP_FUNC,
6234 .v.func = alc269_fixup_pincfg_no_hp_to_lineout,
6235 },
Dylan Reid08a978d2012-11-18 22:56:40 -08006236 [ALC271_FIXUP_AMIC_MIC2] = {
6237 .type = ALC_FIXUP_PINS,
6238 .v.pins = (const struct alc_pincfg[]) {
6239 { 0x14, 0x99130110 }, /* speaker */
6240 { 0x19, 0x01a19c20 }, /* mic */
6241 { 0x1b, 0x99a7012f }, /* int-mic */
6242 { 0x21, 0x0121401f }, /* HP out */
6243 { }
6244 },
6245 },
6246 [ALC271_FIXUP_HP_GATE_MIC_JACK] = {
6247 .type = ALC_FIXUP_FUNC,
6248 .v.func = alc271_hp_gate_mic_jack,
6249 .chained = true,
6250 .chain_id = ALC271_FIXUP_AMIC_MIC2,
6251 },
Takashi Iwai1d045db2011-07-07 18:23:21 +02006252};
6253
6254static const struct snd_pci_quirk alc269_fixup_tbl[] = {
David Henningsson693b6132012-06-22 19:12:10 +02006255 SND_PCI_QUIRK(0x1025, 0x029b, "Acer 1810TZ", ALC269_FIXUP_INV_DMIC),
6256 SND_PCI_QUIRK(0x1025, 0x0349, "Acer AOD260", ALC269_FIXUP_INV_DMIC),
Takashi Iwai420b0fe2012-03-12 12:35:27 +01006257 SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_MIC2_MUTE_LED),
David Henningsson6d3cd5d2013-01-07 12:03:47 +01006258 SND_PCI_QUIRK(0x103c, 0x1972, "HP Pavilion 17", ALC269_FIXUP_MIC1_MUTE_LED),
David Henningsson5ac57552012-04-20 10:01:46 +02006259 SND_PCI_QUIRK(0x1043, 0x1427, "Asus Zenbook UX31E", ALC269VB_FIXUP_DMIC),
Oleksij Rempel148728f2012-09-21 17:44:58 +02006260 SND_PCI_QUIRK(0x1043, 0x1517, "Asus Zenbook UX31A", ALC269VB_FIXUP_DMIC),
Takashi Iwai017f2a12011-07-09 14:42:25 +02006261 SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW),
David Henningsson693b6132012-06-22 19:12:10 +02006262 SND_PCI_QUIRK(0x1043, 0x1b13, "Asus U41SV", ALC269_FIXUP_INV_DMIC),
Takashi Iwaiadabb3e2011-08-03 07:48:37 +02006263 SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_FIXUP_STEREO_DMIC),
6264 SND_PCI_QUIRK(0x1043, 0x831a, "ASUS P901", ALC269_FIXUP_STEREO_DMIC),
6265 SND_PCI_QUIRK(0x1043, 0x834a, "ASUS S101", ALC269_FIXUP_STEREO_DMIC),
6266 SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005", ALC269_FIXUP_STEREO_DMIC),
6267 SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005", ALC269_FIXUP_STEREO_DMIC),
Takashi Iwai1d045db2011-07-07 18:23:21 +02006268 SND_PCI_QUIRK(0x104d, 0x9073, "Sony VAIO", ALC275_FIXUP_SONY_VAIO_GPIO2),
6269 SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
6270 SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
6271 SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO),
6272 SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z),
Dylan Reid08a978d2012-11-18 22:56:40 -08006273 SND_PCI_QUIRK(0x1025, 0x0742, "Acer AO756", ALC271_FIXUP_HP_GATE_MIC_JACK),
Takashi Iwai1d045db2011-07-07 18:23:21 +02006274 SND_PCI_QUIRK_VENDOR(0x1025, "Acer Aspire", ALC271_FIXUP_DMIC),
Takashi Iwai24519912011-08-16 15:08:49 +02006275 SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook", ALC269_FIXUP_LIFEBOOK),
Takashi Iwai1d045db2011-07-07 18:23:21 +02006276 SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE),
6277 SND_PCI_QUIRK(0x17aa, 0x215e, "Thinkpad L512", ALC269_FIXUP_SKU_IGNORE),
6278 SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE),
6279 SND_PCI_QUIRK(0x17aa, 0x21ca, "Thinkpad L412", ALC269_FIXUP_SKU_IGNORE),
6280 SND_PCI_QUIRK(0x17aa, 0x21e9, "Thinkpad Edge 15", ALC269_FIXUP_SKU_IGNORE),
Takashi Iwai707fba32012-08-02 09:04:39 +02006281 SND_PCI_QUIRK(0x17aa, 0x21f6, "Thinkpad T530", ALC269_FIXUP_LENOVO_DOCK),
Felix Kaechelec8415a42012-08-06 23:02:01 +02006282 SND_PCI_QUIRK(0x17aa, 0x21fa, "Thinkpad X230", ALC269_FIXUP_LENOVO_DOCK),
Stefán Freyr84f98fd2012-10-19 22:46:00 +02006283 SND_PCI_QUIRK(0x17aa, 0x21f3, "Thinkpad T430", ALC269_FIXUP_LENOVO_DOCK),
Philipp A. Mohrenweiser4407be62012-08-06 13:14:18 +02006284 SND_PCI_QUIRK(0x17aa, 0x21fb, "Thinkpad T430s", ALC269_FIXUP_LENOVO_DOCK),
David Henningsson108cc102012-07-20 10:37:25 +02006285 SND_PCI_QUIRK(0x17aa, 0x2203, "Thinkpad X230 Tablet", ALC269_FIXUP_LENOVO_DOCK),
David Henningsson012e7eb2012-08-08 08:43:37 +02006286 SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K),
Takashi Iwai1d045db2011-07-07 18:23:21 +02006287 SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
Takashi Iwaia4297b52011-08-23 18:40:12 +02006288
Takashi Iwaia7f3eed2012-02-16 13:03:18 +01006289#if 0
Takashi Iwaia4297b52011-08-23 18:40:12 +02006290 /* Below is a quirk table taken from the old code.
6291 * Basically the device should work as is without the fixup table.
6292 * If BIOS doesn't give a proper info, enable the corresponding
6293 * fixup entry.
Jesper Juhl7d7eb9e2012-04-12 22:11:25 +02006294 */
Takashi Iwaia4297b52011-08-23 18:40:12 +02006295 SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A",
6296 ALC269_FIXUP_AMIC),
6297 SND_PCI_QUIRK(0x1043, 0x1013, "ASUS N61Da", ALC269_FIXUP_AMIC),
Takashi Iwaia4297b52011-08-23 18:40:12 +02006298 SND_PCI_QUIRK(0x1043, 0x1143, "ASUS B53f", ALC269_FIXUP_AMIC),
6299 SND_PCI_QUIRK(0x1043, 0x1133, "ASUS UJ20ft", ALC269_FIXUP_AMIC),
6300 SND_PCI_QUIRK(0x1043, 0x1183, "ASUS K72DR", ALC269_FIXUP_AMIC),
6301 SND_PCI_QUIRK(0x1043, 0x11b3, "ASUS K52DR", ALC269_FIXUP_AMIC),
6302 SND_PCI_QUIRK(0x1043, 0x11e3, "ASUS U33Jc", ALC269_FIXUP_AMIC),
6303 SND_PCI_QUIRK(0x1043, 0x1273, "ASUS UL80Jt", ALC269_FIXUP_AMIC),
6304 SND_PCI_QUIRK(0x1043, 0x1283, "ASUS U53Jc", ALC269_FIXUP_AMIC),
6305 SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS N82JV", ALC269_FIXUP_AMIC),
6306 SND_PCI_QUIRK(0x1043, 0x12d3, "ASUS N61Jv", ALC269_FIXUP_AMIC),
6307 SND_PCI_QUIRK(0x1043, 0x13a3, "ASUS UL30Vt", ALC269_FIXUP_AMIC),
6308 SND_PCI_QUIRK(0x1043, 0x1373, "ASUS G73JX", ALC269_FIXUP_AMIC),
6309 SND_PCI_QUIRK(0x1043, 0x1383, "ASUS UJ30Jc", ALC269_FIXUP_AMIC),
6310 SND_PCI_QUIRK(0x1043, 0x13d3, "ASUS N61JA", ALC269_FIXUP_AMIC),
6311 SND_PCI_QUIRK(0x1043, 0x1413, "ASUS UL50", ALC269_FIXUP_AMIC),
6312 SND_PCI_QUIRK(0x1043, 0x1443, "ASUS UL30", ALC269_FIXUP_AMIC),
6313 SND_PCI_QUIRK(0x1043, 0x1453, "ASUS M60Jv", ALC269_FIXUP_AMIC),
6314 SND_PCI_QUIRK(0x1043, 0x1483, "ASUS UL80", ALC269_FIXUP_AMIC),
6315 SND_PCI_QUIRK(0x1043, 0x14f3, "ASUS F83Vf", ALC269_FIXUP_AMIC),
6316 SND_PCI_QUIRK(0x1043, 0x14e3, "ASUS UL20", ALC269_FIXUP_AMIC),
6317 SND_PCI_QUIRK(0x1043, 0x1513, "ASUS UX30", ALC269_FIXUP_AMIC),
6318 SND_PCI_QUIRK(0x1043, 0x1593, "ASUS N51Vn", ALC269_FIXUP_AMIC),
6319 SND_PCI_QUIRK(0x1043, 0x15a3, "ASUS N60Jv", ALC269_FIXUP_AMIC),
6320 SND_PCI_QUIRK(0x1043, 0x15b3, "ASUS N60Dp", ALC269_FIXUP_AMIC),
6321 SND_PCI_QUIRK(0x1043, 0x15c3, "ASUS N70De", ALC269_FIXUP_AMIC),
6322 SND_PCI_QUIRK(0x1043, 0x15e3, "ASUS F83T", ALC269_FIXUP_AMIC),
6323 SND_PCI_QUIRK(0x1043, 0x1643, "ASUS M60J", ALC269_FIXUP_AMIC),
6324 SND_PCI_QUIRK(0x1043, 0x1653, "ASUS U50", ALC269_FIXUP_AMIC),
6325 SND_PCI_QUIRK(0x1043, 0x1693, "ASUS F50N", ALC269_FIXUP_AMIC),
6326 SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS F5Q", ALC269_FIXUP_AMIC),
6327 SND_PCI_QUIRK(0x1043, 0x1723, "ASUS P80", ALC269_FIXUP_AMIC),
6328 SND_PCI_QUIRK(0x1043, 0x1743, "ASUS U80", ALC269_FIXUP_AMIC),
6329 SND_PCI_QUIRK(0x1043, 0x1773, "ASUS U20A", ALC269_FIXUP_AMIC),
6330 SND_PCI_QUIRK(0x1043, 0x1883, "ASUS F81Se", ALC269_FIXUP_AMIC),
6331 SND_PCI_QUIRK(0x152d, 0x1778, "Quanta ON1", ALC269_FIXUP_DMIC),
6332 SND_PCI_QUIRK(0x17aa, 0x3be9, "Quanta Wistron", ALC269_FIXUP_AMIC),
6333 SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_AMIC),
6334 SND_PCI_QUIRK(0x17ff, 0x059a, "Quanta EL3", ALC269_FIXUP_DMIC),
6335 SND_PCI_QUIRK(0x17ff, 0x059b, "Quanta JR1", ALC269_FIXUP_DMIC),
6336#endif
6337 {}
6338};
6339
6340static const struct alc_model_fixup alc269_fixup_models[] = {
6341 {.id = ALC269_FIXUP_AMIC, .name = "laptop-amic"},
6342 {.id = ALC269_FIXUP_DMIC, .name = "laptop-dmic"},
Takashi Iwai6e72aa52012-06-25 10:52:25 +02006343 {.id = ALC269_FIXUP_STEREO_DMIC, .name = "alc269-dmic"},
6344 {.id = ALC271_FIXUP_DMIC, .name = "alc271-dmic"},
6345 {.id = ALC269_FIXUP_INV_DMIC, .name = "inv-dmic"},
David Henningsson108cc102012-07-20 10:37:25 +02006346 {.id = ALC269_FIXUP_LENOVO_DOCK, .name = "lenovo-dock"},
Takashi Iwai1d045db2011-07-07 18:23:21 +02006347 {}
6348};
6349
6350
Takashi Iwai546bb672012-03-07 08:37:19 +01006351static void alc269_fill_coef(struct hda_codec *codec)
Takashi Iwai1d045db2011-07-07 18:23:21 +02006352{
Kailang Yang526af6e2012-03-07 08:25:20 +01006353 struct alc_spec *spec = codec->spec;
Takashi Iwai1d045db2011-07-07 18:23:21 +02006354 int val;
6355
Kailang Yang526af6e2012-03-07 08:25:20 +01006356 if (spec->codec_variant != ALC269_TYPE_ALC269VB)
Takashi Iwai546bb672012-03-07 08:37:19 +01006357 return;
Kailang Yang526af6e2012-03-07 08:25:20 +01006358
Takashi Iwai1bb7e432011-10-17 16:50:59 +02006359 if ((alc_get_coef0(codec) & 0x00ff) < 0x015) {
Takashi Iwai1d045db2011-07-07 18:23:21 +02006360 alc_write_coef_idx(codec, 0xf, 0x960b);
6361 alc_write_coef_idx(codec, 0xe, 0x8817);
6362 }
6363
Takashi Iwai1bb7e432011-10-17 16:50:59 +02006364 if ((alc_get_coef0(codec) & 0x00ff) == 0x016) {
Takashi Iwai1d045db2011-07-07 18:23:21 +02006365 alc_write_coef_idx(codec, 0xf, 0x960b);
6366 alc_write_coef_idx(codec, 0xe, 0x8814);
6367 }
6368
Takashi Iwai1bb7e432011-10-17 16:50:59 +02006369 if ((alc_get_coef0(codec) & 0x00ff) == 0x017) {
Takashi Iwai1d045db2011-07-07 18:23:21 +02006370 val = alc_read_coef_idx(codec, 0x04);
6371 /* Power up output pin */
6372 alc_write_coef_idx(codec, 0x04, val | (1<<11));
6373 }
6374
Takashi Iwai1bb7e432011-10-17 16:50:59 +02006375 if ((alc_get_coef0(codec) & 0x00ff) == 0x018) {
Takashi Iwai1d045db2011-07-07 18:23:21 +02006376 val = alc_read_coef_idx(codec, 0xd);
6377 if ((val & 0x0c00) >> 10 != 0x1) {
6378 /* Capless ramp up clock control */
6379 alc_write_coef_idx(codec, 0xd, val | (1<<10));
6380 }
6381 val = alc_read_coef_idx(codec, 0x17);
6382 if ((val & 0x01c0) >> 6 != 0x4) {
6383 /* Class D power on reset */
6384 alc_write_coef_idx(codec, 0x17, val | (1<<7));
6385 }
6386 }
6387
6388 val = alc_read_coef_idx(codec, 0xd); /* Class D */
6389 alc_write_coef_idx(codec, 0xd, val | (1<<14));
6390
6391 val = alc_read_coef_idx(codec, 0x4); /* HP */
6392 alc_write_coef_idx(codec, 0x4, val | (1<<11));
Takashi Iwai1d045db2011-07-07 18:23:21 +02006393}
6394
6395/*
6396 */
Takashi Iwai1d045db2011-07-07 18:23:21 +02006397static int patch_alc269(struct hda_codec *codec)
6398{
6399 struct alc_spec *spec;
Takashi Iwai3de95172012-05-07 18:03:15 +02006400 int err;
Takashi Iwai1d045db2011-07-07 18:23:21 +02006401
Takashi Iwai3de95172012-05-07 18:03:15 +02006402 err = alc_alloc_spec(codec, 0x0b);
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02006403 if (err < 0)
Takashi Iwai3de95172012-05-07 18:03:15 +02006404 return err;
6405
6406 spec = codec->spec;
Takashi Iwai37c04202012-12-18 14:22:45 +01006407 spec->shared_mic_vref_pin = 0x18;
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02006408
Herton Ronaldo Krzesinski9f720bb2012-09-27 10:38:14 -03006409 alc_pick_fixup(codec, alc269_fixup_models,
6410 alc269_fixup_tbl, alc269_fixups);
6411 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
6412
6413 alc_auto_parse_customize_define(codec);
6414
Kailang Yang065380f2013-01-10 10:25:48 +01006415 switch (codec->vendor_id) {
6416 case 0x10ec0269:
Takashi Iwai1d045db2011-07-07 18:23:21 +02006417 spec->codec_variant = ALC269_TYPE_ALC269VA;
Takashi Iwai1bb7e432011-10-17 16:50:59 +02006418 switch (alc_get_coef0(codec) & 0x00f0) {
6419 case 0x0010:
Takashi Iwai1d045db2011-07-07 18:23:21 +02006420 if (codec->bus->pci->subsystem_vendor == 0x1025 &&
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02006421 spec->cdefine.platform_type == 1)
Takashi Iwai20ca0c32011-10-17 16:00:35 +02006422 err = alc_codec_rename(codec, "ALC271X");
Takashi Iwai1d045db2011-07-07 18:23:21 +02006423 spec->codec_variant = ALC269_TYPE_ALC269VB;
Takashi Iwai1bb7e432011-10-17 16:50:59 +02006424 break;
6425 case 0x0020:
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02006426 if (codec->bus->pci->subsystem_vendor == 0x17aa &&
6427 codec->bus->pci->subsystem_device == 0x21f3)
Takashi Iwai20ca0c32011-10-17 16:00:35 +02006428 err = alc_codec_rename(codec, "ALC3202");
Takashi Iwai1d045db2011-07-07 18:23:21 +02006429 spec->codec_variant = ALC269_TYPE_ALC269VC;
Takashi Iwai1bb7e432011-10-17 16:50:59 +02006430 break;
Kailang Yangadcc70b2012-05-25 08:08:38 +02006431 case 0x0030:
6432 spec->codec_variant = ALC269_TYPE_ALC269VD;
6433 break;
Takashi Iwai1bb7e432011-10-17 16:50:59 +02006434 default:
Takashi Iwai1d045db2011-07-07 18:23:21 +02006435 alc_fix_pll_init(codec, 0x20, 0x04, 15);
Takashi Iwai1bb7e432011-10-17 16:50:59 +02006436 }
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02006437 if (err < 0)
6438 goto error;
Takashi Iwai546bb672012-03-07 08:37:19 +01006439 spec->init_hook = alc269_fill_coef;
Takashi Iwai1d045db2011-07-07 18:23:21 +02006440 alc269_fill_coef(codec);
Kailang Yang065380f2013-01-10 10:25:48 +01006441 break;
6442
6443 case 0x10ec0280:
6444 case 0x10ec0290:
6445 spec->codec_variant = ALC269_TYPE_ALC280;
6446 break;
6447 case 0x10ec0282:
6448 case 0x10ec0283:
6449 spec->codec_variant = ALC269_TYPE_ALC282;
6450 break;
6451 case 0x10ec0284:
6452 case 0x10ec0292:
6453 spec->codec_variant = ALC269_TYPE_ALC284;
6454 break;
Takashi Iwai1d045db2011-07-07 18:23:21 +02006455 }
6456
Takashi Iwaia4297b52011-08-23 18:40:12 +02006457 /* automatic parse from the BIOS config */
6458 err = alc269_parse_auto_config(codec);
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02006459 if (err < 0)
6460 goto error;
Takashi Iwai1d045db2011-07-07 18:23:21 +02006461
Takashi Iwai3e6179b2011-07-08 16:55:13 +02006462 if (!spec->no_analog && has_cdefine_beep(codec)) {
6463 err = snd_hda_attach_beep_device(codec, 0x1);
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02006464 if (err < 0)
6465 goto error;
Takashi Iwai1d045db2011-07-07 18:23:21 +02006466 set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
Takashi Iwai3e6179b2011-07-08 16:55:13 +02006467 }
Takashi Iwai1d045db2011-07-07 18:23:21 +02006468
Takashi Iwai1d045db2011-07-07 18:23:21 +02006469 codec->patch_ops = alc_patch_ops;
Takashi Iwai2a439522011-07-26 09:52:50 +02006470#ifdef CONFIG_PM
Takashi Iwai1d045db2011-07-07 18:23:21 +02006471 codec->patch_ops.resume = alc269_resume;
6472#endif
Takashi Iwai1d045db2011-07-07 18:23:21 +02006473 spec->shutup = alc269_shutup;
6474
Takashi Iwai589876e2012-02-20 15:47:55 +01006475 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
6476
Takashi Iwai1d045db2011-07-07 18:23:21 +02006477 return 0;
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02006478
6479 error:
6480 alc_free(codec);
6481 return err;
Takashi Iwai1d045db2011-07-07 18:23:21 +02006482}
6483
6484/*
6485 * ALC861
6486 */
6487
Takashi Iwai1d045db2011-07-07 18:23:21 +02006488static int alc861_parse_auto_config(struct hda_codec *codec)
6489{
Takashi Iwai1d045db2011-07-07 18:23:21 +02006490 static const hda_nid_t alc861_ignore[] = { 0x1d, 0 };
Takashi Iwai3e6179b2011-07-08 16:55:13 +02006491 static const hda_nid_t alc861_ssids[] = { 0x0e, 0x0f, 0x0b, 0 };
6492 return alc_parse_auto_config(codec, alc861_ignore, alc861_ssids);
Takashi Iwai1d045db2011-07-07 18:23:21 +02006493}
6494
Takashi Iwai1d045db2011-07-07 18:23:21 +02006495/* Pin config fixes */
6496enum {
Takashi Iwaie652f4c2012-02-13 11:56:25 +01006497 ALC861_FIXUP_FSC_AMILO_PI1505,
6498 ALC861_FIXUP_AMP_VREF_0F,
6499 ALC861_FIXUP_NO_JACK_DETECT,
6500 ALC861_FIXUP_ASUS_A6RP,
Takashi Iwai1d045db2011-07-07 18:23:21 +02006501};
6502
Takashi Iwai31150f22012-01-30 10:54:08 +01006503/* On some laptops, VREF of pin 0x0f is abused for controlling the main amp */
6504static void alc861_fixup_asus_amp_vref_0f(struct hda_codec *codec,
6505 const struct alc_fixup *fix, int action)
6506{
6507 struct alc_spec *spec = codec->spec;
6508 unsigned int val;
6509
6510 if (action != ALC_FIXUP_ACT_INIT)
6511 return;
6512 val = snd_hda_codec_read(codec, 0x0f, 0,
6513 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
6514 if (!(val & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN)))
6515 val |= AC_PINCTL_IN_EN;
6516 val |= AC_PINCTL_VREF_50;
Takashi Iwaicdd03ce2012-04-20 12:34:50 +02006517 snd_hda_set_pin_ctl(codec, 0x0f, val);
Takashi Iwai31150f22012-01-30 10:54:08 +01006518 spec->keep_vref_in_automute = 1;
6519}
6520
Takashi Iwaie652f4c2012-02-13 11:56:25 +01006521/* suppress the jack-detection */
6522static void alc_fixup_no_jack_detect(struct hda_codec *codec,
6523 const struct alc_fixup *fix, int action)
6524{
6525 if (action == ALC_FIXUP_ACT_PRE_PROBE)
6526 codec->no_jack_detect = 1;
Jesper Juhl7d7eb9e2012-04-12 22:11:25 +02006527}
Takashi Iwaie652f4c2012-02-13 11:56:25 +01006528
Takashi Iwai1d045db2011-07-07 18:23:21 +02006529static const struct alc_fixup alc861_fixups[] = {
Takashi Iwaie652f4c2012-02-13 11:56:25 +01006530 [ALC861_FIXUP_FSC_AMILO_PI1505] = {
Takashi Iwai1d045db2011-07-07 18:23:21 +02006531 .type = ALC_FIXUP_PINS,
6532 .v.pins = (const struct alc_pincfg[]) {
6533 { 0x0b, 0x0221101f }, /* HP */
6534 { 0x0f, 0x90170310 }, /* speaker */
6535 { }
6536 }
6537 },
Takashi Iwaie652f4c2012-02-13 11:56:25 +01006538 [ALC861_FIXUP_AMP_VREF_0F] = {
Takashi Iwai31150f22012-01-30 10:54:08 +01006539 .type = ALC_FIXUP_FUNC,
6540 .v.func = alc861_fixup_asus_amp_vref_0f,
Takashi Iwai3b25eb62012-01-25 09:55:46 +01006541 },
Takashi Iwaie652f4c2012-02-13 11:56:25 +01006542 [ALC861_FIXUP_NO_JACK_DETECT] = {
6543 .type = ALC_FIXUP_FUNC,
6544 .v.func = alc_fixup_no_jack_detect,
6545 },
6546 [ALC861_FIXUP_ASUS_A6RP] = {
6547 .type = ALC_FIXUP_FUNC,
6548 .v.func = alc861_fixup_asus_amp_vref_0f,
6549 .chained = true,
6550 .chain_id = ALC861_FIXUP_NO_JACK_DETECT,
6551 }
Takashi Iwai1d045db2011-07-07 18:23:21 +02006552};
6553
6554static const struct snd_pci_quirk alc861_fixup_tbl[] = {
Takashi Iwaie652f4c2012-02-13 11:56:25 +01006555 SND_PCI_QUIRK(0x1043, 0x1393, "ASUS A6Rp", ALC861_FIXUP_ASUS_A6RP),
6556 SND_PCI_QUIRK_VENDOR(0x1043, "ASUS laptop", ALC861_FIXUP_AMP_VREF_0F),
6557 SND_PCI_QUIRK(0x1462, 0x7254, "HP DX2200", ALC861_FIXUP_NO_JACK_DETECT),
6558 SND_PCI_QUIRK(0x1584, 0x2b01, "Haier W18", ALC861_FIXUP_AMP_VREF_0F),
6559 SND_PCI_QUIRK(0x1584, 0x0000, "Uniwill ECS M31EI", ALC861_FIXUP_AMP_VREF_0F),
6560 SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", ALC861_FIXUP_FSC_AMILO_PI1505),
Takashi Iwai1d045db2011-07-07 18:23:21 +02006561 {}
6562};
6563
6564/*
6565 */
Takashi Iwai1d045db2011-07-07 18:23:21 +02006566static int patch_alc861(struct hda_codec *codec)
6567{
6568 struct alc_spec *spec;
Takashi Iwai1d045db2011-07-07 18:23:21 +02006569 int err;
6570
Takashi Iwai3de95172012-05-07 18:03:15 +02006571 err = alc_alloc_spec(codec, 0x15);
6572 if (err < 0)
6573 return err;
Takashi Iwai1d045db2011-07-07 18:23:21 +02006574
Takashi Iwai3de95172012-05-07 18:03:15 +02006575 spec = codec->spec;
Takashi Iwai1d045db2011-07-07 18:23:21 +02006576
Takashi Iwaicb4e4822011-08-23 17:34:25 +02006577 alc_pick_fixup(codec, NULL, alc861_fixup_tbl, alc861_fixups);
6578 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
Takashi Iwai1d045db2011-07-07 18:23:21 +02006579
Takashi Iwaicb4e4822011-08-23 17:34:25 +02006580 /* automatic parse from the BIOS config */
6581 err = alc861_parse_auto_config(codec);
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02006582 if (err < 0)
6583 goto error;
Takashi Iwai1d045db2011-07-07 18:23:21 +02006584
Takashi Iwai3e6179b2011-07-08 16:55:13 +02006585 if (!spec->no_analog) {
6586 err = snd_hda_attach_beep_device(codec, 0x23);
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02006587 if (err < 0)
6588 goto error;
Takashi Iwai3e6179b2011-07-08 16:55:13 +02006589 set_beep_amp(spec, 0x23, 0, HDA_OUTPUT);
6590 }
Takashi Iwai1d045db2011-07-07 18:23:21 +02006591
Takashi Iwai1d045db2011-07-07 18:23:21 +02006592 codec->patch_ops = alc_patch_ops;
Takashi Iwai83012a72012-08-24 18:38:08 +02006593#ifdef CONFIG_PM
Takashi Iwaicb4e4822011-08-23 17:34:25 +02006594 spec->power_hook = alc_power_eapd;
Takashi Iwai1d045db2011-07-07 18:23:21 +02006595#endif
6596
Takashi Iwai589876e2012-02-20 15:47:55 +01006597 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
6598
Takashi Iwai1d045db2011-07-07 18:23:21 +02006599 return 0;
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02006600
6601 error:
6602 alc_free(codec);
6603 return err;
Takashi Iwai1d045db2011-07-07 18:23:21 +02006604}
6605
6606/*
6607 * ALC861-VD support
6608 *
6609 * Based on ALC882
6610 *
6611 * In addition, an independent DAC
6612 */
Takashi Iwai1d045db2011-07-07 18:23:21 +02006613static int alc861vd_parse_auto_config(struct hda_codec *codec)
6614{
Takashi Iwai1d045db2011-07-07 18:23:21 +02006615 static const hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
Takashi Iwai3e6179b2011-07-08 16:55:13 +02006616 static const hda_nid_t alc861vd_ssids[] = { 0x15, 0x1b, 0x14, 0 };
6617 return alc_parse_auto_config(codec, alc861vd_ignore, alc861vd_ssids);
Takashi Iwai1d045db2011-07-07 18:23:21 +02006618}
6619
Takashi Iwai1d045db2011-07-07 18:23:21 +02006620enum {
Takashi Iwai8fdcb6f2011-08-23 17:28:55 +02006621 ALC660VD_FIX_ASUS_GPIO1,
6622 ALC861VD_FIX_DALLAS,
Takashi Iwai1d045db2011-07-07 18:23:21 +02006623};
6624
Takashi Iwai8fdcb6f2011-08-23 17:28:55 +02006625/* exclude VREF80 */
6626static void alc861vd_fixup_dallas(struct hda_codec *codec,
6627 const struct alc_fixup *fix, int action)
6628{
6629 if (action == ALC_FIXUP_ACT_PRE_PROBE) {
Takashi Iwaib78562b2012-12-17 20:06:49 +01006630 snd_hda_override_pin_caps(codec, 0x18, 0x00000734);
6631 snd_hda_override_pin_caps(codec, 0x19, 0x0000073c);
Takashi Iwai8fdcb6f2011-08-23 17:28:55 +02006632 }
6633}
6634
Takashi Iwai1d045db2011-07-07 18:23:21 +02006635static const struct alc_fixup alc861vd_fixups[] = {
6636 [ALC660VD_FIX_ASUS_GPIO1] = {
6637 .type = ALC_FIXUP_VERBS,
6638 .v.verbs = (const struct hda_verb[]) {
Takashi Iwai8fdcb6f2011-08-23 17:28:55 +02006639 /* reset GPIO1 */
Takashi Iwai1d045db2011-07-07 18:23:21 +02006640 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
6641 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
6642 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
6643 { }
6644 }
6645 },
Takashi Iwai8fdcb6f2011-08-23 17:28:55 +02006646 [ALC861VD_FIX_DALLAS] = {
6647 .type = ALC_FIXUP_FUNC,
6648 .v.func = alc861vd_fixup_dallas,
6649 },
Takashi Iwai1d045db2011-07-07 18:23:21 +02006650};
6651
6652static const struct snd_pci_quirk alc861vd_fixup_tbl[] = {
Takashi Iwai8fdcb6f2011-08-23 17:28:55 +02006653 SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_FIX_DALLAS),
Takashi Iwai1d045db2011-07-07 18:23:21 +02006654 SND_PCI_QUIRK(0x1043, 0x1339, "ASUS A7-K", ALC660VD_FIX_ASUS_GPIO1),
Takashi Iwai8fdcb6f2011-08-23 17:28:55 +02006655 SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_FIX_DALLAS),
Takashi Iwai1d045db2011-07-07 18:23:21 +02006656 {}
6657};
6658
Takashi Iwai1d045db2011-07-07 18:23:21 +02006659/*
6660 */
Takashi Iwai1d045db2011-07-07 18:23:21 +02006661static int patch_alc861vd(struct hda_codec *codec)
6662{
6663 struct alc_spec *spec;
Takashi Iwaicb4e4822011-08-23 17:34:25 +02006664 int err;
Takashi Iwai1d045db2011-07-07 18:23:21 +02006665
Takashi Iwai3de95172012-05-07 18:03:15 +02006666 err = alc_alloc_spec(codec, 0x0b);
6667 if (err < 0)
6668 return err;
Takashi Iwai1d045db2011-07-07 18:23:21 +02006669
Takashi Iwai3de95172012-05-07 18:03:15 +02006670 spec = codec->spec;
Takashi Iwai1d045db2011-07-07 18:23:21 +02006671
Takashi Iwaicb4e4822011-08-23 17:34:25 +02006672 alc_pick_fixup(codec, NULL, alc861vd_fixup_tbl, alc861vd_fixups);
6673 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
Takashi Iwai1d045db2011-07-07 18:23:21 +02006674
Takashi Iwaicb4e4822011-08-23 17:34:25 +02006675 /* automatic parse from the BIOS config */
6676 err = alc861vd_parse_auto_config(codec);
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02006677 if (err < 0)
6678 goto error;
Takashi Iwai1d045db2011-07-07 18:23:21 +02006679
Takashi Iwai3e6179b2011-07-08 16:55:13 +02006680 if (!spec->no_analog) {
6681 err = snd_hda_attach_beep_device(codec, 0x23);
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02006682 if (err < 0)
6683 goto error;
Takashi Iwai3e6179b2011-07-08 16:55:13 +02006684 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
6685 }
Takashi Iwai1d045db2011-07-07 18:23:21 +02006686
Takashi Iwai1d045db2011-07-07 18:23:21 +02006687 codec->patch_ops = alc_patch_ops;
6688
Takashi Iwai1d045db2011-07-07 18:23:21 +02006689 spec->shutup = alc_eapd_shutup;
Takashi Iwai1d045db2011-07-07 18:23:21 +02006690
Takashi Iwai589876e2012-02-20 15:47:55 +01006691 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
6692
Takashi Iwai1d045db2011-07-07 18:23:21 +02006693 return 0;
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02006694
6695 error:
6696 alc_free(codec);
6697 return err;
Takashi Iwai1d045db2011-07-07 18:23:21 +02006698}
6699
6700/*
6701 * ALC662 support
6702 *
6703 * ALC662 is almost identical with ALC880 but has cleaner and more flexible
6704 * configuration. Each pin widget can choose any input DACs and a mixer.
6705 * Each ADC is connected from a mixer of all inputs. This makes possible
6706 * 6-channel independent captures.
6707 *
6708 * In addition, an independent DAC for the multi-playback (not used in this
6709 * driver yet).
6710 */
Takashi Iwai1d045db2011-07-07 18:23:21 +02006711
6712/*
6713 * BIOS auto configuration
6714 */
6715
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006716static int alc662_parse_auto_config(struct hda_codec *codec)
6717{
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02006718 static const hda_nid_t alc662_ignore[] = { 0x1d, 0 };
Takashi Iwai3e6179b2011-07-08 16:55:13 +02006719 static const hda_nid_t alc663_ssids[] = { 0x15, 0x1b, 0x14, 0x21 };
6720 static const hda_nid_t alc662_ssids[] = { 0x15, 0x1b, 0x14, 0 };
6721 const hda_nid_t *ssids;
Takashi Iwaiee979a142008-09-02 15:42:20 +02006722
Kailang Yang6227cdc2010-02-25 08:36:52 +01006723 if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 ||
6724 codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670)
Takashi Iwai3e6179b2011-07-08 16:55:13 +02006725 ssids = alc663_ssids;
Kailang Yang6227cdc2010-02-25 08:36:52 +01006726 else
Takashi Iwai3e6179b2011-07-08 16:55:13 +02006727 ssids = alc662_ssids;
6728 return alc_parse_auto_config(codec, alc662_ignore, ssids);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006729}
6730
Todd Broch6be79482010-12-07 16:51:05 -08006731static void alc272_fixup_mario(struct hda_codec *codec,
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01006732 const struct alc_fixup *fix, int action)
Takashi Iwai6fc398c2011-01-13 14:36:37 +01006733{
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01006734 if (action != ALC_FIXUP_ACT_PROBE)
Takashi Iwai6fc398c2011-01-13 14:36:37 +01006735 return;
Todd Broch6be79482010-12-07 16:51:05 -08006736 if (snd_hda_override_amp_caps(codec, 0x2, HDA_OUTPUT,
6737 (0x3b << AC_AMPCAP_OFFSET_SHIFT) |
6738 (0x3b << AC_AMPCAP_NUM_STEPS_SHIFT) |
6739 (0x03 << AC_AMPCAP_STEP_SIZE_SHIFT) |
6740 (0 << AC_AMPCAP_MUTE_SHIFT)))
6741 printk(KERN_WARNING
6742 "hda_codec: failed to override amp caps for NID 0x2\n");
6743}
6744
David Henningsson6cb3b702010-09-09 08:51:44 +02006745enum {
Daniel T Chen2df03512010-10-10 22:39:28 -04006746 ALC662_FIXUP_ASPIRE,
David Henningsson6cb3b702010-09-09 08:51:44 +02006747 ALC662_FIXUP_IDEAPAD,
Todd Broch6be79482010-12-07 16:51:05 -08006748 ALC272_FIXUP_MARIO,
Anisse Astierd2ebd472011-01-20 12:36:21 +01006749 ALC662_FIXUP_CZC_P10T,
David Henningsson94024cd2011-04-29 14:10:55 +02006750 ALC662_FIXUP_SKU_IGNORE,
Takashi Iwaie59ea3e2011-06-29 17:21:00 +02006751 ALC662_FIXUP_HP_RP5800,
Takashi Iwai53c334a2011-08-23 18:27:14 +02006752 ALC662_FIXUP_ASUS_MODE1,
6753 ALC662_FIXUP_ASUS_MODE2,
6754 ALC662_FIXUP_ASUS_MODE3,
6755 ALC662_FIXUP_ASUS_MODE4,
6756 ALC662_FIXUP_ASUS_MODE5,
6757 ALC662_FIXUP_ASUS_MODE6,
6758 ALC662_FIXUP_ASUS_MODE7,
6759 ALC662_FIXUP_ASUS_MODE8,
Takashi Iwai1565cc32012-02-13 12:03:25 +01006760 ALC662_FIXUP_NO_JACK_DETECT,
David Henningssonedfe3bf2012-06-12 13:15:12 +02006761 ALC662_FIXUP_ZOTAC_Z68,
Takashi Iwai125821a2012-06-22 14:30:29 +02006762 ALC662_FIXUP_INV_DMIC,
David Henningsson6cb3b702010-09-09 08:51:44 +02006763};
6764
6765static const struct alc_fixup alc662_fixups[] = {
Daniel T Chen2df03512010-10-10 22:39:28 -04006766 [ALC662_FIXUP_ASPIRE] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01006767 .type = ALC_FIXUP_PINS,
6768 .v.pins = (const struct alc_pincfg[]) {
Daniel T Chen2df03512010-10-10 22:39:28 -04006769 { 0x15, 0x99130112 }, /* subwoofer */
6770 { }
6771 }
6772 },
David Henningsson6cb3b702010-09-09 08:51:44 +02006773 [ALC662_FIXUP_IDEAPAD] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01006774 .type = ALC_FIXUP_PINS,
6775 .v.pins = (const struct alc_pincfg[]) {
David Henningsson6cb3b702010-09-09 08:51:44 +02006776 { 0x17, 0x99130112 }, /* subwoofer */
6777 { }
6778 }
6779 },
Todd Broch6be79482010-12-07 16:51:05 -08006780 [ALC272_FIXUP_MARIO] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01006781 .type = ALC_FIXUP_FUNC,
6782 .v.func = alc272_fixup_mario,
Anisse Astierd2ebd472011-01-20 12:36:21 +01006783 },
6784 [ALC662_FIXUP_CZC_P10T] = {
6785 .type = ALC_FIXUP_VERBS,
6786 .v.verbs = (const struct hda_verb[]) {
6787 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 0},
6788 {}
6789 }
6790 },
David Henningsson94024cd2011-04-29 14:10:55 +02006791 [ALC662_FIXUP_SKU_IGNORE] = {
Takashi Iwai23d30f22012-05-07 17:17:32 +02006792 .type = ALC_FIXUP_FUNC,
6793 .v.func = alc_fixup_sku_ignore,
Takashi Iwaic6b35872011-03-28 12:05:31 +02006794 },
Takashi Iwaie59ea3e2011-06-29 17:21:00 +02006795 [ALC662_FIXUP_HP_RP5800] = {
6796 .type = ALC_FIXUP_PINS,
6797 .v.pins = (const struct alc_pincfg[]) {
6798 { 0x14, 0x0221201f }, /* HP out */
6799 { }
6800 },
6801 .chained = true,
6802 .chain_id = ALC662_FIXUP_SKU_IGNORE
6803 },
Takashi Iwai53c334a2011-08-23 18:27:14 +02006804 [ALC662_FIXUP_ASUS_MODE1] = {
6805 .type = ALC_FIXUP_PINS,
6806 .v.pins = (const struct alc_pincfg[]) {
6807 { 0x14, 0x99130110 }, /* speaker */
6808 { 0x18, 0x01a19c20 }, /* mic */
6809 { 0x19, 0x99a3092f }, /* int-mic */
6810 { 0x21, 0x0121401f }, /* HP out */
6811 { }
6812 },
6813 .chained = true,
6814 .chain_id = ALC662_FIXUP_SKU_IGNORE
6815 },
6816 [ALC662_FIXUP_ASUS_MODE2] = {
Takashi Iwai2996bdb2011-08-18 16:02:24 +02006817 .type = ALC_FIXUP_PINS,
6818 .v.pins = (const struct alc_pincfg[]) {
6819 { 0x14, 0x99130110 }, /* speaker */
6820 { 0x18, 0x01a19820 }, /* mic */
6821 { 0x19, 0x99a3092f }, /* int-mic */
6822 { 0x1b, 0x0121401f }, /* HP out */
6823 { }
6824 },
Takashi Iwai53c334a2011-08-23 18:27:14 +02006825 .chained = true,
6826 .chain_id = ALC662_FIXUP_SKU_IGNORE
6827 },
6828 [ALC662_FIXUP_ASUS_MODE3] = {
6829 .type = ALC_FIXUP_PINS,
6830 .v.pins = (const struct alc_pincfg[]) {
6831 { 0x14, 0x99130110 }, /* speaker */
6832 { 0x15, 0x0121441f }, /* HP */
6833 { 0x18, 0x01a19840 }, /* mic */
6834 { 0x19, 0x99a3094f }, /* int-mic */
6835 { 0x21, 0x01211420 }, /* HP2 */
6836 { }
6837 },
6838 .chained = true,
6839 .chain_id = ALC662_FIXUP_SKU_IGNORE
6840 },
6841 [ALC662_FIXUP_ASUS_MODE4] = {
6842 .type = ALC_FIXUP_PINS,
6843 .v.pins = (const struct alc_pincfg[]) {
6844 { 0x14, 0x99130110 }, /* speaker */
6845 { 0x16, 0x99130111 }, /* speaker */
6846 { 0x18, 0x01a19840 }, /* mic */
6847 { 0x19, 0x99a3094f }, /* int-mic */
6848 { 0x21, 0x0121441f }, /* HP */
6849 { }
6850 },
6851 .chained = true,
6852 .chain_id = ALC662_FIXUP_SKU_IGNORE
6853 },
6854 [ALC662_FIXUP_ASUS_MODE5] = {
6855 .type = ALC_FIXUP_PINS,
6856 .v.pins = (const struct alc_pincfg[]) {
6857 { 0x14, 0x99130110 }, /* speaker */
6858 { 0x15, 0x0121441f }, /* HP */
6859 { 0x16, 0x99130111 }, /* speaker */
6860 { 0x18, 0x01a19840 }, /* mic */
6861 { 0x19, 0x99a3094f }, /* int-mic */
6862 { }
6863 },
6864 .chained = true,
6865 .chain_id = ALC662_FIXUP_SKU_IGNORE
6866 },
6867 [ALC662_FIXUP_ASUS_MODE6] = {
6868 .type = ALC_FIXUP_PINS,
6869 .v.pins = (const struct alc_pincfg[]) {
6870 { 0x14, 0x99130110 }, /* speaker */
6871 { 0x15, 0x01211420 }, /* HP2 */
6872 { 0x18, 0x01a19840 }, /* mic */
6873 { 0x19, 0x99a3094f }, /* int-mic */
6874 { 0x1b, 0x0121441f }, /* HP */
6875 { }
6876 },
6877 .chained = true,
6878 .chain_id = ALC662_FIXUP_SKU_IGNORE
6879 },
6880 [ALC662_FIXUP_ASUS_MODE7] = {
6881 .type = ALC_FIXUP_PINS,
6882 .v.pins = (const struct alc_pincfg[]) {
6883 { 0x14, 0x99130110 }, /* speaker */
6884 { 0x17, 0x99130111 }, /* speaker */
6885 { 0x18, 0x01a19840 }, /* mic */
6886 { 0x19, 0x99a3094f }, /* int-mic */
6887 { 0x1b, 0x01214020 }, /* HP */
6888 { 0x21, 0x0121401f }, /* HP */
6889 { }
6890 },
6891 .chained = true,
6892 .chain_id = ALC662_FIXUP_SKU_IGNORE
6893 },
6894 [ALC662_FIXUP_ASUS_MODE8] = {
6895 .type = ALC_FIXUP_PINS,
6896 .v.pins = (const struct alc_pincfg[]) {
6897 { 0x14, 0x99130110 }, /* speaker */
6898 { 0x12, 0x99a30970 }, /* int-mic */
6899 { 0x15, 0x01214020 }, /* HP */
6900 { 0x17, 0x99130111 }, /* speaker */
6901 { 0x18, 0x01a19840 }, /* mic */
6902 { 0x21, 0x0121401f }, /* HP */
6903 { }
6904 },
6905 .chained = true,
6906 .chain_id = ALC662_FIXUP_SKU_IGNORE
Takashi Iwai2996bdb2011-08-18 16:02:24 +02006907 },
Takashi Iwai1565cc32012-02-13 12:03:25 +01006908 [ALC662_FIXUP_NO_JACK_DETECT] = {
6909 .type = ALC_FIXUP_FUNC,
6910 .v.func = alc_fixup_no_jack_detect,
6911 },
David Henningssonedfe3bf2012-06-12 13:15:12 +02006912 [ALC662_FIXUP_ZOTAC_Z68] = {
6913 .type = ALC_FIXUP_PINS,
6914 .v.pins = (const struct alc_pincfg[]) {
6915 { 0x1b, 0x02214020 }, /* Front HP */
6916 { }
6917 }
6918 },
Takashi Iwai125821a2012-06-22 14:30:29 +02006919 [ALC662_FIXUP_INV_DMIC] = {
6920 .type = ALC_FIXUP_FUNC,
Takashi Iwai6e72aa52012-06-25 10:52:25 +02006921 .v.func = alc_fixup_inv_dmic_0x12,
Takashi Iwai125821a2012-06-22 14:30:29 +02006922 },
David Henningsson6cb3b702010-09-09 08:51:44 +02006923};
6924
Takashi Iwaia9111322011-05-02 11:30:18 +02006925static const struct snd_pci_quirk alc662_fixup_tbl[] = {
Takashi Iwai53c334a2011-08-23 18:27:14 +02006926 SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_FIXUP_ASUS_MODE2),
David Henningssona6c47a82011-02-10 15:39:19 +01006927 SND_PCI_QUIRK(0x1025, 0x0308, "Acer Aspire 8942G", ALC662_FIXUP_ASPIRE),
David Henningsson94024cd2011-04-29 14:10:55 +02006928 SND_PCI_QUIRK(0x1025, 0x031c, "Gateway NV79", ALC662_FIXUP_SKU_IGNORE),
Takashi Iwai125821a2012-06-22 14:30:29 +02006929 SND_PCI_QUIRK(0x1025, 0x0349, "eMachines eM250", ALC662_FIXUP_INV_DMIC),
Daniel T Chen2df03512010-10-10 22:39:28 -04006930 SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE),
Takashi Iwaie59ea3e2011-06-29 17:21:00 +02006931 SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800),
Takashi Iwai1565cc32012-02-13 12:03:25 +01006932 SND_PCI_QUIRK(0x1043, 0x8469, "ASUS mobo", ALC662_FIXUP_NO_JACK_DETECT),
Takashi Iwai53c334a2011-08-23 18:27:14 +02006933 SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_FIXUP_ASUS_MODE2),
Daniel T Chena0e90ac2010-11-20 10:20:35 -05006934 SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD),
Valentine Sinitsynd4118582010-10-01 22:24:08 +06006935 SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD),
David Henningsson6cb3b702010-09-09 08:51:44 +02006936 SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD),
David Henningssonedfe3bf2012-06-12 13:15:12 +02006937 SND_PCI_QUIRK(0x19da, 0xa130, "Zotac Z68", ALC662_FIXUP_ZOTAC_Z68),
Anisse Astierd2ebd472011-01-20 12:36:21 +01006938 SND_PCI_QUIRK(0x1b35, 0x2206, "CZC P10T", ALC662_FIXUP_CZC_P10T),
Takashi Iwai53c334a2011-08-23 18:27:14 +02006939
6940#if 0
6941 /* Below is a quirk table taken from the old code.
6942 * Basically the device should work as is without the fixup table.
6943 * If BIOS doesn't give a proper info, enable the corresponding
6944 * fixup entry.
Jesper Juhl7d7eb9e2012-04-12 22:11:25 +02006945 */
Takashi Iwai53c334a2011-08-23 18:27:14 +02006946 SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC662_FIXUP_ASUS_MODE1),
6947 SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC662_FIXUP_ASUS_MODE3),
6948 SND_PCI_QUIRK(0x1043, 0x1173, "ASUS K73Jn", ALC662_FIXUP_ASUS_MODE1),
6949 SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC662_FIXUP_ASUS_MODE3),
6950 SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC662_FIXUP_ASUS_MODE1),
6951 SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
6952 SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC662_FIXUP_ASUS_MODE1),
6953 SND_PCI_QUIRK(0x1043, 0x1303, "ASUS G60J", ALC662_FIXUP_ASUS_MODE1),
6954 SND_PCI_QUIRK(0x1043, 0x1333, "ASUS G60Jx", ALC662_FIXUP_ASUS_MODE1),
6955 SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
6956 SND_PCI_QUIRK(0x1043, 0x13e3, "ASUS N71JA", ALC662_FIXUP_ASUS_MODE7),
6957 SND_PCI_QUIRK(0x1043, 0x1463, "ASUS N71", ALC662_FIXUP_ASUS_MODE7),
6958 SND_PCI_QUIRK(0x1043, 0x14d3, "ASUS G72", ALC662_FIXUP_ASUS_MODE8),
6959 SND_PCI_QUIRK(0x1043, 0x1563, "ASUS N90", ALC662_FIXUP_ASUS_MODE3),
6960 SND_PCI_QUIRK(0x1043, 0x15d3, "ASUS N50SF F50SF", ALC662_FIXUP_ASUS_MODE1),
6961 SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
6962 SND_PCI_QUIRK(0x1043, 0x16f3, "ASUS K40C K50C", ALC662_FIXUP_ASUS_MODE2),
6963 SND_PCI_QUIRK(0x1043, 0x1733, "ASUS N81De", ALC662_FIXUP_ASUS_MODE1),
6964 SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
6965 SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC662_FIXUP_ASUS_MODE6),
6966 SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC662_FIXUP_ASUS_MODE6),
6967 SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
6968 SND_PCI_QUIRK(0x1043, 0x1793, "ASUS F50GX", ALC662_FIXUP_ASUS_MODE1),
6969 SND_PCI_QUIRK(0x1043, 0x17b3, "ASUS F70SL", ALC662_FIXUP_ASUS_MODE3),
6970 SND_PCI_QUIRK(0x1043, 0x17f3, "ASUS X58LE", ALC662_FIXUP_ASUS_MODE2),
6971 SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
6972 SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC662_FIXUP_ASUS_MODE5),
6973 SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC662_FIXUP_ASUS_MODE6),
6974 SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
6975 SND_PCI_QUIRK(0x1043, 0x1853, "ASUS F50Z", ALC662_FIXUP_ASUS_MODE1),
6976 SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
6977 SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
6978 SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC662_FIXUP_ASUS_MODE3),
6979 SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC662_FIXUP_ASUS_MODE3),
6980 SND_PCI_QUIRK(0x1043, 0x18b3, "ASUS N80Vc", ALC662_FIXUP_ASUS_MODE1),
6981 SND_PCI_QUIRK(0x1043, 0x18c3, "ASUS VX5", ALC662_FIXUP_ASUS_MODE1),
6982 SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS N81Te", ALC662_FIXUP_ASUS_MODE1),
6983 SND_PCI_QUIRK(0x1043, 0x18f3, "ASUS N505Tp", ALC662_FIXUP_ASUS_MODE1),
6984 SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC662_FIXUP_ASUS_MODE1),
6985 SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
6986 SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_FIXUP_ASUS_MODE2),
6987 SND_PCI_QUIRK(0x1043, 0x1943, "ASUS Vx3V", ALC662_FIXUP_ASUS_MODE1),
6988 SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC662_FIXUP_ASUS_MODE1),
6989 SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC662_FIXUP_ASUS_MODE3),
6990 SND_PCI_QUIRK(0x1043, 0x1983, "ASUS N5051A", ALC662_FIXUP_ASUS_MODE1),
6991 SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC662_FIXUP_ASUS_MODE1),
6992 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC662_FIXUP_ASUS_MODE1),
6993 SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_FIXUP_ASUS_MODE2),
6994 SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC662_FIXUP_ASUS_MODE1),
6995 SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC662_FIXUP_ASUS_MODE4),
6996#endif
David Henningsson6cb3b702010-09-09 08:51:44 +02006997 {}
6998};
6999
Todd Broch6be79482010-12-07 16:51:05 -08007000static const struct alc_model_fixup alc662_fixup_models[] = {
7001 {.id = ALC272_FIXUP_MARIO, .name = "mario"},
Takashi Iwai53c334a2011-08-23 18:27:14 +02007002 {.id = ALC662_FIXUP_ASUS_MODE1, .name = "asus-mode1"},
7003 {.id = ALC662_FIXUP_ASUS_MODE2, .name = "asus-mode2"},
7004 {.id = ALC662_FIXUP_ASUS_MODE3, .name = "asus-mode3"},
7005 {.id = ALC662_FIXUP_ASUS_MODE4, .name = "asus-mode4"},
7006 {.id = ALC662_FIXUP_ASUS_MODE5, .name = "asus-mode5"},
7007 {.id = ALC662_FIXUP_ASUS_MODE6, .name = "asus-mode6"},
7008 {.id = ALC662_FIXUP_ASUS_MODE7, .name = "asus-mode7"},
7009 {.id = ALC662_FIXUP_ASUS_MODE8, .name = "asus-mode8"},
Takashi Iwai6e72aa52012-06-25 10:52:25 +02007010 {.id = ALC662_FIXUP_INV_DMIC, .name = "inv-dmic"},
Todd Broch6be79482010-12-07 16:51:05 -08007011 {}
7012};
David Henningsson6cb3b702010-09-09 08:51:44 +02007013
Kailang Yang8663ff72012-06-29 09:35:52 +02007014static void alc662_fill_coef(struct hda_codec *codec)
7015{
7016 int val, coef;
7017
7018 coef = alc_get_coef0(codec);
7019
7020 switch (codec->vendor_id) {
7021 case 0x10ec0662:
7022 if ((coef & 0x00f0) == 0x0030) {
7023 val = alc_read_coef_idx(codec, 0x4); /* EAPD Ctrl */
7024 alc_write_coef_idx(codec, 0x4, val & ~(1<<10));
7025 }
7026 break;
7027 case 0x10ec0272:
7028 case 0x10ec0273:
7029 case 0x10ec0663:
7030 case 0x10ec0665:
7031 case 0x10ec0670:
7032 case 0x10ec0671:
7033 case 0x10ec0672:
7034 val = alc_read_coef_idx(codec, 0xd); /* EAPD Ctrl */
7035 alc_write_coef_idx(codec, 0xd, val | (1<<14));
7036 break;
7037 }
7038}
David Henningsson6cb3b702010-09-09 08:51:44 +02007039
Takashi Iwai1d045db2011-07-07 18:23:21 +02007040/*
7041 */
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007042static int patch_alc662(struct hda_codec *codec)
7043{
7044 struct alc_spec *spec;
Takashi Iwai3de95172012-05-07 18:03:15 +02007045 int err;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007046
Takashi Iwai3de95172012-05-07 18:03:15 +02007047 err = alc_alloc_spec(codec, 0x0b);
7048 if (err < 0)
7049 return err;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007050
Takashi Iwai3de95172012-05-07 18:03:15 +02007051 spec = codec->spec;
Takashi Iwai1f0f4b82011-06-27 10:52:59 +02007052
Takashi Iwai53c334a2011-08-23 18:27:14 +02007053 /* handle multiple HPs as is */
7054 spec->parse_flags = HDA_PINCFG_NO_HP_FIXUP;
7055
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02007056 alc_fix_pll_init(codec, 0x20, 0x04, 15);
7057
Kailang Yang8663ff72012-06-29 09:35:52 +02007058 spec->init_hook = alc662_fill_coef;
7059 alc662_fill_coef(codec);
7060
Takashi Iwai8e5a0502012-06-21 15:49:33 +02007061 alc_pick_fixup(codec, alc662_fixup_models,
7062 alc662_fixup_tbl, alc662_fixups);
7063 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
7064
7065 alc_auto_parse_customize_define(codec);
7066
Takashi Iwai1bb7e432011-10-17 16:50:59 +02007067 if ((alc_get_coef0(codec) & (1 << 14)) &&
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02007068 codec->bus->pci->subsystem_vendor == 0x1025 &&
7069 spec->cdefine.platform_type == 1) {
7070 if (alc_codec_rename(codec, "ALC272X") < 0)
7071 goto error;
Takashi Iwai20ca0c32011-10-17 16:00:35 +02007072 }
Kailang Yang274693f2009-12-03 10:07:50 +01007073
Takashi Iwaib9c51062011-08-24 18:08:07 +02007074 /* automatic parse from the BIOS config */
7075 err = alc662_parse_auto_config(codec);
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02007076 if (err < 0)
7077 goto error;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007078
Takashi Iwai3e6179b2011-07-08 16:55:13 +02007079 if (!spec->no_analog && has_cdefine_beep(codec)) {
7080 err = snd_hda_attach_beep_device(codec, 0x1);
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02007081 if (err < 0)
7082 goto error;
Kailang Yangda00c242010-03-19 11:23:45 +01007083 switch (codec->vendor_id) {
7084 case 0x10ec0662:
7085 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
7086 break;
7087 case 0x10ec0272:
7088 case 0x10ec0663:
7089 case 0x10ec0665:
7090 set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
7091 break;
7092 case 0x10ec0273:
7093 set_beep_amp(spec, 0x0b, 0x03, HDA_INPUT);
7094 break;
7095 }
Kailang Yangcec27c82010-02-04 14:18:18 +01007096 }
Takashi Iwai2134ea42008-01-10 16:53:55 +01007097
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007098 codec->patch_ops = alc_patch_ops;
Takashi Iwai1c716152011-04-07 10:37:16 +02007099 spec->shutup = alc_eapd_shutup;
David Henningsson6cb3b702010-09-09 08:51:44 +02007100
Takashi Iwai589876e2012-02-20 15:47:55 +01007101 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
7102
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007103 return 0;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007104
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02007105 error:
7106 alc_free(codec);
7107 return err;
Kailang Yangb478b992011-05-18 11:51:15 +02007108}
7109
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007110/*
Kailang Yangd1eb57f2010-06-23 16:25:26 +02007111 * ALC680 support
7112 */
Kailang Yangd1eb57f2010-06-23 16:25:26 +02007113
Kailang Yangd1eb57f2010-06-23 16:25:26 +02007114static int alc680_parse_auto_config(struct hda_codec *codec)
7115{
Takashi Iwai3e6179b2011-07-08 16:55:13 +02007116 return alc_parse_auto_config(codec, NULL, NULL);
Kailang Yangd1eb57f2010-06-23 16:25:26 +02007117}
7118
Kailang Yangd1eb57f2010-06-23 16:25:26 +02007119/*
Kailang Yangd1eb57f2010-06-23 16:25:26 +02007120 */
Kailang Yangd1eb57f2010-06-23 16:25:26 +02007121static int patch_alc680(struct hda_codec *codec)
7122{
Kailang Yangd1eb57f2010-06-23 16:25:26 +02007123 int err;
7124
Takashi Iwai1f0f4b82011-06-27 10:52:59 +02007125 /* ALC680 has no aa-loopback mixer */
Takashi Iwai3de95172012-05-07 18:03:15 +02007126 err = alc_alloc_spec(codec, 0);
7127 if (err < 0)
7128 return err;
Takashi Iwai1f0f4b82011-06-27 10:52:59 +02007129
Takashi Iwai1ebec5f2011-08-15 13:21:48 +02007130 /* automatic parse from the BIOS config */
7131 err = alc680_parse_auto_config(codec);
7132 if (err < 0) {
7133 alc_free(codec);
7134 return err;
Kailang Yangd1eb57f2010-06-23 16:25:26 +02007135 }
7136
Kailang Yangd1eb57f2010-06-23 16:25:26 +02007137 codec->patch_ops = alc_patch_ops;
Kailang Yangd1eb57f2010-06-23 16:25:26 +02007138
7139 return 0;
7140}
7141
7142/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07007143 * patch entries
7144 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007145static const struct hda_codec_preset snd_hda_preset_realtek[] = {
Kailang Yang296f0332011-05-18 11:52:36 +02007146 { .id = 0x10ec0221, .name = "ALC221", .patch = patch_alc269 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07007147 { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
Kailang Yangdf694da2005-12-05 19:42:22 +01007148 { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
Kailang Yangf6a92242007-12-13 16:52:54 +01007149 { .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 },
Kailang Yanga361d842007-06-05 12:30:55 +02007150 { .id = 0x10ec0268, .name = "ALC268", .patch = patch_alc268 },
Kailang Yangf6a92242007-12-13 16:52:54 +01007151 { .id = 0x10ec0269, .name = "ALC269", .patch = patch_alc269 },
Kailang Yangebb83ee2009-12-17 12:23:00 +01007152 { .id = 0x10ec0270, .name = "ALC270", .patch = patch_alc269 },
Kailang Yang01afd412008-10-15 11:22:09 +02007153 { .id = 0x10ec0272, .name = "ALC272", .patch = patch_alc662 },
Kailang Yangebb83ee2009-12-17 12:23:00 +01007154 { .id = 0x10ec0275, .name = "ALC275", .patch = patch_alc269 },
Kailang Yang296f0332011-05-18 11:52:36 +02007155 { .id = 0x10ec0276, .name = "ALC276", .patch = patch_alc269 },
David Henningssonbefae822012-06-25 19:49:28 +02007156 { .id = 0x10ec0280, .name = "ALC280", .patch = patch_alc269 },
David Henningsson4e01ec62012-07-18 07:38:46 +02007157 { .id = 0x10ec0282, .name = "ALC282", .patch = patch_alc269 },
Kailang Yang7ff34ad2012-10-06 17:02:30 +02007158 { .id = 0x10ec0283, .name = "ALC283", .patch = patch_alc269 },
Kailang Yang065380f2013-01-10 10:25:48 +01007159 { .id = 0x10ec0284, .name = "ALC284", .patch = patch_alc269 },
Kailang Yang7ff34ad2012-10-06 17:02:30 +02007160 { .id = 0x10ec0290, .name = "ALC290", .patch = patch_alc269 },
David Henningssonaf02dde2012-11-21 08:57:58 +01007161 { .id = 0x10ec0292, .name = "ALC292", .patch = patch_alc269 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +01007162 { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007163 .patch = patch_alc861 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +01007164 { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
7165 { .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 },
7166 { .id = 0x10ec0862, .name = "ALC861-VD", .patch = patch_alc861vd },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007167 { .id = 0x10ec0662, .rev = 0x100002, .name = "ALC662 rev2",
Takashi Iwai4953550a2009-06-30 15:28:30 +02007168 .patch = patch_alc882 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007169 { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1",
7170 .patch = patch_alc662 },
David Henningssoncc667a72011-10-18 14:07:51 +02007171 { .id = 0x10ec0662, .rev = 0x100300, .name = "ALC662 rev3",
7172 .patch = patch_alc662 },
Kailang Yang6dda9f42008-05-27 12:05:31 +02007173 { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 },
Kailang Yangcec27c82010-02-04 14:18:18 +01007174 { .id = 0x10ec0665, .name = "ALC665", .patch = patch_alc662 },
Kailang Yang19a62822012-11-08 10:25:37 +01007175 { .id = 0x10ec0668, .name = "ALC668", .patch = patch_alc662 },
Kailang Yang6227cdc2010-02-25 08:36:52 +01007176 { .id = 0x10ec0670, .name = "ALC670", .patch = patch_alc662 },
Kailang Yangd1eb57f2010-06-23 16:25:26 +02007177 { .id = 0x10ec0680, .name = "ALC680", .patch = patch_alc680 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +01007178 { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07007179 { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
Takashi Iwai4953550a2009-06-30 15:28:30 +02007180 { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc882 },
Clive Messer669faba2008-09-30 15:49:13 +02007181 { .id = 0x10ec0885, .rev = 0x100101, .name = "ALC889A",
Takashi Iwai4953550a2009-06-30 15:28:30 +02007182 .patch = patch_alc882 },
Takashi Iwaicb308f92008-04-16 14:13:29 +02007183 { .id = 0x10ec0885, .rev = 0x100103, .name = "ALC889A",
Takashi Iwai4953550a2009-06-30 15:28:30 +02007184 .patch = patch_alc882 },
Kailang Yangdf694da2005-12-05 19:42:22 +01007185 { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02007186 { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc882 },
Kailang Yang44426082008-10-15 11:18:05 +02007187 { .id = 0x10ec0888, .rev = 0x100101, .name = "ALC1200",
Takashi Iwai4953550a2009-06-30 15:28:30 +02007188 .patch = patch_alc882 },
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02007189 { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc882 },
Takashi Iwai4953550a2009-06-30 15:28:30 +02007190 { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc882 },
Kailang Yang274693f2009-12-03 10:07:50 +01007191 { .id = 0x10ec0892, .name = "ALC892", .patch = patch_alc662 },
Takashi Iwaie16fb6d2011-10-17 16:39:09 +02007192 { .id = 0x10ec0899, .name = "ALC898", .patch = patch_alc882 },
Kailang Yang19a62822012-11-08 10:25:37 +01007193 { .id = 0x10ec0900, .name = "ALC1150", .patch = patch_alc882 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07007194 {} /* terminator */
7195};
Takashi Iwai1289e9e2008-11-27 15:47:11 +01007196
7197MODULE_ALIAS("snd-hda-codec-id:10ec*");
7198
7199MODULE_LICENSE("GPL");
7200MODULE_DESCRIPTION("Realtek HD-audio codec");
7201
7202static struct hda_codec_preset_list realtek_list = {
7203 .preset = snd_hda_preset_realtek,
7204 .owner = THIS_MODULE,
7205};
7206
7207static int __init patch_realtek_init(void)
7208{
7209 return snd_hda_add_codec_preset(&realtek_list);
7210}
7211
7212static void __exit patch_realtek_exit(void)
7213{
7214 snd_hda_delete_codec_preset(&realtek_list);
7215}
7216
7217module_init(patch_realtek_init)
7218module_exit(patch_realtek_exit)